# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet v2.5.69 -> 1.1104 # drivers/video/fbmem.c 1.74 -> 1.75 # drivers/i2c/chips/w83781d.c 1.5 -> 1.6 # drivers/hotplug/cpqphp_core.c 1.15.1.1 -> 1.17 # arch/alpha/kernel/entry.S 1.28 -> 1.29 # net/ipv4/netfilter/ip_conntrack_core.c 1.28 -> 1.29 # arch/ia64/lib/io.c 1.3 -> 1.5 # include/asm-i386/mpspec.h 1.11 -> 1.12 # Documentation/DocBook/kernel-api.tmpl 1.23.1.2 -> 1.25 # include/linux/file.h 1.9 -> 1.10 # arch/ppc64/kernel/signal.c 1.26 -> 1.27 # include/linux/proc_fs.h 1.15 -> 1.17 # drivers/i2c/chips/lm75.c 1.14 -> 1.15 # arch/i386/kernel/timers/Makefile 1.6 -> 1.7 # drivers/atm/horizon.c 1.10 -> 1.11 # drivers/media/video/tda9887.c 1.5 -> 1.6 # include/linux/netfilter_ipv4/ip_nat_core.h 1.1 -> 1.2 # drivers/block/acsi_slm.c 1.11 -> 1.12 # arch/i386/mm/fault.c 1.24 -> 1.26 # include/asm-ppc/hardirq.h 1.18 -> 1.19 # include/asm-ppc/elf.h 1.8 -> 1.9 # drivers/char/esp.c 1.18 -> 1.19 # sound/oss/opl3sa2.c 1.20 -> 1.21 # arch/i386/lib/usercopy.c 1.11 -> 1.12 # include/net/dn_dev.h 1.4 -> 1.5 # drivers/usb/misc/usblcd.c 1.7 -> 1.8 # include/asm-i386/system.h 1.27.1.1 -> 1.29 # net/bluetooth/rfcomm/core.c 1.17 -> 1.18 # drivers/scsi/scsi_error.c 1.48 -> 1.49 # net/ipx/ipx_proc.c 1.2 -> 1.5 # include/linux/agpgart.h 1.2 -> 1.4 # drivers/ide/ide-taskfile.c 1.16 -> 1.18 # drivers/char/vme_scc.c 1.16 -> 1.17 # arch/x86_64/kernel/traps.c 1.19 -> 1.20 # arch/ia64/kernel/palinfo.c 1.13 -> 1.14 # drivers/usb/misc/tiglusb.c 1.17 -> 1.19 # include/asm-ppc64/page.h 1.18 -> 1.19 # drivers/ieee1394/raw1394.c 1.24 -> 1.25 # drivers/char/lp.c 1.25 -> 1.26 # include/linux/pagemap.h 1.35 -> 1.36 # net/ipv4/netfilter/ip_nat_proto_tcp.c 1.3 -> 1.4 # kernel/ksyms.c 1.195 -> 1.199 # include/asm-ppc64/unistd.h 1.19 -> 1.20 # include/linux/if_frad.h 1.2 -> 1.3 # arch/m68k/kernel/entry.S 1.11 -> 1.12 # include/asm-mips64/elf.h 1.5 -> 1.6 # include/net/sctp/user.h 1.9 -> 1.10 # arch/ppc64/kernel/entry.S 1.24 -> 1.26 # drivers/i2c/chips/adm1021.c 1.15 -> 1.16 # net/ipv4/proc.c 1.11 -> 1.12 # arch/i386/kernel/cpu/cpufreq/powernow-k7.c 1.9 -> 1.12 # include/linux/sysrq.h 1.4 -> 1.5 # drivers/net/wan/cosa.c 1.20 -> 1.21 # fs/select.c 1.19 -> 1.20 # drivers/sbus/char/bpp.c 1.13 -> 1.14 # include/asm-ia64/machvec_init.h 1.4 -> 1.6 # drivers/usb/media/dabusb.h 1.5 -> 1.6 # include/linux/elevator.h 1.19 -> 1.20 # drivers/char/isicom.c 1.17 -> 1.18 # include/linux/swap.h 1.76 -> 1.77 # include/asm-i386/edd.h 1.4 -> 1.5 # drivers/net/bmac.c 1.13 -> 1.14 # net/sctp/associola.c 1.38.1.1 -> 1.45 # include/net/dn_route.h 1.6 -> 1.7 # net/ipv4/xfrm4_state.c 1.3 -> 1.4 # arch/ia64/Makefile 1.42 -> 1.44 # drivers/atm/Makefile 1.17 -> 1.19 # arch/ia64/kernel/efi.c 1.19 -> 1.20 # arch/m68k/sun3/prom/printf.c 1.1 -> 1.2 # include/asm-i386/processor.h 1.48 -> 1.50 # net/ipv6/exthdrs.c 1.9 -> 1.10 # fs/file_table.c 1.23 -> 1.24 # net/core/neighbour.c 1.11 -> 1.13 # drivers/char/agp/sis-agp.c 1.15 -> 1.19 # arch/ia64/kernel/fw-emu.c 1.7 -> 1.8 # arch/i386/kernel/apm.c 1.50 -> 1.51 # lib/Makefile 1.21 -> 1.22 # fs/open.c 1.38 -> 1.39 # arch/i386/kernel/cpu/cpufreq/longhaul.c 1.17 -> 1.18 # include/asm-i386/fixmap.h 1.11 -> 1.12 # net/sctp/objcnt.c 1.5 -> 1.6 # drivers/net/skfp/skfddi.c 1.11 -> 1.12 # net/Kconfig 1.11 -> 1.12 # include/asm-ia64/acpi-ext.h 1.1 -> 1.2 # include/asm-ia64/io.h 1.9 -> 1.11 # net/sctp/input.c 1.25 -> 1.28 # arch/ppc64/kernel/udbg.c 1.7 -> 1.8 # net/ipv6/ip6_output.c 1.20 -> 1.21 # drivers/net/sb1000.c 1.16 -> 1.17 # drivers/scsi/aic7xxx/aic7xxx_pci.c 1.12 -> 1.13 # drivers/media/video/mxb.c 1.3 -> 1.4 # net/ipv4/ip_input.c 1.14 -> 1.15 # drivers/net/sk98lin/skproc.c 1.5 -> 1.6 # net/sctp/sm_statefuns.c 1.41.1.1 -> 1.48 # arch/i386/kernel/irq.c 1.34 -> 1.36 # include/linux/raid/md.h 1.26 -> 1.27 # include/asm-m68knommu/hardirq.h 1.2 -> 1.3 # mm/page_alloc.c 1.154 -> 1.156 # include/asm-ppc64/processor.h 1.27 -> 1.29 # include/asm-ia64/spinlock.h 1.9 -> 1.11 # drivers/char/random.c 1.32 -> 1.33 # net/bridge/br_fdb.c 1.5 -> 1.6 # drivers/char/dz.c 1.18 -> 1.20 # arch/sparc/kernel/sparc_ksyms.c 1.17 -> 1.18 # drivers/input/serio/i8042.c 1.26 -> 1.27 # arch/i386/kernel/smp.c 1.30 -> 1.31 # fs/ext3/Makefile 1.9 -> 1.10 # include/net/ipx.h 1.6 -> 1.9 # net/llc/llc_proc.c 1.9 -> 1.10 # drivers/net/pcmcia/nmclan_cs.c 1.13 -> 1.14 # arch/alpha/kernel/core_marvel.c 1.9 -> 1.10 # arch/i386/kernel/head.S 1.26 -> 1.27 # kernel/fork.c 1.118 -> 1.119 # include/linux/sched.h 1.142 -> 1.144 # drivers/ide/ppc/pmac.c 1.10 -> 1.12 # include/asm-ia64/machvec_hpzx1.h 1.6 -> 1.7 # include/linux/ptrace.h 1.8 -> 1.9 # include/asm-ppc64/module.h 1.2 -> 1.3 # drivers/block/ll_rw_blk.c 1.168 -> 1.169 # arch/i386/kernel/vm86.c 1.25 -> 1.26 # kernel/sysctl.c 1.41 -> 1.42 # net/ipv4/xfrm4_tunnel.c 1.4 -> 1.5 # drivers/atm/ambassador.c 1.11 -> 1.12 # drivers/i2c/chips/via686a.c 1.6 -> 1.7 # drivers/media/video/bttv-if.c 1.11 -> 1.13 # drivers/isdn/eicon/eicon_mod.c 1.12 -> 1.13 # drivers/media/video/bttv.h 1.9 -> 1.10 # include/asm-ppc64/ucontext.h 1.2 -> 1.3 # arch/ppc64/kernel/chrp_setup.c 1.21.2.2 -> 1.27 # drivers/media/video/videodev.c 1.19 -> 1.20 # include/net/sctp/ulpevent.h 1.7 -> 1.9 # include/asm-ia64/page.h 1.15 -> 1.17 # net/ipv4/protocol.c 1.5 -> 1.7 # net/bridge/br_ioctl.c 1.8 -> 1.9 # fs/dcache.c 1.51 -> 1.52 # net/sctp/endpointola.c 1.19 -> 1.23 # net/ipv4/af_inet.c 1.44 -> 1.47 # mm/vmscan.c 1.156 -> 1.157 # drivers/isdn/hardware/eicon/divasmain.c 1.8 -> 1.9 # arch/ia64/kernel/setup.c 1.37.1.1 -> 1.41 # arch/um/drivers/mmapper_kern.c 1.4 -> 1.5 # net/ipv6/netfilter/ip6t_ah.c 1.4 -> 1.5 # net/atm/Makefile 1.7 -> 1.8 # drivers/char/agp/frontend.c 1.31 -> 1.37 # include/net/iw_handler.h 1.5 -> 1.6 # net/sctp/sm_make_chunk.c 1.34.1.1 -> 1.46 # arch/sparc/kernel/process.c 1.24 -> 1.25 # include/asm-v850/hardirq.h 1.2 -> 1.3 # drivers/i2c/i2c-core.c 1.32 -> 1.37 # drivers/net/sk98lin/skge.c 1.15 -> 1.16 # drivers/char/agp/generic-3.0.c 1.9 -> 1.14 # arch/ia64/hp/common/sba_iommu.c 1.11 -> 1.20 # arch/ppc64/kernel/rtas.c 1.9 -> 1.11 # drivers/ieee1394/video1394.c 1.34 -> 1.35 # arch/i386/Kconfig 1.56 -> 1.57 # drivers/isdn/hisax/elsa.c 1.37 -> 1.38 # net/ipv4/netfilter/ip_nat_core.c 1.22 -> 1.26 # include/asm-i386/uaccess.h 1.23 -> 1.24 # include/linux/elf.h 1.22 -> 1.23 # drivers/media/video/saa7134/saa7134-i2c.c 1.7 -> 1.9 # arch/ia64/lib/do_csum.S 1.9 -> 1.10 # net/ipv4/netfilter/ip_nat_helper.c 1.12 -> 1.13 # net/x25/x25_proc.c 1.2 -> 1.3 # net/ipx/af_ipx.c 1.29 -> 1.32 # net/ipv4/udp.c 1.35 -> 1.36 # net/sctp/ulpevent.c 1.14 -> 1.18 # net/ipv6/protocol.c 1.3 -> 1.5 # arch/i386/kernel/traps.c 1.51 -> 1.52 # fs/devfs/base.c 1.87 -> 1.88 # init/main.c 1.98 -> 1.99 # fs/intermezzo/sysctl.c 1.8 -> 1.9 # include/asm-i386/numnodes.h 1.3 -> 1.4 # arch/ia64/lib/copy_user.S 1.7 -> 1.8 # arch/mips/arc/misc.c 1.3 -> 1.4 # arch/i386/kernel/Makefile 1.39 -> 1.40 # net/ipv4/fib_semantics.c 1.10 -> 1.11 # include/linux/i2c.h 1.25 -> 1.30 # net/ipv4/netfilter/ip_nat_proto_udp.c 1.1 -> 1.3 # drivers/usb/class/usblp.c 1.42 -> 1.44 # fs/stat.c 1.18 -> 1.19 # include/linux/signal.h 1.10 -> 1.11 # drivers/usb/Kconfig 1.2 -> 1.3 # include/asm-i386/mach-summit/mach_ipi.h 1.2 -> 1.3 # drivers/char/drm/radeon_cp.c 1.18 -> 1.19 # include/asm-ia64/atomic.h 1.5 -> 1.6 # arch/i386/vmlinux.lds.S 1.29 -> 1.30 # net/sctp/transport.c 1.16.1.1 -> 1.20 # include/asm-x86_64/hardirq.h 1.3 -> 1.4 # include/linux/cpu.h 1.5 -> 1.6 # drivers/media/dvb/dvb-core/dvbdev.c 1.8 -> 1.10 # mm/swapfile.c 1.77 -> 1.78 # include/asm-ppc64/sigcontext.h 1.3 -> 1.4 # drivers/net/wan/x25_asy.c 1.5 -> 1.6 # net/sctp/output.c 1.23 -> 1.30 # net/sctp/Kconfig 1.3 -> 1.5 # kernel/cpufreq.c 1.29 -> 1.30 # drivers/char/cyclades.c 1.21 -> 1.22 # drivers/atm/nicstar.c 1.15 -> 1.17 # arch/ia64/kernel/time.c 1.19 -> 1.21 # include/asm-ia64/mca.h 1.6 -> 1.7 # security/dummy.c 1.19 -> 1.20 # net/bridge/br_stp.c 1.5 -> 1.6 # drivers/atm/eni.c 1.12 -> 1.13 # net/ipv6/netfilter/ip6t_frag.c 1.4 -> 1.5 # include/linux/blkdev.h 1.102 -> 1.104 # net/bridge/br_private.h 1.12 -> 1.13 # include/net/ip6_route.h 1.7 -> 1.8 # drivers/atm/zatm.c 1.11 -> 1.12 # net/decnet/Makefile 1.5 -> 1.6 # drivers/serial/core.c 1.59 -> 1.60 # include/asm-m68k/elf.h 1.2 -> 1.3 # arch/i386/kernel/cpu/mtrr/if.c 1.5 -> 1.6 # include/net/compat.h 1.3 -> 1.4 # include/linux/major.h 1.8 -> 1.9 # net/bluetooth/sco.c 1.15 -> 1.16 # arch/ia64/kernel/smpboot.c 1.28 -> 1.32 # net/key/af_key.c 1.33 -> 1.35 # drivers/mtd/maps/sa1100-flash.c 1.9 -> 1.10 # arch/ppc64/kernel/LparData.c 1.8 -> 1.9 # net/bridge/br_input.c 1.10 -> 1.11 # include/linux/fs.h 1.238 -> 1.242 # drivers/atm/lanai.c 1.9 -> 1.10 # arch/ia64/kernel/entry.S 1.39 -> 1.40 # include/asm-ia64/hardirq.h 1.11 -> 1.12 # include/linux/capability.h 1.5 -> 1.6 # net/decnet/dn_table.c 1.5 -> 1.6 # include/linux/netfilter_ipv4/ip_nat_helper.h 1.4 -> 1.5 # drivers/block/paride/pt.c 1.15 -> 1.16 # drivers/sgi/char/sgiserial.c 1.12 -> 1.13 # drivers/usb/image/scanner.c 1.57 -> 1.59 # include/net/sctp/sctp.h 1.30 -> 1.37 # net/ipv6/netfilter/ip6t_rt.c 1.4 -> 1.5 # net/bluetooth/hci_proc.c 1.2 -> 1.3 # fs/sysv/dir.c 1.14 -> 1.15 # net/bridge/br_private_timer.h 1.1 -> (deleted) # drivers/char/ser_a2232.c 1.8 -> 1.9 # drivers/char/n_hdlc.c 1.14 -> 1.15 # fs/udf/dir.c 1.12 -> 1.13 # arch/i386/kernel/ptrace.c 1.19 -> 1.20 # drivers/atm/nicstar.h 1.3 -> 1.5 # drivers/net/mace.c 1.13 -> 1.14 # include/asm-ppc64/types.h 1.2 -> 1.3 # drivers/char/vc_screen.c 1.9 -> 1.10 # drivers/ide/ide.c 1.59 -> 1.61 # drivers/md/md.c 1.166 -> 1.167 # net/atm/proc.c 1.9 -> 1.10 # arch/i386/kernel/reboot.c 1.7 -> 1.8 # net/ipv6/icmp.c 1.26 -> 1.28 # drivers/i2c/busses/i2c-piix4.c 1.8 -> 1.9 # include/net/sctp/ulpqueue.h 1.9 -> 1.10 # net/sunrpc/rpc_pipe.c 1.8 -> 1.9 # arch/ppc64/kernel/ras.c 1.3 -> 1.4 # arch/mips/au1000/common/serial.c 1.15 -> 1.16 # net/ipv4/netfilter/ip_nat_tftp.c 1.2 -> 1.3 # mm/bootmem.c 1.15 -> 1.16 # arch/i386/kernel/mpparse.c 1.39 -> 1.40 # include/asm-ia64/uaccess.h 1.8 -> 1.9 # drivers/char/agp/Makefile 1.19 -> 1.22 # include/asm-ppc64/machdep.h 1.14 -> 1.16 # net/ipv4/netfilter/ip_nat_proto_icmp.c 1.1 -> 1.3 # net/sctp/outqueue.c 1.26 -> 1.34 # include/linux/brlvger.h 1.3 -> 1.4 # net/ipv4/tcp_ipv4.c 1.51 -> 1.52 # drivers/media/video/tvaudio.c 1.17 -> 1.18 # arch/i386/kernel/io_apic.c 1.64 -> 1.65 # drivers/ide/ide-tape.c 1.22 -> 1.23 # net/8021q/vlanproc.c 1.9 -> 1.11 # drivers/hotplug/acpiphp_glue.c 1.8 -> 1.9 # include/asm-sparc64/elf.h 1.13 -> 1.14 # drivers/usb/media/vicam.c 1.34 -> 1.35 # net/decnet/dn_dev.c 1.10 -> 1.12 # include/net/sctp/constants.h 1.12 -> 1.14 # mm/filemap.c 1.191 -> 1.193 # drivers/acpi/acpi_ksyms.c 1.23 -> 1.24 # include/linux/ppp_defs.h 1.1 -> 1.2 # net/decnet/dn_nsp_in.c 1.9 -> 1.10 # fs/namei.c 1.71 -> 1.72 # arch/s390/kernel/traps.c 1.17 -> 1.18 # drivers/isdn/hisax/avm_pci.c 1.42 -> 1.43 # arch/sparc64/solaris/socksys.c 1.11 -> 1.12 # fs/coda/sysctl.c 1.9 -> 1.10 # drivers/hotplug/cpqphp_ctrl.c 1.9.1.1 -> 1.11 # arch/s390/math-emu/math.c 1.6 -> 1.7 # drivers/char/agp/generic.c 1.25 -> 1.35 # drivers/isdn/i4l/isdn_common.c 1.73 -> 1.74 # arch/ia64/ia32/ia32_traps.c 1.4 -> 1.5 # arch/i386/Makefile 1.50 -> 1.51 # net/socket.c 1.56 -> 1.60 # include/asm-ia64/processor.h 1.34 -> 1.36 # drivers/char/synclink.c 1.34 -> 1.35 # drivers/scsi/aic7xxx/aic7xxx_osm.h 1.35 -> 1.37 # include/asm-ppc/spinlock.h 1.11 -> 1.12 # arch/ia64/hp/zx1/hpzx1_machvec.c 1.3 -> 1.4 # arch/cris/drivers/eeprom.c 1.10 -> 1.11 # drivers/isdn/hardware/eicon/divasi.c 1.5 -> 1.6 # drivers/char/agp/sworks-agp.c 1.22 -> 1.28 # include/linux/brlock.h 1.8 -> (deleted) # arch/i386/kernel/dmi_scan.c 1.32 -> 1.33 # drivers/media/video/bttvp.h 1.10 -> 1.11 # net/sctp/proc.c 1.2 -> 1.3 # include/linux/ide.h 1.48 -> 1.50 # drivers/char/rio/riotty.c 1.8 -> 1.9 # include/asm-ia64/machvec_sn2.h 1.7 -> 1.8 # include/asm-ppc64/proc_fs.h 1.1 -> 1.2 # net/ipv4/netfilter/ip_fw_compat.c 1.15 -> 1.17 # net/sunrpc/clnt.c 1.34 -> 1.37 # drivers/net/pcmcia/xirc2ps_cs.c 1.17 -> 1.18 # drivers/char/ftape/zftape/zftape-init.c 1.17 -> 1.18 # net/netlink/netlink_dev.c 1.15 -> 1.16 # drivers/isdn/hisax/niccy.c 1.29 -> 1.30 # fs/nfsd/vfs.c 1.60 -> 1.61 # arch/i386/kernel/suspend_asm.S 1.4 -> 1.5 # net/ipv6/raw.c 1.23 -> 1.25 # arch/ia64/kernel/irq_ia64.c 1.11 -> 1.12 # include/linux/sem.h 1.5 -> 1.6 # drivers/usb/image/scanner.h 1.33 -> 1.35 # kernel/signal.c 1.80 -> 1.82 # include/linux/net.h 1.15 -> 1.16 # net/ipv6/proc.c 1.11 -> 1.12 # drivers/char/keyboard.c 1.30 -> 1.31 # drivers/usb/misc/auerswald.c 1.29 -> 1.30 # arch/um/kernel/mem.c 1.15 -> 1.16 # net/netsyms.c 1.66 -> 1.71 # net/ipv4/netfilter/ipfwadm_core.c 1.14 -> 1.15 # net/ipv6/xfrm6_state.c 1.3 -> 1.4 # drivers/media/video/dpc7146.c 1.1 -> 1.2 # include/asm-i386/mach-bigsmp/mach_ipi.h 1.1 -> 1.2 # include/linux/pci_ids.h 1.91.1.1 -> 1.96 # drivers/ide/ide-disk.c 1.40 -> 1.42 # drivers/usb/serial/usb-serial.c 1.77 -> 1.78 # fs/xattr.c 1.13 -> 1.14 # drivers/hotplug/Kconfig 1.6 -> 1.7 # include/asm-ia64/system.h 1.34 -> 1.35 # include/asm-i386/mach-numaq/mach_apic.h 1.14 -> 1.15 # include/net/protocol.h 1.9 -> 1.10 # drivers/char/dtlk.c 1.11 -> 1.12 # drivers/usb/input/hiddev.c 1.31 -> 1.32 # arch/ia64/mm/init.c 1.33 -> 1.35 # mm/shmem.c 1.117 -> 1.119 # drivers/char/agp/agp.h 1.49 -> 1.62 # arch/x86_64/kernel/irq.c 1.13 -> 1.14 # include/asm-mips/elf.h 1.4 -> 1.5 # include/linux/usb.h 1.75 -> 1.77 # drivers/char/serial167.c 1.21 -> 1.22 # drivers/media/video/tda9875.c 1.12 -> 1.13 # include/asm-i386/mach-summit/mach_mpparse.h 1.5 -> 1.6 # arch/ppc64/kernel/irq.c 1.23 -> 1.25 # arch/sparc/mm/init.c 1.19 -> 1.20 # include/linux/input.h 1.29 -> 1.30 # arch/ia64/hp/zx1/hpzx1_misc.c 1.13 -> (deleted) # drivers/ide/ide-cd.c 1.43 -> 1.44 # fs/super.c 1.100 -> 1.101 # arch/ia64/pci/pci.c 1.26 -> 1.29 # drivers/atm/Kconfig 1.3 -> 1.4 # include/asm-ia64/serial.h 1.2 -> 1.3 # fs/binfmt_elf.c 1.44 -> 1.45 # include/net/sctp/sm.h 1.21 -> 1.24 # arch/i386/kernel/signal.c 1.31 -> 1.32 # drivers/scsi/sg.c 1.52 -> 1.53 # drivers/char/riscom8.c 1.14 -> 1.15 # net/sched/sch_atm.c 1.9 -> 1.10 # arch/ia64/kernel/ia64_ksyms.c 1.21 -> 1.23 # include/linux/blkpg.h 1.4 -> 1.5 # lib/inflate.c 1.2 -> 1.3 # drivers/usb/usb-skeleton.c 1.32 -> 1.35 # arch/ia64/kernel/efivars.c 1.10 -> 1.11 # drivers/net/acenic.c 1.28 -> 1.29 # arch/ppc64/kernel/rtas-proc.c 1.4 -> 1.6 # arch/ppc64/kernel/setup.c 1.21.1.1 -> 1.24 # arch/ia64/kernel/mca.c 1.22 -> 1.29 # arch/ia64/kernel/iosapic.c 1.23 -> 1.27 # arch/i386/kernel/acpi/sleep.c 1.2 -> 1.3 # arch/i386/kernel/ioport.c 1.7 -> 1.8 # arch/i386/kernel/setup.c 1.79 -> 1.81 # drivers/scsi/osst.c 1.42 -> 1.43 # fs/cifs/cifs_debug.c 1.8 -> 1.9 # arch/ia64/kernel/process.c 1.30 -> 1.34 # net/wanrouter/wanproc.c 1.15 -> 1.16 # fs/ncpfs/ncplib_kernel.c 1.10 -> 1.11 # drivers/atm/idt77252.c 1.10 -> 1.12 # arch/i386/kernel/smpboot.c 1.57 -> 1.58 # arch/ppc/kernel/process.c 1.32 -> 1.33 # include/asm-m68k/hardirq.h 1.3 -> 1.4 # net/ipv4/fib_hash.c 1.11 -> 1.12 # arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 1.7 -> 1.8 # drivers/char/tpqic02.c 1.22 -> 1.23 # arch/ia64/hp/sim/simserial.c 1.15 -> 1.16 # fs/nfs/dir.c 1.54 -> 1.55 # drivers/char/agp/intel-agp.c 1.26 -> 1.37 # arch/ia64/kernel/acpi.c 1.36 -> 1.40 # include/asm-ppc64/naca.h 1.5 -> 1.6 # arch/ia64/kernel/machvec.c 1.4 -> 1.5 # include/asm-ia64/kmap_types.h 1.4 -> 1.5 # net/econet/af_econet.c 1.17 -> 1.18 # drivers/input/joydev.c 1.17 -> 1.18 # sound/oss/soundcard.c 1.15 -> 1.16 # drivers/i2c/busses/i2c-i801.c 1.8 -> 1.9 # include/net/dn_fib.h 1.3 -> 1.5 # include/linux/tty.h 1.15 -> 1.16 # drivers/usb/input/xpad.c 1.13 -> 1.14 # ipc/shm.c 1.25 -> 1.27 # include/asm-alpha/elf.h 1.4 -> 1.5 # include/asm-i386/mmzone.h 1.11 -> 1.12 # drivers/net/wan/dlci.c 1.9 -> 1.10 # drivers/ide/arm/icside.c 1.6 -> 1.8 # net/core/dev.c 1.68 -> 1.71 # net/xfrm/xfrm_policy.c 1.24 -> 1.25 # drivers/ide/ide-dma.c 1.13 -> 1.15 # drivers/char/mem.c 1.35 -> 1.36 # drivers/usb/core/usb.c 1.122 -> 1.123 # drivers/usb/misc/brlvger.c 1.16 -> 1.17 # drivers/i2c/busses/i2c-ali15x3.c 1.7 -> 1.8 # arch/ppc64/kernel/traps.c 1.14 -> 1.16 # drivers/char/dsp56k.c 1.12 -> 1.13 # net/bridge/br_stp_timer.c 1.3 -> 1.4 # arch/ppc64/kernel/head.S 1.26 -> 1.31 # drivers/net/depca.c 1.18 -> 1.19 # drivers/isdn/hardware/eicon/divamnt.c 1.5 -> 1.6 # include/asm-ppc64/xics.h 1.4 -> 1.5 # drivers/s390/char/tubio.h 1.11 -> 1.12 # net/ipv4/netfilter/ip_nat_proto_unknown.c 1.2 -> 1.3 # arch/ia64/dig/machvec.c 1.1 -> 1.2 # net/decnet/af_decnet.c 1.24 -> 1.25 # drivers/char/serial_tx3912.c 1.12 -> 1.13 # include/asm-parisc/kmap_types.h 1.2 -> 1.3 # drivers/net/pcmcia/ibmtr_cs.c 1.12 -> 1.13 # fs/ext3/dir.c 1.10 -> 1.11 # arch/i386/mm/highmem.c 1.3 -> 1.4 # arch/ia64/sn/kernel/machvec.c 1.4 -> 1.5 # include/linux/msg.h 1.3 -> 1.4 # drivers/usb/image/mdc800.c 1.29 -> 1.30 # include/asm-h8300/hardirq.h 1.1 -> 1.2 # include/asm-ia64/machvec.h 1.13 -> 1.14 # include/asm-ia64/intrinsics.h 1.5 -> 1.7 # fs/ext2/dir.c 1.21 -> 1.22 # include/asm-ia64/unwind.h 1.4 -> 1.5 # fs/pipe.c 1.24 -> 1.25 # net/sunrpc/sched.c 1.25 -> 1.26 # include/linux/sunrpc/svc.h 1.19 -> 1.20 # include/asm-i386/apicdef.h 1.7 -> 1.8 # fs/lockd/host.c 1.5 -> 1.6 # drivers/input/input.c 1.30 -> 1.31 # fs/cifs/cifsfs.c 1.11 -> 1.12 # arch/ia64/hp/sim/hpsim_machvec.c 1.2 -> 1.3 # include/linux/netfilter_ipv4/ip_nat_protocol.h 1.1 -> 1.2 # include/linux/sysctl.h 1.43 -> 1.44 # arch/ppc64/kernel/xics.c 1.19 -> 1.22 # arch/ia64/ia32/ia32_entry.S 1.23 -> 1.24 # fs/reiserfs/dir.c 1.18 -> 1.19 # include/linux/list.h 1.28 -> 1.29 # net/bridge/br_private_stp.h 1.3 -> 1.4 # net/ipv4/raw.c 1.30 -> 1.31 # drivers/i2c/busses/i2c-isa.c 1.2 -> 1.3 # fs/nfsd/nfssvc.c 1.34 -> 1.35 # Documentation/BK-usage/bk-kernel-howto.txt 1.5 -> 1.6 # net/ipv6/af_inet6.c 1.32 -> 1.37 # drivers/sbus/char/vfc_dev.c 1.10 -> 1.11 # include/asm-ia64/iosapic.h 1.9 -> 1.10 # drivers/net/wireless/wavelan_cs.c 1.20 -> 1.22 # drivers/net/slip.h 1.2 -> 1.3 # fs/ext3/xattr.c 1.14 -> 1.15 # include/asm-ia64/perfmon.h 1.12 -> 1.13 # drivers/char/mwave/mwavedd.h 1.3 -> 1.4 # fs/Kconfig 1.23 -> 1.25 # net/sunrpc/cache.c 1.13 -> 1.14 # net/xfrm/xfrm_user.c 1.19 -> 1.20 # drivers/usb/media/dabusb.c 1.27 -> 1.28 # fs/buffer.c 1.198 -> 1.199 # arch/sparc/mm/srmmu.c 1.32 -> 1.33 # mm/vmalloc.c 1.24 -> 1.25 # drivers/char/agp/Kconfig 1.15 -> 1.19 # arch/ia64/kernel/signal.c 1.22 -> 1.24 # drivers/ide/ide-probe.c 1.41 -> 1.45 # arch/ppc64/kernel/htab.c 1.32 -> 1.33 # arch/ppc64/mm/init.c 1.40 -> 1.42 # arch/ppc64/kernel/open_pic.c 1.11 -> 1.13 # include/linux/skbuff.h 1.22 -> 1.23 # include/asm-i386/smp.h 1.23 -> 1.24 # drivers/char/tty_io.c 1.90 -> 1.94 # drivers/char/agp/i460-agp.c 1.16 -> 1.21 # drivers/net/tulip/tulip_core.c 1.41 -> 1.42 # net/ipv6/ndisc.c 1.33 -> 1.34 # fs/bio.c 1.42 -> 1.43 # drivers/char/pcxx.c 1.10 -> 1.11 # arch/ppc64/kernel/process.c 1.30 -> 1.31 # net/rxrpc/proc.c 1.2 -> 1.3 # drivers/ieee1394/amdtp.c 1.12 -> 1.13 # net/sctp/ipv6.c 1.29.1.6 -> 1.38 # net/sctp/protocol.c 1.40.1.2 -> 1.47 # MAINTAINERS 1.136 -> 1.139 # drivers/s390/char/tubfs.c 1.16 -> 1.17 # drivers/usb/net/rtl8150.c 1.22 -> 1.24 # fs/jffs/inode-v23.c 1.44 -> 1.45 # net/ipv6/netfilter/ip6t_esp.c 1.4 -> 1.5 # arch/ppc64/kernel/pci_dma.c 1.11 -> 1.14 # include/asm-generic/rmap.h 1.4 -> 1.5 # net/irda/irlap_event.c 1.20 -> 1.21 # drivers/char/rio/rio_linux.c 1.19 -> 1.20 # arch/ia64/ia32/sys_ia32.c 1.49.1.1 -> 1.55 # net/compat.c 1.7 -> 1.8 # include/linux/if_ether.h 1.5 -> 1.6 # drivers/media/video/msp3400.c 1.17 -> 1.18 # drivers/char/istallion.c 1.20 -> 1.22 # net/atm/lec.c 1.17 -> 1.21 # drivers/scsi/aic7xxx/aic79xx_osm.h 1.22 -> 1.23 # drivers/char/raw.c 1.31 -> 1.32 # arch/s390/kernel/s390_ksyms.c 1.11 -> 1.12 # arch/ia64/hp/sim/simeth.c 1.5 -> 1.7 # fs/ext2/xattr.c 1.12 -> 1.13 # net/unix/af_unix.c 1.42 -> 1.43 # include/linux/time.h 1.13 -> 1.14 # fs/read_write.c 1.30 -> 1.31 # fs/coda/psdev.c 1.16 -> 1.17 # include/asm-alpha/spinlock.h 1.6 -> 1.7 # drivers/usb/class/cdc-acm.c 1.38 -> 1.39 # drivers/usb/misc/rio500.c 1.20 -> 1.21 # include/asm-i386/mach-summit/mach_apic.h 1.22 -> 1.23 # net/sctp/command.c 1.6 -> 1.7 # include/asm-alpha/hardirq.h 1.7 -> 1.8 # net/bluetooth/rfcomm/sock.c 1.15 -> 1.16 # drivers/scsi/st.c 1.60 -> 1.61 # fs/qnx4/dir.c 1.6 -> 1.7 # arch/ppc64/kernel/open_pic_defs.h 1.1 -> 1.2 # include/asm-i386/unistd.h 1.24 -> 1.25 # include/linux/futex.h 1.6 -> 1.7 # fs/namespace.c 1.39 -> 1.40 # net/atm/svc.c 1.5 -> 1.7 # drivers/char/agp/ali-agp.c 1.15 -> 1.21 # drivers/char/agp/alpha-agp.c 1.3 -> 1.5 # include/linux/wireless.h 1.7 -> 1.8 # drivers/usb/host/ehci-hcd.c 1.47 -> 1.48 # fs/nfs/file.c 1.27 -> 1.28 # include/asm-ia64/ptrace.h 1.9 -> 1.10 # net/sctp/sm_sideeffect.c 1.36.1.1 -> 1.43 # net/atm/pppoatm.c 1.5 -> 1.6 # arch/ppc64/kernel/asm-offsets.c 1.12 -> 1.13 # Makefile 1.405 -> 1.406 # fs/ext2/xattr.h 1.5 -> 1.6 # include/asm-ia64/pal.h 1.5 -> 1.6 # include/asm-ia64/machvec_sn1.h 1.8 -> 1.9 # arch/ia64/kernel/head.S 1.9 -> 1.10 # net/packet/af_packet.c 1.23 -> 1.24 # drivers/net/pcmcia/fmvj18x_cs.c 1.19 -> 1.20 # drivers/char/agp/amd-k8-agp.c 1.30 -> 1.35 # arch/mips64/arc/misc.c 1.2 -> 1.3 # drivers/net/pcmcia/smc91c92_cs.c 1.17 -> 1.18 # sound/core/sound.c 1.25 -> 1.26 # mm/page-writeback.c 1.62 -> 1.64 # net/sunrpc/xprt.c 1.53 -> 1.59 # include/asm-ppc64/mmu.h 1.6 -> 1.7 # include/asm-i386/elf.h 1.8 -> 1.9 # net/core/pktgen.c 1.3 -> 1.4 # drivers/char/mxser.c 1.21 -> 1.22 # net/decnet/dn_neigh.c 1.5 -> 1.7 # drivers/i2c/i2c-keywest.c 1.1 -> 1.2 # arch/ppc64/mm/numa.c 1.2 -> 1.4 # net/bluetooth/l2cap.c 1.24 -> 1.25 # drivers/mtd/mtdchar.c 1.12 -> 1.13 # drivers/char/rocket.c 1.19 -> 1.20 # include/net/sctp/tsnmap.h 1.6 -> 1.7 # net/sctp/inqueue.c 1.6 -> 1.9 # drivers/char/agp/backend.c 1.72 -> 1.81 # arch/ppc64/kernel/syscalls.c 1.9 -> 1.10 # arch/i386/kernel/ldt.c 1.12 -> 1.13 # lib/brlock.c 1.6 -> (deleted) # include/asm-ppc64/ptrace.h 1.1 -> 1.2 # drivers/char/rio/rio_linux.h 1.3 -> 1.4 # drivers/media/video/cpia.c 1.24 -> 1.25 # arch/ppc64/kernel/sys_ppc32.c 1.53.1.5 -> 1.59 # include/linux/ipv6.h 1.6 -> 1.7 # net/sunrpc/xdr.c 1.13 -> 1.14 # net/decnet/TODO 1.4 -> 1.5 # CREDITS 1.81 -> 1.83 # include/asm-sparc64/hardirq.h 1.13 -> 1.15 # drivers/media/video/tda7432.c 1.10 -> 1.11 # drivers/net/wireless/wavelan.p.h 1.11 -> 1.12 # fs/seq_file.c 1.9 -> 1.10 # net/ipv4/netfilter/ip_fw_compat_redir.c 1.5 -> 1.6 # fs/lockd/mon.c 1.8 -> 1.9 # arch/ppc64/kernel/prom.c 1.22 -> 1.25 # drivers/char/tipar.c 1.6 -> 1.7 # include/asm-i386/kmap_types.h 1.13 -> 1.14 # net/core/skbuff.c 1.25 -> 1.26 # net/xfrm/xfrm_state.c 1.23 -> 1.26 # include/linux/security.h 1.16 -> 1.18 # arch/ia64/kernel/salinfo.c 1.2 -> 1.3 # drivers/ieee1394/dv1394.c 1.30 -> 1.31 # drivers/input/evdev.c 1.24 -> 1.25 # drivers/i2c/busses/i2c-viapro.c 1.2 -> 1.3 # arch/ppc64/kernel/iSeries_setup.c 1.10.1.1 -> 1.12 # include/asm-ppc64/elf.h 1.9 -> 1.10 # include/asm-ia64/dma-mapping.h 1.1 -> 1.2 # arch/ia64/lib/swiotlb.c 1.14 -> 1.16 # include/asm-parisc/elf.h 1.4 -> 1.5 # arch/ia64/kernel/perfmon_mckinley.h 1.5 -> 1.6 # include/linux/sunrpc/xprt.h 1.23 -> 1.24 # include/linux/shm.h 1.4 -> 1.5 # include/linux/devfs_fs_kernel.h 1.44 -> 1.45 # arch/ppc64/kernel/smp.c 1.31.2.1 -> 1.34 # net/ipv6/ip6_input.c 1.11 -> 1.12 # fs/nfs/write.c 1.39 -> 1.40 # drivers/media/video/bt832.c 1.2 -> 1.3 # fs/ext2/Makefile 1.8 -> 1.9 # include/asm-ia64/sn/addrs.h 1.4 -> 1.5 # arch/ia64/ia32/ia32_ioctl.c 1.8 -> 1.9 # include/net/ip6_fib.h 1.3 -> 1.4 # drivers/char/stallion.c 1.21 -> 1.23 # drivers/media/video/saa5249.c 1.14 -> 1.15 # drivers/usb/class/bluetty.c 1.40 -> 1.41 # net/ipv6/route.c 1.26 -> 1.31 # include/asm-ia64/percpu.h 1.6 -> 1.7 # net/decnet/dn_rules.c 1.5 -> 1.6 # drivers/scsi/sd.c 1.108 -> 1.109 # arch/ppc64/mm/fault.c 1.9 -> 1.10 # arch/i386/mm/init.c 1.47 -> 1.48 # net/ipv4/tcp_minisocks.c 1.27 -> 1.29 # include/asm-i386/i387.h 1.11 -> 1.12 # fs/minix/dir.c 1.13 -> 1.14 # drivers/sgi/char/shmiq.c 1.9 -> 1.10 # arch/ppc64/kernel/pacaData.c 1.5 -> 1.6 # drivers/usb/storage/unusual_devs.h 1.33 -> 1.37 # drivers/i2c/chips/it87.c 1.3 -> 1.9 # drivers/i2c/i2c-dev.c 1.27 -> 1.29 # net/atm/signaling.c 1.5 -> 1.7 # arch/ia64/kernel/brl_emu.c 1.5 -> 1.6 # net/sched/sch_ingress.c 1.12 -> 1.13 # net/core/wireless.c 1.9 -> 1.12 # arch/alpha/kernel/irq.c 1.20 -> 1.21 # mm/slab.c 1.75 -> 1.79 # arch/i386/kernel/suspend.c 1.14 -> 1.15 # fs/nfs/inode.c 1.76 -> 1.77 # include/linux/socket.h 1.8 -> 1.9 # drivers/block/elevator.c 1.40 -> 1.41 # net/atm/mpoa_proc.c 1.5 -> 1.6 # net/ipv4/netfilter/ip_nat_standalone.c 1.22 -> 1.23 # include/linux/rtnetlink.h 1.10 -> 1.12 # net/ipv4/netfilter/ip_fw_compat_masq.c 1.7 -> 1.10 # kernel/sched.c 1.180 -> 1.181 # include/linux/agp_backend.h 1.27 -> 1.36 # include/asm-sparc/elf.h 1.6 -> 1.7 # net/sctp/adler32.c 1.6.1.1 -> 1.8 # drivers/char/agp/hp-agp.c 1.16 -> 1.21 # drivers/block/deadline-iosched.c 1.17 -> 1.19 # drivers/Makefile 1.32 -> 1.33 # net/ipv6/ip6_fib.c 1.11 -> 1.16 # drivers/usb/host/ehci-q.c 1.45 -> 1.46 # net/sctp/ssnmap.c 1.1 -> 1.2 # drivers/s390/char/tubtty.c 1.10 -> 1.11 # include/asm-x86_64/elf.h 1.5 -> 1.6 # include/net/ipv6.h 1.11 -> 1.12 # scripts/Makefile.build 1.34 -> 1.36 # arch/um/kernel/irq.c 1.7 -> 1.8 # arch/ia64/kernel/gate.S 1.14 -> 1.15 # net/sctp/crc32c.c 1.5 -> 1.6 # net/atm/mpc.c 1.10 -> 1.14 # drivers/s390/char/tuball.c 1.11 -> 1.12 # drivers/ide/ide-io.c 1.8 -> 1.11 # fs/ufs/dir.c 1.13 -> 1.14 # drivers/net/wireless/wavelan_cs.p.h 1.6 -> 1.8 # net/ipv6/udp.c 1.28 -> 1.31 # drivers/char/drm/drm_drv.h 1.17 -> 1.18 # drivers/hotplug/cpqphp.h 1.6.1.1 -> 1.9 # drivers/i2c/busses/i2c-amd8111.c 1.7 -> 1.8 # include/linux/atmdev.h 1.8 -> 1.12 # arch/sparc64/kernel/sparc64_ksyms.c 1.47 -> 1.48 # drivers/usb/serial/console.c 1.2 -> 1.3 # include/net/xfrm.h 1.34 -> 1.37 # arch/ia64/hp/sim/hpsim_console.c 1.6 -> 1.7 # kernel/timer.c 1.52 -> 1.53 # arch/x86_64/kernel/reboot.c 1.3 -> 1.4 # drivers/usb/serial/visor.h 1.19 -> 1.20 # include/asm-i386/suspend.h 1.8 -> 1.9 # drivers/media/video/tuner.c 1.17 -> 1.18 # drivers/char/agp/via-agp.c 1.33 -> 1.39 # arch/um/kernel/sys_call_table.c 1.19 -> 1.20 # drivers/tc/zs.c 1.14 -> 1.16 # drivers/char/ipmi/ipmi_devintf.c 1.7 -> 1.8 # drivers/block/paride/pg.c 1.15 -> 1.16 # include/linux/pfkeyv2.h 1.5 -> 1.6 # net/sctp/bind_addr.c 1.14 -> 1.16 # arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S 1.1 -> 1.2 # include/asm-i386/mach-default/mach_mpparse.h 1.3 -> 1.4 # net/ipv4/netfilter/ipchains_core.c 1.13 -> 1.14 # drivers/char/hvc_console.c 1.13.1.4 -> 1.17 # drivers/char/vt.c 1.43 -> 1.45 # drivers/i2c/busses/i2c-amd756.c 1.6 -> 1.7 # drivers/usb/host/ehci.h 1.19 -> 1.20 # drivers/net/Kconfig 1.25 -> 1.26 # arch/ppc64/kernel/pci.c 1.29 -> 1.30 # arch/ppc64/xmon/xmon.c 1.24 -> 1.26 # drivers/char/sysrq.c 1.26 -> 1.27 # net/ipv4/ipcomp.c 1.4 -> 1.6 # net/ipv4/arp.c 1.19 -> 1.20 # include/asm-i386/ipc.h 1.2 -> 1.3 # arch/ppc64/kernel/misc.S 1.52.2.3 -> 1.57 # arch/ia64/kernel/mca_asm.S 1.6 -> 1.8 # kernel/exit.c 1.100 -> 1.101 # arch/ia64/kernel/irq.c 1.20 -> 1.23 # drivers/char/specialix.c 1.14 -> 1.15 # arch/sparc64/kernel/power.c 1.12 -> 1.13 # net/bridge/br_stp_if.c 1.6 -> 1.7 # include/asm-i386/mach-default/mach_ipi.h 1.1 -> 1.2 # fs/bfs/dir.c 1.18 -> 1.19 # drivers/media/video/tvmixer.c 1.13 -> 1.15 # fs/hugetlbfs/inode.c 1.22 -> 1.23 # net/appletalk/atalk_proc.c 1.2 -> 1.3 # arch/m68k/sun3/prom/init.c 1.1 -> 1.2 # include/asm-ia64/bitops.h 1.12 -> 1.13 # arch/ia64/tools/print_offsets.c 1.16 -> 1.17 # arch/ia64/kernel/unaligned.c 1.11 -> 1.12 # fs/ntfs/inode.c 1.104 -> 1.105 # include/asm-arm/elf.h 1.5 -> 1.6 # drivers/net/wireless/wavelan.c 1.15 -> 1.17 # include/asm-s390/elf.h 1.5 -> 1.6 # include/net/ip_fib.h 1.8 -> 1.9 # arch/ppc64/kernel/signal32.c 1.38 -> 1.39 # include/linux/ipx.h 1.2 -> 1.3 # fs/partitions/check.c 1.109 -> 1.112 # drivers/net/ppp_deflate.c 1.9 -> 1.10 # drivers/input/mousedev.c 1.24 -> 1.25 # arch/arm/common/sa1111.c 1.24 -> 1.25 # include/asm-ia64/pci.h 1.14 -> 1.16 # arch/alpha/kernel/sys_titan.c 1.10 -> 1.11 # Documentation/Changes 1.33 -> 1.34 # drivers/net/setup.c 1.6 -> 1.10 # arch/ppc64/kernel/rtas_flash.c 1.4 -> 1.5 # include/asm-parisc/hardirq.h 1.2 -> 1.3 # drivers/isdn/eicon/eicon_pci.c 1.4 -> 1.5 # drivers/char/misc.c 1.18 -> 1.19 # net/irda/irlap.c 1.18 -> 1.19 # fs/intermezzo/methods.c 1.8 -> 1.9 # net/atm/raw.c 1.2 -> 1.3 # net/ipv6/addrconf.c 1.38 -> 1.39 # drivers/bluetooth/hci_usb.c 1.26 -> 1.27 # arch/ia64/kernel/perfmon.c 1.41 -> 1.43 # drivers/char/moxa.c 1.17 -> 1.18 # crypto/Kconfig 1.12 -> 1.13 # drivers/hotplug/cpqphp_pci.c 1.16 -> 1.18 # drivers/net/ppp_generic.c 1.24 -> 1.26 # drivers/isdn/hisax/diva.c 1.41 -> 1.42 # include/asm-ia64/compat.h 1.11 -> 1.12 # net/sctp/ulpqueue.c 1.17.1.1 -> 1.22 # include/asm-i386/mach-bigsmp/mach_apic.h 1.8 -> 1.9 # net/ipv4/icmp.c 1.27 -> 1.28 # include/linux/efi.h 1.1 -> 1.2 # drivers/usb/Makefile 1.41 -> 1.43 # include/linux/netdevice.h 1.33 -> 1.34 # fs/ext3/xattr.h 1.6 -> 1.7 # drivers/net/pcmcia/3c589_cs.c 1.16 -> 1.17 # arch/ia64/Kconfig 1.20 -> 1.21 # kernel/panic.c 1.10 -> 1.12 # include/asm-ia64/sal.h 1.15 -> 1.16 # include/asm-ppc64/mmzone.h 1.9 -> 1.10 # net/decnet/dn_route.c 1.15 -> 1.16 # drivers/atm/iphase.c 1.18 -> 1.21 # drivers/isdn/capi/capi.c 1.40 -> 1.42 # include/asm-ppc64/io.h 1.7 -> 1.8 # drivers/input/tsdev.c 1.10 -> 1.11 # drivers/char/sh-sci.c 1.18 -> 1.19 # sound/core/info.c 1.24 -> 1.25 # arch/i386/kernel/timers/timer.c 1.6 -> 1.7 # arch/ia64/kernel/traps.c 1.28 -> 1.29 # arch/ia64/kernel/sal.c 1.5 -> 1.6 # arch/ia64/mm/fault.c 1.13 -> 1.14 # drivers/macintosh/macserial.c 1.20 -> 1.21 # sound/sound_core.c 1.17 -> 1.18 # drivers/net/wireless/netwave_cs.c 1.15 -> 1.16 # arch/i386/kernel/sys_i386.c 1.12 -> 1.13 # drivers/char/ppdev.c 1.20 -> 1.21 # net/sctp/tsnmap.c 1.8 -> 1.9 # drivers/isdn/hisax/sedlbauer.c 1.35 -> 1.36 # include/asm-ppc64/topology.h 1.6 -> 1.7 # net/atm/clip.c 1.7 -> 1.10 # net/decnet/dn_nsp_out.c 1.7 -> 1.8 # fs/ext3/fsync.c 1.7 -> 1.8 # drivers/ide/pci/pdc202xx_old.c 1.13 -> 1.15 # arch/ppc64/kernel/Makefile 1.22 -> 1.23 # arch/ppc64/kernel/module.c 1.2 -> 1.4 # arch/ia64/hp/zx1/Makefile 1.6 -> 1.7 # net/ipv4/ip_output.c 1.34 -> 1.35 # drivers/scsi/esp.c 1.24 -> 1.25 # arch/ia64/kernel/ptrace.c 1.20 -> 1.22 # include/asm-ppc64/rtas.h 1.5 -> 1.6 # mm/mincore.c 1.3 -> 1.4 # net/bridge/br_if.c 1.11 -> 1.12 # include/asm-ia64/ia32.h 1.20 -> 1.21 # net/nonet.c 1.1 -> 1.2 # arch/ia64/kernel/smp.c 1.23 -> 1.24 # include/net/sctp/command.h 1.12 -> 1.13 # net/decnet/Kconfig 1.1 -> 1.2 # net/ipv4/route.c 1.52 -> 1.56 # drivers/base/class.c 1.26 -> 1.28 # include/linux/slab.h 1.20 -> 1.21 # arch/ia64/kernel/Makefile 1.16 -> 1.17 # include/net/sctp/structs.h 1.47 -> 1.60 # arch/ppc64/kernel/align.c 1.6 -> 1.8 # drivers/ide/ide-tcq.c 1.2 -> 1.4 # net/ipv4/fib_frontend.c 1.10 -> 1.11 # net/sctp/Makefile 1.7 -> 1.9 # include/asm-alpha/kmap_types.h 1.4 -> 1.5 # include/linux/seq_file.h 1.4 -> 1.6 # arch/ppc64/kernel/ioctl32.c 1.25.1.2 -> 1.30 # drivers/char/amiserial.c 1.19 -> 1.20 # drivers/usb/core/file.c 1.7 -> 1.10 # include/asm-s390/hardirq.h 1.7 -> 1.8 # arch/ppc64/kernel/pSeries_lpar.c 1.20 -> 1.21 # include/linux/sunrpc/xdr.h 1.11 -> 1.12 # drivers/usb/misc/speedtch.c 1.80 -> 1.81 # include/asm-i386/mach-default/mach_apic.h 1.22 -> 1.23 # drivers/macintosh/adb.c 1.18 -> 1.19 # net/sctp/primitive.c 1.9 -> 1.10 # arch/ia64/kernel/acpi-ext.c 1.1 -> 1.3 # fs/fs-writeback.c 1.34 -> 1.35 # net/ipv6/netfilter/ip6t_ipv6header.c 1.4 -> 1.5 # drivers/usb/serial/bus.c 1.7 -> 1.8 # drivers/net/slip.c 1.13 -> 1.14 # net/decnet/dn_fib.c 1.4 -> 1.6 # drivers/char/agp/amd-k7-agp.c 1.19 -> 1.26 # drivers/hotplug/ibmphp_core.c 1.24 -> 1.26 # drivers/char/ip2main.c 1.28 -> 1.31 # include/linux/nfs_fs_sb.h 1.9 -> 1.10 # include/asm-sparc/hardirq.h 1.10 -> 1.12 # arch/i386/mm/pgtable.c 1.11 -> 1.12 # arch/ia64/kernel/unwind.c 1.19 -> 1.22 # drivers/usb/serial/usb-serial.h 1.29 -> 1.31 # net/sctp/socket.c 1.48.1.1 -> 1.69 # net/atm/common.c 1.15 -> 1.19 # include/asm-um/pgtable.h 1.10 -> 1.11 # (new) -> 1.1 include/asm-i386/mach-generic/mach_mpparse.h # (new) -> 1.1 arch/i386/mach-generic/probe.c # (new) -> 1.1 arch/i386/mach-generic/default.c # (new) -> 1.4 drivers/usb/gadget/net2280.c # (new) -> 1.1 include/linux/atm_he.h # (new) -> 1.1 drivers/usb/gadget/Makefile # (new) -> 1.5 drivers/atm/he.c # (new) -> 1.5 drivers/char/agp/nvidia-agp.c # (new) -> 1.1 arch/i386/mach-generic/bigsmp.c # (new) -> 1.3 drivers/usb/gadget/Kconfig # (new) -> 1.1 include/asm-i386/mach-generic/mach_apic.h # (new) -> 1.1 include/linux/atmbr2684.h # (new) -> 1.2 net/atm/br2684.c # (new) -> 1.1 net/ipv4/netfilter/ip_fw_compat.h # (new) -> 1.4 drivers/usb/gadget/zero.c # (new) -> 1.2 include/linux/usb_gadget.h # (new) -> 1.3 drivers/atm/he.h # (new) -> 1.1 fs/ext3/xattr_security.c # (new) -> 1.1 fs/ext2/xattr_security.c # (new) -> 1.1 net/decnet/netfilter/dn_rtmsg.c # (new) -> 1.1 include/asm-ppc64/systemcfg.h # (new) -> 1.1 arch/i386/mach-generic/Makefile # (new) -> 1.1 net/decnet/netfilter/Makefile # (new) -> 1.1 include/asm-i386/genapic.h # (new) -> 1.2 drivers/usb/gadget/usbstring.c # (new) -> 1.1 arch/ppc64/kernel/proc_ppc64.c # (new) -> 1.1 drivers/usb/gadget/net2280.h # (new) -> 1.5 net/sctp/chunk.c # (new) -> 1.1 include/asm-i386/mach-generic/mach_ipi.h # (new) -> 1.1 net/decnet/netfilter/Kconfig # (new) -> 1.1 arch/i386/mach-generic/summit.c # (new) -> 1.3 drivers/usb/gadget/ether.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/04 torvalds@home.transmeta.com 1.1042.107.10 # Linux 2.5.69 # -------------------------------------------- # 03/05/05 anton@samba.org 1.1057.2.13 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/05/04 davem@nuts.ninka.net 1.1042.1.183 # [ATM]: mpc.c warning fixes. # -------------------------------------------- # 03/05/04 davem@nuts.ninka.net 1.1042.1.184 # [NETFILTER IPV6]: Fix warnings. # -------------------------------------------- # 03/05/04 davem@nuts.ninka.net 1.1042.1.185 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/05 davej@tetrachloride.(none) 1.1042.107.11 # Merge tetrachloride.(none):/mnt/raid/src/kernel/2.5/bk-linus # into tetrachloride.(none):/mnt/raid/src/kernel/2.5/agpgart # -------------------------------------------- # 03/05/05 davej@codemonkey.org.uk 1.1042.107.12 # [AGPGART] Disable debugging printk's again. # With the 'AGP bug' solved, we don't need this noise for a while... # -------------------------------------------- # 03/05/05 davej@tetrachloride.(none) 1.1042.108.1 # Merge tetrachloride.(none):/mnt/raid/src/kernel/2.5/bk-linus # into tetrachloride.(none):/mnt/raid/src/kernel/2.5/cpufreq # -------------------------------------------- # 03/05/05 anton@samba.org 1.1062 # Merge samba.org:/scratch/anton/tmp3 # into samba.org:/scratch/anton/linux-2.5_ppc64 # -------------------------------------------- # 03/05/05 anton@samba.org 1.1057.2.14 # Merge samba.org:/scratch/anton/tmp3 # into samba.org:/scratch/anton/linux-2.5_ppc64drivers # -------------------------------------------- # 03/05/04 torvalds@home.transmeta.com 1.1063 # Merge http://ppc.bkbits.net/for-linus-ppc64drivers # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/05 acme@conectiva.com.br 1.1042.104.2 # o list.h: implement list_for_each_entry_safe # -------------------------------------------- # 03/05/05 acme@conectiva.com.br 1.1042.104.3 # o ipx: convert ipx_interface handling to use list_head # -------------------------------------------- # 03/05/05 jgrimm@touki.austin.ibm.com 1.1042.109.1 # [SCTP] Use put_user() in get_peer_addr_params (reported by yjf@standford.edu) # # Standford Checker reported direct touch of user space. # -------------------------------------------- # 03/05/05 jgrimm@touki.austin.ibm.com 1.1042.23.17 # Merge http://linux-lksctp.bkbits.net/lksctp-2.5.work # into touki.austin.ibm.com:/home/jgrimm/bk/lksctp-2.5.work # -------------------------------------------- # 03/05/05 bunk@fs.tum.de 1.1042.93.3 # [PATCH] USB: kill the last occurances of usb_serial_get_by_minor # # I got an error at the final linking of 2.5.68-bk11. It seems the patch # below is needed. # -------------------------------------------- # 03/05/05 geert@linux-m68k.org 1.1042.93.4 # [PATCH] USB: Big endian RTL8150 # # The RTL8150 USB Ethernet driver doesn't work on big endian machines. Here are # patches (for both 2.4.x and 2.5.x) to fix that. The fix was tested on the # 2.4.20 and 2.4.21-rc1 version of the driver on big endian MIPS. # # Changes: # - Fix endianness of rx_creg (from Dimitri Torfs ) # - Kill unused last parameter of async_set_registers() # -------------------------------------------- # 03/05/05 davem@redhat.com 1.1042.93.5 # [PATCH] USB speedtouch fix # # Missing header file. Please apply. # -------------------------------------------- # 03/05/05 philipp@void.at 1.1042.93.6 # [PATCH] USB: unusual_devs.h patch # -------------------------------------------- # 03/05/05 greg@kroah.com 1.1064 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/05 nicolas@dupeux.net 1.1065 # [PATCH] USB: UNUSUAL_DEV for aiptek pocketcam # # Here is the unusual_dev entry i'm using to get my digital camera. # # # diff -cr linux/drivers/usb/storage/unusual_devs.h linux_vaxvms/drivers/usb/storage/unusual_devs.h # *** linux/drivers/usb/storage/unusual_devs.h 2003-03-14 21:32:46.000000000 +0100 # -------------------------------------------- # 03/05/05 jgrimm@touki.austin.ibm.com 1.1042.23.18 # [SCTP] Support SCTP ECN on ipv6. # -------------------------------------------- # 03/05/05 acme@conectiva.com.br 1.1042.104.4 # o ipx: convert ipx_route to use list_head # -------------------------------------------- # 03/05/05 davem@nuts.ninka.net 1.1063.1.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.2 # [IPSEC]: Fix SADB_EALG_{3,}DESCBC values. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.3 # Merge bk://kernel.bkbits.net/acme/ipx-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.4 # [ATM]: Fix some CPP pasting in ambassador driver. # -------------------------------------------- # 03/05/06 chas@locutus.cmf.nrl.navy.mil 1.1063.1.5 # [ATM]: Fix excessive stack usage in iphase driver. # -------------------------------------------- # 03/05/06 chas@locutus.cmf.nrl.navy.mil 1.1063.1.6 # [ATM]: svcs possible race with sigd. # -------------------------------------------- # 03/05/06 steve@gw.chygwyn.com 1.1063.1.7 # [FS]: Add seq_release_private and proc_net_fops_create helpers. # -------------------------------------------- # 03/05/06 steve@gw.chygwyn.com 1.1063.1.8 # [DECNET]: seq file conversions and fixes. # o Removed blksize from decnet device parameters - use the device mtu like we # ought to. # o Removed /proc/net/decnet_route file - I don't think anybody ever used it # and it was lacking a full enough description of the routes to be useful. # ip -D route list is much better :-) # o Added rt_local_src entry to decnet routes so that we get the local source # address right when forwarding. # o Added correct proto argument to struct flowi for routing # o MSG_MORE in sendmsg (ignored, but accepted whereas before we'd error) # o /proc/net/decnet converted to seq_file # o /proc/net/decnet_dev converted to seq_file # o /proc/net/decnet_cache converted to seq_file # o Use pskb_may_pull() and add code to linearize skbs on the input path # except for those containing data. # o Fixed returned packet code (mostly - some left to do) # o update_pmtu() method for decnet dst entries (ip_gre device assumes this # method exists - well I think it does :-) # o Fixed bug in forwarding to get IE bit set correctly # o Fixed compile bugs with CONFIG_DECNET_ROUTE_FWMARK pointed out by Adrian # Bunk # o Fixed zero dest code to grab an address from loopback # o Fixed local routes in dn_route_output_slow() # o Fixed error case in dn_route_input/output_slow() pointed out by Rusty # -------------------------------------------- # 03/05/06 rusty@rustcorp.com.au 1.1063.1.9 # [NETFILTER]: Fix Module Usage in ipchains and ipfwadm. # Gets rid of some warnings. Manipulating our own module count inside the # sockopt is safe, because unregistering that sockopt will block. # -------------------------------------------- # 03/05/06 rusty@rustcorp.com.au 1.1063.1.10 # [NETFILTER]: Make NAT code handle non-linear skbs. # Makes the NAT code and all NAT helpers handle non-linear skbs. # Main trick is to introduce skb_ip_make_writable which handles all # the decloning, linearizing, etc. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.11 # [NETFILTER]: ip_nat_proto_{icmp,udp}.c need ip_nat_core.h # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.12 # [IPV6]: Kill spurious module_{get,put}(). # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.13 # [BLUETOOTH]: Fix hci_usb build. # -------------------------------------------- # 03/05/06 yoshfuji@linux-ipv6.org 1.1063.1.14 # [IPV6]: Fix offset in ICMPV6_HDR_FIELD messages. # -------------------------------------------- # 03/05/06 yoshfuji@linux-ipv6.org 1.1063.1.15 # [IPV^]: Use correct icmp6 type in ip6_pkt_discard. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.2.1 # [SPARC64]: Only use power interrupt when button property exists. # -------------------------------------------- # 03/05/06 chas@cmf.nrl.navy.mil 1.1063.1.16 # [ATM]: Fix foul up in lec driver. # -------------------------------------------- # 03/05/06 torvalds@home.transmeta.com 1.1063.3.1 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.17 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/06 davidm@tiger.hpl.hp.com 1.971.102.22 # ia64: Improve spinlock code to handle contention in shared routine called # with a special convention. Various minor fixes for gcc-pre3.4. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.18 # [IPV6]: Remove illogical bug check in fib6_del. # -------------------------------------------- # 03/05/06 arun.sharma@intel.com 1.971.102.23 # [PATCH] ia64: fix ia32 emulation of rlimit et al # # -------------------------------------------- # 03/05/06 eranian@hpl.hp.com 1.971.102.24 # [PATCH] ia64: perfmon update # # Please apply the following patch on top of 2.5.6x. This patch does the # following: # # - repair broken system-wide overflow notification # - repair broken per-process notification # - fix a problem in the resrved bitmask for opcode # matcher8,9 for McKinley as reported by UIUC. # - forcing of bit2 for pmc8/pmc9 now part of reserved bitmask # - add the unsecure option to perfmon # - update to perfmon 1.4 (similar to 2.4) # -------------------------------------------- # 03/05/06 elenstev@mesatop.com 1.971.102.25 # [PATCH] ia64: spelling fixes # # -------------------------------------------- # 03/05/06 davidm@tiger.hpl.hp.com 1.971.102.26 # ia64: Manual merge of Steve's spelling fixes. # -------------------------------------------- # 03/05/06 alex_williamson@hp.com 1.971.102.27 # [PATCH] ia64: fix timer interrupts getting lost # # This patch fixes the issue of some CPUs not showing timer interrupts # going off. Seems during the process of sync'ing the itc, we jumped over # the next timer value. This patch is against 2.5.67 + ia64. I haven't # seen the problem on 2.4, but a quick looks seems like it's potentially # an issue there too. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.3.2 # Merge gregkh@kernel.bkbits.net:/home/gregkh/linux/i2c-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/06 alex_williamson@hp.com 1.971.102.28 # [PATCH] ia64: interrupt fixes/cleanup # # Here's some cleanups/fixes/changes for interrupts on 2.5.67 + ia64. # Specifically: # # - Cleanup some ugliness with polarity/trigger setup. # # - Add iosapic_enable_intr() to set_rte on an interupt when the # device is enabled. IMHO, we really only want to unmask RTEs # for PRTs we might actually use. This moves the interrupt # distribution here too. # # - When changing a vector from edge to level, call register_intr() # to do it so all the data structures get set correctly. If we # have to guess how to setup an interupt and get it wrong, this # should close some holes in changing it back to the correct type. # # - Register the HCDP interrupt in 8250_hcdp - this is where we have # to guess the polarity/trigger. The real handler will get fixed # up via PCI setup or ACPI namespace serial support, this gets it # associated w/ the port at setup. This should allow interrupts # to work when using builtin UARTs as console on HP Itanium2 boxes. # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.29 # [PATCH] ia64: multi-ioport space support # # This has been in my 2.4 BK tree for a while, but I should have # posted it in case there's feedback from other people working # on large machines. So here it is, in four parts: # # 1 enhance __ia64_mk_io_addr(port) # 2 enhance pcibios_scan_root to get multiple mem & io windows # from ACPI _CRS, and fixup all the resources # 3 add support for /proc/iomem and /proc/ioports # 4 trivial (whitespace, copyright, and move pcibios_fixup_device_resources # closer to related code) # # The current scheme is that IO ports are 64 bits, with the low 24 # bits being the port number within an IO port space, and the upper # bits identifying the space. There is currently a limit of 16 # spaces. # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.30 # [PATCH] ia64: multi-ioport space support (part 2 of 4) # # enhance pcibios_scan_root to get multiple mem & io windows from ACPI _CRS, # and fixup all the resources # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.31 # [PATCH] ia64: multi-ioport space support (part 3 of 4) # # add support for /proc/iomem and /proc/ioports # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.32 # [PATCH] ia64: multi-ioport space support (part 3 of 4) # # trivial (whitespace, copyright, and move pcibios_fixup_device_resources # closer to related code) # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.33 # [PATCH] ia64: new IOC recognition # # This is a trivial patch that makes sba_iommu recognize a new IOC. # Only change is that it will print # # IOC: sx1000 0.1 HPA 0xf8120002000 IOVA space 1024Mb at 0x80000000 # # instead of # # IOC: Unknown (103c:127c) 0.1 HPA 0xf8120002000 IOVA space 1024Mb # at 0x80000000 # -------------------------------------------- # 03/05/06 bjorn_helgaas@hp.com 1.971.102.34 # [PATCH] ia64: vendor-specific ACPI resource cleanup # # This is to # # - handle _CRS with multiple vendor-specific resources # - use acpi_walk_resources() instead of doing it by hand # - make lookup of vendor resource by GUID generic # - cleanup now-unused helper functions # # (This depends on the previous IO port space patches, because # they removed the last of acpi_get_addr_space()). # # My hope is that acpi_vendor_resource_match() and # acpi_find_vendor_resource() can someday move into ACPI, # but that probably depends on getting the idea of labelling # vendor resources with a GUID into the spec. HP does this # and I think is working on putting it in the spec. # -------------------------------------------- # 03/05/06 petrides@redhat.com 1.971.102.35 # [PATCH] ia64: fixes for semtimedop() ia32-compat handling # # Here are two fixes for the ia32-compatibility mode handling # for the new semtimedop() system call for the ia64 architecture. # # The first problem was that treatment of user-mode calls to semtimedop() # with a NULL 4th (struct timespec *) parameter was inconsistent with the # behavior of the same executable on i386 and also with a natively compiled # ia64 binary. A NULL 4th arg to semtimedop() should result in no timeout # being used (like a straight semop() call) rather than in an EFAULT error. # # The second problem was that a legitimate semtimedop() with a timeout was # also resulting in an EFAULT because the fetch of the internal timespec # strucure by sys_semtimedop() from semtimedop32()'s kernel stack was # treated as an invalid user-data reference. This requires temporarily # switching the addressing limit with set_fs(), further requiring that # appropriate parameter checking by performed prior to the switch. # # The const qualifier was removed from the (struct compat_timespec *) arg # to semtimedop32() so that the call to get_compat_timespec() wouldn't # generate a compilation warning. # -------------------------------------------- # 03/05/06 davidm@tiger.hpl.hp.com 1.971.102.36 # ia64: Manual merge of Bjorn Helgaas' sba_iommu patch to make it use seq_file. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.1 # Merge gregkh@kernel.bkbits.net:/home/gregkh/linux/pci-2.5 # into kroah.com:/home/greg/linux/BK/pci-2.5 # -------------------------------------------- # 03/05/06 roland@frob.com 1.1063.5.1 # [PATCH] core dump psinfo.pr_sname letter fix # # This patch makes the state letter in the pr_sname field in core dumps # correct for stopped and zombie threads. The order needed to be changed when # the TASK_* values changed. This matches the letters used in sched.c:show_task. # -------------------------------------------- # 03/05/06 davidm@tiger.hpl.hp.com 1.1063.6.1 # Merge tiger.hpl.hp.com:/data1/bk/vanilla/linux-2.5 # into tiger.hpl.hp.com:/data1/bk/lia64/to-linus-2.5 # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.2 # [PATCH] PCI Hotplug: fix up the compaq driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.3 # [PATCH] PCI Hotplug: fix up the ibm driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.4 # [PATCH] PCI Hotplug: fix compiler warning in ibm driver. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.5 # [PATCH] PCI Hotplug: fix up the acpi driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.6 # [PATCH] PCI Hotplug: fix dependancies for CONFIG_HOTPLUG_PCI_ACPI # # Thanks to Adrian Bunk for pointing this out. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.4.7 # PCI Hotplug: export the acpi_resource_to_address64 function, as the acpi pci hotplug driver needs it. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.3.3 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/06 davidm@tiger.hpl.hp.com 1.1063.6.2 # mca.c: # (show_min_state): Fix typo r11 -> r12. # -------------------------------------------- # 03/05/06 sri@us.ibm.com 1.1042.110.1 # Manual merge. # -------------------------------------------- # 03/05/06 kraxel@bytesex.org 1.1063.3.4 # [PATCH] i2c #1/3: listify i2c core # # This is the first of tree patches for i2c. Trying to get the i2c # cleanups finshed before 2.6.x, so we (hopefully) don't have a # ever-changing i2c subsystem in 2.7.x again (which is very annonying for # driver maintainance). # # Changes: # # * listify i2c-core, i.e. make it use instead of # statically-sized arrays, removed lots of ugly code :) # * added i2c_(get|put)_adapter, changed i2c-dev.c to use these # functions instead maintaining is own adapter list. # * killed the I2C_DF_DUMMY flag which had the strange semantics to # make the i2c subsystem call driver->attach_adapter on detaches. # Added a detach_adapter() callback instead. # * some other minor cleanups along the way ... # -------------------------------------------- # 03/05/06 kraxel@bytesex.org 1.1063.3.5 # [PATCH] i2c #2/3: add i2c_clients_command # # Changes: # # * adds a i2c_clients_command() function to i2c-core which calls # the ->command() callback of all clients attached to a adapter. # * make bttv + saa7134 drivers use that function instead of mucking # with the i2c_adapter struct themself. # -------------------------------------------- # 03/05/06 kraxel@bytesex.org 1.1063.3.6 # [PATCH] i2c #3/3: add class field to i2c_adapter # # This is the last of three patches for i2c. It introduces a new field # to i2c_adapter which classifies the kind of hardware a i2c adapter # belongs to (analog tv card / dvb card / smbus / gfx card ...). i2c chip # drivers can use this infomation to decide whenever they want to look for # hardware on that adapter or not. It doesn't make sense to probe for a # tv tuner on a smbus for example ... # -------------------------------------------- # 03/05/06 torvalds@home.transmeta.com 1.1063.4.8 # Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1063.3.7 # [PATCH] i2c: fix compile error due to previous patches. # -------------------------------------------- # 03/05/06 warp@mercury.d2dc.net 1.1063.3.8 # [PATCH] i2c: it87 patch. # # More or less straight forward patch. # # Fix a typo in the comments at the top. # Show all 9 voltage inputs. # Show all 3 fan inputs. # Allow you to select the temp sensor type from the sysfs interface, # instead of just with the temp_type module option. # (1 = diode, 2 = thermistor, 0 = disabled). # # I'm still trying to figure out the registers for PWM fan controller # support. # -------------------------------------------- # 03/05/06 sri@us.ibm.com 1.1063.5.2 # o net/socket: fix bug in sys_accept # # module_put() gets called twice on error. Once via the explicit module_put and # the second via sock_release(). Also i think we should do a __module_get() with # newsock's owner(although same as the original listening sock). # -------------------------------------------- # 03/05/06 torvalds@home.transmeta.com 1.1063.3.9 # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/06 paulkf@microgate.com 1.1063.3.10 # [PATCH] synclink update # # - Add support for hardware version 2 (universal PCI) of synclink adapter # - Use mod_timer() function # -------------------------------------------- # 03/05/06 paulkf@microgate.com 1.1063.3.11 # [PATCH] n_hdlc update # # - Use C99 initializers # -------------------------------------------- # 03/05/06 arun.sharma@intel.com 1.1063.6.3 # [PATCH] ia64: fix sys32_select() # # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.19 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.20 # Merge bk://kernel.bkbits.net/acme/unix-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.21 # [IPV4/IPV6]: Set owner field in family ops. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1066 # [PATCH] USB: add usb class support for usb drivers that use the USB major # # This also consolodates the devfs calls for the USB drivers. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1067 # [PATCH] USB: converted usblp over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1068 # [PATCH] USB: converted mdc800 over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1069 # [PATCH] USB: converted scanner over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1070 # [PATCH] USB: converted dabusb over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1071 # [PATCH] USB: converted auerswald over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1072 # [PATCH] USB: converted brlvger over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1073 # [PATCH] USB: converted rio500 over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1074 # [PATCH] USB: converted usblcd over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1075 # [PATCH] USB: converted usb-skeleton over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1076 # [PATCH] USB: remove #include from some drivers that do not need it. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1077 # USB: converted hiddev over to new usb_register_dev() changes. # -------------------------------------------- # 03/05/07 rddunlap@osdl.org 1.1063.1.22 # [NET]: Spelling/typo fixes in rtnetlink.h # -------------------------------------------- # 03/05/07 rddunlap@osdl.org 1.1063.1.23 # [IPV6]: Convert /proc/net/rt6_stats to seq_file. # -------------------------------------------- # 03/05/07 bdschuym@pandora.be 1.1063.1.24 # [BRIDGE]: Change pkt_type to PACKET_HOST earlier. # -------------------------------------------- # 03/05/07 shemminger@osdl.org 1.1063.1.25 # [IPV4]: Replace explicit dev->refcount bumps with dev_hold. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1063.1.26 # [NET]: Remove duplicated alloc_skb debug check. # -------------------------------------------- # 03/05/07 chas@cmf.nrl.navy.mil 1.1063.1.27 # [ATM]: Add Forerunner HE support. # -------------------------------------------- # 03/05/07 chas@cmf.nrl.navy.mil 1.1063.1.28 # [ATM]: Forward port br2864 to 2.5.x # -------------------------------------------- # 03/05/07 chas@cmf.nrl.navy.mil 1.1063.1.29 # [ATM]: Clip locking and more atmvcc cleanup. # -------------------------------------------- # 03/05/07 rddunlap@osdl.org 1.1063.1.30 # [IPV6]: Fix typos in ip6_fib.c # -------------------------------------------- # 03/05/07 rddunlap@osdl.org 1.1063.1.31 # [IPV6]: Use time_after() etc. for comparing jiffies. # -------------------------------------------- # 03/05/07 olof@austin.ibm.com 1.1063.1.32 # [TCP]: tcp_twkill leaves death row list in inconsistent state over tcp_timewait_kill. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.33 # [ATM]: Fix build of HE driver. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.12 # Decrement the nr_unstable page state after the COMMIT RPC call # completes instead of before. This ensures that writeback # WB_SYNC_ALL does wait on completion. # # Don't overreport the number of pages we wrote out. It is safer to # underreport. # # Fix missing NFSv3 unstable write accounting in fs/fs-writeback.c # and mm/page-writeback.c # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.13 # Fix typos in close-to-open cache consistency checking. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.14 # Fix a TCP race: check whether or not the socket has been disconnected # before we allow an RPC request to wait on a reply. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.15 # Don't use an RPC child process when reconnecting to a TCP server. # This is more efficient, and also fixes an existing deadlock # situation in which the child could be waiting for an xprt_write_lock # that was being held by the parent. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.16 # Ensure that if we need to reconnect the socket, we also resend # the entire RPC message # # Assorted TCP reconnection fixes. # # Temporarily raise the necessary CAP_NET_BIND_SERVICE capability # if we need to bind the socket to a reserved port during a TCP # reconnection. Check for CAP_NET_BIND_SERVICE at mount time. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.17 # Add the sk->callback_lock spinlocks to the RPC socket callbacks # in order to protect the socket from being released by one # CPU while the other is in a soft interrupt. # -------------------------------------------- # 03/05/07 cel@citi.umich.edu 1.1063.3.18 # the recently-applied patch to fix the rpc_show_tasks() Oops is incomplete. # this applies over 2.5.68 and should address all of the issues in # rpc_show_tasks(). # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.19 # Ensure that Lockd and the NSM (statd) clients always use privileged # ports. Remove the existing code to temporarily raise privileges in # fs/lockd/host.c, and use the new code in net/sunrpc/xprt.c # # There should no longer be a need to temporarily change the fsuid. # Remove this feature. # -------------------------------------------- # 03/05/07 trond.myklebust@fys.uio.no 1.1063.3.20 # UDP and TCP zero copy code for the NFS client. The main interest # of this patch is to eliminate the use of xdr_kmap() and xdr_unmap() # by replacing them with MSG_MORE. xdr_kmap() is deadlock-prone # due to the fact that it has to kmap() several pages at the same time. # -------------------------------------------- # 03/05/07 acme@conectiva.com.br 1.1063.7.1 # o ipx: ipx_interfaces outlives struct sock/socket # # And thus have to do module refcounting... # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.34 # Merge bk://kernel.bkbits.net/acme/ipx-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/07 torvalds@penguin.transmeta.com 1.1063.8.1 # Whee. Fix ancient mailing address. # -------------------------------------------- # 03/05/07 torvalds@penguin.transmeta.com 1.1063.9.1 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into penguin.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1078 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1079 # [PATCH] USB: update my copyrights in a few locations. # -------------------------------------------- # 03/05/07 torvalds@penguin.transmeta.com 1.1078.1.1 # Merge bk://kernel.bkbits.net/gregkh/linux/linus-2.5 # into penguin.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/07 chas@cmf.nrl.navy.mil 1.1063.1.35 # [ATM]: assorted atm patches # -------------------------------------------- # 03/05/07 chas@cmf.nrl.navy.mil 1.1063.1.36 # [ATM] remove iovcnt from atm_skb # skbs has (and has had for a while) scatter/gather support # making the scatter gather in atm redundant. the current iovcnt # schme really isnt being used anyway typically. the atm # layer will need a little more work in the future to take # advantage of the skb scatter/gather support. this patch # removes the iovcnt dependencies and gets the check for # non linear skbs right. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.37 # [IPV4]: Use time_{before,after}() and proper jiffies types in route.c # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.38 # [IPV4]: Two minor errors in jiffies changes. # -------------------------------------------- # 03/05/07 shemminger@osdl.org 1.1063.1.39 # [NET]: Kill more direct references to netdev->refcnt. # -------------------------------------------- # 03/05/07 kuznet@ms2.inr.ac.ru 1.1063.1.40 # [ACENIC]: Comment out netif_wake_queue from acenic watchdog. # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.41 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.1 # [PATCH] tc_zs tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.2 # [PATCH] specialix tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.3 # [PATCH] stallion tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.4 # [PATCH] serial_tx3912 tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.5 # [PATCH] sh-sci tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.6 # [PATCH] ser_a2232 tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.7 # [PATCH] serial167 tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.8 # [PATCH] rocket tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.9 # [PATCH] sgi/char/sgiserial tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.10 # [PATCH] rio tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.11 # [PATCH] riscom8 tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.12 # [PATCH] pcxx tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.13 # [PATCH] mxser tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.14 # [PATCH] istallion tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.15 # [PATCH] moxa tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.16 # [PATCH] ip2main tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.17 # [PATCH] isicom tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.18 # [PATCH] esp tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.19 # [PATCH] hvc_console tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.20 # [PATCH] dz tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.21 # [PATCH] cyclades tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.22 # [PATCH] amiserial tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.23 # [PATCH] macintosh/macserial tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.24 # [PATCH] isdn/capi tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 hannal@us.ibm.com 1.1063.10.25 # [PATCH] vme_scc tty_driver add .owner field remove MOD_INC/DEC_USE_COUNT # -------------------------------------------- # 03/05/07 davem@nuts.ninka.net 1.1063.1.42 # [PKT_SCHED]: Kill iovcnt reference from sch_atm.c # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1063.10.26 # TTY: add tty class support for all tty devices. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1063.10.27 # TTY: changes based on tty_register_device() paramater change. # -------------------------------------------- # 03/05/07 greg@kroah.com 1.1063.10.28 # TTY: remove usb-serial sysfs dev file as it is now redundant. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.2 # Make lib/inflate.c look remotely like ANSI C, so that it can be # properly checked with the rest of the kernel. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.3 # Avoid using undefined preprocessor symbols: check CONFIG_MK7 with # "defined()" rather than using it as a value. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.4 # Use "__attribute__" consistently. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.5 # Allow external checkers to overrid the "cond_syscall()" macro. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.6 # Support a "checking" mode for kernel builds, that runs a # user-supplied source checker on all C files before compiling # them. # # I'll release the actual checker once I've cleaned it up a # bit more (yay, all the copyright paperwork completed!) # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.7 # [PATCH] generic subarchitecture for ia32 # # From: Andi Kleen # # This patch adds an generic x86 subarchitecture. It is intended to provide # an dynamic interface for APIC drivers. There are already three subarchitectures # (bigsmp, summit, default) that only differ in how they drive the local APIC. # A fourth - Unisys ES7000 - is scheduled to be merged soon. # # The subarchitecture concept separated this nicely, but it has the big # drawback that they are compile time options. A Linux vendor cannot # ship own binary kernel rpms for all of these machines. Runtime probing # is needed instead. # # This patch adds a new "generic" subarchitecture that just acts as a # dynamic switching layer for APIC drivers. It only tries to virtualize # the APICs, no attempt is made to cover further incompatiblities. # This means machines like the Visual Workstation, pc9800 or # Voyager are not covered; but these are unlikely to be supported by # binary distributions anyways. # # The generic arch reuses the existing interface in mach_ipi / mach_mpparse.h / # mach_apic.h and just pulls it using some macros into an "struct genapic" # object. The main APIC code does not recognize it, it is all hidden # in the mach-generic include files. # # Auto detection of APIC types is supported in the usual way used by # existing ports like Summit - checking ACPI or mptables for specific # signatures - or it can be specified by the user using a new "apic=" # boot option. I also moved the DMI scan to before the generic # subarchitecture probe, so DMI could be used in future too to probe # specific machines. # # Some minor hacks were needed to avoid circular declaration of a few # symbols, but overall it's fairly clean. # # The patch has been tested on a Summit machine, an generic 4 virtual CPUs # Xeon and on an ES7000. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.8 # [PATCH] Fix .altinstructions linking failures # # From: Andi Kleen # # Some configs didn't link anymore because they got references from # .altinstructions to __exit functions. Fixing it at the linker level is not # easily possible. This patch just discards .text.exit at runtime instead of # link time to avoid this. # # It will also fix a related problem with .eh_frame in modern gcc (so far only # observed on x86-64, but could happen on i386 too) # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.9 # [PATCH] cpia driver __exit fix # # From: Andi Kleen # # This driver was bogusly relying on the dropping of the __exit section at link # time. cpia_exit() is calling proc_cpia_destroy(), which doesn't even exist # if !CONFIG_MODULE. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.10 # [PATCH] fix OSS opl3sa2 compilation # # From: Zwane Mwaikambo # # There was a 2.4 merge from Alan Cox, but a few #ifdef's got shuffled around # in the process, resulting in a broken build for !CONFIG_PM # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.11 # [PATCH] misc fixes # # - ifdef fix in kmap_types.h (Oleg Drokin) # # - remove redundant ext3 inclusions (Burton Windle) # # - Fix misidentified warning printk in vmalloc.c # # - radeon_cp printk warning fix (Randy Dunlap) # # - Update minimum binutils version for the ".incbin" thing in vsyscall.S # # - update raw driver to recent module API. # # - update my email address # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.12 # [PATCH] mwave build fix # # From: Michael Buesch and Paul Schroeder. # # mwavedd.h needs and smapi.h # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.13 # [PATCH] drm timer initialisation fix # # The timer is being initialised too late (in ->open()). If modprobe fails we # get an uninitialised timer warning. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.14 # [PATCH] slab: initialisation cleanup and oops fix # # From: Manfred Spraul # # attached is the promised cleanup/bugfix patch for the slab bootstrap: # # - kmem_cache_init & kmem_cache_sizes_init merged into one function, # called after mem_init(). It's impossible to bring slab to an operational # state without working gfp, thus the early partial initialization is not # necessary. # # - g_cpucache_up set to FULL at the end of kmem_cache_init instead of the # module init call. This is a bugfix: slab was completely initialized, # just the update of the state was missing. # # - some documentation for the bootstrap added. # # The minimal fix for the bug is a two-liner: move g_cpucache_up=FULL from # cpucache_init to kmem_cache_sizes_init, but I want to get rid of # kmem_cache_sizes_init, too. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.15 # [PATCH] sysrq-S, sysrq-U cleanups # # From: Christoph Hellwig # # Change sysrq sync/remount from a magic bdflush hook to proper pdflush # operations. The sync operation reuses most of the regular sys_sync path now # instead of implementing it's own superblock walking and (broken) local disk # detection, the remount implementation has been moved to super.c, cleaned up # and updated for the last two years locking changes. It also shares some code # with the regular remount path now. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.16 # [PATCH] s/UPDATE_ATIME/update_atime/ cleanup # # From: Stewart Smith # # Remove the UPDATE_ATIME() macro, use update_atime() directly. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.17 # [PATCH] irqreturn_t for drivers/net/pcmcia # # From: Zwane Mwaikambo # # update pcmcia drivers for new IRQ API # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.18 # [PATCH] keyboard.c Fix CONFIG_MAGIC_SYSRQ+PrintScreen # # From: Chris Heath # # This patch fixes the PrintScreen key when CONFIG_MAGIC_SYSRQ is enabled. It # allows you to use that key normally when Alt is not being pressed. Patch is # against kernel 2.5.68. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.19 # [PATCH] Don't use devfs names in disk_name() # # From: Christoph Hellwig # # disk_name() (and hence bdevname()) are now returning devfs-style device names # when devfs is enabled. # # This is nice, but these names are very long, and they overflow the 32-char # buffers which these functions use. # # The choices are: # # a) Use a bigger buffer (increase BDEVNAME_SIZE). # # This might be practical. But how big? # # b) return the name in kmalloced memory, make caller free it up. Yuk. # # c) Add a print_bdevname() thing and intersperse that amongst the printk's. # This would work. # # d) Just print the non-devfs device name. That's what this patch does. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.20 # [PATCH] devfs: API changes # # From: Christoph Hellwig # # Some people may already have noticed that I've been revamping the devfs API # recently. The worst offender still left is devfs_register, it's prototype # is: # # devfs_handle_t devfs_register(devfs_handle_t dir, # const char *name, unsigned int flags, # unsigned int major, unsigned int minor, # umode_t mode, void *ops, void *info) # # Of these: # # - dir and flags are always zero # - the return value is never used # - info is only used in one driver which doesn't even need it for # operation # - umode_t always describes a character device # - name very often comes from a stack buffer we sprintf'ed into # # so obviously we really want a much simpler API instead. My first draft for # this was: # # int devfs_mk_cdev(dev_t dev, umode_t mode, # struct file_operations *fops, void *info, # const char *fmt, ...) # # this removes the unused argumens, switches to a proper dev_t for the device # number and allows to directly use a printf-like expression as name, getting # rid of the temporary buffers. # # Now Al has reappeared and put the first steps of his CIDR for charater device # on public ftp and we'll soon have a similar lookup object + fops mechanism in # generic code as we already habe for blockdevices, i.e. the devfs code to # assign fops from an entry will become superflous as generic code already does # it. That means the fops and info arguments are obsolete before they were # introduced, so I'd like to propose the following API instead: # # int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) # # which is much nicer anyway. The educated reader will notice that this is # exactly the same prototype devfs_mk_bdev has so I'll probably get suggestions # to merge those two into some kind of devfs_mk_node soon. Personally I don't # like that as character and blockdevices are two really separate entinities # and I'll like to keep them as separate as possible. # # Example patch that introduces the API and converts drivers/input attached. # # Every driver which calls devfs_mk_cdev (about 50) needs conversion. Note # that the transition can happen in pieces - devfs_register continues to work # after this patch, it's just the plan to get rid of it in the end. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.21 # [PATCH] remove partition_name() # # From: Christoph Hellwig # # partition_name() is a variant of __bdevname() that caches results and # returns a pointrer to kmalloc()ed data instead of printing into a buffer. # Due to it's caching it gets utterly confused when the name for a dev_t # changes (can happen easily now with device mapper and probably in the # future with dynamic dev_t users). # # It's only used by the raid code and most calls are through a wrapper, # bdev_partition_name() which takes a struct block_device * that maybe be # NULL. # # The patch below changes the bdev_partition_name() to call bdevname() if # possible and the other calls where we really have nothing more than a dev_t # to __bdevname. # # Btw, it would be nice if someone who knows the md code a bit better than me # could remove bdev_partition_name() in favour of direct calls to bdevname() # where possible - that would also get rid of the returns pointer to string # on stack issue that this patch can't fix yet. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.22 # [PATCH] switch most remaining drivers over to devfs_mk_bdev # # From: Christoph Hellwig # # This is a pretty huge patch, but splitting it doesn't make a lot # of sense.. # # (USB may still need work) # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.23 # [PATCH] dvbdev fixes # # From: Monchi Abbad # # I found a mistake in the dvbdev.c file when creating the dvb /devfs files, # it created /dev/dvb/adapter0device0 instead of /dev/dvb/adapter0/device0. # But here is a simple fix. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.24 # [PATCH] access_ok() race fix for 80386. # # From: Manfred Spraul # # Real 80386 cpus ignore the write protected bit in the page tables when # running in supervisory mode. Thus the write protected bit must be checked by # software. The current implementation does that check during access_ok(). # This can result in data corruptions, if kswapd starts a swap-out between the # access_ok and the actual write operation. # # To fix this, the patch moves the check from access_ok() into # __copy_to_user_ll(), and redirects all user space writes into # __copy_to_user_ll(). The patch only affects kernels build for 80386 cpus. # Additionally, the patch removes the dead prototypes for __put_user_{1,2,4,8}. # # Due to the uninlining of access_ok, the .text segment is now ~ 8 kB shorter. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.25 # [PATCH] hold i_sem on swapfiles # # If a swapfile is ftruncated while in use, subsequent swapout will scribble on # the filesystem. # # This is a case of root-shoot-foot, but wrecking the fs is a fairly rude # response. And it's easy to fix: hold i_sem across the life of the swapon. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.26 # [PATCH] remove unnecessary PAE pgd set # # From: Dave Hansen , Bill Irwin # # With PAE on, there are only 4 PGD entries. The kernel ones never change, # so there is no need to copy them when a vmalloc fault occurs. This was # this was causing problems with the split pmd patches, but it is still # correct for mainline. # # Tested with and without PAE. I ran it in a loop turning on and off 10 swap # partitions, which is what excited the original bug. # http://bugme.osdl.org/show_bug.cgi?id=640 # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.27 # [PATCH] account for slab reclaim in try_to_free_pages() # # try_to_free_pages() currently fails to notice that it successfully freed slab # pages via shrink_slab(). So it can keep looping and eventually call # out_of_memory(), even though there's a lot of memory now free. # # And even if it doesn't do that, it can free too much memory. # # The patch changes try_to_free_pages() so that it will notice freed slab pages # and will return when enough memory has been freed via shrink_slab(). # # Many options were considered, but must of them were unacceptably inaccurate, # intrusive or sleazy. I ended up putting the accounting into a stack-local # structure which is pointed to by current->reclaim_state. # # One reason for this is that we can cleanly resurrect the current->local_pages # pool by putting it into struct reclaim_state. # # (current->local_pages was removed because the per-cpu page pools in the page # allocator largely duplicate its function. But it is still possible for # interrupt-time allocations to steal just-freed pages, so we might want to put # it back some time.) # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.28 # [PATCH] slab: additional debug checks # # From: Manfred Spraul # # below is the promised patch for better slab debugging, against 2.5.68-mm4: # # Changes: # # - enable redzoning and last user accounting even for large objects, if # that doesn't waste too much memory # # - document why FORCED_DEBUG doesn't enable redzoning&last user accounting # for some caches. # # - check the validity of the bufctl chains in a slab in __free_blocks. # This detects double-free error for the caches without redzoning. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.29 # [PATCH] reduced overheads in fget/fput # # From: Dipankar Sarma # # # fget() shows up on profiles, especially on SMP. Dipankar's patch # special-cases the situation wherein there are no sharers of current->files. # # In this situation we know that no other process can close this file, so it # is not necessary to increment the file's refcount. # # It's ugly as sin, but makes a substantial difference. # # The test is # # dd if=/dev/zero of=foo bs=1 count=1M # # On 4CPU P3 xeon with 1MB L2 cache and 512MB ram: # # kernel sys time std-dev # ------------ -------- ------- # # UP - vanilla 2.104 0.028 # UP - file 1.867 0.019 # # SMP - vanilla 2.976 0.023 # SMP - file 2.719 0.026 # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.30 # [PATCH] allow i8042 interrupt sharing # # Ed Tomlinson has a machine on which some other device grabs IRQ12 first, and # the 8042 doesn't work. Enabling shared iRQs in the 8042 driver fixes it up. # Alan has confirmed that this is OK. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.31 # [PATCH] select() speedup # # From: Christoph Hellwig # # Originally by David Mosberger, testing by Roger Luethi. From the ia64 tree. # # Basically, it avoids going to memory all the time. What this does is make # life a lot easier for gcc, so it can actually do a decent amount of # optimization. The restructuring clearly is less important for out-of-order # CPUs, but even there it gives some benefits. # # More specifically, the loop is now structured to operate one "unsigned long" # at a time, rather than one bit at a time. Of course, you still need to # process all the bits, but most of the relevant state in the inner loop can be # kept in registers. # # Roger Luethi measured the routine on a bunch of different machines (mostly # x86, IIRC: P5, P6, Crusoe, Athlons) and performance improved there, too (and # it should definitely improve performance on any RISC-like architecture). # # # Roger's benchmarking results (vs number of fd's): # # File TCP # Numbfer of fd's: 10 250 500 10 250 500 # # UP, Pentium MMX 233MHz original 8.2 108.5 212.8 11.0 180.0 356.5 # UP, Pentium MMX 233MHz w/patch 7.4 87.6 171.1 10.4 163.6 323.4 # # MP, Pentium MMX 233MHz original 15.7 283.8 562.8 18.9 354.4 705.5 # MP, Pentium MMX 233MHz w/patch 14.6 255.6 506.5 17.8 332.8 664.1 # # UP, Athlon 1394 MHz original 1.3 13.4 26.1 1.9 24.7 48.6 # UP, Athlon 1394 MHz w/patch 1.2 11.0 21.5 1.6 22.3 43.8 # # MP, Athlon 1394 MHz original 1.6 22.4 44.6 1.9 30.9 60.5 # MP, Athlon 1394 MHz w/patch 1.5 21.2 41.7 1.9 30.2 59.6 # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.32 # [PATCH] Move security_d_instantiate hook calls # # From: Stephen Smalley # # This patch moves the security_d_instantiate hook calls in d_instantiate and # d_splice_alias after the inode has been attached to the dentry. This # change is necessary so that security modules can internally call the # getxattr inode operation (which takes a dentry parameter) from this hook to # obtain the inode security label. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.33 # [PATCH] ext3 xattr handler for security modules # # From: Stephen Smalley # # This patch against 2.5.68 implements an xattr handler for ext3 to support the # use of extended attributes by security modules for storing file security # labels. As per the earlier discussion of extended attributes for security # modules, this handler uses a "security." prefix and allows for per-module # attribute names. Security checking for userspace access to these attributes # can be performed by the security module using the LSM hooks in fs/xattr.c, # and the security module is free to internally use the inode operations # without restriction for managing its security labels. Unlike the trusted # namespace, these labels are used internally for access control purposes by # the security modules, and controls over userspace access to them require # finer granularity than capable() supports. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.34 # [PATCH] ext2 xattr handler for security modules # # From: Stephen Smalley # # This patch against 2.5.68 implements an xattr handler for ext2 to support the # use of extended attributes by security modules for storing file security # labels. As per the earlier discussion of extended attributes for security # modules, this handler uses a "security." prefix and allows for per-module # attribute names. Security checking on userspace access to these attributes # can be performed by the security module using the LSM hooks in fs/xattr.c, # and the security module is free to internally use the inode operations # without restriction for managing its security labels. Unlike the trusted # namespace, these labels are used internally for access control purposes by # the security module, and controls over userspace access to them require finer # granularity than capable() supports. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.35 # [PATCH] Change LSM hooks in setxattr # # From: Stephen Smalley # # This patch against 2.5.69 adds a security_inode_post_setxattr hook so that # security modules can update the inode security structure after a successful # setxattr, and it moves the existing security_inode_setxattr hook call after # the taking the inode semaphore so that atomicity is provided for the # security check and the update to the inode security structure. # -------------------------------------------- # 03/05/07 akpm@digeo.com 1.1078.1.36 # [PATCH] Work around include/linux/sunrpc/svc.h compilation # # From: Grzegorz Jaskiewicz # # gcc-2.94 fails to compile this code, alleging an invalid lvalue. # An equivalent transformation fixes it up. # -------------------------------------------- # 03/05/07 torvalds@home.transmeta.com 1.1078.1.37 # Merge conflicting tty devfs cleanups # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1078.1.38 # TTY: fix up lost devfs_mk_cdev change. # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1078.1.39 # USB: change core to use devfs_mk_cdev() instead of devfs_register() # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1078.1.40 # USB: fix up compile error in tiglusb driver due to devfs_mk_cdev() changes. # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1080 # Merge gregkh@kernel.bkbits.net:/home/gregkh/linux/linus-2.5 # into kroah.com:/home/linux/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1081 # TTY: add lock to tty_dev_list, and handle tty names with more than one '/' # # Thanks to Al Viro for pointing out these problems. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/08 chas@locutus.cmf.nrl.navy.mil 1.1078.2.2 # [ATM]: Kill stray ATM_PDU_OVHD reference in lec.c # -------------------------------------------- # 03/05/08 mk@linux-ipv6.org 1.1078.2.3 # [IPSEC]: Fix ipcomp header handling in ipv4 IPCOMP. # -------------------------------------------- # 03/05/08 rddunlap@osdl.org 1.1078.2.4 # [IPV6]: Remove incorrect comment in ip6_fib.c # -------------------------------------------- # 03/05/08 shemminger@osdl.org 1.1078.2.5 # [SYSKONNECT]: /proc module handling fixup. # -------------------------------------------- # 03/05/08 shemminger@osdl.org 1.1078.2.6 # [PKTGEN]: Module and dev cleanup. # -------------------------------------------- # 03/05/08 steve@gw.chygwyn.com 1.1078.2.7 # [DECNET]: Decnet not obeying netdev locking (from shemminger@osdl.org). # -------------------------------------------- # 03/05/08 hch@lst.de 1.1078.2.8 # [SLIP]: Move over to initcalls. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.3.1 # Merge http://linux-lksctp.bkbits.net/lksctp-2.5 # into nuts.ninka.net:/home/davem/src/BK/sctp-2.5 # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.9 # Merge nuts.ninka.net:/home/davem/src/BK/sctp-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.10 # [IPV4]: Fix expiration test in rt_check_expire. # -------------------------------------------- # 03/05/08 rusty@rustcorp.com.au 1.1078.2.11 # [NETFILTER]: Fix skb_checksum args in ip_nat_core.c # -------------------------------------------- # 03/05/08 davem@kernel.bkbits.net 1.1082 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.1 # [PATCH] USB Gadget API (1/6) # # This patch createss , the gadget API # and inlined implementation. # # There's additional kerneldoc, which I won't submit at # this time, available. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.2 # [PATCH] Net2280 driver (2/6) # # This patch creates drivers/usb/gadget/net2280.[hc], # providing a driver for NetChip's "Net2280 PCI USB 2.0 # High Speed Peripheral Controller". # # It implements the API included in the first patch. # # The driver has behaved well with chiprev 0100 under # stress tests with Gadget Zero and the ethernet model # driver, and has passed sanity tests for chiprev 0110. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.3 # [PATCH] USB "Gadget Zero" driver (3/6) # # This patch adds "Gadget Zero" (drivers/usb/gadget/zero.c). # # Gadget Zero is a simple gadget driver that's useful for # testing controller drivers, and as an example to be used # for clone/modify style development. # # This driver implements two configurations, and needs only # two bulk endpoints (in addition to ep0) ... so pretty much # any USB device controller should be usable with it in # one configuration or another. It (optionally) supports # high speed devices, and has passed the USB-IF "chapter 9" # device model conformance tests. # # It's worth noticing the kinds of hardware differences that # gadget drivers need to cope with. Endpoints differ, in # ways that must be reflected various ways in descriptors. # And sometimes chip errata cause interoperability problems; # for example, an sa1100 can't change configurations after # enumerating. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.4 # [PATCH] USB Ethernet Gadget (4/6) # # This patch adds an "Ethernet Gadget" driver, implementing # the CDC Ethernet model (drivers/usb/gadget/ether.c). # # It interops with the current CDC Ether drivers on Linux, # both 2.4 (CDCEther, using Marcelo's latest) and 2.5 # (cdc-ether with recent patches, or on 2.5.68 "usbnet") # # On a net2280, this has successfully streamed dozens of # megabytes per second using "ttcp" (high speed, and using # "usbnet" on the host side), for days at a time. And no # problems using SSH/NFS/etc in lighter duty testing. # # It's possible this will need tweaking to cope with UDC # bugs on Intel's pxa25x controllers, presenting itself # as a non-CDC device. (I'm told altsettings are even # more broken than originally specified to be.) # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.5 # [PATCH] USB Gadget string utility (5/6) # # This adds utility code that gadget drivers can use to manage # string descriptors (drivers/usb/gadget/usbstring.c) in the # common case that the ISO-8859/1 character set is in use. # # Both "Gadget Zero" and the Ethernet gadget code use this. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.6 # [PATCH] kbuild/kbuild for USB Gadgets (6/6) # # This patch adds kconfig/kbuild support for the preceding # code, so that an EXPERIMENTAL option appears in the # USB part of the config menus. # # Once a USB device controller driver is configured (which # just now means net2280, but sa11x0 and pxa25x options # are just waiting for updates!), gadget driver options # are also available. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.7 # [PATCH] USB: gadget cleanup of #ifdefs # # > can you get rid of all of the #ifdef HAVE_DRIVER_MODEL stuff? # # Done. Now this code "knows" it's running in a 2.5 # environment, and needs modifications to run on 2.4. # # I also changed the file modes in the module_parm() # calls so the parameters will be writable when they # eventually show up in sysfs; and fixed a typo. # # Compile-tested with and without DEBUG enabled. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.8 # [PATCH] USB: gadget zero, loopback config fix # # If the host writes OUT packets using URB_ZERO_PACKET # (or its analogue on other USB host systems), then the # loopback configuration should set req->zero, to use that # same transfer termination policy when it writes the # response back IN to the host. # -------------------------------------------- # 03/05/08 david-b@pacbell.net 1.1078.4.9 # [PATCH] USB gadget: net2280: dmachain off, zlp pio ok # # This patch has two small fixes for issues that people # reported to me yesterday: # # - One of the out-of-tree drivers sees odd things # happening when dma chaining is enabled. (The # in-tree drivers seem fine with it.) So disable # for now; it's easily enabled if needed. # # - Zero Length Packets (ZLPs): # # * Should now read/write ok with PIO. # # * On DMA endpoints, explicit ZLPs need PIO. # Until they do, don't allow queuing zero length # buffers onto DMA endpoints. # -------------------------------------------- # 03/05/08 torvalds@penguin.transmeta.com 1.1083 # Use the right CFLAGS for source checking. Fix grammar. # -------------------------------------------- # 03/05/08 greg@kroah.com 1.1081.1.1 # Merge kroah.com:/home/linux/linux/BK/bleed-2.5 # into kroah.com:/home/linux/linux/BK/gadget-2.5 # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.12 # [MPLS]: Add ethernet protocol numbers. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.13 # [NETFILTER]: Fix icmp_reply_translation args. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.14 # [MPLS]: Add MPLS support to PPP. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.15 # [SKFDDI]: Use SET_MODULE_OWNER. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.16 # [IPV6]: Pass route attributes all the way down. # -------------------------------------------- # 03/05/08 davidm@tiger.hpl.hp.com 1.1063.6.4 # ia64: Patch from Asit K. Mallick: fix a few places where last_fph_cpu # wasn't updated and one place in the sigreturn path where # the fph-owner wasn't set. # -------------------------------------------- # 03/05/08 jmorris@intercode.com.au 1.1078.2.17 # [IPSEC]: Use xfrm_state_put in pfkey_msg2xfrm_state. # -------------------------------------------- # 03/05/08 chas@cmf.nrl.navy.mil 1.1078.2.18 # [ATM]: Make he driver code more palatable. # -------------------------------------------- # 03/05/08 davem@nuts.ninka.net 1.1078.2.19 # [NETFILTER]: Fix ip_nat_core.c:manip_pkt return value checks. # -------------------------------------------- # 03/05/08 willy@debian.org 1.1078.2.20 # [DLCI]: Use module_init and fix ioctl handling. # -------------------------------------------- # 03/05/08 ak@muc.de 1.1078.2.21 # [NET]: Clean up socket filter compat handling. # -------------------------------------------- # 03/05/09 nfsclient.adm@hostme.bitkeeper.com 1.1084 # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/ua/repos/n/nfsclient/linux-2.5 # -------------------------------------------- # 03/05/09 davem@nuts.ninka.net 1.1083.1.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/09 yoshfuji@linux-ipv6.org 1.1083.1.2 # [MAINTAINERS/CREDITS]: Add entries for USAGI hackers. # -------------------------------------------- # 03/05/09 jmorris@intercode.com.au 1.1083.1.3 # [XFRM]: Make use of xfrm_state_hold(). # -------------------------------------------- # 03/05/09 jmorris@intercode.com.au 1.1083.1.4 # [XFRM]: Use xfrm_pol_hold(). # -------------------------------------------- # 03/05/09 hch@lst.de 1.1083.1.5 # [NET]: Switch x25_asy over to initcalls. # -------------------------------------------- # 03/05/09 davem@nuts.ninka.net 1.1083.1.6 # [XFRM]: Fix typos in xfrm_state_put() changes. # -------------------------------------------- # 03/05/09 torvalds@home.transmeta.com 1.1083.2.1 # Make aic7xxx driver use ANSI prototypes. My checker tool refuses # to touch K&R C. # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.7 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into penguin.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.3.1 # [PATCH] i2c: add i2c_adapter class support # -------------------------------------------- # 03/05/09 mark@alpha.dyndns.org 1.1083.3.2 # [PATCH] I2C: add more classes # # Add I2C classes for analog and digital cameras, and fix a typo. # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.8 # Annotate LDT system calls with user pointer annotations. # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.9 # Annotate x86 system calls with user pointer annotations. # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.10 # Fix mismatch between i387 user copy function declaration and # definition. # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.11 # Annotate IPC system calls with user pointer annotations # -------------------------------------------- # 03/05/09 torvalds@penguin.transmeta.com 1.1083.1.12 # Annotate vm86_info as a pointer to user space. # -------------------------------------------- # 03/05/09 warp@mercury.d2dc.net 1.1083.3.3 # [PATCH] I2C: Another it87 patch. # # This is against my last. # # While the old code most definitely did /something/ to the register for # setting the fan div, the 'what' is a more interesting question. # # To be honest I could not figure out what it was trying to do, because # the way it was inserting values disagreed with not only the data sheet, # but how it parsed the very same register. # # This corrects the issue, and allows one to properly control the divisor # on all 3 fans, including the (much more limited) 3rd fan. # -------------------------------------------- # 03/05/09 warp@mercury.d2dc.net 1.1083.3.4 # [PATCH] I2C: Yet another it87 patch. # # Ok, after writing up something in the way of a perl script to make some # sense of the data for voltages, and finding that there is no sense to # make, I took a longer look at things. # # The it87 driver in 2.5.x is doing some, down right /odd/ math on the # numbers for the in_input* readings, and the 2.4.x driver is doing # something quite different. # # And while it might be possible to get sane numbers out of the 2.5.x # driver, people /expect/ to get the numbers that they were getting from # 2.4.x. # # So this patch puts things back to the simpler calculations done by the # 2.4.x lm-sensors drivers, and my script confirms that the numbers come # out right. # -------------------------------------------- # 03/05/09 warp@mercury.d2dc.net 1.1083.3.5 # [PATCH] I2C: And another it87 patch. # # Don't provide min/max for in8, which allowed one to scribble on # registers one should not be messing with. (My fault, oops.) # # The setting of the temp high/low registers was off by one, not mine this # time. While I was at it, I reordered a few other register accesses to # be base 0 instead of base 1. # # The temp interface was slightly incorrect, degrees * 100 instead of # degrees * 1000, also fixed. # # And lastly, when changing the fan count divisor, fix up the min setting # to still be roughly the same. (Previously the meaning of the value in # the register changed, but not the value itself, resulting in, undesired # surprises.) # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.3.6 # [PATCH] i2c: register the i2c_adapter_driver so things link up properly in sysfs # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.1.13 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/09 rohit.seth@intel.com 1.1063.6.5 # [PATCH] ia64: enable 1G hugepage size for Mckinley # # -------------------------------------------- # 03/05/09 corbet@lwn.net 1.1083.4.1 # [PATCH] cpufreq class fix # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.4.2 # [PATCH] driver core: Add driver symlink to class devices in sysfs. # # Thanks to Mike Anderson for the idea for this. # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.4.3 # [PATCH] driver core: remove unneeded line in class code. # # Thanks to Jonathan Corbet for pointing this out. # -------------------------------------------- # 03/05/09 vandrove@vc.cvut.cz 1.1083.5.1 # [PATCH] Fix potential runqueue deadlock # # send_sig_info() has been broken since 2.5.60. # # The function can be invoked from a the time interrupt (timer_interrpt -> # do_timer -> update_process_times -> -> update_one_process -> ( # do_process_times, do_it_prof, do_it_virt ) -> -> send_sig -> # send_sig_info) but it uses spin_unlock_irq instead of the correct # spin_unlock_irqrestore. # # This enables interrupts, and later scheduler_tick() locks runqueue # (without disabling interrupts). And if we are unlucky, a new interrupt # comes at this point. And if this interrupt tries to do wake_up() (like # RTC interrupt does), we will deadlock on runqueue lock :-( # # The bug was introduced by signal-fixes-2.5.59-A4, which split the # original send_sig_info into two functions, and in one branch it started # using these unsafe spinlock variants (while the "group" variant uses # irqsave/restore correctly). # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.1.14 # Merge greg@deskfan:linux/BK/i2c-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.4.4 # Merge greg@deskfan:linux/BK/class-2.5 # into kroah.com:/home/greg/linux/BK/class-2.5 # -------------------------------------------- # 03/05/09 greg@kroah.com 1.1083.5.2 # Merge greg@desk:linux/BK/gadget-2.5 # into kroah.com:/home/greg/linux/BK/gadget-2.5 # -------------------------------------------- # 03/05/10 davidm@tiger.hpl.hp.com 1.1063.6.6 # ia64: Prepare for GCC v3.4. Sync with 2.5.69. # -------------------------------------------- # 03/05/10 davidm@tiger.hpl.hp.com 1.1063.6.7 # ia64: Patch by John Marvin: Add virtual mem-map support. # -------------------------------------------- # 03/05/10 davem@nuts.ninka.net 1.1083.6.1 # [TCP]: NULL out newsk->owner in tcp_create_openreq_child(). # -------------------------------------------- # 03/05/10 jgarzik@redhat.com 1.1083.6.2 # [SCTP]: Fix missing Kconfig dependency. # -------------------------------------------- # 03/05/10 shemminger@osdl.org 1.1083.6.3 # [IPV4/IPV6]: inetsw using RCU. # -------------------------------------------- # 03/05/10 yoshfuji@linux-ipv6.org 1.1083.6.4 # [IPV6]: Convert /proc/net/raw6 to seq_file. # -------------------------------------------- # 03/05/10 chas@cmf.nrl.navy.mil 1.1083.6.5 # [ATM]: HE and IPHASE driver fixes. # -------------------------------------------- # 03/05/10 yoshfuji@linux-ipv6.org 1.1083.6.6 # [NET]: Set file_operations->owner as appropriate. # -------------------------------------------- # 03/05/10 davem@nuts.ninka.net 1.1083.6.7 # [VLAN]: vlanproc.c needs module.h # -------------------------------------------- # 03/05/10 torvalds@home.transmeta.com 1.1083.1.15 # Merge master.kernel.org:/home/gregkh/BK/i2c-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/10 torvalds@home.transmeta.com 1.1083.1.16 # Merge master.kernel.org:/home/gregkh/BK/gadget-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/10 torvalds@home.transmeta.com 1.1083.1.17 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/10 axboe@suse.de 1.1083.1.18 # [PATCH] bio_endio() increments bio->bi_sector # # increment bi_sector in bio_endio() so make_request_fn drivers don't # have to do this accounting themselves. # -------------------------------------------- # 03/05/10 axboe@suse.de 1.1083.1.19 # [PATCH] make MO drive work with ide-floppy/ide-cd # # Resend of the ide-cd buggy debug check removal. # # From der.eremit@email.de. # -------------------------------------------- # 03/05/10 axboe@suse.de 1.1083.1.20 # [PATCH] shrink deadline hash size # # Limit deadline hash to 32 entries instead of 1024. This has been benched # and profiled extensively and shows no increased system time. # # Also, move "hot" entries to the front of the list. # -------------------------------------------- # 03/05/10 axboe@suse.de 1.1083.1.21 # [PATCH] dynamic request allocation # # This patch adds dynamic allocation of request structures. Right now we # are reserving 256 requests per initialized queue, which adds up to quite # a lot of memory for even a modest number of queues. For the quoted 4000 # disk systems, it's a disaster. # # Instead, we mempool 4 requests per queue and put an upper limit on the # number of requests that we will put in-flight as well. I've kept the 128 # read/write max in-flight limit for now. It is trivial to experiement # with larger queue sizes now, but I want to change one thing at the time # (the truncate scenario doesn't look all that good with a huge number of # requests, for instance). # # Patch has been in -mm for a while, I'm running it here against stock 2.5 # as well. Additionally, it actually kills quite a bit of code as well # -------------------------------------------- # 03/05/10 nfsclient.adm@hostme.bitkeeper.com 1.1085 # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/ua/repos/n/nfsclient/linux-2.5 # -------------------------------------------- # 03/05/11 hch@lst.de 1.1083.1.22 # [PATCH] switch sb1000 to new style net init & pnp # # This cleans up the driver big time and gets rid of a big ugly wart # in setup.c. Note that I don't have the hardware so this is only # compile-tested. # -------------------------------------------- # 03/05/11 jt@bougret.hpl.hp.com 1.1083.1.23 # [PATCH] irq fixes for wavelan_cs/netwave_cs # # This patch for 2.5.68-bk11 will fix the irq handler of some # obsolete wireless drivers (wavelan, wavelan_cs and netwave_cs) plus # assorted fixes. All those drivers have been tested on a SMP box. # -------------------------------------------- # 03/05/11 jt@bougret.hpl.hp.com 1.1083.1.24 # [PATCH] Wireless Extension 16 # # This patch for 2.5.68-bk11 will update Wireless Extension to # version 16 : # o increase bitrate and frequency number for 802.11g/802.11a # o enhanced iwspy support # o minor tweaks and cleanups # # This patch is only for the core of WE. The patches for the # individual drivers have been sent to their respective maintainers. # Compared to the previous version I sent you a few weeks ago, # I've just updated to the latest kernel. # -------------------------------------------- # 03/05/11 jt@bougret.hpl.hp.com 1.1083.1.25 # [PATCH] WE-16 for Wavelan ISA driver # # This update the Wavelan ISA driver for Wireless Extension 16 # (going with my previous patch). # -------------------------------------------- # 03/05/11 jt@bougret.hpl.hp.com 1.1083.1.26 # [PATCH] WE-16 for Wavelan Pcmcia driver # # This patch update the Wavelan Pcmcia driver for Wireless # Extensions 16, and also remove all the backward compatibility cruft # that is broken anyway. # -------------------------------------------- # 03/05/11 paulus@samba.org 1.1083.1.27 # [PATCH] Update mac ethernet drivers # # This patch updates the bmac and mace ethernet drivers so that their # interrupt routines return an irqreturn_t, and updates the bmac driver # to use a spinlock rather than global cli/sti. # -------------------------------------------- # 03/05/11 dean@arctic.org 1.1083.1.28 # [PATCH] better ali1563 integrated ethernet support # # it turns out the tulip driver is a much better driver for the integrated # ali1563 ethernet than the dmfe driver... the dmfe driver gets tx timeouts # every ~15s and can't receive over 5MB/s. but with the small tulip patch # below i'm seeing 11MB/s+ in both directions without problems. # -------------------------------------------- # 03/05/11 mzyngier@freesurf.fr 1.1083.1.29 # [PATCH] depca update (was Re: [Patch] DMA mapping API for Alpha) # # this patch has been sleeping # in Alan tree for quite some time. It updates the depca driver to the # EISA/sysfs API, gets rid of check_region, and properly reserve memory # region. Patch is against latest BK. # -------------------------------------------- # 03/05/11 jgarzik@redhat.com 1.1083.7.1 # [bk] add useful tip to bk kernel howto # # Kudos to Wayne Scott @ BitMover for this. # -------------------------------------------- # 03/05/11 axboe@suse.de 1.1083.1.30 # [PATCH] Proper 48-bit lba support # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1083.1.31 # Merge bk://kernel.bkbits.net/jgarzik/misc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1083.1.32 # Merge bk://linux-dj.bkbits.net/cpufreq # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1083.1.33 # Merge bk://linux-dj.bkbits.net/agpgart # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 mikpe@csd.uu.se 1.1083.1.34 # [PATCH] restore sysenter MSRs at APM resume # # This changes apm.c to invoke suspend.c's save and restore processor # state procedures around suspends, which fixes the SYSENTER MSR problem. # # The patch also decouples sysenter.c from SOFTWARE_SUSPEND: the variables # used (only!) in suspend_asm.S are moved there, and the include file now # declares the procedures called from apm.c (previously they were only # called from suspend_asm.S). # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1086 # Merge http://nfsclient.bkbits.net/linux-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 B.Zolnierkiewicz@elka.pw.edu.pl 1.1087 # [PATCH] fix lost IDE interrupt problem # # Alan and I were investigating this, but we don't know why the problem # occurs. # # This reverts the previous handling of masked_irq, and fixes the problem. # -------------------------------------------- # 03/05/11 rth@kanga.twiddle.net 1.1083.8.1 # [ALPHA] Fix titan_intr_nop for 2.5 irq api changes. # -------------------------------------------- # 03/05/11 davem@nuts.ninka.net 1.1083.9.1 # [IPV4/IPV6]; Missing schedule_net() in inet{,6}_del_protocol. # -------------------------------------------- # 03/05/11 davem@nuts.ninka.net 1.1083.9.2 # [NETFILTER]: Fix stale skb data pointer usage in ipv4 NAT. # -------------------------------------------- # 03/05/11 davem@kernel.bkbits.net 1.1088 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/05/11 davem@nuts.ninka.net 1.1083.9.3 # [IPV6]: Missing sk->family check in UDPv6 multicast handling. # -------------------------------------------- # 03/05/11 davem@kernel.bkbits.net 1.1089 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1090 # Bartlomiej says: 'Please revert this patch, it is unfinished.' # We'll do it *after* IDE taskfile IO is done # Cset exclude: axboe@suse.de|ChangeSet|20030511184946|49736 # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1091 # Merge bk://are.twiddle.net/axp-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 torvalds@home.transmeta.com 1.1092 # Merge http://lia64.bkbits.net/to-linus-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/11 david-b@pacbell.net 1.1093 # [PATCH] more kbuild tweaks] # # This fixes a typo reported by Geert, and more significantly # fixes static linking so that it works even when only the # device side of USB is enabled, and the host side (CONFIG_USB) # isn't. # -------------------------------------------- # 03/05/11 david-b@pacbell.net 1.1094 # [PATCH] Fix big-endian USB gadget build # # Initializers must be constant expressions, and thus we can't use the # complex expression "cpu_to_le*()" - the end result of which may have a # constant _value_ but the expression itself isn't a constant expression. # # So use the explicitly constant "__constant_cpu_to_*()" expression # instead. # -------------------------------------------- # 03/05/11 rusty@rustcorp.com.au 1.1090.1.1 # [NETFILTER]: Move ip_fw declarations into header file. # -------------------------------------------- # 03/05/11 zaitcev@redhat.com 1.1090.2.1 # [SPARC]: Fix shadowing of global max_pfn, kill BOOTMEM_DEBUG. # -------------------------------------------- # 03/05/11 zaitcev@redhat.com 1.1090.2.2 # [SPARC]: Allow esp to use highmem_io on sparc32. # -------------------------------------------- # 03/05/11 zaitcev@redhat.com 1.1090.2.3 # [SPARC]: New compact show_regs format. # -------------------------------------------- # 03/05/12 bgerst@didntduck.org 1.1095 # [PATCH] Fix ioperm bitmap # # This makes sure that the ioperm bitmap in the TSS is correctly set up # during the first ioperm() call. Without this the TSS bitmap contains # random garbage until the next context switch. # -------------------------------------------- # 03/05/12 torvalds@penguin.transmeta.com 1.1096 # Use '#ifdef' to test for CONFIG_xxx variables, instead of depending # on undefined preprocessor symbols evaluating to zero. # # Make smpboot.c look like ANSI C with proper function declarations. # -------------------------------------------- # 03/05/12 torvalds@penguin.transmeta.com 1.1097 # Add user pointer annotations. # -------------------------------------------- # 03/05/12 torvalds@penguin.transmeta.com 1.1098 # Use '#ifdef' to test for CONFIG_xxx variables, instead of # depending on undefined preprocessor symbols evaluating to zero. # # Make panic.c use proper function prototypes. # -------------------------------------------- # 03/05/12 torvalds@penguin.transmeta.com 1.1099 # Add user pointer annotations to core sysctl files. # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1095.1.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/12 shemminger@osdl.org 1.1095.1.2 # [BRIDGE]: Bridge timer performance enhancement. # -------------------------------------------- # 03/05/12 shemminger@osdl.org 1.1095.1.3 # [NET]: Network packet type using RCU. # * packet type converted from linked list to list_macro # * writer lock replaced with spin lock, readers use RCU # * add __dev_remove_pack for callers that cant sleep. # * af_packet changes to handle and sleeping requirements, and possible # races that could cause. # -------------------------------------------- # 03/05/12 shemminger@osdl.org 1.1095.1.4 # [BRLOCK]: Kill big reader locks, no longer used. # -------------------------------------------- # 03/05/12 shemminger@osdl.org 1.1095.1.5 # [IPV4/IPV6]: synchronize_kernel --> synchronize_net. # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1095.1.6 # [BRLOCK]: Kill stray brlock.h references in sparc/sparc64 headers. # -------------------------------------------- # 03/05/12 jmorris@intercode.com.au 1.1095.1.7 # [IPSEC]: Implement proper IPIP tunnel handling for IPcomp. # -------------------------------------------- # 03/05/12 jmorris@intercode.com.au 1.1095.1.8 # [CRYPTO]: Fix config dependencies. # -------------------------------------------- # 03/05/12 kazunori@miyazawa.org 1.1095.1.9 # [IPV4]: Introduce ip6_append_data. # -------------------------------------------- # 03/05/12 torvalds@penguin.transmeta.com 1.1100 # Add user pointer annotations to socket, file IO and signal # handling. # # This pointed out a bug in x86 sys_rt_sigreturn(), btw. # -------------------------------------------- # 03/05/12 davidm@napali.hpl.hp.com 1.1101 # [PATCH] Add ia64 relocation types to elf.h and clean up # # There is a _lot_ of stuff in linux/elf.h that shouldn't be there. # # This moves the arch-specific stuff in linux/elf.h into the corresponding # asm header files. # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1095.1.10 # [IPV6]: Fix two bugs in ip6_append_data changes. # - Export ip_generic_getfrag # - In udp6 increment v6 udp statistics not v4 one # -------------------------------------------- # 03/05/12 davem@kernel.bkbits.net 1.1102 # Merge davem@nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # into kernel.bkbits.net:/home/davem/sparc-2.5 # -------------------------------------------- # 03/05/12 bunk@fs.tum.de 1.1095.1.11 # [NET]: wireless.c needs module.h # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1095.1.12 # [NETFILTER]: ip_ct_gather_frags no longer needs to linearize. # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1095.1.13 # [PKT_SCHED]: sch_ingress.c does not need to linearize SKBs. # -------------------------------------------- # 03/05/12 davem@nuts.ninka.net 1.1101.1.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1101.2.1 # Add user pointer annotations to mtrr driver. # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1101.2.2 # Fix do_utimes() user pointer annotations. # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1101.2.3 # Make sys_open() declaration match definition. # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1101.2.4 # Don't use undefined preprocessor symbols in expressions. # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1101.1.2 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/12 torvalds@home.transmeta.com 1.1103 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/12 elenstev@mesatop.com 1.1104 # [PATCH] Use '#ifdef' to test for CONFIG_xxx variables # # Don't depend on undefined preprocessor symbols evaluating to zero. # -------------------------------------------- # diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Mon May 12 20:55:48 2003 +++ b/CREDITS Mon May 12 20:55:48 2003 @@ -1549,6 +1549,18 @@ S: 8103 Rein S: Austria +N: Mitsuru Kanda +E: mk@linux-ipv6.org +E: mk@isl.rdc.toshiba.co.jp +E: mk@karaba.org +W: http://www.karaba.org/~mk/ +P: 1024D/2EC7E30D 9A35 D378 F084 9EA4 EFBA 925B 1C93 B376 F0EF BE59 +D: IPsec, IPv6 +D: USAGI/WIDE Project, TOSHIBA CORPORATION +S: 2-47-8, Takinogawa, +S: Kita, Tokyo 114-0023 +S: Japan + N: Jan Kara E: jack@atrey.karlin.mff.cuni.cz E: jack@suse.cz @@ -2200,6 +2212,17 @@ S: Garland, Texas 75044 S: USA +N: Kazunori Miyazawa +E: miyazawa@linux-ipv6.org +E: Kazunori.Miyazawa@jp.yokogawa.com +E: kazunori@miyazawa.org +W: http://www.miyazawa.org/~kazunori/ +D: IPsec, IPv6 +D: USAGI/WIDE Project, Yokogawa Electric Corporation +S: 2-20-4-203, Nakacho, +S: Musashino, Tokyo 180-0006 +S: Japan + N: Patrick Mochel E: mochel@osdl.org E: mochelp@infinity.powertie.org @@ -3027,8 +3050,8 @@ W: http://www.cs.helsinki.fi/Linus.Torvalds P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8 D: Original kernel hacker -S: 1050 Woodduck Avenue -S: Santa Clara, California 95051 +S: 3990 Freedom Circle +S: Santa Clara, California 95054 S: USA N: Marcelo W. Tosatti @@ -3440,6 +3463,17 @@ E: yokota@netlab.is.tsukuba.ac.jp D: Workbit NinjaSCSI-3/32Bi PCMCIA driver D: Workbit NinjaSCSI-32Bi/UDE driver +S: Japan + +N: Hideaki YOSHIFUJI +E: hideaki@yoshifuji.org +E: yoshfuji@linux-ipv6.org +W: http://www.yoshifuji.org/~hideaki/ +P: 1024D/E0620EEA 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA +D: IPv6 and other networking related stuff +D: USAGI/WIDE Project, The University of Tokyo +S: Green House #102, 1-15-5, Nishikata, +S: Bunkyo, Tokyo 113-0024 S: Japan N: Eric Youngdale diff -Nru a/Documentation/BK-usage/bk-kernel-howto.txt b/Documentation/BK-usage/bk-kernel-howto.txt --- a/Documentation/BK-usage/bk-kernel-howto.txt Mon May 12 20:55:47 2003 +++ b/Documentation/BK-usage/bk-kernel-howto.txt Mon May 12 20:55:47 2003 @@ -273,3 +273,11 @@ A tag is just an alias for a specific changeset... and since changesets are ordered, a tag is thus a marker for a specific point in time (or specific state of the tree). + + +3) Is there an easy way to generate One Big Patch versus mainline, + for my long-lived kernel branch? +A. Yes. This requires BK 3.x, though. + + bk export -tpatch -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+ + diff -Nru a/Documentation/Changes b/Documentation/Changes --- a/Documentation/Changes Mon May 12 20:55:48 2003 +++ b/Documentation/Changes Mon May 12 20:55:48 2003 @@ -50,7 +50,7 @@ o Gnu C 2.95.3 # gcc --version o Gnu make 3.78 # make --version -o binutils 2.9.5.0.25 # ld -v +o binutils 2.12 # ld -v o util-linux 2.10o # fdformat --version o module-init-tools 0.9.9 # depmod -V o e2fsprogs 1.29 # tune2fs diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Mon May 12 20:55:47 2003 +++ b/MAINTAINERS Mon May 12 20:55:47 2003 @@ -679,7 +679,7 @@ EXT3 FILE SYSTEM P: Stephen Tweedie, Andrew Morton -M: sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com +M: sct@redhat.com, akpm@digeo.com, adilger@clusterfs.com L: ext3-users@redhat.com S: Maintained @@ -801,20 +801,13 @@ M: drivers@neukum.org S: Maintained -I2C DRIVERS -P: Simon Vogl -M: simon@tk.uni-linz.ac.at -P: Frodo Looijaard -M: frodol@dds.nl -L: linux-i2c@pelican.tk.uni-linz.ac.at -W: http://www.tk.uni-linz.ac.at/~simon/private/i2c -S: Maintained - -SENSORS DRIVERS +I2C AND SENSORS DRIVERS P: Frodo Looijaard M: frodol@dds.nl P: Philip Edelbrock M: phil@netroedge.com +P: Greg Kroah-Hartman +M: greg@kroah.com L: sensors@stimpy.netroedge.com W: http://www.lm-sensors.nu/ S: Maintained @@ -1264,7 +1257,7 @@ NETWORK DEVICE DRIVERS P: Andrew Morton -M: akpm@zip.com.au +M: akpm@digeo.com P: Jeff Garzik M: jgarzik@pobox.com L: linux-net@vger.kernel.org @@ -1285,6 +1278,8 @@ M: pekkas@netcore.fi P: James Morris M: jmorris@intercode.com.au +P: Hideaki YOSHIFUJI +M: yoshfuji@linux-ipv6.org L: netdev@oss.sgi.com S: Maintained diff -Nru a/Makefile b/Makefile --- a/Makefile Mon May 12 20:55:47 2003 +++ b/Makefile Mon May 12 20:55:47 2003 @@ -90,7 +90,7 @@ KBUILD_MODULES := 1 endif -export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE +export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE KBUILD_CHECKSRC # Beautify output # --------------------------------------------------------------------------- @@ -118,6 +118,16 @@ KBUILD_VERBOSE = 1 endif +ifdef C + ifeq ("$(origin C)", "command line") + KBUILD_CHECKSRC = $(C) + endif +endif +ifndef KBUILD_CHECKSRC + KBUILD_CHECKSRC = 0 +endif + + MAKEFLAGS += --no-print-directory # For maximum performance (+ possibly random breakage, uncomment @@ -172,6 +182,7 @@ DEPMOD = /sbin/depmod KALLSYMS = scripts/kallsyms PERL = perl +CHECK = /home/torvalds/parser/check MODFLAGS = -DMODULE CFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS) @@ -189,7 +200,7 @@ export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \ - HOSTCXX HOSTCXXFLAGS LDFLAGS_BLOB LDFLAGS_MODULE + HOSTCXX HOSTCXXFLAGS LDFLAGS_BLOB LDFLAGS_MODULE CHECK export CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE diff -Nru a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c --- a/arch/alpha/kernel/core_marvel.c Mon May 12 20:55:44 2003 +++ b/arch/alpha/kernel/core_marvel.c Mon May 12 20:55:44 2003 @@ -780,7 +780,7 @@ rtc_access.function = 0x49; /* GET_TOY */ if (write) rtc_access.function = 0x48; /* PUT_TOY */ -#if CONFIG_SMP +#ifdef CONFIG_SMP if (smp_processor_id() != boot_cpuid) smp_call_function_on_cpu(__marvel_access_rtc, &rtc_access, diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S --- a/arch/alpha/kernel/entry.S Mon May 12 20:55:44 2003 +++ b/arch/alpha/kernel/entry.S Mon May 12 20:55:44 2003 @@ -849,7 +849,7 @@ about this loop. */ ldq $3, TASK_REAL_PARENT($2) 1: ldl $1, TASK_TGID($3) -#if CONFIG_SMP +#ifdef CONFIG_SMP mov $3, $4 mb ldq $3, TASK_REAL_PARENT($2) diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Mon May 12 20:55:48 2003 +++ b/arch/alpha/kernel/irq.c Mon May 12 20:55:48 2003 @@ -556,7 +556,7 @@ unlock: spin_unlock_irqrestore(&irq_desc[i].lock, flags); } -#if CONFIG_SMP +#ifdef CONFIG_SMP seq_puts(p, "IPI: "); for (i = 0; i < NR_CPUS; i++) if (cpu_online(i)) diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c --- a/arch/alpha/kernel/sys_titan.c Mon May 12 20:55:48 2003 +++ b/arch/alpha/kernel/sys_titan.c Mon May 12 20:55:48 2003 @@ -204,13 +204,14 @@ .set_affinity = titan_set_irq_affinity, }; -static void +static irqreturn_t titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs) { /* * This is a NOP interrupt handler for the purposes of * event counting -- just return. */ + return IRQ_HANDLED; } static void __init diff -Nru a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c --- a/arch/arm/common/sa1111.c Mon May 12 20:55:48 2003 +++ b/arch/arm/common/sa1111.c Mon May 12 20:55:48 2003 @@ -419,7 +419,7 @@ spin_lock_irqsave(&sachip->lock, flags); -#if CONFIG_ARCH_SA1100 +#ifdef CONFIG_ARCH_SA1100 /* * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: * (SA-1110 Developer's Manual, section 9.1.2.1) diff -Nru a/arch/cris/drivers/eeprom.c b/arch/cris/drivers/eeprom.c --- a/arch/cris/drivers/eeprom.c Mon May 12 20:55:46 2003 +++ b/arch/cris/drivers/eeprom.c Mon May 12 20:55:46 2003 @@ -163,7 +163,7 @@ init_waitqueue_head(&eeprom.wait_q); eeprom.busy = 0; -#if CONFIG_ETRAX_I2C_EEPROM_PROBE +#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE #define EETEXT "Found" #else #define EETEXT "Assuming" @@ -191,7 +191,7 @@ eeprom.usec_delay_step = 128; eeprom.adapt_state = 0; -#if CONFIG_ETRAX_I2C_EEPROM_PROBE +#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE i2c_start(); i2c_outbyte(0x80); if(!i2c_getack()) diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Mon May 12 20:55:45 2003 +++ b/arch/i386/Kconfig Mon May 12 20:55:45 2003 @@ -65,19 +65,16 @@ config X86_SUMMIT bool "Summit/EXA (IBM x440)" + depends on SMP help This option is needed for IBM systems that use the Summit/EXA chipset. In particular, it is needed for the x440. If you don't have one of these computers, you should say N here. -config ACPI_SRAT - bool - default y - depends on NUMA && X86_SUMMIT - config X86_BIGSMP bool "Support for other sub-arch SMP systems with more than 8 CPUs" + depends on SMP help This option is needed for the systems that have more than 8 CPUs and if the system is not of any sub-arch type above. @@ -95,8 +92,24 @@ A kernel compiled for the Visual Workstation will not run on PCs and vice versa. See for details. +config X86_GENERICARCH + bool "Generic architecture (Summit, bigsmp, default)" + depends on SMP + help + This option compiles in the Summit, bigsmp, default subarchitectures. + It is intended for a generic binary kernel. + endchoice +config ACPI_SRAT + bool + default y + depends on NUMA && (X86_SUMMIT || X86_GENERICARCH) + +config X86_CYCLONE_TIMER + bool + default y + depends on X86_SUMMIT || X86_GENERICARCH choice prompt "Processor family" @@ -666,7 +679,7 @@ # Common NUMA Features config NUMA bool "Numa Memory Allocation Support" - depends on SMP && HIGHMEM64G && (X86_PC || X86_NUMAQ || (X86_SUMMIT && ACPI && !ACPI_HT_ONLY)) + depends on SMP && HIGHMEM64G && (X86_PC || X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI && !ACPI_HT_ONLY)) default n if X86_PC default y if (X86_NUMAQ || X86_SUMMIT) @@ -764,7 +777,7 @@ # Summit needs it only when NUMA is on config BOOT_IOREMAP bool - depends on (X86_SUMMIT && NUMA) + depends on ((X86_SUMMIT || X86_GENERICARCH) && NUMA) default y endmenu diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Mon May 12 20:55:45 2003 +++ b/arch/i386/Makefile Mon May 12 20:55:45 2003 @@ -73,6 +73,11 @@ mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit mcore-$(CONFIG_X86_SUMMIT) := mach-default +# generic subarchitecture +mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic +mcore-$(CONFIG_X86_GENERICARCH) := mach-default +core-$(CONFIG_X86_GENERICARCH) += arch/i386/mach-generic/ + # default subarch .h files mflags-y += -Iinclude/asm-i386/mach-default diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/Makefile Mon May 12 20:55:45 2003 @@ -17,7 +17,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o -obj-$(CONFIG_APM) += apm.o +obj-$(CONFIG_APM) += apm.o suspend.o obj-$(CONFIG_X86_SMP) += smp.o smpboot.o obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o diff -Nru a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c --- a/arch/i386/kernel/acpi/sleep.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/acpi/sleep.c Mon May 12 20:55:46 2003 @@ -75,7 +75,7 @@ printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n"); return; } -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE printk(KERN_ERR "ACPI: S3 and PAE do not like each other for now, S3 disabled.\n"); return; #endif diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c --- a/arch/i386/kernel/apm.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/apm.c Mon May 12 20:55:44 2003 @@ -226,6 +226,7 @@ #include #include #include +#include #include "io_ports.h" @@ -1212,7 +1213,9 @@ spin_unlock(&i8253_lock); write_sequnlock_irq(&xtime_lock); + save_processor_state(); err = set_system_power_state(APM_STATE_SUSPEND); + restore_processor_state(); write_seqlock_irq(&xtime_lock); spin_lock(&i8253_lock); diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c Mon May 12 20:55:46 2003 @@ -147,7 +147,7 @@ #ifdef SUSPMOD_DEBUG #define dprintk(msg...) printk(KERN_DEBUG "cpufreq:" msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif /** diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c Mon May 12 20:55:44 2003 @@ -37,7 +37,7 @@ #ifdef DEBUG #define dprintk(msg...) printk(msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif static unsigned int numscales=16, numvscales; diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Mon May 12 20:55:44 2003 @@ -32,7 +32,7 @@ #ifdef DEBUG #define dprintk(msg...) printk(msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif #define PFX "powernow: " @@ -89,7 +89,7 @@ rdmsr (msr, l__, h__); \ val = l__; \ val |= ((u64)h__<<32); \ -} while(0); +} while(0) #endif #ifndef wrmsrl @@ -236,20 +236,24 @@ if (have_a0 == 1) /* A0 errata 5 */ __asm__("\tcli\n"); - rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); - fidvidctl.bits.SGTC = latency; /* Stop grant timeout counter */ - fidvidctl.bits.FID = fid; - fidvidctl.bits.FIDC = 1; + /* First change the frequency. */ + if (fidvidctl.bits.FID != fid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + fidvidctl.bits.SGTC = latency; /* Stop grant timeout counter */ + fidvidctl.bits.FID = fid; + fidvidctl.bits.FIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + } - /* Set the voltage lazily. Ie, only do voltage transition - if its changed since last time (Some speeds have the same voltage) */ + /* Now change voltage. */ if (fidvidctl.bits.VID != vid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); fidvidctl.bits.VID = vid; fidvidctl.bits.VIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); } - wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); if (have_a0 == 1) __asm__("\tsti\n"); @@ -386,6 +390,10 @@ static int __init powernow_init (void) { + if (dmi_broken & BROKEN_CPUFREQ) { + printk (KERN_INFO PFX "Disabled at boot time by DMI,\n"); + return -ENODEV; + } if (check_powernow()==0) return -ENODEV; return cpufreq_register_driver(&powernow_driver); diff -Nru a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c --- a/arch/i386/kernel/cpu/mtrr/if.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/cpu/mtrr/if.c Mon May 12 20:55:45 2003 @@ -70,7 +70,7 @@ /* RED-PEN: seq_file can seek now. this is ignored. */ static ssize_t -mtrr_write(struct file *file, const char *buf, size_t len, loff_t * ppos) +mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) /* Format of control line: "base=%Lx size=%Lx type=%s" OR: "disable=%d" @@ -133,12 +133,13 @@ static int mtrr_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long __arg) { int err; mtrr_type type; struct mtrr_sentry sentry; struct mtrr_gentry gentry; + void __user *arg = (void __user *) __arg; switch (cmd) { default: @@ -146,7 +147,7 @@ case MTRRIOC_ADD_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, @@ -157,7 +158,7 @@ case MTRRIOC_SET_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_add(sentry.base, sentry.size, sentry.type, 0); if (err < 0) @@ -166,7 +167,7 @@ case MTRRIOC_DEL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_file_del(sentry.base, sentry.size, file, 0); if (err < 0) @@ -175,14 +176,14 @@ case MTRRIOC_KILL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_del(-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_ENTRY: - if (copy_from_user(&gentry, (void *) arg, sizeof gentry)) + if (copy_from_user(&gentry, arg, sizeof gentry)) return -EFAULT; if (gentry.regnum >= num_var_ranges) return -EINVAL; @@ -198,13 +199,13 @@ gentry.type = type; } - if (copy_to_user((void *) arg, &gentry, sizeof gentry)) + if (copy_to_user(arg, &gentry, sizeof gentry)) return -EFAULT; break; case MTRRIOC_ADD_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, @@ -215,7 +216,7 @@ case MTRRIOC_SET_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0); if (err < 0) @@ -224,7 +225,7 @@ case MTRRIOC_DEL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_file_del(sentry.base, sentry.size, file, 1); if (err < 0) @@ -233,21 +234,21 @@ case MTRRIOC_KILL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (copy_from_user(&sentry, (void *) arg, sizeof sentry)) + if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; err = mtrr_del_page(-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_PAGE_ENTRY: - if (copy_from_user(&gentry, (void *) arg, sizeof gentry)) + if (copy_from_user(&gentry, arg, sizeof gentry)) return -EFAULT; if (gentry.regnum >= num_var_ranges) return -EINVAL; mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type); gentry.type = type; - if (copy_to_user((void *) arg, &gentry, sizeof gentry)) + if (copy_to_user(arg, &gentry, sizeof gentry)) return -EFAULT; break; } diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/dmi_scan.c Mon May 12 20:55:46 2003 @@ -511,6 +511,14 @@ return 0; } +static __init int acer_cpufreq_pst(struct dmi_blacklist *d) +{ + printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident); + printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n"); + printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n"); + dmi_broken |= BROKEN_CPUFREQ; + return 0; +} /* @@ -822,6 +830,17 @@ { disable_smbus, "IBM", { MATCH(DMI_SYS_VENDOR, "IBM"), + NO_MATCH, NO_MATCH, NO_MATCH + } }, + + /* + * Some Athlon laptops have really fucked PST tables. + * A BIOS update is all that can save them. + * Mention this, and disable cpufreq. + */ + { acer_cpufreq_pst, "Acer Aspire", { + MATCH(DMI_SYS_VENDOR, "Insyde Software"), + MATCH(DMI_BIOS_VERSION, "3A71"), NO_MATCH, NO_MATCH, NO_MATCH } }, diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S --- a/arch/i386/kernel/head.S Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/head.S Mon May 12 20:55:44 2003 @@ -483,7 +483,7 @@ .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ -#if CONFIG_SMP +#ifdef CONFIG_SMP .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ #endif diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/io_apic.c Mon May 12 20:55:45 2003 @@ -280,7 +280,9 @@ extern unsigned long irq_affinity[NR_IRQS]; static int __cacheline_aligned pending_irq_balance_apicid[NR_IRQS]; -static int irqbalance_disabled = NO_BALANCE_IRQ; + +#define IRQBALANCE_CHECK_ARCH -999 +static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; static int physical_balance = 0; struct irq_cpu_info { @@ -342,8 +344,10 @@ unsigned long allowed_mask; unsigned int new_cpu; - if (irqbalance_disabled) + if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH && NO_BALANCE_IRQ) return; + else if (irqbalance_disabled) + return; allowed_mask = cpu_online_map & irq_affinity[irq]; new_cpu = move(cpu, allowed_mask, now, 1); diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c --- a/arch/i386/kernel/ioport.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/ioport.c Mon May 12 20:55:46 2003 @@ -84,15 +84,17 @@ t->ts_io_bitmap = bitmap; } - tss = init_tss + get_cpu(); - if (bitmap) - tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */ - /* * do it in the per-thread copy and in the TSS ... */ set_bitmap(t->ts_io_bitmap, from, num, !turn_on); - set_bitmap(tss->io_bitmap, from, num, !turn_on); + tss = init_tss + get_cpu(); + if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */ + set_bitmap(tss->io_bitmap, from, num, !turn_on); + } else { + memcpy(tss->io_bitmap, t->ts_io_bitmap, IO_BITMAP_BYTES); + tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */ + } put_cpu(); out: return ret; diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c --- a/arch/i386/kernel/irq.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/irq.c Mon May 12 20:55:44 2003 @@ -92,7 +92,7 @@ * each architecture has to answer this themselves, it doesn't deserve * a generic callback i think. */ -#if CONFIG_X86 +#ifdef CONFIG_X86 printk("unexpected IRQ trap at vector %02x\n", irq); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -173,7 +173,7 @@ if (cpu_online(j)) seq_printf(p, "%10u ", nmi_count(j)); seq_putc(p, '\n'); -#if CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) @@ -189,7 +189,7 @@ return 0; } -#if CONFIG_SMP +#ifdef CONFIG_SMP inline void synchronize_irq(unsigned int irq) { while (irq_desc[irq].status & IRQ_INPROGRESS) @@ -828,7 +828,7 @@ #define HEX_DIGITS 8 -static unsigned int parse_hex_value (const char *buffer, +static unsigned int parse_hex_value (const char __user *buffer, unsigned long count, unsigned long *ret) { unsigned char hexnum [HEX_DIGITS]; @@ -865,7 +865,7 @@ return 0; } -#if CONFIG_SMP +#ifdef CONFIG_SMP static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; @@ -878,7 +878,7 @@ return sprintf (page, "%08lx\n", irq_affinity[(long)data]); } -static int irq_affinity_write_proc (struct file *file, const char *buffer, +static int irq_affinity_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { int irq = (long) data, full_count = count, err; @@ -914,7 +914,7 @@ return sprintf (page, "%08lx\n", *mask); } -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned long *mask = (unsigned long *) data, full_count = count, err; @@ -944,7 +944,7 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); -#if CONFIG_SMP +#ifdef CONFIG_SMP { struct proc_dir_entry *entry; diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c --- a/arch/i386/kernel/ldt.c Mon May 12 20:55:47 2003 +++ b/arch/i386/kernel/ldt.c Mon May 12 20:55:47 2003 @@ -119,7 +119,7 @@ } } -static int read_ldt(void * ptr, unsigned long bytecount) +static int read_ldt(void __user * ptr, unsigned long bytecount) { int err; unsigned long size; @@ -148,7 +148,7 @@ return bytecount; } -static int read_default_ldt(void * ptr, unsigned long bytecount) +static int read_default_ldt(void __user * ptr, unsigned long bytecount) { int err; unsigned long size; @@ -167,7 +167,7 @@ return err; } -static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) +static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) { struct mm_struct * mm = current->mm; __u32 entry_1, entry_2, *lp; @@ -226,7 +226,7 @@ return error; } -asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) { int ret = -ENOSYS; diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c --- a/arch/i386/kernel/mpparse.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/mpparse.c Mon May 12 20:55:45 2003 @@ -73,7 +73,9 @@ /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map; +#ifndef CONFIG_X86_GENERICARCH int x86_summit = 0; +#endif u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; /* diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c --- a/arch/i386/kernel/ptrace.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/ptrace.c Mon May 12 20:55:45 2003 @@ -155,7 +155,7 @@ */ static int ptrace_get_thread_area(struct task_struct *child, - int idx, struct user_desc *user_desc) + int idx, struct user_desc __user *user_desc) { struct user_desc info; struct desc_struct *desc; @@ -206,7 +206,7 @@ */ static int ptrace_set_thread_area(struct task_struct *child, - int idx, struct user_desc *user_desc) + int idx, struct user_desc __user *user_desc) { struct user_desc info; struct desc_struct *desc; @@ -458,7 +458,7 @@ ret = 0; if (!child->used_math) init_fpu(child); - get_fpregs((struct user_i387_struct *)data, child); + get_fpregs((struct user_i387_struct __user *)data, child); break; } @@ -469,7 +469,7 @@ break; } child->used_math = 1; - set_fpregs(child, (struct user_i387_struct *)data); + set_fpregs(child, (struct user_i387_struct __user *)data); ret = 0; break; } @@ -482,7 +482,7 @@ } if (!child->used_math) init_fpu(child); - ret = get_fpxregs((struct user_fxsr_struct *)data, child); + ret = get_fpxregs((struct user_fxsr_struct __user *)data, child); break; } @@ -493,18 +493,18 @@ break; } child->used_math = 1; - ret = set_fpxregs(child, (struct user_fxsr_struct *)data); + ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data); break; } case PTRACE_GET_THREAD_AREA: ret = ptrace_get_thread_area(child, - addr, (struct user_desc *) data); + addr, (struct user_desc __user *) data); break; case PTRACE_SET_THREAD_AREA: ret = ptrace_set_thread_area(child, - addr, (struct user_desc *) data); + addr, (struct user_desc __user *) data); break; default: diff -Nru a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c --- a/arch/i386/kernel/reboot.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/reboot.c Mon May 12 20:55:45 2003 @@ -215,7 +215,7 @@ void machine_restart(char * __unused) { -#if CONFIG_SMP +#ifdef CONFIG_SMP int cpuid; cpuid = GET_APIC_ID(apic_read(APIC_ID)); diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/setup.c Mon May 12 20:55:46 2003 @@ -91,6 +91,7 @@ extern void early_cpu_init(void); extern void dmi_scan_machine(void); +extern void generic_apic_probe(char *); extern int root_mountflags; extern char _text, _etext, _edata, _end; extern int blk_nohighio; @@ -596,7 +597,7 @@ } else { if (highmem_pages == -1) highmem_pages = 0; -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM if (highmem_pages >= max_pfn) { printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn)); highmem_pages = 0; @@ -959,6 +960,13 @@ smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ #endif paging_init(); + + dmi_scan_machine(); + +#ifdef CONFIG_X86_GENERICARCH + generic_apic_probe(*cmdline_p); +#endif + #ifdef CONFIG_ACPI_BOOT /* * Parse the ACPI tables for possible boot-time SMP configuration. @@ -980,7 +988,6 @@ conswitchp = &dummy_con; #endif #endif - dmi_scan_machine(); } static int __init highio_setup(char *str) diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c --- a/arch/i386/kernel/signal.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/signal.c Mon May 12 20:55:46 2003 @@ -116,7 +116,7 @@ } asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) { struct pt_regs *regs = (struct pt_regs *) &uss; return do_sigaltstack(uss, uoss, regs->esp); @@ -244,6 +244,11 @@ goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ + /* + * THIS CANNOT WORK! "&st" is a kernel address, and "do_sigaltstack()" + * takes a user address (and verifies that it is a user address). End + * result: it does exactly _nothing_. + */ do_sigaltstack(&st, NULL, regs->esp); return eax; diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c --- a/arch/i386/kernel/smp.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/smp.c Mon May 12 20:55:44 2003 @@ -123,7 +123,7 @@ return SET_APIC_DEST_FIELD(mask); } -static inline void __send_IPI_shortcut(unsigned int shortcut, int vector) +inline void __send_IPI_shortcut(unsigned int shortcut, int vector) { /* * Subtle. In the case of the 'never do double writes' workaround @@ -155,7 +155,7 @@ __send_IPI_shortcut(APIC_DEST_SELF, vector); } -static inline void send_IPI_mask_bitmask(int mask, int vector) +inline void send_IPI_mask_bitmask(int mask, int vector) { unsigned long cfg; unsigned long flags; @@ -186,7 +186,7 @@ local_irq_restore(flags); } -static inline void send_IPI_mask_sequence(int mask, int vector) +inline void send_IPI_mask_sequence(int mask, int vector) { unsigned long cfg, flags; unsigned int query_cpu, query_mask; diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/smpboot.c Mon May 12 20:55:46 2003 @@ -1153,7 +1153,7 @@ zap_low_mappings(); } -void __init smp_intr_init() +void __init smp_intr_init(void) { /* * IRQ0 must be given a fixed assignment and initialized, diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c --- a/arch/i386/kernel/suspend.c Mon May 12 20:55:48 2003 +++ b/arch/i386/kernel/suspend.c Mon May 12 20:55:48 2003 @@ -27,9 +27,7 @@ #include static struct saved_context saved_context; -unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx; -unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi; -unsigned long saved_context_eflags; +static void fix_processor_context(void); extern void enable_sep_cpu(void *); @@ -107,7 +105,7 @@ do_fpu_end(); } -void fix_processor_context(void) +static void fix_processor_context(void) { int cpu = smp_processor_id(); struct tss_struct * t = init_tss + cpu; diff -Nru a/arch/i386/kernel/suspend_asm.S b/arch/i386/kernel/suspend_asm.S --- a/arch/i386/kernel/suspend_asm.S Mon May 12 20:55:46 2003 +++ b/arch/i386/kernel/suspend_asm.S Mon May 12 20:55:46 2003 @@ -6,6 +6,28 @@ #include #include + .data +saved_context_eax: + .long 0 +saved_context_ebx: + .long 0 +saved_context_ecx: + .long 0 +saved_context_edx: + .long 0 +saved_context_esp: + .long 0 +saved_context_ebp: + .long 0 +saved_context_esi: + .long 0 +saved_context_edi: + .long 0 +saved_context_eflags: + .long 0 + + .text + ENTRY(do_magic) pushl %ebx cmpl $0,8(%esp) diff -Nru a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c --- a/arch/i386/kernel/sys_i386.c Mon May 12 20:55:49 2003 +++ b/arch/i386/kernel/sys_i386.c Mon May 12 20:55:49 2003 @@ -26,7 +26,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage int sys_pipe(unsigned long * fildes) +asmlinkage int sys_pipe(unsigned long __user * fildes) { int fd[2]; int error; @@ -88,7 +88,7 @@ unsigned long offset; }; -asmlinkage int old_mmap(struct mmap_arg_struct *arg) +asmlinkage int old_mmap(struct mmap_arg_struct __user *arg) { struct mmap_arg_struct a; int err = -EFAULT; @@ -106,15 +106,15 @@ } -extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern asmlinkage int sys_select(int, fd_set __user *, fd_set __user *, fd_set __user *, struct timeval __user *); struct sel_arg_struct { unsigned long n; - fd_set *inp, *outp, *exp; - struct timeval *tvp; + fd_set __user *inp, *outp, *exp; + struct timeval __user *tvp; }; -asmlinkage int old_select(struct sel_arg_struct *arg) +asmlinkage int old_select(struct sel_arg_struct __user *arg) { struct sel_arg_struct a; @@ -130,7 +130,7 @@ * This is really horribly ugly. */ asmlinkage int sys_ipc (uint call, int first, int second, - int third, void *ptr, long fifth) + int third, void __user *ptr, long fifth) { int version, ret; @@ -139,10 +139,10 @@ switch (call) { case SEMOP: - return sys_semtimedop (first, (struct sembuf *)ptr, second, NULL); + return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); case SEMTIMEDOP: - return sys_semtimedop(first, (struct sembuf *)ptr, second, - (const struct timespec *)fifth); + return sys_semtimedop(first, (struct sembuf __user *)ptr, second, + (const struct timespec __user *)fifth); case SEMGET: return sys_semget (first, second, third); @@ -150,13 +150,13 @@ union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) + if (get_user(fourth.__pad, (void * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third); case MSGRCV: switch (version) { @@ -166,7 +166,7 @@ return -EINVAL; if (copy_from_user(&tmp, - (struct ipc_kludge *) ptr, + (struct ipc_kludge __user *) ptr, sizeof (tmp))) return -EFAULT; return sys_msgrcv (first, tmp.msgp, second, @@ -174,35 +174,36 @@ } default: return sys_msgrcv (first, - (struct msgbuf *) ptr, + (struct msgbuf __user *) ptr, second, fifth, third); } case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); case SHMAT: switch (version) { default: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char __user *) ptr, second, &raddr); if (ret) return ret; - return put_user (raddr, (ulong *) third); + return put_user (raddr, (ulong __user *) third); } case 1: /* iBCS2 emulator entry point */ if (!segment_eq(get_fs(), get_ds())) return -EINVAL; - return sys_shmat (first, (char *) ptr, second, (ulong *) third); + /* The "(ulong *) third" is valid _only_ because of the kernel segment thing */ + return sys_shmat (first, (char __user *) ptr, second, (ulong *) third); } case SHMDT: - return sys_shmdt ((char *)ptr); + return sys_shmdt ((char __user *)ptr); case SHMGET: return sys_shmget (first, second, third); case SHMCTL: return sys_shmctl (first, second, - (struct shmid_ds *) ptr); + (struct shmid_ds __user *) ptr); default: return -ENOSYS; } @@ -211,7 +212,7 @@ /* * Old cruft */ -asmlinkage int sys_uname(struct old_utsname * name) +asmlinkage int sys_uname(struct old_utsname __user * name) { int err; if (!name) @@ -222,7 +223,7 @@ return err?-EFAULT:0; } -asmlinkage int sys_olduname(struct oldold_utsname * name) +asmlinkage int sys_olduname(struct oldold_utsname __user * name) { int error; diff -Nru a/arch/i386/kernel/timers/Makefile b/arch/i386/kernel/timers/Makefile --- a/arch/i386/kernel/timers/Makefile Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/timers/Makefile Mon May 12 20:55:44 2003 @@ -4,4 +4,4 @@ obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o -obj-$(CONFIG_X86_SUMMIT) += timer_cyclone.o +obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o diff -Nru a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c --- a/arch/i386/kernel/timers/timer.c Mon May 12 20:55:49 2003 +++ b/arch/i386/kernel/timers/timer.c Mon May 12 20:55:49 2003 @@ -6,12 +6,12 @@ /* list of externed timers */ extern struct timer_opts timer_pit; extern struct timer_opts timer_tsc; -#ifdef CONFIG_X86_SUMMIT +#ifdef CONFIG_X86_CYCLONE_TIMER extern struct timer_opts timer_cyclone; #endif /* list of timers, ordered by preference, NULL terminated */ static struct timer_opts* timers[] = { -#ifdef CONFIG_X86_SUMMIT +#ifdef CONFIG_X86_CYCLONE_TIMER &timer_cyclone, #endif &timer_tsc, diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Mon May 12 20:55:45 2003 +++ b/arch/i386/kernel/traps.c Mon May 12 20:55:45 2003 @@ -101,7 +101,7 @@ stack = (unsigned long*)&stack; printk("Call Trace:"); -#if CONFIG_KALLSYMS +#ifdef CONFIG_KALLSYMS printk("\n"); #endif i = 1; @@ -438,7 +438,7 @@ unsigned char reason = get_nmi_reason(); if (!(reason & 0xc0)) { -#if CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c --- a/arch/i386/kernel/vm86.c Mon May 12 20:55:44 2003 +++ b/arch/i386/kernel/vm86.c Mon May 12 20:55:44 2003 @@ -170,7 +170,7 @@ static int do_vm86_irq_handling(int subfunction, int irqnumber); static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); -asmlinkage int sys_vm86old(struct vm86_struct * v86) +asmlinkage int sys_vm86old(struct vm86_struct __user * v86) { struct kernel_vm86_struct info; /* declare this _on top_, * this avoids wasting of stack space. @@ -199,7 +199,7 @@ } -asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86) +asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct __user * v86) { struct kernel_vm86_struct info; /* declare this _on top_, * this avoids wasting of stack space. @@ -239,7 +239,7 @@ goto out; info.regs32 = (struct pt_regs *) &subfunction; info.vm86plus.is_vm86pus = 1; - tsk->thread.vm86_info = (struct vm86_struct *)v86; + tsk->thread.vm86_info = (struct vm86_struct __user *)v86; do_sys_vm86(&info, tsk); ret = 0; /* we never return here */ out: diff -Nru a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c --- a/arch/i386/lib/usercopy.c Mon May 12 20:55:44 2003 +++ b/arch/i386/lib/usercopy.c Mon May 12 20:55:44 2003 @@ -6,6 +6,9 @@ * Copyright 1997 Linus Torvalds */ #include +#include +#include +#include #include #include @@ -483,6 +486,53 @@ unsigned long __copy_to_user_ll(void *to, const void *from, unsigned long n) { +#ifndef CONFIG_X86_WP_WORKS_OK + if (unlikely(boot_cpu_data.wp_works_ok == 0) && + ((unsigned long )to) < TASK_SIZE) { + /* + * CPU does not honor the WP bit when writing + * from supervisory mode, and due to preemption or SMP, + * the page tables can change at any time. + * Do it manually. Manfred + */ + while (n) { + unsigned long offset = ((unsigned long)to)%PAGE_SIZE; + unsigned long len = PAGE_SIZE - offset; + int retval; + struct page *pg; + void *maddr; + + if (len > n) + len = n; + +survive: + down_read(¤t->mm->mmap_sem); + retval = get_user_pages(current, current->mm, + (unsigned long )to, 1, 1, 0, &pg, NULL); + + if (retval == -ENOMEM && current->pid == 1) { + up_read(¤t->mm->mmap_sem); + blk_congestion_wait(WRITE, HZ/50); + goto survive; + } + + if (retval != 1) + break; + + maddr = kmap_atomic(pg, KM_USER0); + memcpy(maddr + offset, from, len); + kunmap_atomic(maddr, KM_USER0); + set_page_dirty_lock(pg); + put_page(pg); + up_read(¤t->mm->mmap_sem); + + from += len; + to += len; + n -= len; + } + return n; + } +#endif if (movsl_is_ok(to, from, n)) __copy_user(to, from, n); else diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/Makefile Mon May 12 20:55:49 2003 @@ -0,0 +1,18 @@ +# +# Makefile for the generic architecture +# + +EXTRA_CFLAGS += -I../kernel + +obj-y := probe.o summit.o bigsmp.o default.o + + +# +# Makefile for the generic architecture +# + +EXTRA_CFLAGS += -I../kernel + +obj-y := probe.o summit.o bigsmp.o default.o + + diff -Nru a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/bigsmp.c Mon May 12 20:55:49 2003 @@ -0,0 +1,23 @@ +/* + * APIC driver for "bigsmp" XAPIC machines with more than 8 virtual CPUs. + * Drives the local APIC in "clustered mode". + */ +#define APIC_DEFINITION 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int dmi_bigsmp; /* can be set by dmi scanners */ + +static __init int probe_bigsmp(void) +{ + return dmi_bigsmp; +} + +struct genapic apic_bigsmp = APIC_INIT("bigsmp", probe_bigsmp); diff -Nru a/arch/i386/mach-generic/default.c b/arch/i386/mach-generic/default.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/default.c Mon May 12 20:55:49 2003 @@ -0,0 +1,22 @@ +/* + * Default generic APIC driver. This handles upto 8 CPUs. + */ +#define APIC_DEFINITION 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* should be called last. */ +static __init int probe_default(void) +{ + return 1; +} + +struct genapic apic_default = APIC_INIT("default", probe_default); diff -Nru a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/probe.c Mon May 12 20:55:49 2003 @@ -0,0 +1,96 @@ +/* Copyright 2003 Andi Kleen, SuSE Labs. + * Subject to the GNU Public License, v.2 + * + * Generic x86 APIC driver probe layer. + */ +#include +#include +#include +#include +#include +#include +#include + +extern struct genapic apic_summit; +extern struct genapic apic_bigsmp; +extern struct genapic apic_default; + +struct genapic *genapic = &apic_default; + +struct genapic *apic_probe[] __initdata = { + &apic_summit, + &apic_bigsmp, + &apic_default, /* must be last */ + NULL, +}; + +void __init generic_apic_probe(char *command_line) +{ + char *s; + int i; + int changed = 0; + + s = strstr(command_line, "apic="); + if (s && (s == command_line || isspace(s[-1]))) { + char *p = strchr(s, ' '), old; + if (!p) + p = strchr(s, '\0'); + old = *p; + *p = 0; + for (i = 0; !changed && apic_probe[i]; i++) { + if (!strcmp(apic_probe[i]->name, s+5)) { + changed = 1; + genapic = apic_probe[i]; + } + } + if (!changed) + printk(KERN_ERR "Unknown genapic `%s' specified.\n", s); + *p = old; + } + for (i = 0; !changed && apic_probe[i]; i++) { + if (apic_probe[i]->probe()) { + changed = 1; + genapic = apic_probe[i]; + } + } + /* Not visible without early console */ + if (!changed) + panic("Didn't find an APIC driver"); + + printk(KERN_INFO "Using APIC driver %s\n", genapic->name); +} + +/* These functions can switch the APIC even after the initial ->probe() */ + +int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) +{ + int i; + for (i = 0; apic_probe[i]; ++i) { + if (apic_probe[i]->mps_oem_check(mpc,oem,productid)) { + genapic = apic_probe[i]; + printk(KERN_INFO "Switched to APIC driver `%s'.\n", + genapic->name); + return 1; + } + } + return 0; +} + +int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + int i; + for (i = 0; apic_probe[i]; ++i) { + if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { + genapic = apic_probe[i]; + printk(KERN_INFO "Switched to APIC driver `%s'.\n", + genapic->name); + return 1; + } + } + return 0; +} + +int hard_smp_processor_id(void) +{ + return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID)); +} diff -Nru a/arch/i386/mach-generic/summit.c b/arch/i386/mach-generic/summit.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/summit.c Mon May 12 20:55:49 2003 @@ -0,0 +1,22 @@ +/* + * APIC driver for the IBM "Summit" chipset. + */ +#define APIC_DEFINITION 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static __init int probe_summit(void) +{ + /* probed later in mptable/ACPI hooks */ + return 0; +} + +struct genapic apic_summit = APIC_INIT("summit", probe_summit); diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c --- a/arch/i386/mm/fault.c Mon May 12 20:55:44 2003 +++ b/arch/i386/mm/fault.c Mon May 12 20:55:44 2003 @@ -29,87 +29,6 @@ extern void die(const char *,struct pt_regs *,long); -#ifndef CONFIG_X86_WP_WORKS_OK -/* - * Ugly, ugly, but the goto's result in better assembly.. - */ -int __verify_write(const void * addr, unsigned long size) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct * vma; - unsigned long start = (unsigned long) addr; - - if (!size || segment_eq(get_fs(),KERNEL_DS)) - return 1; - - down_read(&mm->mmap_sem); - vma = find_vma(current->mm, start); - if (!vma) - goto bad_area; - if (vma->vm_start > start) - goto check_stack; - -good_area: - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - size--; - size += start & ~PAGE_MASK; - size >>= PAGE_SHIFT; - start &= PAGE_MASK; - - for (;;) { - survive: - switch (handle_mm_fault(current->mm, vma, start, 1)) { - case VM_FAULT_SIGBUS: - goto bad_area; - case VM_FAULT_OOM: - goto out_of_memory; - case VM_FAULT_MINOR: - case VM_FAULT_MAJOR: - break; - default: - BUG(); - } - if (!size) - break; - size--; - start += PAGE_SIZE; - if (start < vma->vm_end) - continue; - vma = vma->vm_next; - if (!vma || vma->vm_start != start) - goto bad_area; - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area;; - } - /* - * We really need to hold mmap_sem over the whole access to - * userspace, else another thread could change permissions. - * This is unfixable, so don't use i386-class machines for - * critical servers. - */ - up_read(&mm->mmap_sem); - return 1; - -check_stack: - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (expand_stack(vma, start) == 0) - goto good_area; - -bad_area: - up_read(&mm->mmap_sem); - return 0; - -out_of_memory: - if (current->pid == 1) { - yield(); - goto survive; - } - goto bad_area; -} -#endif - /* * Unlock any spinlocks which will prevent us from getting the * message out @@ -405,8 +324,12 @@ if (!pgd_present(*pgd_k)) goto no_context; - set_pgd(pgd, *pgd_k); - + + /* + * set_pgd(pgd, *pgd_k); here would be useless on PAE + * and redundant with the set_pmd() on non-PAE. + */ + pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); if (!pmd_present(*pmd_k)) diff -Nru a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c --- a/arch/i386/mm/highmem.c Mon May 12 20:55:47 2003 +++ b/arch/i386/mm/highmem.c Mon May 12 20:55:47 2003 @@ -36,7 +36,7 @@ idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM if (!pte_none(*(kmap_pte-idx))) BUG(); #endif @@ -48,7 +48,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type) { -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Mon May 12 20:55:48 2003 +++ b/arch/i386/mm/init.c Mon May 12 20:55:48 2003 @@ -55,7 +55,7 @@ { pmd_t *pmd_table; -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); if (pmd_table != pmd_offset(pgd, 0)) @@ -188,7 +188,7 @@ return 0; } -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM pte_t *kmap_pte; pgprot_t kmap_prot; @@ -265,7 +265,7 @@ unsigned long vaddr; pgd_t *pgd_base = swapper_pg_dir; -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE int i; /* Init entries of the first-level page table to the zero page */ for (i = 0; i < PTRS_PER_PGD; i++) @@ -295,7 +295,7 @@ permanent_kmaps_init(pgd_base); -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE /* * Add low memory identity-mappings - SMP needs it when * starting up on an AP from real-mode. In the non-PAE @@ -317,7 +317,7 @@ * us, because pgd_clear() is a no-op on i386. */ for (i = 0; i < USER_PTRS_PER_PGD; i++) -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page))); #else set_pgd(swapper_pg_dir+i, __pgd(0)); @@ -363,7 +363,7 @@ load_cr3(swapper_pg_dir); -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE /* * We will bail out later - printk doesn't work right now so * the user would just see a hanging kernel. @@ -487,7 +487,7 @@ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ); -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE if (!cpu_has_pae) panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); #endif @@ -505,7 +505,7 @@ #endif } -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE struct kmem_cache_s *pae_pgd_cachep; void __init pgtable_cache_init(void) diff -Nru a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c --- a/arch/i386/mm/pgtable.c Mon May 12 20:55:49 2003 +++ b/arch/i386/mm/pgtable.c Mon May 12 20:55:49 2003 @@ -141,7 +141,7 @@ { struct page *pte; -#if CONFIG_HIGHPTE +#ifdef CONFIG_HIGHPTE pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT, 0); #else pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); @@ -151,7 +151,7 @@ return pte; } -#if CONFIG_X86_PAE +#ifdef CONFIG_X86_PAE pgd_t *pgd_alloc(struct mm_struct *mm) { diff -Nru a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S --- a/arch/i386/vmlinux.lds.S Mon May 12 20:55:45 2003 +++ b/arch/i386/vmlinux.lds.S Mon May 12 20:55:45 2003 @@ -85,7 +85,11 @@ __alt_instructions = .; .altinstructions : { *(.altinstructions) } __alt_instructions_end = .; - .altinstr_replacement : { *(.altinstr_replacement) } + .altinstr_replacement : { *(.altinstr_replacement) } + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : { *(.exit.text) } + .exit.data : { *(.exit.data) } . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } @@ -106,8 +110,6 @@ /* Sections to be discarded */ /DISCARD/ : { - *(.exit.text) - *(.exit.data) *(.exitcall.exit) } diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Mon May 12 20:55:49 2003 +++ b/arch/ia64/Kconfig Mon May 12 20:55:49 2003 @@ -381,6 +381,10 @@ depends on MCKINLEY bool "4GB" +config HUGETLB_PAGE_SIZE_1GB + depends on MCKINLEY + bool "1GB" + config HUGETLB_PAGE_SIZE_256MB bool "256MB" diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile --- a/arch/ia64/Makefile Mon May 12 20:55:44 2003 +++ b/arch/ia64/Makefile Mon May 12 20:55:44 2003 @@ -23,6 +23,7 @@ CFLAGS_KERNEL := -mconstant-gp GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') +GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f2 -d'.') GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP)) @@ -35,7 +36,14 @@ endif ifneq ($(GCC_VERSION),2) - cflags-y += -frename-registers --param max-inline-insns=5000 + cflags-$(CONFIG_ITANIUM) += -frename-registers +endif + +ifeq ($(GCC_VERSION),3) + ifeq ($(GCC_MINOR_VERSION),4) + cflags-$(CONFIG_ITANIUM) += -mtune=merced + cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley + endif endif cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC) += -mb-step @@ -48,14 +56,14 @@ core-y += arch/ia64/kernel/ arch/ia64/mm/ core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/ core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ -core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ arch/ia64/hp/common/ arch/ia64/hp/zx1/ \ - arch/ia64/hp/sim/ +core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/ drivers-$(CONFIG_PCI) += arch/ia64/pci/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ +drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ boot := arch/ia64/boot tools := arch/ia64/tools diff -Nru a/arch/ia64/dig/machvec.c b/arch/ia64/dig/machvec.c --- a/arch/ia64/dig/machvec.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/dig/machvec.c Mon May 12 20:55:46 2003 @@ -1,2 +1,3 @@ -#define MACHVEC_PLATFORM_NAME dig +#define MACHVEC_PLATFORM_NAME dig +#define MACHVEC_PLATFORM_HEADER #include diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Mon May 12 20:55:45 2003 +++ b/arch/ia64/hp/common/sba_iommu.c Mon May 12 20:55:45 2003 @@ -1,9 +1,9 @@ /* ** IA64 System Bus Adapter (SBA) I/O MMU manager ** -** (c) Copyright 2002 Alex Williamson -** (c) Copyright 2002 Grant Grundler -** (c) Copyright 2002 Hewlett-Packard Company +** (c) Copyright 2002-2003 Alex Williamson +** (c) Copyright 2002-2003 Grant Grundler +** (c) Copyright 2002-2003 Hewlett-Packard Company ** ** Portions (c) 2000 Grant Grundler (from parisc I/O MMU code) ** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) @@ -30,17 +30,39 @@ #include #include #include +#include +#include #include #include /* ia64_get_itc() */ #include #include /* PAGE_OFFSET */ +#include +#include /* wmb() */ +#include -#define DRIVER_NAME "SBA" +#define PFX "IOC: " +/* +** This option allows cards capable of 64bit DMA to bypass the IOMMU. If +** not defined, all DMA will be 32bit and go through the TLB. +*/ #define ALLOW_IOV_BYPASS + +/* +** If a device prefetches beyond the end of a valid pdir entry, it will cause +** a hard failure, ie. MCA. Version 3.0 and later of the zx1 LBA should +** disconnect on 4k boundaries and prevent such issues. If the device is +** particularly agressive, this option will keep the entire pdir valid such +** that prefetching will hit a valid address. This could severely impact +** error containment, and is therefore off by default. The page that is +** used for spill-over is poisoned, so that should help debugging somewhat. +*/ +#undef FULL_VALID_PDIR + #define ENABLE_MARK_CLEAN + /* ** The number of debug flags is a clue - this code is fragile. */ @@ -52,6 +74,10 @@ #undef DEBUG_LARGE_SG_ENTRIES #undef DEBUG_BYPASS +#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY) +#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive +#endif + #define SBA_INLINE __inline__ /* #define SBA_INLINE */ @@ -96,12 +122,8 @@ #define ASSERT(expr) #endif -#define KB(x) ((x) * 1024) -#define MB(x) (KB (KB (x))) -#define GB(x) (MB (KB (x))) - /* -** The number of pdir entries to "free" before issueing +** The number of pdir entries to "free" before issuing ** a read to PCOM register to flush out PCOM writes. ** Interacts with allocation granularity (ie 4 or 8 entries ** allocated and free'd/purged at a time might make this @@ -109,30 +131,24 @@ */ #define DELAYED_RESOURCE_CNT 16 -#define DEFAULT_DMA_HINT_REG(d) 0 - -#define ZX1_FUNC_ID_VALUE ((PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP) -#define ZX1_MC_ID ((PCI_DEVICE_ID_HP_ZX1_MC << 16) | PCI_VENDOR_ID_HP) +#define DEFAULT_DMA_HINT_REG 0 -#define SBA_FUNC_ID 0x0000 /* function id */ -#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ +#define ZX1_IOC_ID ((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP) +#define REO_IOC_ID ((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP) +#define SX1000_IOC_ID ((PCI_DEVICE_ID_HP_SX1000_IOC << 16) | PCI_VENDOR_ID_HP) -#define SBA_FUNC_SIZE 0x10000 /* SBA configuration function reg set */ - -unsigned int __initdata zx1_func_offsets[] = {0x1000, 0x4000, 0x8000, - 0x9000, 0xa000, -1}; - -#define SBA_IOC_OFFSET 0x1000 - -#define MAX_IOC 1 /* we only have 1 for now*/ +#define ZX1_IOC_OFFSET 0x1000 /* ACPI reports SBA, we want IOC */ +#define IOC_FUNC_ID 0x000 +#define IOC_FCLASS 0x008 /* function class, bist, header, rev... */ #define IOC_IBASE 0x300 /* IO TLB */ #define IOC_IMASK 0x308 #define IOC_PCOM 0x310 #define IOC_TCNFG 0x318 #define IOC_PDIR_BASE 0x320 -#define IOC_IOVA_SPACE_BASE 0x40000000 /* IOVA ranges start at 1GB */ +/* AGP GART driver looks for this */ +#define ZX1_SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL /* ** IOC supports 4/8/16/64KB page sizes (see TCNFG register) @@ -152,7 +168,7 @@ #define IOVP_MASK PAGE_MASK struct ioc { - unsigned long ioc_hpa; /* I/O MMU base address */ + void *ioc_hpa; /* I/O MMU base address */ char *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ unsigned long ibase; /* pdir IOV Space base */ @@ -193,37 +209,37 @@ #endif #endif - /* STUFF We don't need in performance path */ + /* Stuff we don't need in performance path */ + struct ioc *next; /* list of IOC's in system */ + acpi_handle handle; /* for multiple IOC's */ + const char *name; + unsigned int func_id; + unsigned int rev; /* HW revision of chip */ + u32 iov_size; unsigned int pdir_size; /* in bytes, determined by IOV Space size */ + struct pci_dev *sac_only_dev; }; -struct sba_device { - struct sba_device *next; /* list of SBA's in system */ - const char *name; - unsigned long sba_hpa; /* base address */ - spinlock_t sba_lock; - unsigned int flags; /* state/functionality enabled */ - unsigned int hw_rev; /* HW revision of chip */ - - unsigned int num_ioc; /* number of on-board IOC's */ - struct ioc ioc[MAX_IOC]; -}; +static struct ioc *ioc_list; +static int reserve_sba_gart = 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define sba_sg_address(sg) (page_address((sg)->page) + (sg)->offset) +#else +#define sba_sg_address(sg) ((sg)->address ? (sg)->address : \ + page_address((sg)->page) + (sg)->offset) +#endif -static struct sba_device *sba_list; -static int sba_count; -static int reserve_sba_gart = 1; -static struct pci_dev sac_only_dev; +#ifdef FULL_VALID_PDIR +static u64 prefetch_spill_page; +#endif -#define sba_sg_address(sg) (page_address((sg)->page) + (sg)->offset) -#define sba_sg_len(sg) (sg->length) -#define sba_sg_iova(sg) (sg->dma_address) -#define sba_sg_iova_len(sg) (sg->dma_length) - -/* REVISIT - fix me for multiple SBAs/IOCs */ -#define GET_IOC(dev) (sba_list->ioc) -#define SBA_SET_AGP(sba_dev) (sba_dev->flags |= 0x1) -#define SBA_GET_AGP(sba_dev) (sba_dev->flags & 0x1) +#ifdef CONFIG_PCI +# define GET_IOC(dev) (((dev)->bus == &pci_bus_type) \ + ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL) +#else +# define GET_IOC(dev) NULL +#endif /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up @@ -232,10 +248,7 @@ ** rather than the HW. I/O MMU allocation alogorithms can be ** faster with smaller size is (to some degree). */ -#define DMA_CHUNK_SIZE (BITS_PER_LONG*IOVP_SIZE) - -/* Looks nice and keeps the compiler happy */ -#define SBA_DEV(d) ((struct sba_device *) (d)) +#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE) #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) @@ -255,7 +268,7 @@ * sba_dump_tlb - debugging only - print IOMMU operating parameters * @hpa: base address of the IOMMU * - * Print the size/location of the IO MMU Pdir. + * Print the size/location of the IO MMU PDIR. */ static void sba_dump_tlb(char *hpa) @@ -273,19 +286,19 @@ #ifdef ASSERT_PDIR_SANITY /** - * sba_dump_pdir_entry - debugging only - print one IOMMU Pdir entry + * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry * @ioc: IO MMU structure which owns the pdir we are interested in. * @msg: text to print ont the output line. * @pide: pdir index. * - * Print one entry of the IO MMU Pdir in human readable form. + * Print one entry of the IO MMU PDIR in human readable form. */ static void sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) { /* start printing from lowest pde in rval */ - u64 *ptr = &(ioc->pdir_base[pide & ~(BITS_PER_LONG - 1)]); - unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + u64 *ptr = &ioc->pdir_base[pide & ~(BITS_PER_LONG - 1)]; + unsigned long *rptr = (unsigned long *) &ioc->res_map[(pide >>3) & -sizeof(unsigned long)]; uint rcnt; printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", @@ -296,7 +309,7 @@ printk(KERN_DEBUG "%s %2d %p %016Lx\n", (rcnt == (pide & (BITS_PER_LONG - 1))) ? " -->" : " ", - rcnt, ptr, *ptr ); + rcnt, ptr, (unsigned long long) *ptr ); rcnt++; ptr++; } @@ -359,17 +372,18 @@ * print the SG list so we can verify it's correct by hand. */ static void -sba_dump_sg(struct ioc *ioc, struct scatterlist *startsg, int nents) +sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) { while (nents-- > 0) { printk(KERN_DEBUG " %d : DMA %08lx/%05x CPU %p\n", nents, - (unsigned long) sba_sg_iova(startsg), sba_sg_iova_len(startsg), + startsg->dma_address, startsg->dma_length, sba_sg_address(startsg)); startsg++; } } + static void -sba_check_sg(struct ioc *ioc, struct scatterlist *startsg, int nents) +sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) { struct scatterlist *the_sg = startsg; int the_nents = nents; @@ -398,9 +412,11 @@ #define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ /* Convert from IOVP to IOVA and vice versa. */ -#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir))) +#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | \ + ((hint_reg)<<(ioc->hint_shift_pdir))) #define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase)) +/* FIXME : review these macros to verify correctness and usage */ #define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) #define RESMAP_MASK(n) ~(~0UL << (n)) @@ -408,7 +424,7 @@ /** - * sba_search_bitmap - find free space in IO Pdir resource bitmap + * sba_search_bitmap - find free space in IO PDIR resource bitmap * @ioc: IO MMU structure which owns the pdir we are interested in. * @bits_wanted: number of entries we need. * @@ -445,7 +461,7 @@ ** We need the alignment to invalidate I/O TLB using ** SBA HW features in the unmap path. */ - unsigned long o = 1UL << get_order(bits_wanted << IOVP_SHIFT); + unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT); uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o); unsigned long mask; @@ -491,7 +507,7 @@ /** - * sba_alloc_range - find free bits and mark them in IO Pdir resource bitmap + * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap * @ioc: IO MMU structure which owns the pdir we are interested in. * @size: number of bytes to create a mapping for * @@ -520,7 +536,8 @@ if (pide >= (ioc->res_size << 3)) { pide = sba_search_bitmap(ioc, pages_needed); if (pide >= (ioc->res_size << 3)) - panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa); + panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", + ioc->ioc_hpa); } #ifdef ASSERT_PDIR_SANITY @@ -553,7 +570,7 @@ /** - * sba_free_range - unmark bits in IO Pdir resource bitmap + * sba_free_range - unmark bits in IO PDIR resource bitmap * @ioc: IO MMU structure which owns the pdir we are interested in. * @iova: IO virtual address which was previously allocated. * @size: number of bytes to create a mapping for @@ -600,14 +617,14 @@ /** - * sba_io_pdir_entry - fill in one IO Pdir entry - * @pdir_ptr: pointer to IO Pdir entry - * @phys_page: phys CPU address of page to map + * sba_io_pdir_entry - fill in one IO PDIR entry + * @pdir_ptr: pointer to IO PDIR entry + * @vba: Virtual CPU address of buffer to map * * SBA Mapping Routine * - * Given a physical address (phys_page, arg1) sba_io_pdir_entry() - * loads the I/O Pdir entry pointed to by pdir_ptr (arg0). + * Given a virtual address (vba, arg1) sba_io_pdir_entry() + * loads the I/O PDIR entry pointed to by pdir_ptr (arg0). * Each IO Pdir entry consists of 8 bytes as shown below * (LSB == bit 0): * @@ -619,12 +636,21 @@ * V == Valid Bit * U == Unused * PPN == Physical Page Number + * + * The physical address fields are filled with the results of virt_to_phys() + * on the vba. */ -#define SBA_VALID_MASK 0x80000000000000FFULL -#define sba_io_pdir_entry(pdir_ptr, phys_page) *pdir_ptr = (phys_page | SBA_VALID_MASK) -#define sba_io_page(pdir_ptr) (*pdir_ptr & ~SBA_VALID_MASK) - +#if 1 +#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL) \ + | 0x8000000000000000ULL) +#else +void SBA_INLINE +sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba) +{ + *pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL); +} +#endif #ifdef ENABLE_MARK_CLEAN /** @@ -640,7 +666,7 @@ pg_addr = PAGE_ALIGN((unsigned long) addr); end = (unsigned long) addr + size; while (pg_addr + PAGE_SIZE <= end) { - struct page *page = virt_to_page(pg_addr); + struct page *page = virt_to_page((void *)pg_addr); set_bit(PG_arch_1, &page->flags); pg_addr += PAGE_SIZE; } @@ -648,12 +674,12 @@ #endif /** - * sba_mark_invalid - invalidate one or more IO Pdir entries + * sba_mark_invalid - invalidate one or more IO PDIR entries * @ioc: IO MMU structure which owns the pdir we are interested in. * @iova: IO Virtual Address mapped earlier * @byte_cnt: number of bytes this mapping covers. * - * Marking the IO Pdir entry(ies) as Invalid and invalidate + * Marking the IO PDIR entry(ies) as Invalid and invalidate * corresponding IO TLB entry. The PCOM (Purge Command Register) * is to purge stale entries in the IO TLB when unmapping entries. * @@ -687,15 +713,24 @@ iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ +#ifndef FULL_VALID_PDIR /* - ** clear I/O Pdir entry "valid" bit + ** clear I/O PDIR entry "valid" bit ** Do NOT clear the rest - save it for debugging. ** We should only clear bits that have previously ** been enabled. */ - ioc->pdir_base[off] &= ~SBA_VALID_MASK; + ioc->pdir_base[off] &= ~(0x80000000000000FFULL); +#else + /* + ** If we want to maintain the PDIR as valid, put in + ** the spill page so devices prefetching won't + ** cause a hard fail. + */ + ioc->pdir_base[off] = (0x80000000000000FFULL | prefetch_spill_page); +#endif } else { - u32 t = get_order(byte_cnt) + IOVP_SHIFT; + u32 t = get_order(byte_cnt) + PAGE_SHIFT; iovp |= t; ASSERT(t <= 31); /* 2GB! Max value of "size" field */ @@ -703,14 +738,18 @@ do { /* verify this pdir entry is enabled */ ASSERT(ioc->pdir_base[off] >> 63); +#ifndef FULL_VALID_PDIR /* clear I/O Pdir entry "valid" bit first */ - ioc->pdir_base[off] &= ~SBA_VALID_MASK; + ioc->pdir_base[off] &= ~(0x80000000000000FFULL); +#else + ioc->pdir_base[off] = (0x80000000000000FFULL | prefetch_spill_page); +#endif off++; byte_cnt -= IOVP_SIZE; } while (byte_cnt > 0); } - WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM); + WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM); } /** @@ -718,26 +757,23 @@ * @dev: instance of PCI owned by the driver that's asking. * @addr: driver buffer to map. * @size: number of bytes to map in driver buffer. - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ dma_addr_t -sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +sba_map_single(struct device *dev, void *addr, size_t size, int dir) { struct ioc *ioc; - unsigned long flags; + unsigned long flags; dma_addr_t iovp; dma_addr_t offset; u64 *pdir_start; int pide; #ifdef ALLOW_IOV_BYPASS - unsigned long phys_addr = virt_to_phys(addr); + unsigned long pci_addr = virt_to_phys(addr); #endif - if (!sba_list) - panic("sba_map_single: no SBA found!\n"); - ioc = GET_IOC(dev); ASSERT(ioc); @@ -745,7 +781,7 @@ /* ** Check if the PCI device can DMA to ptr... if so, just return ptr */ - if ((phys_addr & ~dev->dma_mask) == 0) { + if (dev && dev->dma_mask && (pci_addr & ~*dev->dma_mask) == 0) { /* ** Device is bit capable of DMA'ing to the buffer... ** just return the PCI address of ptr @@ -756,8 +792,8 @@ spin_unlock_irqrestore(&ioc->res_lock, flags); #endif DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n", - dev->dma_mask, phys_addr); - return phys_addr; + *dev->dma_mask, pci_addr); + return pci_addr; } #endif @@ -790,8 +826,7 @@ while (size > 0) { ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ - - sba_io_pdir_entry(pdir_start, virt_to_phys(addr)); + sba_io_pdir_entry(pdir_start, (unsigned long) addr); DBG_RUN(" pdir 0x%p %lx\n", pdir_start, *pdir_start); @@ -799,12 +834,15 @@ size -= IOVP_SIZE; pdir_start++; } + /* force pdir update */ + wmb(); + /* form complete address */ #ifdef ASSERT_PDIR_SANITY sba_check_pdir(ioc,"Check after sba_map_single()"); #endif spin_unlock_irqrestore(&ioc->res_lock, flags); - return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG(direction)); + return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); } /** @@ -812,23 +850,19 @@ * @dev: instance of PCI owned by the driver that's asking. * @iova: IOVA of driver buffer previously mapped. * @size: number of bytes mapped in driver buffer. - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, - int direction) +void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir) { struct ioc *ioc; #if DELAYED_RESOURCE_CNT > 0 struct sba_dma_pair *d; #endif - unsigned long flags; + unsigned long flags; dma_addr_t offset; - if (!sba_list) - panic("sba_map_single: no SBA found!\n"); - ioc = GET_IOC(dev); ASSERT(ioc); @@ -845,7 +879,7 @@ DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova); #ifdef ENABLE_MARK_CLEAN - if (direction == PCI_DMA_FROMDEVICE) { + if (dir == DMA_FROM_DEVICE) { mark_clean(phys_to_virt(iova), size); } #endif @@ -861,29 +895,6 @@ size += offset; size = ROUNDUP(size, IOVP_SIZE); -#ifdef ENABLE_MARK_CLEAN - /* - ** Don't need to hold the spinlock while telling VM pages are "clean". - ** The pages are "busy" in the resource map until we mark them free. - ** But tell VM pages are clean *before* releasing the resource - ** in order to avoid race conditions. - */ - if (direction == PCI_DMA_FROMDEVICE) { - u32 iovp = (u32) SBA_IOVP(ioc,iova); - unsigned int pide = PDIR_INDEX(iovp); - u64 *pdirp = &(ioc->pdir_base[pide]); - size_t byte_cnt = size; - void *addr; - - do { - addr = phys_to_virt(sba_io_page(pdirp)); - mark_clean(addr, min(byte_cnt, IOVP_SIZE)); - pdirp++; - byte_cnt -= IOVP_SIZE; - } while (byte_cnt > 0); - } -#endif - spin_lock_irqsave(&ioc->res_lock, flags); #ifdef CONFIG_PROC_FS ioc->usingle_calls++; @@ -909,7 +920,40 @@ sba_free_range(ioc, iova, size); READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ +#ifdef ENABLE_MARK_CLEAN + if (dir == DMA_FROM_DEVICE) { + u32 iovp = (u32) SBA_IOVP(ioc,iova); + int off = PDIR_INDEX(iovp); + void *addr; + + if (size <= IOVP_SIZE) { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, size); + } else { + size_t byte_cnt = size; + + do { + addr = phys_to_virt(ioc->pdir_base[off] & + ~0xE000000000000FFFULL); + mark_clean(addr, min(byte_cnt, IOVP_SIZE)); + off++; + byte_cnt -= IOVP_SIZE; + + } while (byte_cnt > 0); + } + } +#endif spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support. + ** For Astro based systems this isn't a big deal WRT performance. + ** As long as 2.4 kernels copyin/copyout data from/to userspace, + ** we don't need the syncdma. The issue here is I/O MMU cachelines + ** are *not* coherent in all cases. May be hwrev dependent. + ** Need to investigate more. + asm volatile("syncdma"); + */ } @@ -922,29 +966,25 @@ * See Documentation/DMA-mapping.txt */ void * -sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +sba_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handle, int flags) { - void *ret; - - if (!hwdev) { - /* only support PCI */ - *dma_handle = 0; - return 0; - } + struct ioc *ioc; + void *addr; - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + addr = (void *) __get_free_pages(flags, get_order(size)); + if (!addr) + return NULL; - if (ret) { - memset(ret, 0, size); - /* - * REVISIT: if sba_map_single starts needing more - * than dma_mask from the device, this needs to be - * updated. - */ - *dma_handle = sba_map_single(&sac_only_dev, ret, size, 0); - } + /* + * REVISIT: if sba_map_single starts needing more than dma_mask from the + * device, this needs to be updated. + */ + ioc = GET_IOC(hwdev); + ASSERT(ioc); + *dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0); - return ret; + memset(addr, 0, size); + return addr; } @@ -957,117 +997,245 @@ * * See Documentation/DMA-mapping.txt */ -void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) +void sba_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { sba_unmap_single(hwdev, dma_handle, size, 0); free_pages((unsigned long) vaddr, get_order(size)); } +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x1UL + #ifdef DEBUG_LARGE_SG_ENTRIES int dump_run_sg = 0; #endif -#define SG_ENT_VIRT_PAGE(sg) page_address((sg)->page) -#define SG_ENT_PHYS_PAGE(SG) virt_to_phys(SG_ENT_VIRT_PAGE(SG)) - /** - * sba_coalesce_chunks - preprocess the SG list + * sba_fill_pdir - write allocated SG entries into IO PDIR * @ioc: IO MMU structure which owns the pdir we are interested in. - * @startsg: input=SG list output=DMA addr/len pairs filled in + * @startsg: list of IOVA/size pairs * @nents: number of entries in startsg list - * @direction: R/W or both. * - * Walk the SG list and determine where the breaks are in the DMA stream. - * Allocate IO Pdir resources and fill them in separate loop. - * Returns the number of DMA streams used for output IOVA list. - * Note each DMA stream can consume multiple IO Pdir entries. - * - * Code is written assuming some coalescing is possible. + * Take preprocessed SG list and write corresponding entries + * in the IO PDIR. */ + static SBA_INLINE int -sba_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, - int nents, int direction) +sba_fill_pdir( + struct ioc *ioc, + struct scatterlist *startsg, + int nents) { - struct scatterlist *dma_sg = startsg; /* return array */ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; - ASSERT(nents > 1); + dma_sg--; + while (nents-- > 0) { + int cnt = startsg->dma_length; + startsg->dma_length = 0; - do { - unsigned int dma_cnt = 1; /* number of pages in DMA stream */ - unsigned int pide; /* index into IO Pdir array */ - u64 *pdirp; /* pointer into IO Pdir array */ - unsigned long dma_offset, dma_len; /* cumulative DMA stream */ +#ifdef DEBUG_LARGE_SG_ENTRIES + if (dump_run_sg) + printk(" %2d : %08lx/%05x %p\n", + nents, startsg->dma_address, cnt, + sba_sg_address(startsg)); +#else + DBG_RUN_SG(" %d : %08lx/%05x %p\n", + nents, startsg->dma_address, cnt, + sba_sg_address(startsg)); +#endif + /* + ** Look for the start of a new DMA stream + */ + if (startsg->dma_address & PIDE_FLAG) { + u32 pide = startsg->dma_address & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + startsg->dma_address = 0; + dma_sg++; + dma_sg->dma_address = pide | ioc->ibase; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } /* - ** Prepare for first/next DMA stream + ** Look for a VCONTIG chunk */ - dma_len = sba_sg_len(startsg); - dma_offset = (unsigned long) sba_sg_address(startsg); + if (cnt) { + unsigned long vaddr = (unsigned long) sba_sg_address(startsg); + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + dma_sg->dma_length += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + sba_io_pdir_entry(pdirp, vaddr); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } startsg++; - nents--; + } + /* force pdir update */ + wmb(); + +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = 0; +#endif + return(n_mappings); +} + + +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + + +/** + * sba_coalesce_chunks - preprocess the SG list + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: list of IOVA/size pairs + * @nents: number of entries in startsg list + * + * First pass is to walk the SG list and determine where the breaks are + * in the DMA stream. Allocates PDIR entries but does not fill them. + * Returns the number of DMA chunks. + * + * Doing the fill seperate from the coalescing/allocation keeps the + * code simpler. Future enhancement could make one pass through + * the sglist do both. + */ +static SBA_INLINE int +sba_coalesce_chunks( struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { + unsigned long vaddr = (unsigned long) sba_sg_address(startsg); /* - ** We want to know how many entries can be coalesced - ** before trying to allocate IO Pdir space. - ** IOVAs can then be allocated "naturally" aligned - ** to take advantage of the block IO TLB flush. + ** Prepare for first/next DMA stream */ - while (nents) { - unsigned long end_offset = dma_offset + dma_len; + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += vaddr; + dma_offset = vaddr & ~IOVP_MASK; - /* prev entry must end on a page boundary */ - if (end_offset & IOVP_MASK) - break; + /* PARANOID: clear entries */ + startsg->dma_address = startsg->dma_length = 0; - /* next entry start on a page boundary? */ - if (startsg->offset) - break; + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while (--nents > 0) { + unsigned long vaddr; /* tmp */ + + startsg++; + + /* PARANOID */ + startsg->dma_address = startsg->dma_length = 0; + + /* catch brokenness in SCSI layer */ + ASSERT(startsg->length <= DMA_CHUNK_SIZE); /* - ** make sure current dma stream won't exceed - ** DMA_CHUNK_SIZE if coalescing entries. + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. */ - if (((end_offset + startsg->length + ~IOVP_MASK) - & IOVP_MASK) - > DMA_CHUNK_SIZE) + if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) + > DMA_CHUNK_SIZE) break; - dma_len += sba_sg_len(startsg); - startsg++; - nents--; - dma_cnt++; - } + /* + ** Then look for virtually contiguous blocks. + ** + ** append the next transaction? + */ + vaddr = (unsigned long) sba_sg_address(startsg); + if (vcontig_end == vaddr) + { + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; + continue; + } - ASSERT(dma_len <= DMA_CHUNK_SIZE); +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = (vcontig_len > IOVP_SIZE); +#endif - /* allocate IO Pdir resource. - ** returns index into (u64) IO Pdir array. - ** IOVA is formed from this. - */ - pide = sba_alloc_range(ioc, dma_cnt << IOVP_SHIFT); - pdirp = &(ioc->pdir_base[pide]); + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + vcontig_sg->dma_length = vcontig_len; - /* fill_pdir: write stream into IO Pdir */ - while (dma_cnt--) { - sba_io_pdir_entry(pdirp, SG_ENT_PHYS_PAGE(startsg)); - startsg++; - pdirp++; - } + vcontig_sg = startsg; + vcontig_len = startsg->length; - /* "output" IOVA */ - sba_sg_iova(dma_sg) = SBA_IOVA(ioc, - ((dma_addr_t) pide << IOVP_SHIFT), - dma_offset, - DEFAULT_DMA_HINT_REG(direction)); - sba_sg_iova_len(dma_sg) = dma_len; + /* + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. + */ + if (DMA_CONTIG(vcontig_end, vaddr)) + { + vcontig_end = vcontig_len + vaddr; + dma_len += vcontig_len; + continue; + } else { + break; + } + } - dma_sg++; + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + vcontig_sg->dma_length = vcontig_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + ASSERT(dma_len <= DMA_CHUNK_SIZE); + dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG + | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset); n_mappings++; - } while (nents); + } return n_mappings; } @@ -1075,60 +1243,51 @@ /** * sba_map_sg - map Scatter/Gather list - * @dev: instance of PCI device owned by the driver that's asking. + * @dev: instance of PCI owned by the driver that's asking. * @sglist: array of buffer/length pairs * @nents: number of entries in list - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, - int direction) +int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int dir) { struct ioc *ioc; - int filled = 0; + int coalesced, filled = 0; unsigned long flags; #ifdef ALLOW_IOV_BYPASS struct scatterlist *sg; #endif - DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n", __FUNCTION__, nents, - sba_sg_address(sglist), sba_sg_len(sglist)); - - if (!sba_list) - panic("sba_map_single: no SBA found!\n"); - + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); ioc = GET_IOC(dev); ASSERT(ioc); #ifdef ALLOW_IOV_BYPASS - if (dev->dma_mask >= ioc->dma_mask) { - for (sg = sglist ; filled < nents ; filled++, sg++) { - sba_sg_iova(sg) = virt_to_phys(sba_sg_address(sg)); - sba_sg_iova_len(sg) = sba_sg_len(sg); + if (dev && dev->dma_mask && (ioc->dma_mask & ~*dev->dma_mask) == 0) { + for (sg = sglist ; filled < nents ; filled++, sg++){ + sg->dma_length = sg->length; + sg->dma_address = virt_to_phys(sba_sg_address(sg)); } #ifdef CONFIG_PROC_FS spin_lock_irqsave(&ioc->res_lock, flags); ioc->msg_bypass++; spin_unlock_irqrestore(&ioc->res_lock, flags); #endif - DBG_RUN_SG("%s() DONE %d mappings bypassed\n", __FUNCTION__, filled); return filled; } #endif /* Fast path single entry scatterlists. */ if (nents == 1) { - sba_sg_iova(sglist) = sba_map_single(dev, - (void *) sba_sg_iova(sglist), - sba_sg_len(sglist), direction); - sba_sg_iova_len(sglist) = sba_sg_len(sglist); + sglist->dma_length = sglist->length; + sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length, + dir); #ifdef CONFIG_PROC_FS /* ** Should probably do some stats counting, but trying to ** be precise quickly starts wasting CPU time. */ #endif - DBG_RUN_SG("%s() DONE 1 mapping\n", __FUNCTION__); return 1; } @@ -1145,11 +1304,26 @@ #ifdef CONFIG_PROC_FS ioc->msg_calls++; #endif - + /* - ** coalesce and program the I/O Pdir + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. */ - filled = sba_coalesce_chunks(ioc, sglist, nents, direction); + coalesced = sba_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = sba_fill_pdir(ioc, sglist, nents); #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) @@ -1161,6 +1335,7 @@ spin_unlock_irqrestore(&ioc->res_lock, flags); + ASSERT(coalesced == filled); DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); return filled; @@ -1172,23 +1347,19 @@ * @dev: instance of PCI owned by the driver that's asking. * @sglist: array of buffer/length pairs * @nents: number of entries in list - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, - int direction) +void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir) { struct ioc *ioc; #ifdef ASSERT_PDIR_SANITY unsigned long flags; #endif - DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n", - __FUNCTION__, nents, sba_sg_address(sglist), sba_sg_len(sglist)); - - if (!sba_list) - panic("sba_map_single: no SBA found!\n"); + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sba_sg_address(sglist), sglist->length); ioc = GET_IOC(dev); ASSERT(ioc); @@ -1203,10 +1374,9 @@ spin_unlock_irqrestore(&ioc->res_lock, flags); #endif - while (sba_sg_len(sglist) && nents--) { + while (nents && sglist->dma_length) { - sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist), - sba_sg_iova_len(sglist), direction); + sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir); #ifdef CONFIG_PROC_FS /* ** This leaves inconsistent data in the stats, but we can't @@ -1214,9 +1384,11 @@ ** were coalesced to a single entry. The stats are fun, ** but speed is more important. */ - ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> IOVP_SHIFT; + ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length + + IOVP_SIZE - 1) >> PAGE_SHIFT; #endif - ++sglist; + sglist++; + nents--; } DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); @@ -1229,87 +1401,76 @@ } -unsigned long -sba_dma_address (struct scatterlist *sg) -{ - return ((unsigned long)sba_sg_iova(sg)); -} - -int -sba_dma_supported (struct pci_dev *dev, u64 mask) -{ - return 1; -} - /************************************************************** * * Initialization and claim * ***************************************************************/ - -static void -sba_ioc_init(struct sba_device *sba_dev, struct ioc *ioc, int ioc_num) +static void __init +ioc_iova_init(struct ioc *ioc) { - u32 iova_space_size, iova_space_mask; - void * pdir_base; - int pdir_size, iov_order, tcnfg; + u32 iova_space_mask; + int iov_order, tcnfg; + int agp_found = 0; + struct pci_dev *device; +#ifdef FULL_VALID_PDIR + unsigned long index; +#endif /* - ** Firmware programs the maximum IOV space size into the imask reg + ** Firmware programs the base and size of a "safe IOVA space" + ** (one that doesn't overlap memory or LMMIO space) in the + ** IBASE and IMASK registers. */ - iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1; + ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1UL; + ioc->iov_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1; /* ** iov_order is always based on a 1GB IOVA space since we want to ** turn on the other half for AGP GART. */ - iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT)); - ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + iov_order = get_order(ioc->iov_size >> (IOVP_SHIFT - PAGE_SHIFT)); + ioc->pdir_size = (ioc->iov_size / IOVP_SIZE) * sizeof(u64); - DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n", - __FUNCTION__, ioc->ioc_hpa, iova_space_size>>20, - iov_order + PAGE_SHIFT, ioc->pdir_size); + DBG_INIT("%s() hpa %p IOV %dMB (%d bits) PDIR size 0x%x\n", + __FUNCTION__, ioc->ioc_hpa, ioc->iov_size >> 20, + iov_order + PAGE_SHIFT, ioc->pdir_size); - /* XXX DMA HINTs not used */ + /* FIXME : DMA HINTs not used */ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); - ioc->pdir_base = pdir_base = - (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); - if (NULL == pdir_base) - { - panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); - } - memset(pdir_base, 0, pdir_size); + ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL, + get_order(ioc->pdir_size)); + if (!ioc->pdir_base) + panic(PFX "Couldn't allocate I/O Page Table\n"); + + memset(ioc->pdir_base, 0, ioc->pdir_size); DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n", - __FUNCTION__, pdir_base, pdir_size, + __FUNCTION__, ioc->pdir_base, ioc->pdir_size, ioc->hint_shift_pdir, ioc->hint_mask_pdir); - ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); - WRITE_REG(virt_to_phys(pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE); + ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base); + WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE); - DBG_INIT(" base %p\n", pdir_base); + DBG_INIT(" base %p\n", ioc->pdir_base); /* build IMASK for IOC and Elroy */ iova_space_mask = 0xffffffff; - iova_space_mask <<= (iov_order + IOVP_SHIFT); - - ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL; - - ioc->imask = iova_space_mask; /* save it */ + iova_space_mask <<= (iov_order + PAGE_SHIFT); + ioc->imask = iova_space_mask; DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__, ioc->ibase, ioc->imask); /* - ** XXX DMA HINT registers are programmed with default hint + ** FIXME: Hint registers are programmed with default hint ** values during boot, so hints should be sane even if we ** can't reprogram them the way drivers want. */ - - WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK); + WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK); /* ** Setting the upper bits makes checking for bypass addresses @@ -1317,34 +1478,30 @@ */ ioc->imask |= 0xFFFFFFFF00000000UL; - /* Set I/O Pdir page size to system page size */ - switch (IOVP_SHIFT) { - case 12: /* 4K */ - tcnfg = 0; - break; - case 13: /* 8K */ - tcnfg = 1; - break; - case 14: /* 16K */ - tcnfg = 2; - break; - case 16: /* 64K */ - tcnfg = 3; + /* Set I/O PDIR Page size to system page size */ + switch (PAGE_SHIFT) { + case 12: tcnfg = 0; break; /* 4K */ + case 13: tcnfg = 1; break; /* 8K */ + case 14: tcnfg = 2; break; /* 16K */ + case 16: tcnfg = 3; break; /* 64K */ + default: + panic(PFX "Unsupported system page size %d", + 1 << PAGE_SHIFT); break; } - WRITE_REG(tcnfg, ioc->ioc_hpa+IOC_TCNFG); + WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG); /* ** Program the IOC's ibase and enable IOVA translation ** Bit zero == enable bit. */ - WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa+IOC_IBASE); + WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE); /* ** Clear I/O TLB of any possible entries. ** (Yes. This is a bit paranoid...but so what) */ - WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM); + WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM); /* ** If an AGP device is present, only use half of the IOV space @@ -1354,346 +1511,468 @@ ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - if (SBA_GET_AGP(sba_dev)) { - DBG_INIT("%s() AGP Device found, reserving 512MB for GART support\n", __FUNCTION__); + pci_for_each_dev(device) + agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); + + if (agp_found && reserve_sba_gart) { + DBG_INIT("%s: AGP device found, reserving half of IOVA for GART support\n", + __FUNCTION__); ioc->pdir_size /= 2; - ((u64 *)pdir_base)[PDIR_INDEX(iova_space_size/2)] = 0x0000badbadc0ffeeULL; + ((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE; } +#ifdef FULL_VALID_PDIR + /* + ** Check to see if the spill page has been allocated, we don't need more than + ** one across multiple SBAs. + */ + if (!prefetch_spill_page) { + char *spill_poison = "SBAIOMMU POISON"; + int poison_size = 16; + void *poison_addr, *addr; + + addr = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE)); + if (!addr) + panic(PFX "Couldn't allocate PDIR spill page\n"); + + poison_addr = addr; + for ( ; (u64) poison_addr < addr + IOVP_SIZE; poison_addr += poison_size) + memcpy(poison_addr, spill_poison, poison_size); + + prefetch_spill_page = virt_to_phys(addr); + + DBG_INIT("%s() prefetch spill addr: 0x%lx\n", __FUNCTION__, prefetch_spill_page); + } + /* + ** Set all the PDIR entries valid w/ the spill page as the target + */ + for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++) + ((u64 *)ioc->pdir_base)[index] = (0x80000000000000FF | prefetch_spill_page); +#endif - DBG_INIT("%s() DONE\n", __FUNCTION__); } +static void __init +ioc_resource_init(struct ioc *ioc) +{ + spin_lock_init(&ioc->res_lock); + /* resource map size dictated by pdir_size */ + ioc->res_size = ioc->pdir_size / sizeof(u64); /* entries */ + ioc->res_size >>= 3; /* convert bit count to byte count */ + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); -/************************************************************************** -** -** SBA initialization code (HW and SW) -** -** o identify SBA chip itself -** o FIXME: initialize DMA hints for reasonable defaults -** -**************************************************************************/ + ioc->res_map = (char *) __get_free_pages(GFP_KERNEL, + get_order(ioc->res_size)); + if (!ioc->res_map) + panic(PFX "Couldn't allocate resource map\n"); -static void -sba_hw_init(struct sba_device *sba_dev) -{ - int i; - int num_ioc; - u64 dma_mask; - u32 func_id; + memset(ioc->res_map, 0, ioc->res_size); + /* next available IOVP - circular search */ + ioc->res_hint = (unsigned long *) ioc->res_map; - /* - ** Identify the SBA so we can set the dma_mask. We can make a virtual - ** dma_mask of the memory subsystem such that devices not implmenting - ** a full 64bit mask might still be able to bypass efficiently. - */ - func_id = READ_REG(sba_dev->sba_hpa + SBA_FUNC_ID); +#ifdef ASSERT_PDIR_SANITY + /* Mark first bit busy - ie no IOVA 0 */ + ioc->res_map[0] = 0x1; + ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE; +#endif +#ifdef FULL_VALID_PDIR + /* Mark the last resource used so we don't prefetch beyond IOVA space */ + ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */ + ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FF + | prefetch_spill_page); +#endif - if (func_id == ZX1_FUNC_ID_VALUE) { - dma_mask = 0xFFFFFFFFFFUL; - } else { - dma_mask = 0xFFFFFFFFFFFFFFFFUL; - } + DBG_INIT("%s() res_map %x %p\n", __FUNCTION__, + ioc->res_size, (void *) ioc->res_map); +} + +static void __init +ioc_sac_init(struct ioc *ioc) +{ + struct pci_dev *sac = NULL; + struct pci_controller *controller = NULL; - DBG_INIT("%s(): ioc->dma_mask == 0x%lx\n", __FUNCTION__, dma_mask); - /* - ** Leaving in the multiple ioc code from parisc for the future, - ** currently there are no muli-ioc mckinley sbas - */ - sba_dev->ioc[0].ioc_hpa = SBA_IOC_OFFSET; - num_ioc = 1; + * pci_alloc_coherent() must return a DMA address which is + * SAC (single address cycle) addressable, so allocate a + * pseudo-device to enforce that. + */ + sac = kmalloc(sizeof(*sac), GFP_KERNEL); + if (!sac) + panic(PFX "Couldn't allocate struct pci_dev"); + memset(sac, 0, sizeof(*sac)); - sba_dev->num_ioc = num_ioc; - for (i = 0; i < num_ioc; i++) { - sba_dev->ioc[i].dma_mask = dma_mask; - sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa; - sba_ioc_init(sba_dev, &(sba_dev->ioc[i]), i); - } + controller = kmalloc(sizeof(*controller), GFP_KERNEL); + if (!controller) + panic(PFX "Couldn't allocate struct pci_controller"); + memset(controller, 0, sizeof(*controller)); + + controller->iommu = ioc; + sac->sysdata = controller; + sac->dma_mask = 0xFFFFFFFFUL; +#ifdef CONFIG_PCI + sac->dev.bus = &pci_bus_type; +#endif + ioc->sac_only_dev = sac; } -static void -sba_common_init(struct sba_device *sba_dev) +static void __init +ioc_zx1_init(struct ioc *ioc) { - int i; + if (ioc->rev < 0x20) + panic(PFX "IOC 2.0 or later required for IOMMU support\n"); - /* add this one to the head of the list (order doesn't matter) - ** This will be useful for debugging - especially if we get coredumps - */ - sba_dev->next = sba_list; - sba_list = sba_dev; - sba_count++; - - for(i=0; i< sba_dev->num_ioc; i++) { - int res_size; - - /* resource map size dictated by pdir_size */ - res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */ - res_size >>= 3; /* convert bit count to byte count */ - DBG_INIT("%s() res_size 0x%x\n", - __FUNCTION__, res_size); - - sba_dev->ioc[i].res_size = res_size; - sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); - - if (NULL == sba_dev->ioc[i].res_map) - { - panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ ); - } + ioc->dma_mask = 0xFFFFFFFFFFUL; +} - memset(sba_dev->ioc[i].res_map, 0, res_size); - /* next available IOVP - circular search */ - if ((sba_dev->hw_rev & 0xFF) >= 0x20) { - sba_dev->ioc[i].res_hint = (unsigned long *) - sba_dev->ioc[i].res_map; - } else { - u64 reserved_iov; +typedef void (initfunc)(struct ioc *); - /* Yet another 1.x hack */ - printk(KERN_DEBUG "zx1 1.x: Starting resource hint offset into " - "IOV space to avoid initial zero value IOVA\n"); - sba_dev->ioc[i].res_hint = (unsigned long *) - &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]); - - sba_dev->ioc[i].res_map[0] = 0x1; - sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL; - - for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) { - u64 *res_ptr = (u64 *) sba_dev->ioc[i].res_map; - int index = PDIR_INDEX(reserved_iov); - int res_word; - u64 mask; - - res_word = (int)(index / BITS_PER_LONG); - mask = 0x1UL << (index - (res_word * BITS_PER_LONG)); - res_ptr[res_word] |= mask; - sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (SBA_VALID_MASK | reserved_iov); +struct ioc_iommu { + u32 func_id; + char *name; + initfunc *init; +}; - } - } +static struct ioc_iommu ioc_iommu_info[] __initdata = { + { ZX1_IOC_ID, "zx1", ioc_zx1_init }, + { REO_IOC_ID, "REO" }, + { SX1000_IOC_ID, "sx1000" }, +}; -#ifdef ASSERT_PDIR_SANITY - /* Mark first bit busy - ie no IOVA 0 */ - sba_dev->ioc[i].res_map[0] = 0x1; - sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL; -#endif +static struct ioc * __init +ioc_init(u64 hpa, void *handle) +{ + struct ioc *ioc; + struct ioc_iommu *info; + + ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); + if (!ioc) + return NULL; + + memset(ioc, 0, sizeof(*ioc)); - DBG_INIT("%s() %d res_map %x %p\n", __FUNCTION__, - i, res_size, (void *)sba_dev->ioc[i].res_map); + ioc->next = ioc_list; + ioc_list = ioc; + + ioc->handle = handle; + ioc->ioc_hpa = ioremap(hpa, 0x1000); + + ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID); + ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL; + ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL; /* conservative */ + + for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) { + if (ioc->func_id == info->func_id) { + ioc->name = info->name; + if (info->init) + (info->init)(ioc); + } } - sba_dev->sba_lock = SPIN_LOCK_UNLOCKED; + if (!ioc->name) { + ioc->name = kmalloc(24, GFP_KERNEL); + if (ioc->name) + sprintf((char *) ioc->name, "Unknown (%04x:%04x)", + ioc->func_id & 0xFFFF, (ioc->func_id >> 16) & 0xFFFF); + else + ioc->name = "Unknown"; + } + + ioc_iova_init(ioc); + ioc_resource_init(ioc); + ioc_sac_init(ioc); + + printk(KERN_INFO PFX + "%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", + ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, + hpa, ioc->iov_size >> 20, ioc->ibase); + + return ioc; } + + +/************************************************************************** +** +** SBA initialization code (HW and SW) +** +** o identify SBA chip itself +** o FIXME: initialize DMA hints for reasonable defaults +** +**************************************************************************/ + #ifdef CONFIG_PROC_FS -static int sba_proc_info(char *buf, char **start, off_t offset, int len) +static void * +ioc_start(struct seq_file *s, loff_t *pos) { - struct sba_device *sba_dev; struct ioc *ioc; - int total_pages; + loff_t n = *pos; + + for (ioc = ioc_list; ioc; ioc = ioc->next) + if (!n--) + return ioc; + + return NULL; +} + +static void * +ioc_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct ioc *ioc = v; + + ++*pos; + return ioc->next; +} + +static void +ioc_stop(struct seq_file *s, void *v) +{ +} + +static int +ioc_show(struct seq_file *s, void *v) +{ + struct ioc *ioc = v; + int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ unsigned long i = 0, avg = 0, min, max; - for (sba_dev = sba_list; sba_dev; sba_dev = sba_dev->next) { - ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */ - total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ - - sprintf(buf, "%s rev %d.%d\n", "Hewlett-Packard zx1 SBA", - ((sba_dev->hw_rev >> 4) & 0xF), (sba_dev->hw_rev & 0xF)); - sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", buf, - (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ total_pages); - - sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, - total_pages - ioc->used_pages, ioc->used_pages, - (int) (ioc->used_pages * 100 / total_pages)); - - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ - - min = max = ioc->avg_search[0]; - for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { - avg += ioc->avg_search[i]; - if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; - if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; - } - avg /= SBA_SEARCH_SAMPLE; - sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", - buf, min, avg, max); - - sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", - buf, ioc->msingle_calls, ioc->msingle_pages, - (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n", + ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF)); + seq_printf(s, "IO PDIR size : %d bytes (%d entries)\n", + (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ + total_pages); + + seq_printf(s, "IO PDIR entries : %ld free %ld used (%d%%)\n", + total_pages - ioc->used_pages, ioc->used_pages, + (int) (ioc->used_pages * 100 / total_pages)); + + seq_printf(s, "Resource bitmap : %d bytes (%d pages)\n", + ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ + + min = max = ioc->avg_search[0]; + for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { + avg += ioc->avg_search[i]; + if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; + if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; + } + avg /= SBA_SEARCH_SAMPLE; + seq_printf(s, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", min, avg, max); + + seq_printf(s, "pci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", + ioc->msingle_calls, ioc->msingle_pages, + (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); #ifdef ALLOW_IOV_BYPASS - sprintf(buf, "%spci_map_single(): %12ld bypasses\n", - buf, ioc->msingle_bypass); + seq_printf(s, "pci_map_single(): %12ld bypasses\n", ioc->msingle_bypass); #endif - sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", - buf, ioc->usingle_calls, ioc->usingle_pages, - (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls)); + seq_printf(s, "pci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", + ioc->usingle_calls, ioc->usingle_pages, + (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls)); #ifdef ALLOW_IOV_BYPASS - sprintf(buf, "%spci_unmap_single: %12ld bypasses\n", - buf, ioc->usingle_bypass); + seq_printf(s, "pci_unmap_single: %12ld bypasses\n", ioc->usingle_bypass); #endif - sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", - buf, ioc->msg_calls, ioc->msg_pages, - (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); + seq_printf(s, "pci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + ioc->msg_calls, ioc->msg_pages, + (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); #ifdef ALLOW_IOV_BYPASS - sprintf(buf, "%spci_map_sg() : %12ld bypasses\n", - buf, ioc->msg_bypass); + seq_printf(s, "pci_map_sg() : %12ld bypasses\n", ioc->msg_bypass); #endif - sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", - buf, ioc->usg_calls, ioc->usg_pages, - (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); - } - return strlen(buf); + seq_printf(s, "pci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + ioc->usg_calls, ioc->usg_pages, (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); + + return 0; } +static struct seq_operations ioc_seq_ops = { + .start = ioc_start, + .next = ioc_next, + .stop = ioc_stop, + .show = ioc_show +}; + static int -sba_resource_map(char *buf, char **start, off_t offset, int len) +ioc_open(struct inode *inode, struct file *file) { - struct ioc *ioc = sba_list->ioc; /* FIXME: Multi-IOC support! */ - unsigned int *res_ptr; - int i; + return seq_open(file, &ioc_seq_ops); +} - if (!ioc) - return 0; +static struct file_operations ioc_fops = { + .open = ioc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; - res_ptr = (unsigned int *)ioc->res_map; - buf[0] = '\0'; - for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) { - if ((i & 7) == 0) - strcat(buf,"\n "); - sprintf(buf, "%s %08x", buf, *res_ptr); - } - strcat(buf, "\n"); +static int +ioc_map_show(struct seq_file *s, void *v) +{ + struct ioc *ioc = v; + unsigned int i, *res_ptr = (unsigned int *)ioc->res_map; - return strlen(buf); + for (i = 0; i < ioc->res_size / sizeof(unsigned int); ++i, ++res_ptr) + seq_printf(s, "%s%08x", (i & 7) ? " " : "\n ", *res_ptr); + seq_printf(s, "\n"); + + return 0; } -#endif -/* -** Determine if sba should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -void __init sba_init(void) +static struct seq_operations ioc_map_ops = { + .start = ioc_start, + .next = ioc_next, + .stop = ioc_stop, + .show = ioc_map_show +}; + +static int +ioc_map_open(struct inode *inode, struct file *file) { - struct sba_device *sba_dev; - u32 func_id, hw_rev; - u32 *func_offset = NULL; - int i, agp_found = 0; - static char sba_rev[6]; - struct pci_dev *device = NULL; - u64 hpa = 0; + return seq_open(file, &ioc_map_ops); +} - if (!(device = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_SBA, NULL))) - return; +static struct file_operations ioc_map_fops = { + .open = ioc_map_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (pci_resource_flags(device, i) == IORESOURCE_MEM) { - hpa = (u64) ioremap(pci_resource_start(device, i), - pci_resource_len(device, i)); - break; - } +static void __init +ioc_proc_init(void) +{ + if (ioc_list) { + struct proc_dir_entry *dir, *entry; + + dir = proc_mkdir("bus/mckinley", 0); + entry = create_proc_entry(ioc_list->name, 0, dir); + if (entry) + entry->proc_fops = &ioc_fops; + + entry = create_proc_entry("bitmap", 0, dir); + if (entry) + entry->proc_fops = &ioc_map_fops; } +} +#endif - func_id = READ_REG(hpa + SBA_FUNC_ID); - if (func_id != ZX1_FUNC_ID_VALUE) - return; +void +sba_connect_bus(struct pci_bus *bus) +{ + acpi_handle handle, parent; + acpi_status status; + struct ioc *ioc; - strcpy(sba_rev, "zx1"); - func_offset = zx1_func_offsets; + if (!PCI_CONTROLLER(bus)) + panic(PFX "no sysdata on bus %d!\n",bus->number); - /* Read HW Rev First */ - hw_rev = READ_REG(hpa + SBA_FCLASS) & 0xFFUL; + if (PCI_CONTROLLER(bus)->iommu) + return; + + handle = PCI_CONTROLLER(bus)->acpi_handle; + if (!handle) + return; /* - * Not all revision registers of the chipset are updated on every - * turn. Must scan through all functions looking for the highest rev + * The IOC scope encloses PCI root bridges in the ACPI + * namespace, so work our way out until we find an IOC we + * claimed previously. */ - if (func_offset) { - for (i = 0 ; func_offset[i] != -1 ; i++) { - u32 func_rev; - - func_rev = READ_REG(hpa + SBA_FCLASS + func_offset[i]) & 0xFFUL; - DBG_INIT("%s() func offset: 0x%x rev: 0x%x\n", - __FUNCTION__, func_offset[i], func_rev); - if (func_rev > hw_rev) - hw_rev = func_rev; - } - } - - printk(KERN_INFO "%s found %s %d.%d at %s, HPA 0x%lx\n", DRIVER_NAME, - sba_rev, ((hw_rev >> 4) & 0xF), (hw_rev & 0xF), - device->slot_name, hpa); + do { + for (ioc = ioc_list; ioc; ioc = ioc->next) + if (ioc->handle == handle) { + PCI_CONTROLLER(bus)->iommu = ioc; + return; + } - if ((hw_rev & 0xFF) < 0x20) { - printk(KERN_INFO "%s: SBA rev less than 2.0 not supported", DRIVER_NAME); - return; - } + status = acpi_get_parent(handle, &parent); + handle = parent; + } while (ACPI_SUCCESS(status)); - sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); - if (NULL == sba_dev) { - printk(KERN_ERR DRIVER_NAME " - couldn't alloc sba_device\n"); - return; - } + printk(KERN_WARNING "No IOC for PCI Bus %02x:%02x in ACPI\n", PCI_SEGMENT(bus), bus->number); +} - memset(sba_dev, 0, sizeof(struct sba_device)); +static int __init +acpi_sba_ioc_add(struct acpi_device *device) +{ + struct ioc *ioc; + acpi_status status; + u64 hpa, length; + struct acpi_device_info dev_info; - for(i=0; iioc[i].res_lock)); + status = hp_acpi_csr_space(device->handle, &hpa, &length); + if (ACPI_FAILURE(status)) + return 1; - sba_dev->hw_rev = hw_rev; - sba_dev->sba_hpa = hpa; + status = acpi_get_object_info(device->handle, &dev_info); + if (ACPI_FAILURE(status)) + return 1; /* - * We pass this fake device from alloc_consistent to ensure - * we only use SAC for alloc_consistent mappings. + * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI + * root bridges, and its CSR space includes the IOC function. */ - sac_only_dev.dma_mask = 0xFFFFFFFFUL; + if (strncmp("HWP0001", dev_info.hardware_id, 7) == 0) + hpa += ZX1_IOC_OFFSET; - /* - * We need to check for an AGP device, if we find one, then only - * use part of the IOVA space for PCI DMA, the rest is for GART. - * REVISIT for multiple IOC. - */ - pci_for_each_dev(device) - agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); + ioc = ioc_init(hpa, device->handle); + if (!ioc) + return 1; - if (agp_found && reserve_sba_gart) - SBA_SET_AGP(sba_dev); + return 0; +} - sba_hw_init(sba_dev); - sba_common_init(sba_dev); +static struct acpi_driver acpi_sba_ioc_driver = { + name: "IOC IOMMU Driver", + ids: "HWP0001,HWP0004", + ops: { + add: acpi_sba_ioc_add, + }, +}; -#ifdef CONFIG_PROC_FS - { - struct proc_dir_entry * proc_mckinley_root; +static int __init +sba_init(void) +{ + MAX_DMA_ADDRESS = ~0UL; + + acpi_bus_register_driver(&acpi_sba_ioc_driver); - proc_mckinley_root = proc_mkdir("bus/mckinley",0); - create_proc_info_entry(sba_rev, 0, proc_mckinley_root, sba_proc_info); - create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map); +#ifdef CONFIG_PCI + { + struct pci_bus *b; + pci_for_each_bus(b) + sba_connect_bus(b); } #endif + +#ifdef CONFIG_PROC_FS + ioc_proc_init(); +#endif + return 0; } +subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */ + static int __init -nosbagart (char *str) +nosbagart(char *str) { reserve_sba_gart = 0; return 1; } -__setup("nosbagart",nosbagart); +int +sba_dma_supported (struct device *dev, u64 mask) +{ + /* make sure it's at least 32bit capable */ + return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL); +} + +__setup("nosbagart", nosbagart); -EXPORT_SYMBOL(sba_init); EXPORT_SYMBOL(sba_map_single); EXPORT_SYMBOL(sba_unmap_single); EXPORT_SYMBOL(sba_map_sg); EXPORT_SYMBOL(sba_unmap_sg); -EXPORT_SYMBOL(sba_dma_address); EXPORT_SYMBOL(sba_dma_supported); -EXPORT_SYMBOL(sba_alloc_consistent); -EXPORT_SYMBOL(sba_free_consistent); +EXPORT_SYMBOL(sba_alloc_coherent); +EXPORT_SYMBOL(sba_free_coherent); diff -Nru a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c --- a/arch/ia64/hp/sim/hpsim_console.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/hp/sim/hpsim_console.c Mon May 12 20:55:48 2003 @@ -59,7 +59,7 @@ static struct tty_driver *simcons_console_device (struct console *c, int *index) { - extern struct tty_driver hp_serial_driver; + extern struct tty_driver hp_simserial_driver; *index = c->index; - return &hp_serial_driver; + return &hp_simserial_driver; } diff -Nru a/arch/ia64/hp/sim/hpsim_machvec.c b/arch/ia64/hp/sim/hpsim_machvec.c --- a/arch/ia64/hp/sim/hpsim_machvec.c Mon May 12 20:55:47 2003 +++ b/arch/ia64/hp/sim/hpsim_machvec.c Mon May 12 20:55:47 2003 @@ -1,2 +1,3 @@ -#define MACHVEC_PLATFORM_NAME hpsim +#define MACHVEC_PLATFORM_NAME hpsim +#define MACHVEC_PLATFORM_HEADER #include diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c --- a/arch/ia64/hp/sim/simeth.c Mon May 12 20:55:47 2003 +++ b/arch/ia64/hp/sim/simeth.c Mon May 12 20:55:47 2003 @@ -55,7 +55,7 @@ static int simeth_tx(struct sk_buff *skb, struct net_device *dev); static int simeth_rx(struct net_device *dev); static struct net_device_stats *simeth_get_stats(struct net_device *dev); -static void simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void set_multicast_list(struct net_device *dev); static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr); @@ -494,20 +494,21 @@ /* * Interrupt handler (Yes, we can do it too !!!) */ -static void +static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; if ( dev == NULL ) { printk(KERN_WARNING "simeth: irq %d for unknown device\n", irq); - return; + return IRQ_NONE; } /* - * very simple loop because we get interrupts only when receving + * very simple loop because we get interrupts only when receiving */ while (simeth_rx(dev)); + return IRQ_HANDLED; } static struct net_device_stats * diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/hp/sim/simserial.c Mon May 12 20:55:46 2003 @@ -103,7 +103,8 @@ { 0, 0} }; -static struct tty_driver hp_serial_driver, callout_driver; +struct tty_driver hp_simserial_driver; +static struct tty_driver callout_driver; static int serial_refcount; static struct async_struct *IRQ_ports[NR_IRQS]; @@ -184,7 +185,7 @@ /* * This is the serial driver's interrupt routine for a single port */ -static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { struct async_struct * info; @@ -195,13 +196,14 @@ info = IRQ_ports[irq]; if (!info || !info->tty) { printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info); - return; + return IRQ_NONE; } /* * pretty simple in our case, because we only get interrupts * on inbound traffic */ receive_chars(info->tty, regs); + return IRQ_HANDLED; } /* @@ -768,7 +770,7 @@ { unsigned long flags; int retval=0; - void (*handler)(int, void *, struct pt_regs *); + irqreturn_t (*handler)(int, void *, struct pt_regs *); struct serial_state *state= info->state; unsigned long page; @@ -808,8 +810,7 @@ } else handler = rs_interrupt_single; - retval = request_irq(state->irq, handler, IRQ_T(info), - "simserial", NULL); + retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL); if (retval) { if (capable(CAP_SYS_ADMIN)) { if (info->tty) @@ -1028,43 +1029,43 @@ /* Initialize the tty_driver structure */ - memset(&hp_serial_driver, 0, sizeof(struct tty_driver)); - hp_serial_driver.magic = TTY_DRIVER_MAGIC; - hp_serial_driver.driver_name = "simserial"; - hp_serial_driver.name = "ttyS"; - hp_serial_driver.major = TTY_MAJOR; - hp_serial_driver.minor_start = 64; - hp_serial_driver.num = 1; - hp_serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - hp_serial_driver.subtype = SERIAL_TYPE_NORMAL; - hp_serial_driver.init_termios = tty_std_termios; - hp_serial_driver.init_termios.c_cflag = + memset(&hp_simserial_driver, 0, sizeof(struct tty_driver)); + hp_simserial_driver.magic = TTY_DRIVER_MAGIC; + hp_simserial_driver.driver_name = "simserial"; + hp_simserial_driver.name = "ttyS"; + hp_simserial_driver.major = TTY_MAJOR; + hp_simserial_driver.minor_start = 64; + hp_simserial_driver.num = 1; + hp_simserial_driver.type = TTY_DRIVER_TYPE_SERIAL; + hp_simserial_driver.subtype = SERIAL_TYPE_NORMAL; + hp_simserial_driver.init_termios = tty_std_termios; + hp_simserial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - hp_serial_driver.flags = TTY_DRIVER_REAL_RAW; - hp_serial_driver.refcount = &serial_refcount; - hp_serial_driver.table = serial_table; - hp_serial_driver.termios = serial_termios; - hp_serial_driver.termios_locked = serial_termios_locked; - - hp_serial_driver.open = rs_open; - hp_serial_driver.close = rs_close; - hp_serial_driver.write = rs_write; - hp_serial_driver.put_char = rs_put_char; - hp_serial_driver.flush_chars = rs_flush_chars; - hp_serial_driver.write_room = rs_write_room; - hp_serial_driver.chars_in_buffer = rs_chars_in_buffer; - hp_serial_driver.flush_buffer = rs_flush_buffer; - hp_serial_driver.ioctl = rs_ioctl; - hp_serial_driver.throttle = rs_throttle; - hp_serial_driver.unthrottle = rs_unthrottle; - hp_serial_driver.send_xchar = rs_send_xchar; - hp_serial_driver.set_termios = rs_set_termios; - hp_serial_driver.stop = rs_stop; - hp_serial_driver.start = rs_start; - hp_serial_driver.hangup = rs_hangup; - hp_serial_driver.break_ctl = rs_break; - hp_serial_driver.wait_until_sent = rs_wait_until_sent; - hp_serial_driver.read_proc = rs_read_proc; + hp_simserial_driver.flags = TTY_DRIVER_REAL_RAW; + hp_simserial_driver.refcount = &serial_refcount; + hp_simserial_driver.table = serial_table; + hp_simserial_driver.termios = serial_termios; + hp_simserial_driver.termios_locked = serial_termios_locked; + + hp_simserial_driver.open = rs_open; + hp_simserial_driver.close = rs_close; + hp_simserial_driver.write = rs_write; + hp_simserial_driver.put_char = rs_put_char; + hp_simserial_driver.flush_chars = rs_flush_chars; + hp_simserial_driver.write_room = rs_write_room; + hp_simserial_driver.chars_in_buffer = rs_chars_in_buffer; + hp_simserial_driver.flush_buffer = rs_flush_buffer; + hp_simserial_driver.ioctl = rs_ioctl; + hp_simserial_driver.throttle = rs_throttle; + hp_simserial_driver.unthrottle = rs_unthrottle; + hp_simserial_driver.send_xchar = rs_send_xchar; + hp_simserial_driver.set_termios = rs_set_termios; + hp_simserial_driver.stop = rs_stop; + hp_simserial_driver.start = rs_start; + hp_simserial_driver.hangup = rs_hangup; + hp_simserial_driver.break_ctl = rs_break; + hp_simserial_driver.wait_until_sent = rs_wait_until_sent; + hp_simserial_driver.read_proc = rs_read_proc; /* * Let's have a little bit of fun ! @@ -1087,14 +1088,14 @@ * The callout device is just like normal device except for * major number and the subtype code. */ - callout_driver = hp_serial_driver; + callout_driver = hp_simserial_driver; callout_driver.name = "cua"; callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; callout_driver.read_proc = 0; callout_driver.proc_entry = 0; - if (tty_register_driver(&hp_serial_driver)) + if (tty_register_driver(&hp_simserial_driver)) panic("Couldn't register simserial driver\n"); if (tty_register_driver(&callout_driver)) diff -Nru a/arch/ia64/hp/zx1/Makefile b/arch/ia64/hp/zx1/Makefile --- a/arch/ia64/hp/zx1/Makefile Mon May 12 20:55:49 2003 +++ b/arch/ia64/hp/zx1/Makefile Mon May 12 20:55:49 2003 @@ -5,5 +5,4 @@ # Copyright (C) Alex Williamson (alex_williamson@hp.com) # -obj-y := hpzx1_misc.o obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o diff -Nru a/arch/ia64/hp/zx1/hpzx1_machvec.c b/arch/ia64/hp/zx1/hpzx1_machvec.c --- a/arch/ia64/hp/zx1/hpzx1_machvec.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/hp/zx1/hpzx1_machvec.c Mon May 12 20:55:46 2003 @@ -1,2 +1,3 @@ -#define MACHVEC_PLATFORM_NAME hpzx1 +#define MACHVEC_PLATFORM_NAME hpzx1 +#define MACHVEC_PLATFORM_HEADER #include diff -Nru a/arch/ia64/hp/zx1/hpzx1_misc.c b/arch/ia64/hp/zx1/hpzx1_misc.c --- a/arch/ia64/hp/zx1/hpzx1_misc.c Mon May 12 20:55:46 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,348 +0,0 @@ -/* - * Misc. support for HP zx1 chipset support - * - * Copyright (C) 2002-2003 Hewlett-Packard Co - * Alex Williamson - * Bjorn Helgaas - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include - -extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, struct acpi_object_list *, - unsigned long *); - -#define PFX "hpzx1: " - -static int hpzx1_devices; - -struct fake_pci_dev { - struct fake_pci_dev *next; - struct pci_dev *pci_dev; - unsigned long csr_base; - unsigned long csr_size; - unsigned long mapped_csrs; // ioremapped - int sizing; // in middle of BAR sizing operation? -} *fake_pci_dev_list; - -static struct pci_ops *orig_pci_ops; - -struct fake_pci_dev * -lookup_fake_dev (struct pci_bus *bus, unsigned int devfn) -{ - struct fake_pci_dev *fake_dev; - - for (fake_dev = fake_pci_dev_list; fake_dev; fake_dev = fake_dev->next) - if (fake_dev->pci_dev->bus == bus && fake_dev->pci_dev->devfn == devfn) - return fake_dev; - return NULL; -} - -static int -hp_cfg_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - struct fake_pci_dev *fake_dev = lookup_fake_dev(bus, devfn); - - if (!fake_dev) - return (*orig_pci_ops->read)(bus, devfn, where, size, value); - - if (where == PCI_BASE_ADDRESS_0) { - if (fake_dev->sizing) - *value = ~(fake_dev->csr_size - 1); - else - *value = ((fake_dev->csr_base & PCI_BASE_ADDRESS_MEM_MASK) - | PCI_BASE_ADDRESS_SPACE_MEMORY); - fake_dev->sizing = 0; - return PCIBIOS_SUCCESSFUL; - } - switch (size) { - case 1: *value = readb(fake_dev->mapped_csrs + where); break; - case 2: *value = readw(fake_dev->mapped_csrs + where); break; - case 4: *value = readl(fake_dev->mapped_csrs + where); break; - default: - printk(KERN_WARNING"hp_cfg_read: bad size = %d bytes", size); - break; - } - if (where == PCI_COMMAND) - *value |= PCI_COMMAND_MEMORY; /* SBA omits this */ - return PCIBIOS_SUCCESSFUL; -} - -static int -hp_cfg_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - struct fake_pci_dev *fake_dev = lookup_fake_dev(bus, devfn); - - if (!fake_dev) - return (*orig_pci_ops->write)(bus, devfn, where, size, value); - - if (where == PCI_BASE_ADDRESS_0) { - if (value == ((1UL << 8*size) - 1)) - fake_dev->sizing = 1; - return PCIBIOS_SUCCESSFUL; - } - switch (size) { - case 1: writeb(value, fake_dev->mapped_csrs + where); break; - case 2: writew(value, fake_dev->mapped_csrs + where); break; - case 4: writel(value, fake_dev->mapped_csrs + where); break; - default: - printk(KERN_WARNING"hp_cfg_write: bad size = %d bytes", size); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops hp_pci_conf = { - .read = hp_cfg_read, - .write = hp_cfg_write -}; - -static void -hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size) -{ - struct fake_pci_dev *fake; - int slot, ret; - struct pci_dev *dev; - struct pci_bus *b, *bus = NULL; - u8 hdr; - - fake = kmalloc(sizeof(*fake), GFP_KERNEL); - if (!fake) { - printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name, (void *) addr); - return; - } - - memset(fake, 0, sizeof(*fake)); - fake->csr_base = addr; - fake->csr_size = size; - fake->mapped_csrs = (unsigned long) ioremap(addr, size); - fake->sizing = 0; - - pci_for_each_bus(b) - if (busnum == b->number) { - bus = b; - break; - } - - if (!bus) { - printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)\n", - busnum, name, (void *) addr); - kfree(fake); - return; - } - - for (slot = 0x1e; slot; slot--) - if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0))) - break; - - if (slot < 0) { - printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02x\n", - name, (void *) addr, busnum); - kfree(fake); - return; - } - - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - printk(KERN_ERR PFX "No memory for %s (0x%p)\n", name, (void *) addr); - kfree(fake); - return; - } - - bus->ops = &hp_pci_conf; // replace pci ops for this bus - - fake->pci_dev = dev; - fake->next = fake_pci_dev_list; - fake_pci_dev_list = fake; - - memset(dev, 0, sizeof(*dev)); - dev->bus = bus; - dev->sysdata = fake; - dev->dev.parent = bus->dev; - dev->dev.bus = &pci_bus_type; - dev->devfn = PCI_DEVFN(slot, 0); - pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor); - pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); - pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr); - dev->hdr_type = hdr & 0x7f; - - pci_setup_device(dev); - - // pci_insert_device() without running /sbin/hotplug - list_add_tail(&dev->bus_list, &bus->devices); - list_add_tail(&dev->global_list, &pci_devices); - - strcpy(dev->dev.bus_id, dev->slot_name); - ret = device_register(&dev->dev); - if (ret < 0) - printk(KERN_INFO PFX "fake device registration failed (%d)\n", ret); - - printk(KERN_INFO PFX "%s at 0x%lx; pci dev %s\n", name, addr, dev->slot_name); - - hpzx1_devices++; -} - -struct acpi_hp_vendor_long { - u8 guid_id; - u8 guid[16]; - u8 csr_base[8]; - u8 csr_length[8]; -}; - -#define HP_CCSR_LENGTH 0x21 -#define HP_CCSR_TYPE 0x2 -#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \ - 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad) - -extern acpi_status acpi_get_crs(acpi_handle, struct acpi_buffer *); -extern struct acpi_resource *acpi_get_crs_next(struct acpi_buffer *, int *); -extern union acpi_resource_data *acpi_get_crs_type(struct acpi_buffer *, int *, int); -extern void acpi_dispose_crs(struct acpi_buffer *); - -static acpi_status -hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) -{ - int i, offset = 0; - acpi_status status; - struct acpi_buffer buf; - struct acpi_resource_vendor *res; - struct acpi_hp_vendor_long *hp_res; - efi_guid_t vendor_guid; - - *csr_base = 0; - *csr_length = 0; - - status = acpi_get_crs(obj, &buf); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PFX "Unable to get _CRS data on object\n"); - return status; - } - - res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR); - if (!res) { - printk(KERN_ERR PFX "Failed to find config space for device\n"); - acpi_dispose_crs(&buf); - return AE_NOT_FOUND; - } - - hp_res = (struct acpi_hp_vendor_long *)(res->reserved); - - if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) { - printk(KERN_ERR PFX "Unknown Vendor data\n"); - acpi_dispose_crs(&buf); - return AE_TYPE; /* Revisit error? */ - } - - memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t)); - if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) { - printk(KERN_ERR PFX "Vendor GUID does not match\n"); - acpi_dispose_crs(&buf); - return AE_TYPE; /* Revisit error? */ - } - - for (i = 0 ; i < 8 ; i++) { - *csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8)); - *csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8)); - } - - acpi_dispose_crs(&buf); - - return AE_OK; -} - -static acpi_status -hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret) -{ - u64 csr_base = 0, csr_length = 0; - acpi_status status; - char *name = context; - char fullname[16]; - - status = hp_csr_space(obj, &csr_base, &csr_length); - if (ACPI_FAILURE(status)) - return status; - - /* - * Only SBA shows up in ACPI namespace, so its CSR space - * includes both SBA and IOC. Make SBA and IOC show up - * separately in PCI space. - */ - sprintf(fullname, "%s SBA", name); - hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000); - sprintf(fullname, "%s IOC", name); - hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000); - - return AE_OK; -} - -static acpi_status -hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret) -{ - u64 csr_base = 0, csr_length = 0; - acpi_status status; - acpi_native_uint busnum; - char *name = context; - char fullname[32]; - - status = hp_csr_space(obj, &csr_base, &csr_length); - if (ACPI_FAILURE(status)) - return status; - - status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum); - if (ACPI_FAILURE(status)) { - printk(KERN_WARNING PFX "evaluate _BBN fail=0x%x\n", status); - busnum = 0; // no _BBN; stick it on bus 0 - } - - sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum); - hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length); - - return AE_OK; -} - -static void -hpzx1_acpi_dev_init(void) -{ - extern struct pci_ops *pci_root_ops; - - orig_pci_ops = pci_root_ops; - - /* - * Make fake PCI devices for the following hardware in the - * ACPI namespace. This makes it more convenient for drivers - * because they can claim these devices based on PCI - * information, rather than needing to know about ACPI. The - * 64-bit "HPA" space for this hardware is available as BAR - * 0/1. - * - * HWP0001: Single IOC SBA w/o IOC in namespace - * HWP0002: LBA device - * HWP0003: AGP LBA device - */ - acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL); - acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL); - acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL); -} - -extern void sba_init(void); - -static int -hpzx1_init (void) -{ - /* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */ - MAX_DMA_ADDRESS = ~0UL; - - hpzx1_acpi_dev_init(); - sba_init(); - return 0; -} - -subsys_initcall(hpzx1_init); diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S Mon May 12 20:55:47 2003 +++ b/arch/ia64/ia32/ia32_entry.S Mon May 12 20:55:47 2003 @@ -273,9 +273,9 @@ data8 sys32_sigsuspend data8 compat_sys_sigpending data8 sys_sethostname - data8 sys32_setrlimit /* 75 */ - data8 sys32_old_getrlimit - data8 sys32_getrusage + data8 compat_sys_setrlimit /* 75 */ + data8 compat_sys_old_getrlimit + data8 compat_sys_getrusage data8 sys32_gettimeofday data8 sys32_settimeofday data8 sys32_getgroups16 /* 80 */ @@ -312,7 +312,7 @@ data8 sys_vhangup data8 sys32_ni_syscall /* used to be sys_idle */ data8 sys32_ni_syscall - data8 sys32_wait4 + data8 compat_sys_wait4 data8 sys_swapoff /* 115 */ data8 sys32_sysinfo data8 sys32_ipc @@ -389,7 +389,7 @@ data8 sys32_ni_syscall /* streams1 */ data8 sys32_ni_syscall /* streams2 */ data8 sys32_vfork /* 190 */ - data8 sys32_getrlimit + data8 compat_sys_getrlimit data8 sys32_mmap2 data8 sys32_truncate64 data8 sys32_ftruncate64 diff -Nru a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c --- a/arch/ia64/ia32/ia32_ioctl.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/ia32/ia32_ioctl.c Mon May 12 20:55:48 2003 @@ -3,13 +3,16 @@ * * Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 Don Dugger - * Copyright (C) 2001-2002 Hewlett-Packard Co + * Copyright (C) 2001-2003 Hewlett-Packard Co * David Mosberger-Tang */ #include #include #include /* argh, msdos_fs.h isn't self-contained... */ +#include /* argh, msdos_fs.h isn't self-contained... */ + +#include #include #include @@ -32,8 +35,6 @@ #include #define __KERNEL__ #include - -#include #include <../drivers/char/drm/drm.h> #include <../drivers/char/drm/mga_drm.h> diff -Nru a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c --- a/arch/ia64/ia32/ia32_traps.c Mon May 12 20:55:45 2003 +++ b/arch/ia64/ia32/ia32_traps.c Mon May 12 20:55:45 2003 @@ -103,7 +103,7 @@ * C1 reg you need in case of a stack fault, 0x040 is the stack * fault bit. We should only be taking one exception at a time, * so if this combination doesn't produce any single exception, - * then we have a bad program that isn't syncronizing its FPU usage + * then we have a bad program that isn't synchronizing its FPU usage * and it will suffer the consequences since we won't be able to * fully reproduce the context of the exception */ diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Mon May 12 20:55:47 2003 +++ b/arch/ia64/ia32/sys_ia32.c Mon May 12 20:55:47 2003 @@ -53,10 +53,10 @@ #include #include #include +#include #include #include -#include #define DEBUG 0 @@ -177,7 +177,7 @@ { int err; - if (stat->size > MAX_NON_LFS) + if ((u64) stat->size > MAX_NON_LFS) return -EOVERFLOW; if (clear_user(ubuf, sizeof(*ubuf))) @@ -243,8 +243,7 @@ return -ENOMEM; if (old_prot) - if (copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE)) - return -EFAULT; + copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE); down_write(¤t->mm->mmap_sem); { @@ -837,8 +836,9 @@ } } + size = FDS_BYTES(n); ret = -EINVAL; - if (n < 0) + if (n < 0 || size < n) goto out_nofds; if (n > current->files->max_fdset) @@ -850,7 +850,6 @@ * long-words. */ ret = -ENOMEM; - size = FDS_BYTES(n); bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; @@ -928,8 +927,7 @@ static struct iovec * get_compat_iovec (struct compat_iovec *iov32, struct iovec *iov_buf, u32 count, int type) { - int i; - u32 buf, len; + u32 i, buf, len; struct iovec *ivp, *iov; /* Get the "struct iovec" from user memory */ @@ -1005,77 +1003,6 @@ return ret; } -#define RLIM_INFINITY32 0x7fffffff -#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) - -struct rlimit32 { - int rlim_cur; - int rlim_max; -}; - -extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim); - -asmlinkage long -sys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim) -{ - mm_segment_t old_fs = get_fs(); - struct rlimit r; - int ret; - - set_fs(KERNEL_DS); - ret = sys_getrlimit(resource, &r); - set_fs(old_fs); - if (!ret) { - ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur); - ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max); - } - return ret; -} - -asmlinkage long -sys32_getrlimit (unsigned int resource, struct rlimit32 *rlim) -{ - mm_segment_t old_fs = get_fs(); - struct rlimit r; - int ret; - - set_fs(KERNEL_DS); - ret = sys_getrlimit(resource, &r); - set_fs(old_fs); - if (!ret) { - if (r.rlim_cur >= 0xffffffff) - r.rlim_cur = 0xffffffff; - if (r.rlim_max >= 0xffffffff) - r.rlim_max = 0xffffffff; - ret = put_user(r.rlim_cur, &rlim->rlim_cur); - ret |= put_user(r.rlim_max, &rlim->rlim_max); - } - return ret; -} - -extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim); - -asmlinkage long -sys32_setrlimit (unsigned int resource, struct rlimit32 *rlim) -{ - struct rlimit r; - int ret; - mm_segment_t old_fs = get_fs(); - - if (resource >= RLIM_NLIMITS) - return -EINVAL; - if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max)) - return -EFAULT; - if (r.rlim_cur == RLIM_INFINITY32) - r.rlim_cur = RLIM_INFINITY; - if (r.rlim_max == RLIM_INFINITY32) - r.rlim_max = RLIM_INFINITY; - set_fs(KERNEL_DS); - ret = sys_setrlimit(resource, &r); - set_fs(old_fs); - return ret; -} - /* * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. * @@ -1648,19 +1575,35 @@ return err; } +extern int sem_ctls[]; +#define sc_semopm (sem_ctls[2]) + static long -semtimedop32(int semid, struct sembuf *tsems, int nsems, - const struct compat_timespec *timeout32) +semtimedop32(int semid, struct sembuf *tsops, int nsops, + struct compat_timespec *timeout32) { struct timespec t; - if (get_user (t.tv_sec, &timeout32->tv_sec) || - get_user (t.tv_nsec, &timeout32->tv_nsec)) + mm_segment_t oldfs; + long ret; + + /* parameter checking precedence should mirror sys_semtimedop() */ + if (nsops < 1 || semid < 0) + return -EINVAL; + if (nsops > sc_semopm) + return -E2BIG; + if (!access_ok(VERIFY_READ, tsops, nsops * sizeof(struct sembuf)) || + get_compat_timespec(&t, timeout32)) return -EFAULT; - return sys_semtimedop(semid, tsems, nsems, &t); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_semtimedop(semid, tsops, nsops, &t); + set_fs(oldfs); + return ret; } asmlinkage long -sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth) { int version; @@ -1668,12 +1611,15 @@ call &= 0xffff; switch (call) { + case SEMTIMEDOP: + if (fifth) + return semtimedop32(first, (struct sembuf *)AA(ptr), + second, (struct compat_timespec *)AA(fifth)); + /* else fall through for normal semop() */ case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - return sys_semtimedop(first, (struct sembuf *)AA(ptr), second, NULL); - case SEMTIMEDOP: - return semtimedop32(first, (struct sembuf *)AA(ptr), second, - (const struct compat_timespec *)AA(fifth)); + return sys_semtimedop(first, (struct sembuf *)AA(ptr), second, + NULL); case SEMGET: return sys_semget(first, second, third); case SEMCTL: @@ -1724,98 +1670,10 @@ return i; } -struct rusage32 { - struct compat_timeval ru_utime; - struct compat_timeval ru_stime; - int ru_maxrss; - int ru_ixrss; - int ru_idrss; - int ru_isrss; - int ru_minflt; - int ru_majflt; - int ru_nswap; - int ru_inblock; - int ru_oublock; - int ru_msgsnd; - int ru_msgrcv; - int ru_nsignals; - int ru_nvcsw; - int ru_nivcsw; -}; - -static int -put_rusage (struct rusage32 *ru, struct rusage *r) -{ - int err; - - if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) - return -EFAULT; - - err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); - err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); - err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); - err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); - err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); - err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); - err |= __put_user (r->ru_idrss, &ru->ru_idrss); - err |= __put_user (r->ru_isrss, &ru->ru_isrss); - err |= __put_user (r->ru_minflt, &ru->ru_minflt); - err |= __put_user (r->ru_majflt, &ru->ru_majflt); - err |= __put_user (r->ru_nswap, &ru->ru_nswap); - err |= __put_user (r->ru_inblock, &ru->ru_inblock); - err |= __put_user (r->ru_oublock, &ru->ru_oublock); - err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); - err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); - err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); - err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); - err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); - return err; -} - -asmlinkage long -sys32_wait4 (int pid, unsigned int *stat_addr, int options, struct rusage32 *ru) -{ - if (!ru) - return sys_wait4(pid, stat_addr, options, NULL); - else { - struct rusage r; - int ret; - unsigned int status; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); - set_fs(old_fs); - if (put_rusage(ru, &r)) - return -EFAULT; - if (stat_addr && put_user(status, stat_addr)) - return -EFAULT; - return ret; - } -} - asmlinkage long sys32_waitpid (int pid, unsigned int *stat_addr, int options) { - return sys32_wait4(pid, stat_addr, options, NULL); -} - - -extern asmlinkage long sys_getrusage (int who, struct rusage *ru); - -asmlinkage long -sys32_getrusage (int who, struct rusage32 *ru) -{ - struct rusage r; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret = sys_getrusage(who, &r); - set_fs(old_fs); - if (put_rusage (ru, &r)) - return -EFAULT; - return ret; + return compat_sys_wait4(pid, stat_addr, options, NULL); } static unsigned int @@ -2211,7 +2069,7 @@ ret = -EIO; break; } - for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { put_user(getreg(child, i), (unsigned int *) A(data)); data += sizeof(int); } @@ -2223,7 +2081,7 @@ ret = -EIO; break; } - for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) { + for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) { get_user(tmp, (unsigned int *) A(data)); putreg(child, i, tmp); data += sizeof(int); @@ -2299,7 +2157,7 @@ return(-EINVAL); /* Trying to gain more privileges? */ asm volatile ("mov %0=ar.eflag ;;" : "=r"(old)); - if (level > ((old >> 12) & 3)) { + if ((unsigned int) level > ((old >> 12) & 3)) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; } diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile --- a/arch/ia64/kernel/Makefile Mon May 12 20:55:49 2003 +++ b/arch/ia64/kernel/Makefile Mon May 12 20:55:49 2003 @@ -11,6 +11,8 @@ obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_FSYS) += fsys.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o +obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o +obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_IOSAPIC) += iosapic.o diff -Nru a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c --- a/arch/ia64/kernel/acpi-ext.c Mon May 12 20:55:49 2003 +++ b/arch/ia64/kernel/acpi-ext.c Mon May 12 20:55:49 2003 @@ -3,69 +3,99 @@ * * Copyright (C) 2003 Hewlett-Packard * Copyright (C) Alex Williamson + * Copyright (C) Bjorn Helgaas * - * Vendor specific extensions to ACPI. These are used by both - * HP and NEC. + * Vendor specific extensions to ACPI. */ #include +#include #include #include #include #include -/* - * Note: Strictly speaking, this is only needed for HP and NEC machines. - * However, NEC machines identify themselves as DIG-compliant, so there is - * no easy way to #ifdef this out. - */ +struct acpi_vendor_descriptor { + u8 guid_id; + efi_guid_t guid; +}; + +struct acpi_vendor_info { + struct acpi_vendor_descriptor *descriptor; + u8 *data; + u32 length; +}; + acpi_status -hp_acpi_csr_space (acpi_handle obj, u64 *csr_base, u64 *csr_length) +acpi_vendor_resource_match(struct acpi_resource *resource, void *context) { - int i, offset = 0; - acpi_status status; - struct acpi_buffer buf; - struct acpi_resource_vendor *res; - struct acpi_hp_vendor_long *hp_res; - efi_guid_t vendor_guid; - - *csr_base = 0; - *csr_length = 0; - - status = acpi_get_crs(obj, &buf); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n"); - return status; - } - - res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR); - if (!res) { - printk(KERN_ERR PREFIX "Failed to find config space for device\n"); - acpi_dispose_crs(&buf); + struct acpi_vendor_info *info = (struct acpi_vendor_info *) context; + struct acpi_resource_vendor *vendor; + struct acpi_vendor_descriptor *descriptor; + u32 length; + + if (resource->id != ACPI_RSTYPE_VENDOR) + return AE_OK; + + vendor = (struct acpi_resource_vendor *) &resource->data; + descriptor = (struct acpi_vendor_descriptor *) vendor->reserved; + if (vendor->length <= sizeof(*info->descriptor) || + descriptor->guid_id != info->descriptor->guid_id || + efi_guidcmp(descriptor->guid, info->descriptor->guid)) + return AE_OK; + + length = vendor->length - sizeof(struct acpi_vendor_descriptor); + info->data = acpi_os_allocate(length); + if (!info->data) + return AE_NO_MEMORY; + + memcpy(info->data, vendor->reserved + sizeof(struct acpi_vendor_descriptor), length); + info->length = length; + return AE_CTRL_TERMINATE; +} + +acpi_status +acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor *id, + u8 **data, u32 *length) +{ + struct acpi_vendor_info info; + + info.descriptor = id; + info.data = 0; + + acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, &info); + if (!info.data) return AE_NOT_FOUND; - } - hp_res = (struct acpi_hp_vendor_long *)(res->reserved); + *data = info.data; + *length = info.length; + return AE_OK; +} + +struct acpi_vendor_descriptor hp_ccsr_descriptor = { + .guid_id = 2, + .guid = EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad) +}; + +acpi_status +hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) +{ + acpi_status status; + u8 *data; + u32 length; + int i; + + status = acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length); - if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) { - printk(KERN_ERR PREFIX "Unknown Vendor data\n"); - acpi_dispose_crs(&buf); - return AE_TYPE; /* Revisit error? */ - } - - memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t)); - if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) { - printk(KERN_ERR PREFIX "Vendor GUID does not match\n"); - acpi_dispose_crs(&buf); - return AE_TYPE; /* Revisit error? */ - } - - for (i = 0 ; i < 8 ; i++) { - *csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8)); - *csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8)); - } + if (ACPI_FAILURE(status) || length != 16) + return AE_NOT_FOUND; + + memcpy(csr_base, data, sizeof(*csr_base)); + memcpy(csr_length, data + 8, sizeof(*csr_length)); + acpi_os_free(data); - acpi_dispose_crs(&buf); return AE_OK; } + +EXPORT_SYMBOL(hp_acpi_csr_space); diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/acpi.c Mon May 12 20:55:46 2003 @@ -115,134 +115,6 @@ #endif } -#ifdef CONFIG_ACPI - -/** - * acpi_get_crs - Return the current resource settings for a device - * obj: A handle for this device - * buf: A buffer to be populated by this call. - * - * Pass a valid handle, typically obtained by walking the namespace and a - * pointer to an allocated buffer, and this function will fill in the buffer - * with a list of acpi_resource structures. - */ -acpi_status -acpi_get_crs (acpi_handle obj, struct acpi_buffer *buf) -{ - acpi_status result; - buf->length = 0; - buf->pointer = NULL; - - result = acpi_get_current_resources(obj, buf); - if (result != AE_BUFFER_OVERFLOW) - return result; - buf->pointer = kmalloc(buf->length, GFP_KERNEL); - if (!buf->pointer) - return -ENOMEM; - - return acpi_get_current_resources(obj, buf); -} - -struct acpi_resource * -acpi_get_crs_next (struct acpi_buffer *buf, int *offset) -{ - struct acpi_resource *res; - - if (*offset >= buf->length) - return NULL; - - res = buf->pointer + *offset; - *offset += res->length; - return res; -} - -union acpi_resource_data * -acpi_get_crs_type (struct acpi_buffer *buf, int *offset, int type) -{ - for (;;) { - struct acpi_resource *res = acpi_get_crs_next(buf, offset); - if (!res) - return NULL; - if (res->id == type) - return &res->data; - } -} - -void -acpi_dispose_crs (struct acpi_buffer *buf) -{ - kfree(buf->pointer); -} - -void -acpi_get_crs_addr (struct acpi_buffer *buf, int type, u64 *base, u64 *size, u64 *tra) -{ - int offset = 0; - struct acpi_resource_address16 *addr16; - struct acpi_resource_address32 *addr32; - struct acpi_resource_address64 *addr64; - - for (;;) { - struct acpi_resource *res = acpi_get_crs_next(buf, &offset); - if (!res) - return; - switch (res->id) { - case ACPI_RSTYPE_ADDRESS16: - addr16 = (struct acpi_resource_address16 *) &res->data; - - if (type == addr16->resource_type) { - *base = addr16->min_address_range; - *size = addr16->address_length; - *tra = addr16->address_translation_offset; - return; - } - break; - case ACPI_RSTYPE_ADDRESS32: - addr32 = (struct acpi_resource_address32 *) &res->data; - if (type == addr32->resource_type) { - *base = addr32->min_address_range; - *size = addr32->address_length; - *tra = addr32->address_translation_offset; - return; - } - break; - case ACPI_RSTYPE_ADDRESS64: - addr64 = (struct acpi_resource_address64 *) &res->data; - if (type == addr64->resource_type) { - *base = addr64->min_address_range; - *size = addr64->address_length; - *tra = addr64->address_translation_offset; - return; - } - break; - } - } -} - -int -acpi_get_addr_space(void *obj, u8 type, u64 *base, u64 *length, u64 *tra) -{ - acpi_status status; - struct acpi_buffer buf; - - *base = 0; - *length = 0; - *tra = 0; - - status = acpi_get_crs((acpi_handle)obj, &buf); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n"); - return status; - } - - acpi_get_crs_addr(&buf, type, base, length, tra); - - acpi_dispose_crs(&buf); - - return AE_OK; -} -#endif /* CONFIG_ACPI */ - #ifdef CONFIG_ACPI_BOOT #define ACPI_MAX_PLATFORM_INTERRUPTS 256 @@ -324,7 +196,8 @@ printk(" enabled"); #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; - if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus]) + if (hard_smp_processor_id() + == (unsigned int) smp_boot_data.cpu_phys_id[total_cpus]) printk(" (BSP)"); #endif } @@ -918,8 +791,7 @@ return 0; /* Turn it on */ - vector = iosapic_register_intr (gsi, polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - trigger ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + vector = iosapic_register_intr (gsi, polarity, trigger); return vector; } diff -Nru a/arch/ia64/kernel/brl_emu.c b/arch/ia64/kernel/brl_emu.c --- a/arch/ia64/kernel/brl_emu.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/kernel/brl_emu.c Mon May 12 20:55:48 2003 @@ -59,7 +59,7 @@ unsigned long next_ip; struct siginfo siginfo; struct illegal_op_return rv; - int tmp_taken, unimplemented_address; + long tmp_taken, unimplemented_address; rv.fkt = (unsigned long) -1; diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c Mon May 12 20:55:44 2003 +++ b/arch/ia64/kernel/efi.c Mon May 12 20:55:44 2003 @@ -203,16 +203,16 @@ STUB_RESET_SYSTEM(virt, ) void -efi_gettimeofday (struct timeval *tv) +efi_gettimeofday (struct timespec *ts) { efi_time_t tm; - memset(tv, 0, sizeof(tv)); + memset(ts, 0, sizeof(ts)); if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) return; - tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); - tv->tv_usec = tm.nanosecond / 1000; + ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); + ts->tv_nsec = tm.nanosecond; } static int @@ -512,7 +512,7 @@ /* Show what we know for posterity */ c16 = __va(efi.systab->fw_vendor); if (c16) { - for (i = 0;i < sizeof(vendor) && *c16; ++i) + for (i = 0;i < (int) sizeof(vendor) && *c16; ++i) vendor[i] = *c16++; vendor[i] = '\0'; } @@ -520,7 +520,7 @@ printk(KERN_INFO "EFI v%u.%.02u by %s:", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); - for (i = 0; i < efi.systab->nr_tables; i++) { + for (i = 0; i < (int) efi.systab->nr_tables; i++) { if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { efi.mps = __va(config_tables[i].table); printk(" MPS=0x%lx", config_tables[i].table); diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c --- a/arch/ia64/kernel/efivars.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/efivars.c Mon May 12 20:55:46 2003 @@ -138,8 +138,7 @@ static inline unsigned long utf8_strsize(efi_char16_t *data, unsigned long maxlength) { - return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * - sizeof(efi_char16_t); + return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); } @@ -170,8 +169,7 @@ efi_guid_t *vendor_guid) { - int i, short_name_size = variable_name_size / - sizeof(efi_char16_t) + 38; + int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38; char *short_name; efivar_entry_t *new_efivar; @@ -192,7 +190,7 @@ /* Convert Unicode to normal chars (assume top bits are 0), ala UTF-8 */ - for (i=0; i diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S Mon May 12 20:55:47 2003 +++ b/arch/ia64/kernel/head.S Mon May 12 20:55:47 2003 @@ -733,3 +733,82 @@ SET_REG(b5); #endif /* CONFIG_IA64_BRL_EMU */ + +#ifdef CONFIG_SMP + /* + * This routine handles spinlock contention. It uses a non-standard calling + * convention to avoid converting leaf routines into interior routines. Because + * of this special convention, there are several restrictions: + * + * - do not use gp relative variables, this code is called from the kernel + * and from modules, r1 is undefined. + * - do not use stacked registers, the caller owns them. + * - do not use the scratch stack space, the caller owns it. + * - do not use any registers other than the ones listed below + * + * Inputs: + * ar.pfs - saved CFM of caller + * ar.ccv - 0 (and available for use) + * r28 - available for use. + * r29 - available for use. + * r30 - available for use. + * r31 - address of lock, available for use. + * b7 - return address + * p14 - available for use. + * + * If you patch this code to use more registers, do not forget to update + * the clobber lists for spin_lock() in include/asm-ia64/spinlock.h. + */ + +#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + +GLOBAL_ENTRY(ia64_spinlock_contention_pre3_4) + .prologue + .save ar.pfs, r0 // this code effectively has a zero frame size + .save rp, r28 + .body + nop 0 + nop 0 + .restore sp // pop existing prologue after next insn + mov b6 = r28 + .prologue + .save ar.pfs, r0 + .altrp b6 + .body +.wait: + // exponential backoff, kdb, lockmeter etc. go in here + hint @pause + ld4.bias r30=[r31] + nop 0 + ;; + cmp4.eq p14,p0=r30,r0 +(p14) br.cond.sptk.few b6 // lock is now free, try to acquire + br.cond.sptk.few .wait +END(ia64_spinlock_contention_pre3_4) + +#else + +GLOBAL_ENTRY(ia64_spinlock_contention) + .prologue + .altrp b6 + .body +.wait: + // exponential backoff, kdb, lockmeter etc. go in here + hint @pause + ld4.bias r30=[r31] + ;; + cmp4.ne p14,p0=r30,r0 + mov r30 = 1 +(p14) br.cond.sptk.few .wait + ;; + cmpxchg4.acq r30=[r31], r30, ar.ccv + ;; + cmp4.ne p14,p0=r0,r30 +(p14) br.cond.sptk.few .wait + + br.ret.sptk.many b6 // lock is now taken +END(ia64_spinlock_contention) + +#endif + +#endif /* CONFIG_SMP */ diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c --- a/arch/ia64/kernel/ia64_ksyms.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/ia64_ksyms.c Mon May 12 20:55:46 2003 @@ -46,6 +46,7 @@ EXPORT_SYMBOL(__ia64_memcpy_fromio); EXPORT_SYMBOL(__ia64_memcpy_toio); EXPORT_SYMBOL(__ia64_memset_c_io); +EXPORT_SYMBOL(io_space); #include EXPORT_SYMBOL_NOVERS(__down); @@ -56,6 +57,12 @@ #include EXPORT_SYMBOL(clear_page); +#ifdef CONFIG_VIRTUAL_MEM_MAP +#include +EXPORT_SYMBOL(vmalloc_end); +EXPORT_SYMBOL(ia64_pfn_valid); +#endif + #include EXPORT_SYMBOL(cpu_info__per_cpu); EXPORT_SYMBOL(kernel_thread); @@ -161,3 +168,11 @@ EXPORT_SYMBOL(unw_access_fr); EXPORT_SYMBOL(unw_access_ar); EXPORT_SYMBOL(unw_access_pr); + +#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +extern void ia64_spinlock_contention_pre3_4 (void); +EXPORT_SYMBOL(ia64_spinlock_contention_pre3_4); +#else +extern void ia64_spinlock_contention (void); +EXPORT_SYMBOL(ia64_spinlock_contention); +#endif diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/iosapic.c Mon May 12 20:55:46 2003 @@ -581,9 +581,8 @@ register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n", - isa_irq, gsi, - polarity == IOSAPIC_POL_HIGH ? "high" : "low", trigger == IOSAPIC_EDGE ? "edge" : "level", - dest, vector); + isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low", + trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector); /* program the IOSAPIC routing table */ set_rte(vector, dest); @@ -635,7 +634,6 @@ (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1); if ((gsi_base == 0) && pcat_compat) { - /* * Map the legacy ISA devices into the IOSAPIC data. Some of these may * get reprogrammed later on with data from the ACPI Interrupt Source @@ -646,20 +644,11 @@ } } -static void __init -fixup_vector (int vector, unsigned int gsi, const char *pci_id) +void +iosapic_enable_intr (unsigned int vector) { - struct hw_interrupt_type *irq_type = &irq_type_iosapic_level; - irq_desc_t *idesc; unsigned int dest; - idesc = irq_desc(vector); - if (idesc->handler != irq_type) { - if (idesc->handler != &no_irq_type) - printk(KERN_INFO "IOSAPIC: changing vector %d from %s to %s\n", - vector, idesc->handler->typename, irq_type->typename); - idesc->handler = irq_type; - } #ifdef CONFIG_SMP /* * For platforms that do not support interrupt redirect via the XTP interface, we @@ -687,10 +676,12 @@ #endif set_rte(vector, dest); - printk(KERN_INFO "IOSAPIC: %s -> GSI 0x%x -> CPU 0x%04x vector %d\n", - pci_id, gsi, dest, vector); + printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n", + vector, dest); } +#ifdef CONFIG_ACPI_PCI + void __init iosapic_parse_prt (void) { @@ -699,6 +690,8 @@ unsigned int gsi; int vector; char pci_id[16]; + struct hw_interrupt_type *irq_type = &irq_type_iosapic_level; + irq_desc_t *idesc; list_for_each(node, &acpi_prt.entries) { entry = list_entry(node, struct acpi_prt_entry, node); @@ -711,6 +704,9 @@ vector = gsi_to_vector(gsi); if (vector < 0) { + if (find_iosapic(gsi) < 0) + continue; + /* allocate a vector for this interrupt line */ if (pcat_compat && (gsi < 16)) vector = isa_irq_to_vector(gsi); @@ -718,11 +714,22 @@ /* new GSI; allocate a vector for it */ vector = ia64_alloc_vector(); - register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW, IOSAPIC_LEVEL); + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW, + IOSAPIC_LEVEL); } snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]", entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin); - fixup_vector(vector, gsi, pci_id); + /* + * If vector was previously initialized to a different + * handler, re-initialize. + */ + idesc = irq_desc(vector); + if (idesc->handler != irq_type) + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW, + IOSAPIC_LEVEL); + } } + +#endif /* CONFIG_ACPI */ diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/kernel/irq.c Mon May 12 20:55:48 2003 @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -33,6 +32,7 @@ #include #include #include +#include #include #include @@ -50,7 +50,7 @@ * Linux has a controller-independent x86 interrupt architecture. * every controller has a 'controller-template', that is used * by the main code to do the right thing. Each driver-visible - * interrupt source is transparently wired to the apropriate + * interrupt source is transparently wired to the appropriate * controller. Thus drivers need not be aware of the * interrupt-controller. * @@ -91,7 +91,8 @@ * Special irq handlers. */ -void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ return IRQ_NONE; } /* * Generic no controller code @@ -107,7 +108,7 @@ * each architecture has to answer this themselves, it doesn't deserve * a generic callback i think. */ -#if CONFIG_X86 +#ifdef CONFIG_X86 printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -121,7 +122,7 @@ ack_APIC_irq(); #endif #endif -#if CONFIG_IA64 +#ifdef CONFIG_IA64 printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); #endif } @@ -141,9 +142,11 @@ }; atomic_t irq_err_count; -#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG atomic_t irq_mis_count; #endif +#endif /* * Generic, controller-independent functions: @@ -178,9 +181,10 @@ #endif seq_printf(p, " %14s", idesc->handler->typename); seq_printf(p, " %s", action->name); + for (action=action->next; action; action = action->next) seq_printf(p, ", %s", action->name); - + seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&idesc->lock, flags); @@ -190,21 +194,23 @@ if (cpu_online(j)) seq_printf(p, "%10u ", nmi_count(j)); seq_putc(p, '\n'); -#if defined(CONFIG_SMP) && defined(CONFIG_X86) +#ifdef CONFIG_X86_LOCAL_APIC seq_puts(p, "LOC: "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) - seq_printf(p, "%10u ", apic_timer_irqs[j]); + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); -#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG) +#ifdef CONFIG_X86_IO_APIC +#ifdef APIC_MISMATCH_DEBUG seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif +#endif return 0; } -#if CONFIG_SMP +#ifdef CONFIG_SMP inline void synchronize_irq(unsigned int irq) { while (irq_desc(irq)->status & IRQ_INPROGRESS) @@ -219,21 +225,46 @@ * waste of time and is not what some drivers would * prefer. */ -int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +int handle_IRQ_event(unsigned int irq, + struct pt_regs *regs, struct irqaction *action) { int status = 1; /* Force the "do bottom halves" bit */ + int retval = 0; + struct irqaction *first_action = action; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { status |= action->flags; - action->handler(irq, action->dev_id, regs); + retval |= action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); + if (retval != 1) { + static int count = 100; + if (count) { + count--; + if (retval) { + printk("irq event %d: bogus retval mask %x\n", + irq, retval); + } else { + printk("irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk("handlers:\n"); + action = first_action; + do { + printk("[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); + } + } return status; } @@ -455,7 +486,7 @@ */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -482,7 +513,7 @@ return -EINVAL; action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); + kmalloc(sizeof(struct irqaction), GFP_ATOMIC); if (!action) return -ENOMEM; @@ -511,10 +542,7 @@ * does not return until any executing interrupts for this IRQ * have completed. * - * This function may be called from interrupt context. - * - * Bugs: Attempting to free an irq in a handler for the same irq hangs - * the machine. + * This function must not be called from interrupt context. */ void free_irq(unsigned int irq, void *dev_id) @@ -545,11 +573,8 @@ } spin_unlock_irqrestore(&desc->lock,flags); -#ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ - while (desc->status & IRQ_INPROGRESS) - synchronize_irq(irq); -#endif + synchronize_irq(irq); kfree(action); return; } @@ -664,7 +689,6 @@ * only return ISA irq numbers - just so that we reset them * all to a known state. */ - unsigned int probe_irq_mask(unsigned long val) { int i; @@ -705,7 +729,7 @@ * The interrupt probe logic state is returned to its previous * value. * - * BUGS: When used in a module (which arguably shouldnt happen) + * BUGS: When used in a module (which arguably shouldn't happen) * nothing prevents two IRQ probe callers from overlapping. The * results of this are non-optimal. */ @@ -748,6 +772,8 @@ struct irqaction *old, **p; irq_desc_t *desc = irq_desc(irq); + if (desc->handler == &no_irq_type) + return -ENOSYS; /* * Some drivers like serial.c use request_irq() heavily, * so we have to be careful not to interfere with a @@ -808,11 +834,11 @@ #define HEX_DIGITS 8 -static int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret) +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) { unsigned char hexnum [HEX_DIGITS]; - unsigned long value; - int i; + unsigned long value, i; if (!count) return -EINVAL; @@ -844,7 +870,7 @@ return 0; } -#if CONFIG_SMP +#ifdef CONFIG_SMP static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; @@ -947,15 +973,16 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); -#if CONFIG_SMP +#ifdef CONFIG_SMP { struct proc_dir_entry *entry; + /* create /proc/irq/1234/smp_affinity */ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); if (entry) { entry->nlink = 1; - entry->data = (void *)(unsigned long)irq; + entry->data = (void *)(long)irq; entry->read_proc = irq_affinity_read_proc; entry->write_proc = irq_affinity_write_proc; } diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c --- a/arch/ia64/kernel/irq_ia64.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/irq_ia64.c Mon May 12 20:55:46 2003 @@ -145,7 +145,7 @@ } #ifdef CONFIG_SMP -extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs); static struct irqaction ipi_irqaction = { .handler = handle_IPI, diff -Nru a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c --- a/arch/ia64/kernel/machvec.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/machvec.c Mon May 12 20:55:46 2003 @@ -1,12 +1,14 @@ #include +#include + #ifdef CONFIG_IA64_GENERIC #include #include -#include #include +#include struct ia64_machine_vector ia64_mv; @@ -42,4 +44,10 @@ void machvec_noop (void) { +} + +void +machvec_memory_fence (void) +{ + mb(); } diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/mca.c Mon May 12 20:55:46 2003 @@ -3,6 +3,9 @@ * Purpose: Generic MCA handling layer * * Updated for latest kernel + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + * * Copyright (C) 2002 Dell Computer Corporation * Copyright (C) Matt Domsch (Matt_Domsch@dell.com) * @@ -18,6 +21,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * + * 03/04/15 D. Mosberger Added INIT backtrace support. * 02/03/25 M. Domsch GUID cleanups * * 02/01/04 J. Hall Aligned MCA stack to 16 bytes, added platform vs. CPU @@ -39,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +52,7 @@ #include #include +#include #include #include #include @@ -139,7 +145,7 @@ /* Get the MCA error record */ if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) - return platform_err; // no record retrieved + return platform_err; /* no record retrieved */ /* TODO: * 1. analyze error logs to determine recoverability @@ -166,7 +172,7 @@ } -void +irqreturn_t ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n", @@ -174,20 +180,186 @@ /* Get the CMC error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0); + return IRQ_HANDLED; +} + +static void +show_min_state (pal_min_state_area_t *minstate) +{ + u64 iip = minstate->pmsa_iip + ((struct ia64_psr *)(&minstate->pmsa_ipsr))->ri; + u64 xip = minstate->pmsa_xip + ((struct ia64_psr *)(&minstate->pmsa_xpsr))->ri; + + printk("NaT bits\t%016lx\n", minstate->pmsa_nat_bits); + printk("pr\t\t%016lx\n", minstate->pmsa_pr); + printk("b0\t\t%016lx ", minstate->pmsa_br0); print_symbol("%s\n", minstate->pmsa_br0); + printk("ar.rsc\t\t%016lx\n", minstate->pmsa_rsc); + printk("cr.iip\t\t%016lx ", iip); print_symbol("%s\n", iip); + printk("cr.ipsr\t\t%016lx\n", minstate->pmsa_ipsr); + printk("cr.ifs\t\t%016lx\n", minstate->pmsa_ifs); + printk("xip\t\t%016lx ", xip); print_symbol("%s\n", xip); + printk("xpsr\t\t%016lx\n", minstate->pmsa_xpsr); + printk("xfs\t\t%016lx\n", minstate->pmsa_xfs); + printk("b1\t\t%016lx ", minstate->pmsa_br1); + print_symbol("%s\n", minstate->pmsa_br1); + + printk("\nstatic registers r0-r15:\n"); + printk(" r0- 3 %016lx %016lx %016lx %016lx\n", + 0UL, minstate->pmsa_gr[0], minstate->pmsa_gr[1], minstate->pmsa_gr[2]); + printk(" r4- 7 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_gr[3], minstate->pmsa_gr[4], + minstate->pmsa_gr[5], minstate->pmsa_gr[6]); + printk(" r8-11 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_gr[7], minstate->pmsa_gr[8], + minstate->pmsa_gr[9], minstate->pmsa_gr[10]); + printk("r12-15 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_gr[11], minstate->pmsa_gr[12], + minstate->pmsa_gr[13], minstate->pmsa_gr[14]); + + printk("\nbank 0:\n"); + printk("r16-19 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank0_gr[0], minstate->pmsa_bank0_gr[1], + minstate->pmsa_bank0_gr[2], minstate->pmsa_bank0_gr[3]); + printk("r20-23 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank0_gr[4], minstate->pmsa_bank0_gr[5], + minstate->pmsa_bank0_gr[6], minstate->pmsa_bank0_gr[7]); + printk("r24-27 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank0_gr[8], minstate->pmsa_bank0_gr[9], + minstate->pmsa_bank0_gr[10], minstate->pmsa_bank0_gr[11]); + printk("r28-31 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank0_gr[12], minstate->pmsa_bank0_gr[13], + minstate->pmsa_bank0_gr[14], minstate->pmsa_bank0_gr[15]); + + printk("\nbank 1:\n"); + printk("r16-19 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank1_gr[0], minstate->pmsa_bank1_gr[1], + minstate->pmsa_bank1_gr[2], minstate->pmsa_bank1_gr[3]); + printk("r20-23 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank1_gr[4], minstate->pmsa_bank1_gr[5], + minstate->pmsa_bank1_gr[6], minstate->pmsa_bank1_gr[7]); + printk("r24-27 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank1_gr[8], minstate->pmsa_bank1_gr[9], + minstate->pmsa_bank1_gr[10], minstate->pmsa_bank1_gr[11]); + printk("r28-31 %016lx %016lx %016lx %016lx\n", + minstate->pmsa_bank1_gr[12], minstate->pmsa_bank1_gr[13], + minstate->pmsa_bank1_gr[14], minstate->pmsa_bank1_gr[15]); +} + +static void +fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) +{ + u64 *dst_banked, *src_banked, bit, shift, nat_bits; + int i; + + /* + * First, update the pt-regs and switch-stack structures with the contents stored + * in the min-state area: + */ + if (((struct ia64_psr *) &ms->pmsa_ipsr)->ic == 0) { + pt->cr_ipsr = ms->pmsa_xpsr; + pt->cr_iip = ms->pmsa_xip; + pt->cr_ifs = ms->pmsa_xfs; + } else { + pt->cr_ipsr = ms->pmsa_ipsr; + pt->cr_iip = ms->pmsa_iip; + pt->cr_ifs = ms->pmsa_ifs; + } + pt->ar_rsc = ms->pmsa_rsc; + pt->pr = ms->pmsa_pr; + pt->r1 = ms->pmsa_gr[0]; + pt->r2 = ms->pmsa_gr[1]; + pt->r3 = ms->pmsa_gr[2]; + sw->r4 = ms->pmsa_gr[3]; + sw->r5 = ms->pmsa_gr[4]; + sw->r6 = ms->pmsa_gr[5]; + sw->r7 = ms->pmsa_gr[6]; + pt->r8 = ms->pmsa_gr[7]; + pt->r9 = ms->pmsa_gr[8]; + pt->r10 = ms->pmsa_gr[9]; + pt->r11 = ms->pmsa_gr[10]; + pt->r12 = ms->pmsa_gr[11]; + pt->r13 = ms->pmsa_gr[12]; + pt->r14 = ms->pmsa_gr[13]; + pt->r15 = ms->pmsa_gr[14]; + dst_banked = &pt->r16; /* r16-r31 are contiguous in struct pt_regs */ + src_banked = ms->pmsa_bank1_gr; + for (i = 0; i < 16; ++i) + dst_banked[i] = src_banked[i]; + pt->b0 = ms->pmsa_br0; + sw->b1 = ms->pmsa_br1; + + /* construct the NaT bits for the pt-regs structure: */ +# define PUT_NAT_BIT(dst, addr) \ + do { \ + bit = nat_bits & 1; nat_bits >>= 1; \ + shift = ((unsigned long) addr >> 3) & 0x3f; \ + dst = ((dst) & ~(1UL << shift)) | (bit << shift); \ + } while (0) + + /* Rotate the saved NaT bits such that bit 0 corresponds to pmsa_gr[0]: */ + shift = ((unsigned long) &ms->pmsa_gr[0] >> 3) & 0x3f; + nat_bits = (ms->pmsa_nat_bits >> shift) | (ms->pmsa_nat_bits << (64 - shift)); + + PUT_NAT_BIT(sw->caller_unat, &pt->r1); + PUT_NAT_BIT(sw->caller_unat, &pt->r2); + PUT_NAT_BIT(sw->caller_unat, &pt->r3); + PUT_NAT_BIT(sw->ar_unat, &sw->r4); + PUT_NAT_BIT(sw->ar_unat, &sw->r5); + PUT_NAT_BIT(sw->ar_unat, &sw->r6); + PUT_NAT_BIT(sw->ar_unat, &sw->r7); + PUT_NAT_BIT(sw->caller_unat, &pt->r8); PUT_NAT_BIT(sw->caller_unat, &pt->r9); + PUT_NAT_BIT(sw->caller_unat, &pt->r10); PUT_NAT_BIT(sw->caller_unat, &pt->r11); + PUT_NAT_BIT(sw->caller_unat, &pt->r12); PUT_NAT_BIT(sw->caller_unat, &pt->r13); + PUT_NAT_BIT(sw->caller_unat, &pt->r14); PUT_NAT_BIT(sw->caller_unat, &pt->r15); + nat_bits >>= 16; /* skip over bank0 NaT bits */ + PUT_NAT_BIT(sw->caller_unat, &pt->r16); PUT_NAT_BIT(sw->caller_unat, &pt->r17); + PUT_NAT_BIT(sw->caller_unat, &pt->r18); PUT_NAT_BIT(sw->caller_unat, &pt->r19); + PUT_NAT_BIT(sw->caller_unat, &pt->r20); PUT_NAT_BIT(sw->caller_unat, &pt->r21); + PUT_NAT_BIT(sw->caller_unat, &pt->r22); PUT_NAT_BIT(sw->caller_unat, &pt->r23); + PUT_NAT_BIT(sw->caller_unat, &pt->r24); PUT_NAT_BIT(sw->caller_unat, &pt->r25); + PUT_NAT_BIT(sw->caller_unat, &pt->r26); PUT_NAT_BIT(sw->caller_unat, &pt->r27); + PUT_NAT_BIT(sw->caller_unat, &pt->r28); PUT_NAT_BIT(sw->caller_unat, &pt->r29); + PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31); } -/* - * This routine will be used to deal with platform specific handling - * of the init, i.e. drop into the kernel debugger on server machine, - * or if the processor is part of some parallel machine without a - * console, then we would call the appropriate debug hooks here. - */ void -init_handler_platform (struct pt_regs *regs) +init_handler_platform (sal_log_processor_info_t *proc_ptr, + struct pt_regs *pt, struct switch_stack *sw) { + struct unw_frame_info info; + /* if a kernel debugger is available call it here else just dump the registers */ - show_regs(regs); /* dump the state info */ + /* + * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be + * generated via the BMC's command-line interface, but since the console is on the + * same serial line, the user will need some time to switch out of the BMC before + * the dump begins. + */ + printk("Delaying for 5 seconds...\n"); + udelay(5*1000000); + show_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area); + + printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm); + fetch_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area, pt, sw); + unw_init_from_interruption(&info, current, pt, sw); + ia64_do_show_stack(&info, NULL); + + if (!tasklist_lock.write_lock) + read_lock(&tasklist_lock); + { + struct task_struct *g, *t; + do_each_thread (g, t) { + if (t == current) + continue; + + printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); + show_stack(t); + } while_each_thread (g, t); + } + if (!tasklist_lock.write_lock) + read_unlock(&tasklist_lock); + + printk("\nINIT dump complete. Please reboot now.\n"); while (1); /* hang city if no debugger */ } @@ -263,7 +435,6 @@ /* * routine to process and prepare to dump min_state_save * information for debugging purposes. - * */ void ia64_process_min_state_save (pal_min_state_area_t *pmss) @@ -272,8 +443,6 @@ u64 *tpmss_ptr = (u64 *)pmss; u64 *return_min_state_ptr = ia64_mca_min_state_save_info; - /* dump out the min_state_area information */ - for (i=0;i>=1; } p += sprintf(p, "\n\tLoad hints : "); for(k=0; k < 8; k++ ) { - if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]); + if (cci.pcci_ld_hints & 0x1) + p += sprintf(p, "[%s]", cache_ld_hints[k]); cci.pcci_ld_hints >>=1; } - p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \ - "\tTag LSB : %d\n" \ - "\tTag MSB : %d\n", - 1<0 ; j--) { @@ -379,15 +380,14 @@ continue; } - p += sprintf(p, "\n%s Translation Cache Level %d:\n" \ - "\tHash sets : %d\n" \ - "\tAssociativity : %d\n" \ - "\tNumber of entries : %d\n" \ - "\tFlags : ", - cache_types[j+tc_info.tc_unified], i+1, - tc_info.tc_num_sets, - tc_info.tc_associativity, - tc_info.tc_num_entries); + p += sprintf(p, + "\n%s Translation Cache Level %d:\n" + "\tHash sets : %d\n" + "\tAssociativity : %d\n" + "\tNumber of entries : %d\n" + "\tFlags : ", + cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets, + tc_info.tc_associativity, tc_info.tc_num_entries); if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized "); if (tc_info.tc_unified) p += sprintf(p, "Unified "); @@ -436,17 +436,18 @@ if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0; - p += sprintf(p, "RSE stacked physical registers : %ld\n" \ - "RSE load/store hints : %ld (%s)\n", - phys_stacked, - hints.ph_data, - hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); - - if (ia64_pal_debug_info(&iregs, &dregs)) return 0; - - p += sprintf(p, "Instruction debug register pairs : %ld\n" \ - "Data debug register pairs : %ld\n", - iregs, dregs); + p += sprintf(p, + "RSE stacked physical registers : %ld\n" + "RSE load/store hints : %ld (%s)\n", + phys_stacked, hints.ph_data, + hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)"); + + if (ia64_pal_debug_info(&iregs, &dregs)) + return 0; + + p += sprintf(p, + "Instruction debug register pairs : %ld\n" + "Data debug register pairs : %ld\n", iregs, dregs); return p - page; } @@ -563,26 +564,21 @@ */ if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0; - p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \ - "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" \ - "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", - cur_ver.pal_version_s.pv_pal_vendor, - min_ver.pal_version_s.pv_pal_vendor, - - cur_ver.pal_version_s.pv_pal_a_model>>4, - cur_ver.pal_version_s.pv_pal_a_model&0xf, - cur_ver.pal_version_s.pv_pal_a_rev, - min_ver.pal_version_s.pv_pal_a_model>>4, - min_ver.pal_version_s.pv_pal_a_model&0xf, - min_ver.pal_version_s.pv_pal_a_rev, - - cur_ver.pal_version_s.pv_pal_b_model>>4, - cur_ver.pal_version_s.pv_pal_b_model&0xf, - cur_ver.pal_version_s.pv_pal_b_rev, - min_ver.pal_version_s.pv_pal_b_model>>4, - min_ver.pal_version_s.pv_pal_b_model&0xf, - min_ver.pal_version_s.pv_pal_b_rev); - + p += sprintf(p, + "PAL_vendor : 0x%02x (min=0x%02x)\n" + "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" + "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", + cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor, + + cur_ver.pal_version_s.pv_pal_a_model>>4, + cur_ver.pal_version_s.pv_pal_a_model&0xf, cur_ver.pal_version_s.pv_pal_a_rev, + min_ver.pal_version_s.pv_pal_a_model>>4, + min_ver.pal_version_s.pv_pal_a_model&0xf, min_ver.pal_version_s.pv_pal_a_rev, + + cur_ver.pal_version_s.pv_pal_b_model>>4, + cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev, + min_ver.pal_version_s.pv_pal_b_model>>4, + min_ver.pal_version_s.pv_pal_b_model&0xf, min_ver.pal_version_s.pv_pal_b_rev); return p - page; } @@ -595,26 +591,20 @@ if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0; - p += sprintf(p, "PMC/PMD pairs : %d\n" \ - "Counter width : %d bits\n" \ - "Cycle event number : %d\n" \ - "Retired event number : %d\n" \ - "Implemented PMC : ", - pm_info.pal_perf_mon_info_s.generic, - pm_info.pal_perf_mon_info_s.width, - pm_info.pal_perf_mon_info_s.cycles, - pm_info.pal_perf_mon_info_s.retired); + p += sprintf(p, + "PMC/PMD pairs : %d\n" + "Counter width : %d bits\n" + "Cycle event number : %d\n" + "Retired event number : %d\n" + "Implemented PMC : ", + pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width, + pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired); p = bitregister_process(p, pm_buffer, 256); - p += sprintf(p, "\nImplemented PMD : "); - p = bitregister_process(p, pm_buffer+4, 256); - p += sprintf(p, "\nCycles count capable : "); - p = bitregister_process(p, pm_buffer+8, 256); - p += sprintf(p, "\nRetired bundles count capable : "); #ifdef CONFIG_ITANIUM @@ -646,12 +636,11 @@ if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0; - p += sprintf(p, "Processor/Clock ratio : %ld/%ld\n" \ - "Bus/Clock ratio : %ld/%ld\n" \ - "ITC/Clock ratio : %ld/%ld\n", - proc.num, proc.den, - bus.num, bus.den, - itc.num, itc.den); + p += sprintf(p, + "Processor/Clock ratio : %ld/%ld\n" + "Bus/Clock ratio : %ld/%ld\n" + "ITC/Clock ratio : %ld/%ld\n", + proc.num, proc.den, bus.num, bus.den, itc.num, itc.den); return p - page; } @@ -665,7 +654,7 @@ u64 tr_buffer[4]; pal_vm_info_1_u_t vm_info_1; pal_vm_info_2_u_t vm_info_2; - int i, j; + u64 i, j; u64 max[3], pgm; struct ifa_reg { u64 valid:1; @@ -711,7 +700,7 @@ status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); if (status != 0) { - printk(KERN_ERR "palinfo: pal call failed on tr[%d:%d]=%ld\n", + printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n", i, j, status); continue; } @@ -725,34 +714,29 @@ rid_reg = (struct rid_reg *)&tr_buffer[3]; pgm = -1 << (itir_reg->ps - 12); - p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \ - "\tppn : 0x%lx\n" \ - "\tvpn : 0x%lx\n" \ - "\tps : ", - - "ID"[i], - j, - tr_valid.pal_tr_valid_s.access_rights_valid, - tr_valid.pal_tr_valid_s.priv_level_valid, - tr_valid.pal_tr_valid_s.dirty_bit_valid, - tr_valid.pal_tr_valid_s.mem_attr_valid, - (gr_reg->ppn & pgm)<< 12, - (ifa_reg->vpn & pgm)<< 12); + p += sprintf(p, + "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n" + "\tppn : 0x%lx\n" + "\tvpn : 0x%lx\n" + "\tps : ", + "ID"[i], j, + tr_valid.pal_tr_valid_s.access_rights_valid, + tr_valid.pal_tr_valid_s.priv_level_valid, + tr_valid.pal_tr_valid_s.dirty_bit_valid, + tr_valid.pal_tr_valid_s.mem_attr_valid, + (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12); p = bitvector_process(p, 1<< itir_reg->ps); - p += sprintf(p, "\n\tpl : %d\n" \ - "\tar : %d\n" \ - "\trid : %x\n" \ - "\tp : %d\n" \ - "\tma : %d\n" \ - "\td : %d\n", - gr_reg->pl, - gr_reg->ar, - rid_reg->rid, - gr_reg->p, - gr_reg->ma, - gr_reg->d); + p += sprintf(p, + "\n\tpl : %d\n" + "\tar : %d\n" + "\trid : %x\n" + "\tp : %d\n" + "\tma : %d\n" + "\td : %d\n", + gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma, + gr_reg->d); } } return p - page; @@ -776,7 +760,7 @@ { "tr_info", tr_info, } }; -#define NR_PALINFO_ENTRIES (sizeof(palinfo_entries)/sizeof(palinfo_entry_t)) +#define NR_PALINFO_ENTRIES (int) ARRAY_SIZE(palinfo_entries) /* * this array is used to keep track of the proc entries we create. This is diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/kernel/perfmon.c Mon May 12 20:55:48 2003 @@ -2,7 +2,7 @@ * This file implements the perfmon subsystem which is used * to program the IA-64 Performance Monitoring Unit (PMU). * - * Originaly Written by Ganesh Venkitachalam, IBM Corp. + * Originally Written by Ganesh Venkitachalam, IBM Corp. * Copyright (C) 1999 Ganesh Venkitachalam * * Modifications by Stephane Eranian, Hewlett-Packard Co. @@ -224,8 +224,9 @@ unsigned int protected:1; /* allow access to creator of context only */ unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ unsigned int excl_idle:1; /* exclude idle task in system wide session */ + unsigned int unsecure:1; /* sp = 0 for non self-monitored task */ unsigned int trap_reason:2; /* reason for going into pfm_block_ovfl_reset() */ - unsigned int reserved:21; + unsigned int reserved:20; } pfm_context_flags_t; #define PFM_TRAP_REASON_NONE 0x0 /* default value */ @@ -278,6 +279,7 @@ #define ctx_fl_using_dbreg ctx_flags.using_dbreg #define ctx_fl_excl_idle ctx_flags.excl_idle #define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_unsecure ctx_flags.unsecure /* * global information about all sessions @@ -362,8 +364,9 @@ #define PFM_CMD_IDX(cmd) (cmd) -#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \ - && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) +#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) \ + && (PFM_CMD_IDX(cmd) < (int) PFM_CMD_COUNT) \ + && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) #define PFM_CMD_USE_PID(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0) #define PFM_CMD_READ_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0) @@ -646,7 +649,7 @@ /* * This function is called from pfm_destroy_context() and also from pfm_inherit() - * to explicitely remove the sampling buffer mapping from the user level address space. + * to explicitly remove the sampling buffer mapping from the user level address space. */ static int pfm_remove_smpl_mapping(struct task_struct *task) @@ -724,8 +727,7 @@ static unsigned long pfm_smpl_entry_size(unsigned long *which, unsigned long size) { - unsigned long res = 0; - int i; + unsigned long i, res = 0; for (i=0; i < size; i++, which++) res += hweight64(*which); @@ -1076,10 +1078,15 @@ * and it must be a valid CPU */ cpu = ffz(~pfx->ctx_cpu_mask); +#ifdef CONFIG_SMP if (cpu_online(cpu) == 0) { +#else + if (cpu != 0) { +#endif DBprintk(("CPU%d is not online\n", cpu)); return -EINVAL; } + /* * check for pre-existing pinning, if conflicting reject */ @@ -1225,6 +1232,7 @@ ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; ctx->ctx_fl_frozen = 0; ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; @@ -1251,9 +1259,11 @@ DBprintk(("context=%p, pid=%d notify_task=%p\n", (void *)ctx, task->pid, ctx->ctx_notify_task)); - DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d\n", + DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d unsecure=%d\n", (void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, - ctx->ctx_fl_block, ctx->ctx_fl_system, ctx->ctx_fl_excl_idle)); + ctx->ctx_fl_block, ctx->ctx_fl_system, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_unsecure)); /* * when no notification is required, we can make this visible at the last moment @@ -1659,7 +1669,7 @@ if (!PMD_IS_IMPL(cnum)) goto abort_mission; /* * we can only read the register that we use. That includes - * the one we explicitely initialize AND the one we want included + * the one we explicitly initialize AND the one we want included * in the sampling buffer (smpl_regs). * * Having this restriction allows optimization in the ctxsw routine @@ -1871,7 +1881,7 @@ * if blocking, then post the semaphore. * if non-blocking, then we ensure that the task will go into * pfm_overflow_must_block() before returning to user mode. - * We cannot explicitely reset another task, it MUST always + * We cannot explicitly reset another task, it MUST always * be done by the task itself. This works for system wide because * the tool that is controlling the session is doing "self-monitoring". * @@ -1882,7 +1892,10 @@ DBprintk(("unblocking %d \n", task->pid)); up(sem); } else { + struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); task->thread.pfm_ovfl_block_reset = 1; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + set_bit(TIF_NOTIFY_RESUME, &info->flags); } #if 0 /* @@ -2051,7 +2064,7 @@ /* * reinforce secure monitoring: cannot toggle psr.up */ - ia64_psr(regs)->sp = 1; + if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1; return 0; } @@ -2159,11 +2172,11 @@ * never leaves the current CPU and the state * is shared by all processes running on it */ - for (i=0; i < pmu_conf.num_ibrs; i++) { + for (i=0; i < (int) pmu_conf.num_ibrs; i++) { ia64_set_ibr(i, 0UL); } ia64_srlz_i(); - for (i=0; i < pmu_conf.num_dbrs; i++) { + for (i=0; i < (int) pmu_conf.num_dbrs; i++) { ia64_set_dbr(i, 0UL); } ia64_srlz_d(); @@ -2505,7 +2518,7 @@ /* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)} #endif }; -#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) +#define PFM_CMD_COUNT ARRAY_SIZE(pfm_cmd_tab) static int check_task_state(struct task_struct *task) @@ -2732,12 +2745,13 @@ * again */ th->pfm_ovfl_block_reset = 0; + clear_thread_flag(TIF_NOTIFY_RESUME); /* * do some sanity checks first */ if (!ctx) { - printk(KERN_DEBUG "perfmon: [%d] has no PFM context\n", current->pid); + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); return; } /* @@ -2899,15 +2913,18 @@ /* * main overflow processing routine. - * it can be called from the interrupt path or explicitely during the context switch code + * it can be called from the interrupt path or explicitly during the context switch code + * Arguments: + * mode: 0=coming from PMU interrupt, 1=coming from ctxsw + * * Return: * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen */ static unsigned long -pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +pfm_overflow_handler(int mode, struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { - unsigned long mask; struct thread_struct *t; + unsigned long mask; unsigned long old_val; unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; int i; @@ -2998,10 +3015,10 @@ /* * check for sampling buffer * - * if present, record sample. We propagate notification ONLY when buffer - * becomes full. + * if present, record sample only when a 64-bit counter has overflowed. + * We propagate notification ONLY when buffer becomes full. */ - if(CTX_HAS_SMPL(ctx)) { + if(CTX_HAS_SMPL(ctx) && ovfl_pmds) { ret = pfm_record_sample(task, ctx, ovfl_pmds, regs); if (ret == 1) { /* @@ -3046,12 +3063,55 @@ * ctx_notify_task could already be NULL, checked in pfm_notify_user() */ if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_notify_task != task) { - t->pfm_ovfl_block_reset = 1; /* will cause blocking */ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCKSIG; } else { - t->pfm_ovfl_block_reset = 1; /* will cause blocking */ ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG; } + /* + * we cannot block in system wide mode and we do not go + * through the PMU ctxsw code. Therefore we can generate + * the notification here. In system wide mode, the current + * task maybe different from the task controlling the session + * on this CPU, therefore owner can be different from current. + * + * In per-process mode, this function gets called from + * the interrupt handler or pfm_load_regs(). The mode argument + * tells where we are coming from. When coming from the interrupt + * handler, it is safe to notify (send signal) right here because + * we do not hold any runqueue locks needed by send_sig_info(). + * + * However when coming from ctxsw, we cannot send the signal here. + * It must be deferred until we are sure we do not hold any runqueue + * related locks. The current task maybe different from the owner + * only in UP mode. The deferral is implemented using the + * TIF_NOTIFY_RESUME mechanism. In this case, the pending work + * is checked when the task is about to leave the kernel (see + * entry.S). As of this version of perfmon, a kernel only + * task cannot be monitored in per-process mode. Therefore, + * when this function gets called from pfm_load_regs(), we know + * we have a user level task which will eventually either exit + * or leave the kernel, and thereby go through the checkpoint + * for TIF_*. + */ + if (ctx->ctx_fl_system || mode == 0) { + pfm_notify_user(ctx); + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + } else { + struct thread_info *info; + + /* + * given that TIF_NOTIFY_RESUME is not specific to + * perfmon, we need to have a second level check to + * verify the source of the notification. + */ + task->thread.pfm_ovfl_block_reset = 1; + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + info = ((struct thread_info *) ((char *) task + IA64_TASK_SIZE)); + set_bit(TIF_NOTIFY_RESUME, &info->flags); + } /* * keep the PMU frozen until either pfm_restart() or @@ -3059,7 +3119,10 @@ */ ctx->ctx_fl_frozen = 1; - DBprintk_ovfl(("return pmc0=0x%x must_block=%ld reason=%d\n", + DBprintk_ovfl(("current [%d] owner [%d] mode=%d return pmc0=0x%x must_block=%ld reason=%d\n", + current->pid, + PMU_OWNER() ? PMU_OWNER()->pid : -1, + mode, ctx->ctx_fl_frozen ? 0x1 : 0x0, t->pfm_ovfl_block_reset, ctx->ctx_fl_trap_reason)); @@ -3068,7 +3131,7 @@ return 0x1UL; } -static void +static irqreturn_t pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) { u64 pmc0; @@ -3083,7 +3146,7 @@ if (pfm_alternate_intr_handler) { (*pfm_alternate_intr_handler->handler)(irq, arg, regs); put_cpu(); - return; + return IRQ_HANDLED; } /* @@ -3108,19 +3171,21 @@ printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d has " "no PFM context\n", task->pid); put_cpu(); - return; + return IRQ_HANDLED; } /* * assume PMC[0].fr = 1 at this point */ - pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs); + pmc0 = pfm_overflow_handler(0, task, ctx, pmc0, regs); /* * we can only update pmc0 when the overflow - * is for the current context. In UP the current - * task may not be the one owning the PMU + * is for the current context or we are in system + * wide mode. In UP (per-task) the current + * task may not be the one owning the PMU, + * same thing for system-wide. */ - if (task == current) { + if (task == current || ctx->ctx_fl_system) { /* * We always clear the overflow status bits and either unfreeze * or keep the PMU frozen. @@ -3134,6 +3199,7 @@ pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++; } put_cpu_no_resched(); + return IRQ_HANDLED; } /* for debug only */ @@ -3387,11 +3453,11 @@ * in the next version of perfmon. */ if (ctx->ctx_fl_using_dbreg) { - for (i=0; i < pmu_conf.num_ibrs; i++) { + for (i=0; i < (int) pmu_conf.num_ibrs; i++) { ia64_set_ibr(i, t->ibr[i]); } ia64_srlz_i(); - for (i=0; i < pmu_conf.num_dbrs; i++) { + for (i=0; i < (int) pmu_conf.num_dbrs; i++) { ia64_set_dbr(i, t->dbr[i]); } ia64_srlz_d(); @@ -3402,7 +3468,7 @@ * this path cannot be used in SMP */ if (owner == task) { - if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) + if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) DBprintk(("invalid last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid)); @@ -3454,7 +3520,7 @@ * Side effect on ctx_fl_frozen is possible. */ if (t->pmc[0] & ~0x1) { - t->pmc[0] = pfm_overflow_handler(task, ctx, t->pmc[0], NULL); + t->pmc[0] = pfm_overflow_handler(1, task, ctx, t->pmc[0], NULL); } /* @@ -3676,7 +3742,7 @@ * */ - if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) + if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) printk(KERN_DEBUG "perfmon: [%d] last_cpu=%d\n", task->pid, atomic_read(&ctx->ctx_last_cpu)); @@ -3754,16 +3820,20 @@ preempt_disable(); /* - * make sure child cannot mess up the monitoring session + * for secure sessions, make sure child cannot mess up + * the monitoring session. */ - ia64_psr(regs)->sp = 1; - DBprintk(("enabling psr.sp for [%d]\n", task->pid)); - + if (ctx->ctx_fl_unsecure == 0) { + ia64_psr(regs)->sp = 1; + DBprintk(("enabling psr.sp for [%d]\n", task->pid)); + } else { + DBprintk(("psr.sp=%d [%d]\n", ia64_psr(regs)->sp, task->pid)); + } /* * if there was a virtual mapping for the sampling buffer * the mapping is NOT inherited across fork() (see VM_DONTCOPY), - * so we don't have to explicitely remove it here. + * so we don't have to explicitly remove it here. * * * Part of the clearing of fields is also done in diff -Nru a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h --- a/arch/ia64/kernel/perfmon_mckinley.h Mon May 12 20:55:48 2003 +++ b/arch/ia64/kernel/perfmon_mckinley.h Mon May 12 20:55:48 2003 @@ -25,8 +25,8 @@ /* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -143,10 +143,7 @@ case 8: val8 = *val; val13 = th->pmc[13]; val14 = th->pmc[14]; - *val |= 1UL << 2; /* bit 2 must always be 1 */ check_case1 = 1; - break; - case 9: *val |= 1UL << 2; /* bit 2 must always be 1 */ break; case 13: val8 = th->pmc[8]; val13 = *val; diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/kernel/process.c Mon May 12 20:55:46 2003 @@ -43,8 +43,8 @@ #include "sigframe.h" -static void -do_show_stack (struct unw_frame_info *info, void *arg) +void +ia64_do_show_stack (struct unw_frame_info *info, void *arg) { unsigned long ip, sp, bsp; char buf[80]; /* don't make it so big that it overflows the stack! */ @@ -57,7 +57,7 @@ unw_get_sp(info, &sp); unw_get_bsp(info, &bsp); - snprintf(buf, sizeof(buf), " [<%016lx>] %%s sp=0x%016lx bsp=0x%016lx\n", + snprintf(buf, sizeof(buf), " [<%016lx>] %%s\n\t\t\t\tsp=%016lx bsp=%016lx\n", ip, sp, bsp); print_symbol(buf, ip); } while (unw_unwind(info) >= 0); @@ -73,12 +73,12 @@ show_stack (struct task_struct *task) { if (!task) - unw_init_running(do_show_stack, 0); + unw_init_running(ia64_do_show_stack, 0); else { struct unw_frame_info info; unw_init_from_blocked_task(&info, task); - do_show_stack(&info, 0); + ia64_do_show_stack(&info, 0); } } @@ -123,8 +123,8 @@ if (user_mode(regs)) { /* print the stacked registers */ - unsigned long val, sof, *bsp, ndirty; - int i, is_nat = 0; + unsigned long val, *bsp, ndirty; + int i, sof, is_nat = 0; sof = regs->cr_ifs & 0x7f; /* size of frame */ ndirty = (regs->loadrs >> 19); @@ -135,7 +135,7 @@ ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } else - show_stack(0); + show_stack(NULL); } void @@ -379,6 +379,7 @@ # define THREAD_FLAGS_TO_SET 0 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); + p->thread.last_fph_cpu = -1; #ifdef CONFIG_IA32_SUPPORT /* * If we're cloning an IA32 task then save the IA32 extra diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c Mon May 12 20:55:49 2003 +++ b/arch/ia64/kernel/ptrace.c Mon May 12 20:55:49 2003 @@ -202,17 +202,16 @@ get_rnat (struct pt_regs *pt, struct switch_stack *sw, unsigned long *krbs, unsigned long *urnat_addr) { - unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, kmask = ~0UL; + unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0UL; unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; long num_regs; kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; /* - * First, figure out which bit number slot 0 in user-land maps - * to in the kernel rnat. Do this by figuring out how many - * register slots we're beyond the user's backingstore and - * then computing the equivalent address in kernel space. + * First, figure out which bit number slot 0 in user-land maps to in the kernel + * rnat. Do this by figuring out how many register slots we're beyond the user's + * backingstore and then computing the equivalent address in kernel space. */ num_regs = ia64_rse_num_regs(ubspstore, urnat_addr + 1); slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); @@ -222,8 +221,8 @@ if (ubspstore + 63 > urnat_addr) { /* some bits need to be merged in from pt->ar_rnat */ - kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); - urnat = (pt->ar_rnat & ~kmask); + umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1); + urnat = (pt->ar_rnat & umask); } if (rnat0_kaddr >= kbsp) { rnat0 = sw->ar_rnat; @@ -235,7 +234,7 @@ } else if (rnat1_kaddr > krbs) { rnat1 = *rnat1_kaddr; } - urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & kmask; + urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & ~umask; return urnat; } @@ -246,17 +245,19 @@ put_rnat (struct pt_regs *pt, struct switch_stack *sw, unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat) { - unsigned long rnat0 = 0, rnat1 = 0, rnat = 0, *slot0_kaddr, kmask = ~0UL, mask; - unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; - long num_regs; + unsigned long rnat0 = 0, rnat1 = 0, *slot0_kaddr, umask = 0, mask, m; + unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift, slot, ndirty; + long num_regs, nbits; + + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); + nbits = ndirty % 63; kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; /* - * First, figure out which bit number slot 0 in user-land maps - * to in the kernel rnat. Do this by figuring out how many - * register slots we're beyond the user's backingstore and - * then computing the equivalent address in kernel space. + * First, figure out which bit number slot 0 in user-land maps to in the kernel + * rnat. Do this by figuring out how many register slots we're beyond the user's + * backingstore and then computing the equivalent address in kernel space. */ num_regs = (long) ia64_rse_num_regs(ubspstore, urnat_addr + 1); slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); @@ -264,29 +265,37 @@ rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr); rnat0_kaddr = rnat1_kaddr - 64; +printk("%s: ubspstore=%p urnat_addr=%p\n", __FUNCTION__, ubspstore, urnat_addr); if (ubspstore + 63 > urnat_addr) { /* some bits need to be place in pt->ar_rnat: */ - kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); - pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask); + slot = ia64_rse_slot_num(ubspstore); + umask = ((1UL << slot) - 1); + pt->ar_rnat = (pt->ar_rnat & ~umask) | (urnat & umask); + nbits -= slot; + if (nbits <= 0) + return; } + mask = (1UL << nbits) - 1; /* * Note: Section 11.1 of the EAS guarantees that bit 63 of an * rnat slot is ignored. so we don't have to clear it here. */ rnat0 = (urnat << shift); - mask = ~0UL << shift; + m = mask << shift; +printk("%s: rnat0=%016lx, m=%016lx, rnat0_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat0, m, rnat0_kaddr, kbsp); if (rnat0_kaddr >= kbsp) { - sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat0 & mask); + sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat0 & m); } else if (rnat0_kaddr > krbs) { - *rnat0_kaddr = ((*rnat0_kaddr & ~mask) | (rnat0 & mask)); + *rnat0_kaddr = ((*rnat0_kaddr & ~m) | (rnat0 & m)); } rnat1 = (urnat >> (63 - shift)); - mask = ~0UL >> (63 - shift); + m = mask >> (63 - shift); +printk("%s: rnat1=%016lx, m=%016lx, rnat1_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat1, m, rnat1_kaddr, kbsp); if (rnat1_kaddr >= kbsp) { - sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat1 & mask); + sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat1 & m); } else if (rnat1_kaddr > krbs) { - *rnat1_kaddr = ((*rnat1_kaddr & ~mask) | (rnat1 & mask)); + *rnat1_kaddr = ((*rnat1_kaddr & ~m) | (rnat1 & m)); } } @@ -589,6 +598,7 @@ psr->mfh = 0; ia64_save_fpu(&task->thread.fph[0]); task->thread.flags |= IA64_THREAD_FPH_VALID; + task->thread.last_fph_cpu = smp_processor_id(); } } @@ -608,12 +618,11 @@ ia64_flush_fph(task); if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) { task->thread.flags |= IA64_THREAD_FPH_VALID; + task->thread.last_fph_cpu = -1; /* force reload */ memset(&task->thread.fph, 0, sizeof(task->thread.fph)); } -#ifndef CONFIG_SMP if (ia64_get_fpu_owner() == task) ia64_set_fpu_owner(0); -#endif psr->dfh = 1; } @@ -702,7 +711,9 @@ case PT_R4: case PT_R5: case PT_R6: case PT_R7: if (write_access) { /* read NaT bit first: */ - ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, data, &nat); + unsigned long dummy; + + ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, &dummy, &nat); if (ret < 0) return ret; } diff -Nru a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c --- a/arch/ia64/kernel/sal.c Mon May 12 20:55:49 2003 +++ b/arch/ia64/kernel/sal.c Mon May 12 20:55:49 2003 @@ -116,7 +116,7 @@ p = (char *) (systab + 1); for (i = 0; i < systab->entry_count; i++) { /* - * The first byte of each entry type contains the type desciptor. + * The first byte of each entry type contains the type descriptor. */ switch (*p) { case SAL_DESC_ENTRY_POINT: diff -Nru a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c --- a/arch/ia64/kernel/salinfo.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/kernel/salinfo.c Mon May 12 20:55:48 2003 @@ -38,7 +38,7 @@ { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, }, }; -#define NR_SALINFO_ENTRIES (sizeof(salinfo_entries)/sizeof(salinfo_entry_t)) +#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries) /* * One for each feature and one more for the directory entry... diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c Mon May 12 20:55:44 2003 +++ b/arch/ia64/kernel/setup.c Mon May 12 20:55:44 2003 @@ -59,7 +59,10 @@ struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; +unsigned long ia64_max_cacheline_size; unsigned long ia64_iobase; /* virtual address for I/O accesses */ +struct io_space io_space[MAX_IO_SPACES]; +unsigned int num_io_spaces; unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ @@ -412,6 +415,11 @@ } ia64_iobase = (unsigned long) ioremap(phys_iobase, 0); + /* setup legacy IO port space */ + io_space[0].mmio_base = ia64_iobase; + io_space[0].sparse = 1; + num_io_spaces = 1; + #ifdef CONFIG_SMP cpu_physical_id(0) = hard_smp_processor_id(); #endif @@ -421,7 +429,7 @@ #ifdef CONFIG_ACPI_BOOT acpi_boot_init(); #endif -#ifdef CONFIG_SERIAL_HCDP +#ifdef CONFIG_SERIAL_8250_HCDP if (efi.hcdp) { void setup_serial_hcdp(void *); @@ -494,7 +502,7 @@ memcpy(features, " standard", 10); cp = features; sep = 0; - for (i = 0; i < sizeof(feature_bits)/sizeof(feature_bits[0]); ++i) { + for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) { if (mask & feature_bits[i].mask) { if (sep) *cp++ = sep; @@ -625,6 +633,39 @@ /* start_kernel() requires this... */ } +static void +get_max_cacheline_size (void) +{ + unsigned long line_size, max = 1; + u64 l, levels, unique_caches; + pal_cache_config_info_t cci; + s64 status; + + status = ia64_pal_cache_summary(&levels, &unique_caches); + if (status != 0) { + printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n", + __FUNCTION__, status); + max = SMP_CACHE_BYTES; + goto out; + } + + for (l = 0; l < levels; ++l) { + status = ia64_pal_cache_config_info(l, /* cache_type (data_or_unified)= */ 2, + &cci); + if (status != 0) { + printk(KERN_ERR + "%s: ia64_pal_cache_config_info(l=%lu) failed (status=%ld)\n", + __FUNCTION__, l, status); + max = SMP_CACHE_BYTES; + } + line_size = 1 << cci.pcci_line_size; + if (line_size > max) + max = line_size; + } + out: + if (max > ia64_max_cacheline_size) + ia64_max_cacheline_size = max; +} /* * cpu_init() initializes state that is per-CPU. This function acts @@ -667,6 +708,8 @@ #ifdef CONFIG_NUMA cpu_info->node_data = get_node_data_ptr(); #endif + + get_max_cacheline_size(); /* * We can't pass "local_cpu_data" to identify_cpu() because we haven't called diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c --- a/arch/ia64/kernel/signal.c Mon May 12 20:55:47 2003 +++ b/arch/ia64/kernel/signal.c Mon May 12 20:55:47 2003 @@ -142,8 +142,13 @@ __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); psr->mfh = 0; /* drop signal handler's fph contents... */ - if (!psr->dfh) + if (psr->dfh) + current->thread.last_fph_cpu = -1; + else { __ia64_load_fpu(current->thread.fph); + ia64_set_fpu_owner(current); + current->thread.last_fph_cpu = smp_processor_id(); + } } return err; } @@ -523,7 +528,7 @@ else errno = -errno; } - } else if (scr->pt.r10 != -1) + } else if ((long) scr->pt.r10 != -1) /* * A system calls has to be restarted only if one of the error codes * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned. If r10 diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c --- a/arch/ia64/kernel/smp.c Mon May 12 20:55:49 2003 +++ b/arch/ia64/kernel/smp.c Mon May 12 20:55:49 2003 @@ -2,7 +2,7 @@ * SMP Support * * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999, 2001 David Mosberger-Tang + * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang * * Lots of stuff stolen from arch/alpha/kernel/smp.c * @@ -87,7 +87,7 @@ cpu_halt(); } -void +irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { int this_cpu = get_cpu(); @@ -147,10 +147,11 @@ mb(); /* Order data access and bit testing. */ } put_cpu(); + return IRQ_HANDLED; } /* - * Called with preeemption disabled + * Called with preeemption disabled. */ static inline void send_IPI_single (int dest_cpu, int op) @@ -160,12 +161,12 @@ } /* - * Called with preeemption disabled + * Called with preeemption disabled. */ static inline void send_IPI_allbutself (int op) { - int i; + unsigned int i; for (i = 0; i < NR_CPUS; i++) { if (cpu_online(i) && i != smp_processor_id()) @@ -174,7 +175,7 @@ } /* - * Called with preeemption disabled + * Called with preeemption disabled. */ static inline void send_IPI_all (int op) @@ -187,7 +188,7 @@ } /* - * Called with preeemption disabled + * Called with preeemption disabled. */ static inline void send_IPI_self (int op) @@ -196,7 +197,7 @@ } /* - * Called with preeemption disabled + * Called with preeemption disabled. */ void smp_send_reschedule (int cpu) diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c Mon May 12 20:55:45 2003 +++ b/arch/ia64/kernel/smpboot.c Mon May 12 20:55:45 2003 @@ -192,6 +192,7 @@ { long i, delta, adj, adjust_latency = 0, done = 0; unsigned long flags, rt, master_time_stamp, bound; + extern void ia64_cpu_local_tick (void); #if DEBUG_ITC_SYNC struct { long rt; /* roundtrip time */ @@ -246,6 +247,16 @@ printk(KERN_INFO "CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, " "maxerr %lu cycles)\n", smp_processor_id(), master, delta, rt); + + /* + * Check whether we sync'd the itc ahead of the next timer interrupt. If so, just + * reset it. + */ + if (time_after(ia64_get_itc(), local_cpu_data->itm_next)) { + Dprintk("CPU %d: oops, jumped a timer tick; resetting timer.\n", + smp_processor_id()); + ia64_cpu_local_tick(); + } } /* @@ -279,15 +290,6 @@ smp_setup_percpu_timer(); - if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { - /* - * Synchronize the ITC with the BP - */ - Dprintk("Going to syncup ITC with BP.\n"); - - ia64_sync_itc(0); - } - /* * Get our bogomips. */ @@ -310,6 +312,18 @@ local_irq_enable(); calibrate_delay(); local_cpu_data->loops_per_jiffy = loops_per_jiffy; + + if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { + /* + * Synchronize the ITC with the BP. Need to do this after irqs are + * enabled because ia64_sync_itc() calls smp_call_function_single(), which + * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls + * local_bh_enable(), which bugs out if irqs are not enabled... + */ + Dprintk("Going to syncup ITC with BP.\n"); + ia64_sync_itc(0); + } + /* * Allow the master to continue. */ @@ -394,13 +408,26 @@ return 0; } -unsigned long cache_decay_ticks; /* # of ticks an idle task is considered cache-hot */ +static int __init +decay (char *str) +{ + int ticks; + get_option (&str, &ticks); + cache_decay_ticks = ticks; + return 1; +} + +__setup("decay=", decay); + +/* + * # of ticks an idle task is considered cache-hot. Highly application-dependent. There + * are apps out there which are known to suffer significantly with values >= 4. + */ +unsigned long cache_decay_ticks = 10; /* equal to MIN_TIMESLICE */ static void smp_tune_scheduling (void) { - cache_decay_ticks = 10; /* XXX base this on PAL info and cache-bandwidth estimate */ - printk(KERN_INFO "task migration cache decay timeout: %ld msecs.\n", (cache_decay_ticks + 1) * 1000 / HZ); } diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c Mon May 12 20:55:45 2003 +++ b/arch/ia64/kernel/time.c Mon May 12 20:55:45 2003 @@ -83,11 +83,26 @@ return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; } +static inline void +set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) +{ + while (nsec > NSEC_PER_SEC) { + nsec -= NSEC_PER_SEC; + ++sec; + } + while (nsec < 0) { + nsec += NSEC_PER_SEC; + --sec; + } + ts->tv_sec = sec; + ts->tv_nsec = nsec; +} + void do_settimeofday (struct timeval *tv) { - time_t sec = tv->tv_sec; - long nsec = tv->tv_usec * 1000; + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_usec * 1000; write_seqlock_irq(&xtime_lock); { @@ -99,13 +114,12 @@ */ nsec -= gettimeoffset(); - while (nsec < 0) { - nsec += 1000000000; - sec--; - } + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - xtime.tv_sec = sec; - xtime.tv_nsec = nsec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; @@ -166,8 +180,8 @@ usec = (nsec + offset) / 1000; - while (unlikely(usec >= 1000000)) { - usec -= 1000000; + while (unlikely(usec >= USEC_PER_SEC)) { + usec -= USEC_PER_SEC; ++sec; } @@ -175,8 +189,8 @@ tv->tv_usec = usec; } -static void -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t +timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm; @@ -221,7 +235,7 @@ do { /* * If we're too close to the next clock tick for comfort, we increase the - * saftey margin by intentionally dropping the next tick(s). We do NOT update + * safety margin by intentionally dropping the next tick(s). We do NOT update * itm.next because that would force us to call do_timer() which in turn would * let our clock run too fast (with the potentially devastating effect of * losing monotony of time). @@ -231,12 +245,13 @@ ia64_set_itm(new_itm); /* double check, in case we got hit by a (slow) PMI: */ } while (time_after_eq(ia64_get_itc(), new_itm)); + return IRQ_HANDLED; } /* * Encapsulate access to the itm structure for SMP. */ -void __init +void ia64_cpu_local_tick (void) { int cpu = smp_processor_id(); @@ -281,7 +296,7 @@ if (status != 0) { /* invent "random" values */ printk(KERN_ERR - "SAL/PAL failed to obtain frequency info---inventing reasonably values\n"); + "SAL/PAL failed to obtain frequency info---inventing reasonable values\n"); platform_base_freq = 100000000; itc_ratio.num = 3; itc_ratio.den = 1; @@ -305,8 +320,8 @@ local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; local_cpu_data->itc_freq = itc_freq; - local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000; - local_cpu_data->nsec_per_cyc = ((1000000000UL<cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC; + local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<curr.reg + unw.save_order[i]; if (reg->where == UNW_WHERE_GR_SAVE) { reg->where = UNW_WHERE_GR; @@ -698,7 +698,7 @@ */ if (sr->imask) { unsigned char kind, mask = 0, *cp = sr->imask; - unsigned long t; + int t; static const unsigned char limit[3] = { UNW_REG_F31, UNW_REG_R7, UNW_REG_B5 }; @@ -1214,13 +1214,13 @@ spin_unlock(&unw.lock); /* - * XXX We'll deadlock here if we interrupt a thread that is - * holding a read lock on script->lock. A try_write_lock() - * might be mighty handy here... Alternatively, we could - * disable interrupts whenever we hold a read-lock, but that - * seems silly. + * We'd deadlock here if we interrupted a thread that is holding a read lock on + * script->lock. Thus, if the write_trylock() fails, we simply bail out. The + * alternative would be to disable interrupts whenever we hold a read-lock, but + * that seems silly. */ - write_lock(&script->lock); + if (!write_trylock(&script->lock)) + return NULL; spin_lock(&unw.lock); { @@ -1888,22 +1888,21 @@ return -1; } -void -unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw) +static void +init_frame_info (struct unw_frame_info *info, struct task_struct *t, + struct switch_stack *sw, unsigned long stktop) { - unsigned long rbslimit, rbstop, stklimit, stktop, sol; + unsigned long rbslimit, rbstop, stklimit; STAT(unsigned long start, flags;) STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc()); /* - * Subtle stuff here: we _could_ unwind through the - * switch_stack frame but we don't want to do that because it - * would be slow as each preserved register would have to be - * processed. Instead, what we do here is zero out the frame - * info and start the unwind process at the function that - * created the switch_stack frame. When a preserved value in - * switch_stack needs to be accessed, run_script() will + * Subtle stuff here: we _could_ unwind through the switch_stack frame but we + * don't want to do that because it would be slow as each preserved register would + * have to be processed. Instead, what we do here is zero out the frame info and + * start the unwind process at the function that created the switch_stack frame. + * When a preserved value in switch_stack needs to be accessed, run_script() will * initialize the appropriate pointer on demand. */ memset(info, 0, sizeof(*info)); @@ -1914,7 +1913,6 @@ rbstop = rbslimit; stklimit = (unsigned long) t + IA64_STK_OFFSET; - stktop = (unsigned long) sw - 16; if (stktop <= rbstop) stktop = rbstop; @@ -1924,34 +1922,58 @@ info->memstk.top = stktop; info->task = t; info->sw = sw; - info->sp = info->psp = (unsigned long) (sw + 1) - 16; - info->pt = 0; + info->sp = info->psp = stktop; + info->pr = sw->pr; + UNW_DPRINT(3, "unwind.%s:\n" + " task 0x%lx\n" + " rbs = [0x%lx-0x%lx)\n" + " stk = [0x%lx-0x%lx)\n" + " pr 0x%lx\n" + " sw 0x%lx\n" + " sp 0x%lx\n", + __FUNCTION__, (unsigned long) t, rbslimit, rbstop, stktop, stklimit, + info->pr, (unsigned long) info->sw, info->sp); + STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); +} + +void +unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t, + struct pt_regs *pt, struct switch_stack *sw) +{ + unsigned long sof; + + init_frame_info(info, t, sw, pt->r12); + info->cfm_loc = &pt->cr_ifs; + info->unat_loc = &pt->ar_unat; + info->pfs_loc = &pt->ar_pfs; + sof = *info->cfm_loc & 0x7f; + info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof); + info->ip = pt->cr_iip + ia64_psr(pt)->ri; + info->pt = (unsigned long) pt; + UNW_DPRINT(3, "unwind.%s:\n" + " bsp 0x%lx\n" + " sof 0x%lx\n" + " ip 0x%lx\n", + __FUNCTION__, info->bsp, sof, info->ip); + find_save_locs(info); +} + +void +unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw) +{ + unsigned long sol; + + init_frame_info(info, t, sw, (unsigned long) (sw + 1) - 16); info->cfm_loc = &sw->ar_pfs; sol = (*info->cfm_loc >> 7) & 0x7f; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol); info->ip = sw->b0; - info->pr = sw->pr; - UNW_DPRINT(3, - "unwind.%s\n" - " rbslimit 0x%lx\n" - " rbstop 0x%lx\n" - " stklimit 0x%lx\n" - " stktop 0x%lx\n" - " task 0x%lx\n" - " sw 0x%lx\n", - __FUNCTION__, rbslimit, rbstop, stklimit, stktop, - (unsigned long)(info->task), - (unsigned long)(info->sw)); - UNW_DPRINT(3, - " sp/psp 0x%lx\n" - " sol 0x%lx\n" - " bsp 0x%lx\n" - " ip 0x%lx\n" - " pr 0x%lx\n", - info->sp, sol, info->bsp, info->ip, info->pr); - + UNW_DPRINT(3, "unwind.%s:\n" + " bsp 0x%lx\n" + " sol 0x%lx\n" + " ip 0x%lx\n", + __FUNCTION__, info->bsp, sol, info->ip); find_save_locs(info); - STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags)); } void diff -Nru a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S --- a/arch/ia64/lib/copy_user.S Mon May 12 20:55:45 2003 +++ b/arch/ia64/lib/copy_user.S Mon May 12 20:55:45 2003 @@ -316,7 +316,7 @@ // Beginning of long mempcy (i.e. > 16 bytes) // .long_copy_user: - tbit.nz p6,p7=src1,0 // odd alignement + tbit.nz p6,p7=src1,0 // odd alignment and tmp=7,tmp ;; cmp.eq p10,p8=r0,tmp diff -Nru a/arch/ia64/lib/do_csum.S b/arch/ia64/lib/do_csum.S --- a/arch/ia64/lib/do_csum.S Mon May 12 20:55:45 2003 +++ b/arch/ia64/lib/do_csum.S Mon May 12 20:55:45 2003 @@ -137,7 +137,7 @@ mov saved_pr=pr // preserve predicates (rotation) (p6) br.ret.spnt.many rp // return if zero or negative length - mov hmask=-1 // intialize head mask + mov hmask=-1 // initialize head mask tbit.nz p15,p0=buf,0 // is buf an odd address? and first1=-8,buf // 8-byte align down address of first1 element diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c --- a/arch/ia64/lib/io.c Mon May 12 20:55:44 2003 +++ b/arch/ia64/lib/io.c Mon May 12 20:55:44 2003 @@ -51,84 +51,79 @@ #ifdef CONFIG_IA64_GENERIC +#undef __ia64_inb +#undef __ia64_inw +#undef __ia64_inl +#undef __ia64_outb +#undef __ia64_outw +#undef __ia64_outl +#undef __ia64_readb +#undef __ia64_readw +#undef __ia64_readl +#undef __ia64_readq +#undef __ia64_writeb +#undef __ia64_writew +#undef __ia64_writel +#undef __ia64_writeq + unsigned int -ia64_inb (unsigned long port) +__ia64_inb (unsigned long port) { - return __ia64_inb(port); + return ___ia64_inb(port); } unsigned int -ia64_inw (unsigned long port) +__ia64_inw (unsigned long port) { - return __ia64_inw(port); + return ___ia64_inw(port); } unsigned int -ia64_inl (unsigned long port) +__ia64_inl (unsigned long port) { - return __ia64_inl(port); + return ___ia64_inl(port); } void -ia64_outb (unsigned char val, unsigned long port) +__ia64_outb (unsigned char val, unsigned long port) { - __ia64_outb(val, port); + ___ia64_outb(val, port); } void -ia64_outw (unsigned short val, unsigned long port) +__ia64_outw (unsigned short val, unsigned long port) { - __ia64_outw(val, port); + ___ia64_outw(val, port); } void -ia64_outl (unsigned int val, unsigned long port) +__ia64_outl (unsigned int val, unsigned long port) { - __ia64_outl(val, port); + ___ia64_outl(val, port); } unsigned char -ia64_readb (void *addr) +__ia64_readb (void *addr) { - return __ia64_readb (addr); + return ___ia64_readb (addr); } unsigned short -ia64_readw (void *addr) +__ia64_readw (void *addr) { - return __ia64_readw (addr); + return ___ia64_readw (addr); } unsigned int -ia64_readl (void *addr) +__ia64_readl (void *addr) { - return __ia64_readl (addr); + return ___ia64_readl (addr); } unsigned long -ia64_readq (void *addr) +__ia64_readq (void *addr) { - return __ia64_readq (addr) + return ___ia64_readq (addr); } - - -/* define aliases: */ - -asm (".global __ia64_inb, __ia64_inw, __ia64_inl"); -asm ("__ia64_inb = ia64_inb"); -asm ("__ia64_inw = ia64_inw"); -asm ("__ia64_inl = ia64_inl"); - -asm (".global __ia64_outb, __ia64_outw, __ia64_outl"); -asm ("__ia64_outb = ia64_outb"); -asm ("__ia64_outw = ia64_outw"); -asm ("__ia64_outl = ia64_outl"); - -asm (".global __ia64_readb, __ia64_readw, __ia64_readl, __ia64_readq"); -asm ("__ia64_readb = ia64_readb"); -asm ("__ia64_readw = ia64_readw"); -asm ("__ia64_readl = ia64_readl"); -asm ("__ia64_readq = ia64_readq"); - #endif /* CONFIG_IA64_GENERIC */ diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c --- a/arch/ia64/lib/swiotlb.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/lib/swiotlb.c Mon May 12 20:55:48 2003 @@ -5,7 +5,10 @@ * I/O TLBs (aka DMA address translation hardware). * Copyright (C) 2000 Asit Mallick * Copyright (C) 2000 Goutham Rao + * Copyright (C) 2000, 2003 Hewlett-Packard Co + * David Mosberger-Tang * + * 03/05/07 davidm Switch from PCI-DMA to generic device DMA API. * 00/12/13 davidm Rename to swiotlb.c and add mark_clean() to avoid * unnecessary i-cache flushing. */ @@ -92,7 +95,7 @@ void swiotlb_init (void) { - int i; + unsigned long i; /* * Get IO TLB memory from the low pages @@ -121,7 +124,7 @@ * Allocates bounce buffer and returns its kernel virtual address. */ static void * -map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction) +map_single (struct device *hwdev, char *buffer, size_t size, int dir) { unsigned long flags; char *dma_addr; @@ -161,7 +164,7 @@ if (io_tlb_list[index] >= nslots) { int count = 0; - for (i = index; i < index + nslots; i++) + for (i = index; i < (int) (index + nslots); i++) io_tlb_list[i] = 0; for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && io_tlb_list[i]; i--) @@ -195,7 +198,7 @@ * needed when we sync the memory. Then we sync the buffer if needed. */ io_tlb_orig_addr[index] = buffer; - if (direction == PCI_DMA_TODEVICE || direction == PCI_DMA_BIDIRECTIONAL) + if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) memcpy(dma_addr, buffer, size); return dma_addr; @@ -205,7 +208,7 @@ * dma_addr is the kernel virtual address of the bounce buffer to unmap. */ static void -unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +unmap_single (struct device *hwdev, char *dma_addr, size_t size, int dir) { unsigned long flags; int i, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; @@ -215,7 +218,7 @@ /* * First, sync the memory before unmapping the entry */ - if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL)) + if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) /* * bounce... copy the data back into the original buffer * and delete the * bounce buffer. @@ -239,7 +242,7 @@ for (i = index + nslots - 1; i >= index; i--) io_tlb_list[i] = ++count; /* - * Step 2: merge the returned slots with the preceeding slots, if + * Step 2: merge the returned slots with the preceding slots, if * available (non zero) */ for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && @@ -250,49 +253,46 @@ } static void -sync_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) +sync_single (struct device *hwdev, char *dma_addr, size_t size, int dir) { int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; char *buffer = io_tlb_orig_addr[index]; /* * bounce... copy the data back into/from the original buffer - * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ? + * XXX How do you handle DMA_BIDIRECTIONAL here ? */ - if (direction == PCI_DMA_FROMDEVICE) + if (dir == DMA_FROM_DEVICE) memcpy(buffer, dma_addr, size); - else if (direction == PCI_DMA_TODEVICE) + else if (dir == DMA_TO_DEVICE) memcpy(dma_addr, buffer, size); else BUG(); } void * -swiotlb_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handle, int flags) { - unsigned long pci_addr; - int gfp = GFP_ATOMIC; + unsigned long dev_addr; void *ret; - /* - * Alloc_consistent() is defined to return memory < 4GB, no matter what the DMA - * mask says. - */ - gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */ - ret = (void *)__get_free_pages(gfp, get_order(size)); + /* XXX fix me: the DMA API should pass us an explicit DMA mask instead: */ + flags |= GFP_DMA; + + ret = (void *)__get_free_pages(flags, get_order(size)); if (!ret) return NULL; memset(ret, 0, size); - pci_addr = virt_to_phys(ret); - if (hwdev && (pci_addr & ~hwdev->dma_mask) != 0) - panic("swiotlb_alloc_consistent: allocated memory is out of range for PCI device"); - *dma_handle = pci_addr; + dev_addr = virt_to_phys(ret); + if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + panic("swiotlb_alloc_consistent: allocated memory is out of range for device"); + *dma_handle = dev_addr; return ret; } void -swiotlb_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { free_pages((unsigned long) vaddr, get_order(size)); } @@ -305,34 +305,34 @@ * swiotlb_unmap_single or swiotlb_dma_sync_single is performed. */ dma_addr_t -swiotlb_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) +swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir) { - unsigned long pci_addr = virt_to_phys(ptr); + unsigned long dev_addr = virt_to_phys(ptr); - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); /* * Check if the PCI device can DMA to ptr... if so, just return ptr */ - if ((pci_addr & ~hwdev->dma_mask) == 0) + if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) == 0) /* * Device is bit capable of DMA'ing to the buffer... just return the PCI * address of ptr */ - return pci_addr; + return dev_addr; /* * get a bounce buffer: */ - pci_addr = virt_to_phys(map_single(hwdev, ptr, size, direction)); + dev_addr = virt_to_phys(map_single(hwdev, ptr, size, dir)); /* * Ensure that the address returned is DMA'ble: */ - if ((pci_addr & ~hwdev->dma_mask) != 0) + if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) panic("map_single: bounce buffer is not DMA'ble"); - return pci_addr; + return dev_addr; } /* @@ -363,15 +363,15 @@ * device wrote there. */ void -swiotlb_unmap_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +swiotlb_unmap_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { - char *dma_addr = phys_to_virt(pci_addr); + char *dma_addr = phys_to_virt(dev_addr); - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) - unmap_single(hwdev, dma_addr, size, direction); - else if (direction == PCI_DMA_FROMDEVICE) + unmap_single(hwdev, dma_addr, size, dir); + else if (dir == DMA_FROM_DEVICE) mark_clean(dma_addr, size); } @@ -385,21 +385,21 @@ * again owns the buffer. */ void -swiotlb_sync_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction) +swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { - char *dma_addr = phys_to_virt(pci_addr); + char *dma_addr = phys_to_virt(dev_addr); - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) - sync_single(hwdev, dma_addr, size, direction); - else if (direction == PCI_DMA_FROMDEVICE) + sync_single(hwdev, dma_addr, size, dir); + else if (dir == DMA_FROM_DEVICE) mark_clean(dma_addr, size); } /* * Map a set of buffers described by scatterlist in streaming mode for DMA. This is the - * scather-gather version of the above swiotlb_map_single interface. Here the scatter + * scatter-gather version of the above swiotlb_map_single interface. Here the scatter * gather list elements are each tagged with the appropriate dma address and length. They * are obtained via sg_dma_{address,length}(SG). * @@ -412,23 +412,22 @@ * Device ownership issues as mentioned above for swiotlb_map_single are the same here. */ int -swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +swiotlb_map_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) { void *addr; - unsigned long pci_addr; + unsigned long dev_addr; int i; - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); for (i = 0; i < nelems; i++, sg++) { addr = SG_ENT_VIRT_ADDRESS(sg); - pci_addr = virt_to_phys(addr); - if ((pci_addr & ~hwdev->dma_mask) != 0) - sg->dma_address = (dma_addr_t) - map_single(hwdev, addr, sg->length, direction); + dev_addr = virt_to_phys(addr); + if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0) + sg->dma_address = (dma_addr_t) map_single(hwdev, addr, sg->length, dir); else - sg->dma_address = pci_addr; + sg->dma_address = dev_addr; sg->dma_length = sg->length; } return nelems; @@ -439,17 +438,17 @@ * here are the same as for swiotlb_unmap_single() above. */ void -swiotlb_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +swiotlb_unmap_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) { int i; - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction); - else if (direction == PCI_DMA_FROMDEVICE) + unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); + else if (dir == DMA_FROM_DEVICE) mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } @@ -461,16 +460,16 @@ * usage. */ void -swiotlb_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) { int i; - if (direction == PCI_DMA_NONE) + if (dir == DMA_NONE) BUG(); for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction); + sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); } /* @@ -479,7 +478,7 @@ * you would pass 0x00ffffff as the mask to this function. */ int -swiotlb_pci_dma_supported (struct pci_dev *hwdev, u64 mask) +swiotlb_dma_supported (struct device *hwdev, u64 mask) { return 1; } @@ -491,6 +490,6 @@ EXPORT_SYMBOL(swiotlb_unmap_sg); EXPORT_SYMBOL(swiotlb_sync_single); EXPORT_SYMBOL(swiotlb_sync_sg); -EXPORT_SYMBOL(swiotlb_alloc_consistent); -EXPORT_SYMBOL(swiotlb_free_consistent); -EXPORT_SYMBOL(swiotlb_pci_dma_supported); +EXPORT_SYMBOL(swiotlb_alloc_coherent); +EXPORT_SYMBOL(swiotlb_free_coherent); +EXPORT_SYMBOL(swiotlb_dma_supported); diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c --- a/arch/ia64/mm/fault.c Mon May 12 20:55:49 2003 +++ b/arch/ia64/mm/fault.c Mon May 12 20:55:49 2003 @@ -58,6 +58,18 @@ if (in_atomic() || !mm) goto no_context; +#ifdef CONFIG_VIRTUAL_MEM_MAP + /* + * If fault is in region 5 and we are in the kernel, we may already + * have the mmap_sem (pfn_valid macro is called during mmap). There + * is no vma for region 5 addr's anyway, so skip getting the semaphore + * and go directly to the exception handling code. + */ + + if ((REGION_NUMBER(address) == 5) && !user_mode(regs)) + goto bad_area_no_up; +#endif + down_read(&mm->mmap_sem); vma = find_vma_prev(mm, address, &prev_vma); @@ -139,6 +151,9 @@ bad_area: up_read(&mm->mmap_sem); +#ifdef CONFIG_VIRTUAL_MEM_MAP + bad_area_no_up: +#endif if ((isr & IA64_ISR_SP) || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/mm/init.c Mon May 12 20:55:46 2003 @@ -38,6 +38,13 @@ unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; +#ifdef CONFIG_VIRTUAL_MEM_MAP +# define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */ + unsigned long vmalloc_end = VMALLOC_END_INIT; + static struct page *vmem_map; + static unsigned long num_dma_physpages; +#endif + static int pgt_cache_water[2] = { 25, 50 }; void @@ -48,13 +55,13 @@ low = pgt_cache_water[0]; high = pgt_cache_water[1]; - if (pgtable_cache_size > high) { + if (pgtable_cache_size > (u64) high) { do { if (pgd_quicklist) free_page((unsigned long)pgd_alloc_one_fast(0)); if (pmd_quicklist) free_page((unsigned long)pmd_alloc_one_fast(0, 0)); - } while (pgtable_cache_size > low); + } while (pgtable_cache_size > (u64) low); } } @@ -337,6 +344,139 @@ ia64_tlb_init(); } +#ifdef CONFIG_VIRTUAL_MEM_MAP + +static int +create_mem_map_page_table (u64 start, u64 end, void *arg) +{ + unsigned long address, start_page, end_page; + struct page *map_start, *map_end; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); + map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); + + start_page = (unsigned long) map_start & PAGE_MASK; + end_page = PAGE_ALIGN((unsigned long) map_end); + + for (address = start_page; address < end_page; address += PAGE_SIZE) { + pgd = pgd_offset_k(address); + if (pgd_none(*pgd)) + pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE)); + pmd = pmd_offset(pgd, address); + + if (pmd_none(*pmd)) + pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE)); + pte = pte_offset_kernel(pmd, address); + + if (pte_none(*pte)) + set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages(PAGE_SIZE)) >> PAGE_SHIFT, + PAGE_KERNEL)); + } + return 0; +} + +struct memmap_init_callback_data { + struct page *start; + struct page *end; + int nid; + unsigned long zone; +}; + +static int +virtual_memmap_init (u64 start, u64 end, void *arg) +{ + struct memmap_init_callback_data *args; + struct page *map_start, *map_end; + + args = (struct memmap_init_callback_data *) arg; + + map_start = vmem_map + (__pa(start) >> PAGE_SHIFT); + map_end = vmem_map + (__pa(end) >> PAGE_SHIFT); + + if (map_start < args->start) + map_start = args->start; + if (map_end > args->end) + map_end = args->end; + + /* + * We have to initialize "out of bounds" struct page elements that fit completely + * on the same pages that were allocated for the "in bounds" elements because they + * may be referenced later (and found to be "reserved"). + */ + map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page); + map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end) + / sizeof(struct page)); + + if (map_start < map_end) + memmap_init_zone(map_start, (unsigned long) (map_end - map_start), + args->nid, args->zone, page_to_pfn(map_start)); + return 0; +} + +void +memmap_init (struct page *start, unsigned long size, int nid, + unsigned long zone, unsigned long start_pfn) +{ + if (!vmem_map) + memmap_init_zone(start, size, nid, zone, start_pfn); + else { + struct memmap_init_callback_data args; + + args.start = start; + args.end = start + size; + args.nid = nid; + args.zone = zone; + + efi_memmap_walk(virtual_memmap_init, &args); + } +} + +int +ia64_pfn_valid (unsigned long pfn) +{ + char byte; + + return __get_user(byte, (char *) pfn_to_page(pfn)) == 0; +} + +static int +count_dma_pages (u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + if (end <= MAX_DMA_ADDRESS) + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + +static int +find_largest_hole (u64 start, u64 end, void *arg) +{ + u64 *max_gap = arg; + + static u64 last_end = PAGE_OFFSET; + + /* NOTE: this algorithm assumes efi memmap table is ordered */ + + if (*max_gap < (start - last_end)) + *max_gap = start - last_end; + last_end = end; + return 0; +} +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + +static int +count_pages (u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + /* * Set up the page tables. */ @@ -348,18 +488,70 @@ extern void discontig_paging_init(void); discontig_paging_init(); + efi_memmap_walk(count_pages, &num_physpages); } #else /* !CONFIG_DISCONTIGMEM */ void paging_init (void) { - unsigned long max_dma, zones_size[MAX_NR_ZONES]; + unsigned long max_dma; + unsigned long zones_size[MAX_NR_ZONES]; +# ifdef CONFIG_VIRTUAL_MEM_MAP + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long max_gap; +# endif /* initialize mem_map[] */ memset(zones_size, 0, sizeof(zones_size)); + num_physpages = 0; + efi_memmap_walk(count_pages, &num_physpages); + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; + +# ifdef CONFIG_VIRTUAL_MEM_MAP + memset(zholes_size, 0, sizeof(zholes_size)); + + num_dma_physpages = 0; + efi_memmap_walk(count_dma_pages, &num_dma_physpages); + + if (max_low_pfn < max_dma) { + zones_size[ZONE_DMA] = max_low_pfn; + zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages; + } else { + zones_size[ZONE_DMA] = max_dma; + zholes_size[ZONE_DMA] = max_dma - num_dma_physpages; + if (num_physpages > num_dma_physpages) { + zones_size[ZONE_NORMAL] = max_low_pfn - max_dma; + zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma) + - (num_physpages - num_dma_physpages)); + } + } + + max_gap = 0; + efi_memmap_walk(find_largest_hole, (u64 *)&max_gap); + if (max_gap < LARGE_GAP) { + vmem_map = (struct page *) 0; + free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, zholes_size); + mem_map = contig_page_data.node_mem_map; + } + else { + unsigned long map_size; + + /* allocate virtual_mem_map */ + + map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page)); + vmalloc_end -= map_size; + vmem_map = (struct page *) vmalloc_end; + efi_memmap_walk(create_mem_map_page_table, 0); + + free_area_init_node(0, &contig_page_data, vmem_map, zones_size, 0, zholes_size); + + mem_map = contig_page_data.node_mem_map; + printk("Virtual mem_map starts at 0x%p\n", mem_map); + } +# else /* !CONFIG_VIRTUAL_MEM_MAP */ if (max_low_pfn < max_dma) zones_size[ZONE_DMA] = max_low_pfn; else { @@ -367,19 +559,11 @@ zones_size[ZONE_NORMAL] = max_low_pfn - max_dma; } free_area_init(zones_size); +# endif /* !CONFIG_VIRTUAL_MEM_MAP */ } #endif /* !CONFIG_DISCONTIGMEM */ static int -count_pages (u64 start, u64 end, void *arg) -{ - unsigned long *count = arg; - - *count += (end - start) >> PAGE_SHIFT; - return 0; -} - -static int count_reserved_pages (u64 start, u64 end, void *arg) { unsigned long num_reserved = 0; @@ -406,7 +590,7 @@ * any drivers that may need the PCI DMA interface are initialized or bootmem has * been freed. */ - platform_pci_dma_init(); + platform_dma_init(); #endif #ifndef CONFIG_DISCONTIGMEM @@ -415,9 +599,6 @@ max_mapnr = max_low_pfn; #endif - num_physpages = 0; - efi_memmap_walk(count_pages, &num_physpages); - high_memory = __va(max_low_pfn * PAGE_SIZE); for_each_pgdat(pgdat) @@ -445,7 +626,7 @@ num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS; if (num_pgt_pages > nr_free_pages() / 10) num_pgt_pages = nr_free_pages() / 10; - if (num_pgt_pages > pgt_cache_water[1]) + if (num_pgt_pages > (u64) pgt_cache_water[1]) pgt_cache_water[1] = num_pgt_pages; /* install the gate page in the global page table: */ diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c Mon May 12 20:55:46 2003 +++ b/arch/ia64/pci/pci.c Mon May 12 20:55:46 2003 @@ -5,6 +5,7 @@ * * Copyright (C) 2002 Hewlett-Packard Co * David Mosberger-Tang + * Bjorn Helgaas * * Note: Above list of copyright holders is incomplete... */ @@ -116,31 +117,10 @@ subsys_initcall(pci_acpi_init); -static void __init -pcibios_fixup_resource(struct resource *res, u64 offset) -{ - res->start += offset; - res->end += offset; -} - -void __init -pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) -{ - int i; - - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - if (!dev->resource[i].start) - continue; - if (dev->resource[i].flags & IORESOURCE_MEM) - pcibios_fixup_resource(&dev->resource[i], - PCI_CONTROLLER(dev)->mem_offset); - } -} - /* Called by ACPI when it finds a new root bus. */ static struct pci_controller * -alloc_pci_controller(int seg) +alloc_pci_controller (int seg) { struct pci_controller *controller; @@ -153,8 +133,8 @@ return controller; } -struct pci_bus * -scan_root_bus(int bus, struct pci_ops *ops, void *sysdata) +static struct pci_bus * +scan_root_bus (int bus, struct pci_ops *ops, void *sysdata) { struct pci_bus *b; @@ -184,23 +164,185 @@ return b; } +static int +alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags) +{ + struct resource *res; + + res = kmalloc(sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + memset(res, 0, sizeof(*res)); + res->name = name; + res->start = start; + res->end = end; + res->flags = flags; + + if (request_resource(root, res)) + return -EBUSY; + + return 0; +} + +static u64 +add_io_space (struct acpi_resource_address64 *addr) +{ + u64 offset; + int sparse = 0; + int i; + + if (addr->address_translation_offset == 0) + return IO_SPACE_BASE(0); /* part of legacy IO space */ + + if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION) + sparse = 1; + + offset = (u64) ioremap(addr->address_translation_offset, 0); + for (i = 0; i < num_io_spaces; i++) + if (io_space[i].mmio_base == offset && + io_space[i].sparse == sparse) + return IO_SPACE_BASE(i); + + if (num_io_spaces == MAX_IO_SPACES) { + printk("Too many IO port spaces\n"); + return ~0; + } + + i = num_io_spaces++; + io_space[i].mmio_base = offset; + io_space[i].sparse = sparse; + + return IO_SPACE_BASE(i); +} + +static acpi_status +count_window (struct acpi_resource *resource, void *data) +{ + unsigned int *windows = (unsigned int *) data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = acpi_resource_to_address64(resource, &addr); + if (ACPI_SUCCESS(status)) + if (addr.resource_type == ACPI_MEMORY_RANGE || + addr.resource_type == ACPI_IO_RANGE) + (*windows)++; + + return AE_OK; +} + +struct pci_root_info { + struct pci_controller *controller; + char *name; +}; + +static acpi_status +add_window (struct acpi_resource *res, void *data) +{ + struct pci_root_info *info = (struct pci_root_info *) data; + struct pci_window *window; + struct acpi_resource_address64 addr; + acpi_status status; + unsigned long flags, offset = 0; + struct resource *root; + + status = acpi_resource_to_address64(res, &addr); + if (ACPI_SUCCESS(status)) { + if (addr.resource_type == ACPI_MEMORY_RANGE) { + flags = IORESOURCE_MEM; + root = &iomem_resource; + offset = addr.address_translation_offset; + } else if (addr.resource_type == ACPI_IO_RANGE) { + flags = IORESOURCE_IO; + root = &ioport_resource; + offset = add_io_space(&addr); + if (offset == ~0) + return AE_OK; + } else + return AE_OK; + + window = &info->controller->window[info->controller->windows++]; + window->resource.flags |= flags; + window->resource.start = addr.min_address_range; + window->resource.end = addr.max_address_range; + window->offset = offset; + + if (alloc_resource(info->name, root, addr.min_address_range + offset, + addr.max_address_range + offset, flags)) + printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n", + addr.min_address_range + offset, addr.max_address_range + offset, + root->name, info->name); + } + + return AE_OK; +} + struct pci_bus * -pcibios_scan_root(void *handle, int seg, int bus) +pcibios_scan_root (void *handle, int seg, int bus) { + struct pci_root_info info; struct pci_controller *controller; - u64 base, size, offset; + unsigned int windows = 0; + char *name; printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus); controller = alloc_pci_controller(seg); if (!controller) - return NULL; + goto out1; controller->acpi_handle = handle; - acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset); - controller->mem_offset = offset; + acpi_walk_resources(handle, METHOD_NAME__CRS, count_window, &windows); + controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL); + if (!controller->window) + goto out2; + + name = kmalloc(16, GFP_KERNEL); + if (!name) + goto out3; + + sprintf(name, "PCI Bus %02x:%02x", seg, bus); + info.controller = controller; + info.name = name; + acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info); return scan_root_bus(bus, pci_root_ops, controller); + +out3: + kfree(controller->window); +out2: + kfree(controller); +out1: + return NULL; +} + +void __init +pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus) +{ + struct pci_controller *controller = PCI_CONTROLLER(dev); + struct pci_window *window; + int i, j; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + if (!dev->resource[i].start) + continue; + +#define contains(win, res) ((res)->start >= (win)->start && \ + (res)->end <= (win)->end) + + for (j = 0; j < controller->windows; j++) { + window = &controller->window[j]; + if (((dev->resource[i].flags & IORESOURCE_MEM && + window->resource.flags & IORESOURCE_MEM) || + (dev->resource[i].flags & IORESOURCE_IO && + window->resource.flags & IORESOURCE_IO)) && + contains(&window->resource, &dev->resource[i])) { + dev->resource[i].start += window->offset; + dev->resource[i].end += window->offset; + } + } + } } /* diff -Nru a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c --- a/arch/ia64/sn/kernel/machvec.c Mon May 12 20:55:47 2003 +++ b/arch/ia64/sn/kernel/machvec.c Mon May 12 20:55:47 2003 @@ -33,9 +33,11 @@ #include #ifdef CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn1 +#define MACHVEC_PLATFORM_NAME sn1 +#define MACHVEC_PLATFORM_HEADER #else CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn2 +#define MACHVEC_PLATFORM_NAME sn2 +#define MACHVEC_PLATFORM_HEADER #else #error "unknown platform" #endif diff -Nru a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c --- a/arch/ia64/tools/print_offsets.c Mon May 12 20:55:48 2003 +++ b/arch/ia64/tools/print_offsets.c Mon May 12 20:55:48 2003 @@ -193,7 +193,7 @@ printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by " "arch/ia64/tools/print_offsets.\n *\n */\n\n"); - for (i = 0; i < sizeof (tab) / sizeof (tab[0]); ++i) + for (i = 0; i < (int) (sizeof (tab) / sizeof (tab[0])); ++i) { if (tab[i].name[0] == '\0') printf ("\n"); diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S --- a/arch/m68k/kernel/entry.S Mon May 12 20:55:44 2003 +++ b/arch/m68k/kernel/entry.S Mon May 12 20:55:44 2003 @@ -188,7 +188,7 @@ #if 0 -#if CONFIG_AMIGA +#ifdef CONFIG_AMIGA ami_inthandler: addql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT SAVE_ALL_INT diff -Nru a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c --- a/arch/m68k/sun3/prom/init.c Mon May 12 20:55:48 2003 +++ b/arch/m68k/sun3/prom/init.c Mon May 12 20:55:48 2003 @@ -32,7 +32,7 @@ void __init prom_init(struct linux_romvec *rp) { -#if CONFIG_AP1000 +#ifdef CONFIG_AP1000 extern struct linux_romvec *ap_prom_init(void); rp = ap_prom_init(); #endif diff -Nru a/arch/m68k/sun3/prom/printf.c b/arch/m68k/sun3/prom/printf.c --- a/arch/m68k/sun3/prom/printf.c Mon May 12 20:55:44 2003 +++ b/arch/m68k/sun3/prom/printf.c Mon May 12 20:55:44 2003 @@ -38,7 +38,7 @@ bptr = ppbuf; -#if CONFIG_AP1000 +#ifdef CONFIG_AP1000 ap_write(1,bptr,strlen(bptr)); #else diff -Nru a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S --- a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S Mon May 12 20:55:48 2003 +++ b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S Mon May 12 20:55:48 2003 @@ -93,7 +93,7 @@ move.l %d0, 0x180(%a1) /* Set PLL register */ nop -#if CONFIG_CLOCK_140MHz +#ifdef CONFIG_CLOCK_140MHz /* * Set initial clock frequency. This assumes M5249C3 board * is fitted with 11.2896MHz crystal. It will program the diff -Nru a/arch/mips/arc/misc.c b/arch/mips/arc/misc.c --- a/arch/mips/arc/misc.c Mon May 12 20:55:45 2003 +++ b/arch/mips/arc/misc.c Mon May 12 20:55:45 2003 @@ -19,7 +19,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif romvec->halt(); @@ -29,7 +29,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif romvec->pdown(); @@ -40,7 +40,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif romvec->restart(); @@ -50,7 +50,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif romvec->reboot(); @@ -60,7 +60,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif romvec->imode(); diff -Nru a/arch/mips/au1000/common/serial.c b/arch/mips/au1000/common/serial.c --- a/arch/mips/au1000/common/serial.c Mon May 12 20:55:45 2003 +++ b/arch/mips/au1000/common/serial.c Mon May 12 20:55:45 2003 @@ -2681,8 +2681,8 @@ (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", state->port, state->irq, uart_config[state->type].name); - tty_register_device(&serial_driver, state->line); - tty_register_device(&callout_driver, state->line); + tty_register_device(&serial_driver, state->line, NULL); + tty_register_device(&callout_driver, state->line, NULL); } return 0; } @@ -2769,8 +2769,8 @@ state->iomem_base ? "iomem" : "port", state->iomem_base ? (unsigned long)state->iomem_base : state->port, state->irq, uart_config[state->type].name); - tty_register_device(&serial_driver, state->line); - tty_register_device(&callout_driver, state->line); + tty_register_device(&serial_driver, state->line, NULL); + tty_register_device(&callout_driver, state->line, NULL); return state->line + SERIAL_DEV_OFFSET; } diff -Nru a/arch/mips64/arc/misc.c b/arch/mips64/arc/misc.c --- a/arch/mips64/arc/misc.c Mon May 12 20:55:47 2003 +++ b/arch/mips64/arc/misc.c Mon May 12 20:55:47 2003 @@ -29,7 +29,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif ARC_CALL0(halt); @@ -41,7 +41,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif ARC_CALL0(pdown); @@ -54,7 +54,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif ARC_CALL0(restart); @@ -66,7 +66,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif ARC_CALL0(reboot); @@ -78,7 +78,7 @@ { bc_disable(); cli(); -#if CONFIG_SCSI_SGIWD93 +#ifdef CONFIG_SCSI_SGIWD93 reset_wd33c93(sgiwd93_host); #endif ARC_CALL0(imode); diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c --- a/arch/ppc/kernel/process.c Mon May 12 20:55:46 2003 +++ b/arch/ppc/kernel/process.c Mon May 12 20:55:46 2003 @@ -524,7 +524,7 @@ while (count < 16 && sp > prev_sp && sp < stack_top && (sp & 3) == 0) { if (count == 0) { printk("Call trace:"); -#if CONFIG_KALLSYMS +#ifdef CONFIG_KALLSYMS printk("\n"); #endif } else { @@ -534,7 +534,7 @@ } else ret = *(unsigned long *)(sp + 4); printk(" [%08lx] ", ret); -#if CONFIG_KALLSYMS +#ifdef CONFIG_KALLSYMS print_symbol("%s", ret); printk("\n"); #endif diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c --- a/arch/ppc64/kernel/LparData.c Mon May 12 20:55:45 2003 +++ b/arch/ppc64/kernel/LparData.c Mon May 12 20:55:45 2003 @@ -61,7 +61,7 @@ 0xc8a5d9c4, /* desc = "HvRD" ebcdic */ sizeof(struct HvReleaseData), offsetof(struct naca_struct, xItVpdAreas), - (struct naca_struct *)(KERNELBASE+0x4000), /* 64-bit Naca address */ + (struct naca_struct *)(NACA_VIRT_ADDR), /* 64-bit Naca address */ 0x6000, /* offset of LparMap within loadarea (see head.S) */ 0, 1, /* tags inactive */ diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile --- a/arch/ppc64/kernel/Makefile Mon May 12 20:55:49 2003 +++ b/arch/ppc64/kernel/Makefile Mon May 12 20:55:49 2003 @@ -15,7 +15,7 @@ iSeries_IoMmTable.o iSeries_irq.o \ iSeries_VpdInfo.o XmPciLpEvent.o \ HvCall.o HvLpConfig.o LparData.o mf_proc.o \ - proc_pmc.o iSeries_setup.o ItLpQueue.o hvCall.o \ + iSeries_setup.o ItLpQueue.o hvCall.o \ mf.o HvLpEvent.o iSeries_proc.o obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ @@ -25,6 +25,7 @@ obj-y += open_pic.o xics.o pSeries_htab.o rtas.o \ chrp_setup.o i8259.o ras.o prom.o +obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o diff -Nru a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c --- a/arch/ppc64/kernel/align.c Mon May 12 20:55:49 2003 +++ b/arch/ppc64/kernel/align.c Mon May 12 20:55:49 2003 @@ -237,7 +237,7 @@ dsisr = regs->dsisr; /* Power4 doesn't set DSISR for an alignment interrupt */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) { + if (!cpu_alignexc_sets_dsisr()) { unsigned int real_instr; if (__get_user(real_instr, (unsigned int *)regs->nip)) return 0; @@ -309,6 +309,7 @@ /* Doing stfs, have to convert to single */ enable_kernel_fp(); cvt_df(¤t->thread.fpr[reg], (float *)&data.v[4], ¤t->thread.fpscr); + disable_kernel_fp(); } else data.dd = current->thread.fpr[reg]; @@ -342,6 +343,7 @@ /* Doing lfs, have to convert to double */ enable_kernel_fp(); cvt_fd((float *)&data.v[4], ¤t->thread.fpr[reg], ¤t->thread.fpscr); + disable_kernel_fp(); } else current->thread.fpr[reg] = data.dd; diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c --- a/arch/ppc64/kernel/asm-offsets.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/asm-offsets.c Mon May 12 20:55:47 2003 @@ -59,14 +59,14 @@ /* naca */ DEFINE(PACA, offsetof(struct naca_struct, paca)); - DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize)); + DEFINE(DCACHEL1LINESIZE, offsetof(struct systemcfg, dCacheL1LineSize)); DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize)); DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage)); - DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize)); + DEFINE(ICACHEL1LINESIZE, offsetof(struct systemcfg, iCacheL1LineSize)); DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize)); DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage)); DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size)); - DEFINE(PLATFORM, offsetof(struct naca_struct, platform)); + DEFINE(PLATFORM, offsetof(struct systemcfg, platform)); /* paca */ DEFINE(PACA_SIZE, sizeof(struct paca_struct)); diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c --- a/arch/ppc64/kernel/chrp_setup.c Mon May 12 20:55:44 2003 +++ b/arch/ppc64/kernel/chrp_setup.c Mon May 12 20:55:44 2003 @@ -263,6 +263,8 @@ char *os; static int display_character, set_indicator; static int max_width; + static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED; + static int pending_newline = 0; /* did last write end with unprinted newline? */ if (!rtas.base) return; @@ -278,34 +280,79 @@ display_character = rtas_token("display-character"); set_indicator = rtas_token("set-indicator"); } - if (display_character == RTAS_UNKNOWN_SERVICE) { - /* use hex display */ - if (set_indicator == RTAS_UNKNOWN_SERVICE) - return; - rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); + + if(display_character == RTAS_UNKNOWN_SERVICE) { + /* use hex display if available */ + if(set_indicator != RTAS_UNKNOWN_SERVICE) + rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); return; } - rtas_call(display_character, 1, 1, NULL, '\r'); + spin_lock(&progress_lock); + /* Last write ended with newline, but we didn't print it since + * it would just clear the bottom line of output. Print it now + * instead. + * + * If no newline is pending, print a CR to start output at the + * beginning of the line. + */ + if(pending_newline) { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + pending_newline = 0; + } else + rtas_call(display_character, 1, 1, NULL, '\r'); + width = max_width; os = s; - while ( *os ) - { - if ( (*os == '\n') || (*os == '\r') ) + while (*os) { + if(*os == '\n' || *os == '\r') { + /* Blank to end of line. */ + while(width-- > 0) + rtas_call(display_character, 1, 1, NULL, ' '); + + /* If newline is the last character, save it + * until next call to avoid bumping up the + * display output. + */ + if(*os == '\n' && !os[1]) { + pending_newline = 1; + spin_unlock(&progress_lock); + return; + } + + /* RTAS wants CR-LF, not just LF */ + + if(*os == '\n') { + rtas_call(display_character, 1, 1, NULL, '\r'); + rtas_call(display_character, 1, 1, NULL, '\n'); + } else { + /* CR might be used to re-draw a line, so we'll + * leave it alone and not add LF. + */ + rtas_call(display_character, 1, 1, NULL, *os); + } + width = max_width; - else + } else { width--; - rtas_call(display_character, 1, 1, NULL, *os++ ); + rtas_call(display_character, 1, 1, NULL, *os); + } + + os++; + /* if we overwrite the screen length */ - if ( width == 0 ) + if ( width <= 0 ) while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) os++; } - + /* Blank to end of line. */ while ( width-- > 0 ) rtas_call(display_character, 1, 1, NULL, ' ' ); + + spin_unlock(&progress_lock); } extern void setup_default_decr(void); diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S --- a/arch/ppc64/kernel/entry.S Mon May 12 20:55:44 2003 +++ b/arch/ppc64/kernel/entry.S Mon May 12 20:55:44 2003 @@ -225,10 +225,6 @@ bl .sys32_rt_sigreturn b 80f -_GLOBAL(ppc64_sigreturn) - bl .sys_sigreturn - b 80f - _GLOBAL(ppc64_rt_sigreturn) bl .sys_rt_sigreturn @@ -412,11 +408,6 @@ ld r4,GPR4(r1) ld r1,GPR1(r1) - /* - * What if we took an exception and stole this segment, we may - * fault on the above addresses and globber SRR0/1. Should check RI - * bit and repeat - Anton - */ rfid /* Note: this must change if we start using the TIF_NOTIFY_RESUME bit */ diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S --- a/arch/ppc64/kernel/head.S Mon May 12 20:55:46 2003 +++ b/arch/ppc64/kernel/head.S Mon May 12 20:55:46 2003 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -49,8 +51,9 @@ * 0x0100 - 0x2fff : pSeries Interrupt prologs * 0x3000 - 0x3fff : Interrupt support * 0x4000 - 0x4fff : NACA - * 0x5000 - 0x5fff : Initial segment table + * 0x5000 - 0x5fff : SystemCfg * 0x6000 : iSeries and common interrupt prologs + * 0x9000 - 0x9fff : Initial segment table */ /* @@ -123,6 +126,10 @@ * All of it must fit below the first exception vector at 0x100. */ _GLOBAL(__secondary_hold) + mfmsr r24 + ori r24,r24,MSR_RI + mtmsrd r24 /* RI on */ + /* Grab our linux cpu number */ mr r24,r3 @@ -362,11 +369,11 @@ STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint ) /* Space for the naca. Architected to be located at real address - * 0x4000. Various tools rely on this location being fixed. + * NACA_PHYS_ADDR. Various tools rely on this location being fixed. * The first dword of the naca is required by iSeries LPAR to * point to itVpdAreas. On pSeries native, this value is not used. */ - . = 0x4000 + . = NACA_PHYS_ADDR .globl __end_interrupts .globl __start_naca __end_interrupts: @@ -380,21 +387,14 @@ .llong 0x0 .llong paca - /* - * Space for the initial segment table - * For LPAR, the hypervisor must fill in at least one entry - * before we get control (with relocate on) - */ - . = 0x5000 + . = SYSTEMCFG_PHYS_ADDR .globl __end_naca - .globl __start_stab + .globl __start_systemcfg __end_naca: -__start_stab: - - - . = 0x6000 - .globl __end_stab -__end_stab: +__start_systemcfg: + . = (SYSTEMCFG_PHYS_ADDR + PAGE_SIZE) + .globl __end_systemcfg +__end_systemcfg: #ifdef CONFIG_PPC_ISERIES /* @@ -408,7 +408,7 @@ .llong 1 /* # ESIDs to be mapped by hypervisor */ .llong 1 /* # memory ranges to be mapped by hypervisor */ - .llong 5 /* Page # of segment table within load area */ + .llong STAB0_PAGE /* Page # of segment table within load area */ .llong 0 /* Reserved */ .llong 0 /* Reserved */ .llong 0 /* Reserved */ @@ -529,6 +529,20 @@ MachineCheck_FWNMI: EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common) + /* + * Space for the initial segment table + * For LPAR, the hypervisor must fill in at least one entry + * before we get control (with relocate on) + */ + . = STAB0_PHYS_ADDR + .globl __start_stab +__start_stab: + + . = (STAB0_PHYS_ADDR + PAGE_SIZE) + .globl __end_stab +__end_stab: + + /*** Common interrupt handlers ***/ STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException ) @@ -782,11 +796,16 @@ FPUnavailable_common: EXCEPTION_PROLOG_COMMON bne .load_up_fpu /* if from user, just load it up */ - li r20,0 + addi r3,r1,STACK_FRAME_OVERHEAD +#ifdef DO_SOFT_DISABLE + ld r20,SOFTE(r1) +#else + rldicl r20,r23,49,63 /* copy EE bit from saved MSR */ +#endif li r6,0x800 - bl .save_remaining_regs /* if from kernel, take a trap */ - bl .KernelFP - b .ret_from_except + bl .save_remaining_regs + bl .KernelFPUnavailableException + BUG_OPCODE .globl SystemCall_common SystemCall_common: @@ -1032,7 +1051,7 @@ slbmfee r23,r22 rldicl r23,r23,37,63 cmpwi r23,0 - beq 3f /* Found an invalid entry */ + beq 4f /* Found an invalid entry */ addi r22,r22,1 cmpldi r22,64 @@ -1041,18 +1060,37 @@ /* No free entry - just take the next entry, round-robin */ /* XXX we should get the number of SLB entries from the naca */ SLB_NUM_ENTRIES = 64 - mfspr r21,SPRG3 +2: mfspr r21,SPRG3 ld r22,PACASTABRR(r21) addi r23,r22,1 cmpdi r23,SLB_NUM_ENTRIES - blt 2f + blt 3f li r23,1 -2: std r23,PACASTABRR(r21) +3: std r23,PACASTABRR(r21) /* r20 = vsid, r22 = entry */ -3: + + /* + * Never cast out the segment for our kernel stack. Since we + * dont invalidate the ERAT we could have a valid translation + * for the kernel stack during the first part of exception exit + * which gets invalidated due to a tlbie from another cpu at a + * non recoverable point (after setting srr0/1) - Anton + */ + slbmfee r23,r22 + srdi r23,r23,28 + /* + * This is incorrect (r1 is not the kernel stack) if we entered + * from userspace but there is no critical window from userspace + * so this should be OK. Also if we cast out the userspace stack + * segment while in userspace we will fault it straight back in. + */ + srdi r21,r1,28 + cmpd r21,r23 + beq- 2b + /* Put together the vsid portion of the entry. */ - li r21,0 +4: li r21,0 rldimi r21,r20,12,0 ori r20,r21,1024 ori r20,r20,128 /* set class bit for kernel region */ @@ -1060,17 +1098,6 @@ ori r20,r20,256 /* map kernel region with large ptes */ #endif - /* - * XXX we should handle this in the exception exit path in 2.5, - * we need to make this path quick - Anton - */ - /* Invalidate the old entry */ - slbmfee r21,r22 - lis r23,-2049 - ori r23,r23,65535 - and r21,r21,r23 - slbie r21 - /* Put together the esid portion of the entry. */ mfspr r21,DAR /* Get the new esid */ rldicl r21,r21,36,28 /* Permits a full 36b of ESID */ @@ -1252,9 +1279,12 @@ addi r2,r2,0x4000 addi r2,r2,0x4000 + LOADADDR(r9,systemcfg) + SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR) + std r4,0(r9) /* set the systemcfg pointer */ + LOADADDR(r9,naca) - SET_REG_TO_CONST(r4, KERNELBASE) - addi r4,r4,0x4000 + SET_REG_TO_CONST(r4, NACA_VIRT_ADDR) std r4,0(r9) /* set the naca pointer */ /* Get the pointer to the segment table */ @@ -1285,13 +1315,18 @@ /* Relocate the TOC from a virt addr to a real addr */ sub r2,r2,r3 + /* setup the systemcfg pointer which is needed by prom_init */ + LOADADDR(r9,systemcfg) + sub r9,r9,r3 /* addr of the variable systemcfg */ + SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR) + sub r4,r4,r3 + std r4,0(r9) /* set the value of systemcfg */ + /* setup the naca pointer which is needed by prom_init */ LOADADDR(r9,naca) sub r9,r9,r3 /* addr of the variable naca */ - - SET_REG_TO_CONST(r4, KERNELBASE) + SET_REG_TO_CONST(r4, NACA_VIRT_ADDR) sub r4,r4,r3 - addi r4,r4,0x4000 std r4,0(r9) /* set the value of naca */ /* DRENG / PPPBBB Fix the following comment!!! -Peter */ @@ -1410,11 +1445,13 @@ copy_to_here: /* + * load_up_fpu(unused, unused, tsk) * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. * On SMP we know the fpu is free, since we give it up every - * switch. -- Cort + * switch (ie, no lazy save of the FP registers). + * On entry: r13 == 'current' && last_task_used_math != 'current' */ _STATIC(load_up_fpu) mfmsr r5 /* grab the current MSR */ @@ -1432,27 +1469,30 @@ ld r4,last_task_used_math@l(r3) cmpi 0,r4,0 beq 1f - addi r4,r4,THREAD /* want THREAD of last_task_used_math */ + /* Save FP state to last_task_used_math's THREAD struct */ + addi r4,r4,THREAD SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,THREAD_FPSCR(r4) + /* Disable FP for last_task_used_math */ ld r5,PT_REGS(r4) ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r20,MSR_FP|MSR_FE0|MSR_FE1 - andc r4,r4,r20 /* disable FP for previous task */ + andc r4,r4,r20 std r4,_MSR-STACK_FRAME_OVERHEAD(r5) 1: #endif /* CONFIG_SMP */ /* enable use of FP after return */ ld r4,PACACURRENT(r13) addi r5,r4,THREAD /* Get THREAD */ - lwz r4,THREAD_FPEXC_MODE(r5) + ld r4,THREAD_FPEXC_MODE(r5) ori r23,r23,MSR_FP or r23,r23,r4 lfd fr0,THREAD_FPSCR(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) #ifndef CONFIG_SMP + /* Update last_task_used_math to 'current' */ subi r4,r5,THREAD /* Back to 'current' */ std r4,last_task_used_math@l(r3) #endif /* CONFIG_SMP */ @@ -1460,19 +1500,16 @@ b fast_exception_return /* - * FP unavailable trap from kernel - print a message, but let - * the task use FP in the kernel until it returns to user mode. + * disable_kernel_fp() + * Disable the FPU. */ -_GLOBAL(KernelFP) - ld r3,_MSR(r1) - ori r3,r3,MSR_FP - std r3,_MSR(r1) /* enable use of FP after return */ - LOADADDR(r3,86f) - ld r4,PACACURRENT(r13) /* current */ - ld r5,_NIP(r1) - b .ret_from_except -86: .string "floating point used in kernel (task=%p, pc=%x)\n" - .align 4 +_GLOBAL(disable_kernel_fp) + mfmsr r3 + rldicl r0,r3,(63-MSR_FP_LG),1 + rldicl r3,r0,(MSR_FP_LG+1),0 + mtmsrd r3 /* disable use of fpu now */ + isync + blr /* * giveup_fpu(tsk) @@ -1562,8 +1599,8 @@ sc /* HvCall_setASR */ #else /* set the ASR */ - addi r3,0,0x4000 /* r3 = ptr to naca */ - lhz r3,PLATFORM(r3) /* r3 = platform flags */ + li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR bne 98f mfspr r3,PVR @@ -1642,10 +1679,20 @@ bl .reloc_offset mr r26,r3 + mfmsr r6 + ori r6,r6,MSR_RI + mtmsrd r6 /* RI on */ + + /* setup the systemcfg pointer which is needed by *tab_initialize */ + LOADADDR(r6,systemcfg) + sub r6,r6,r26 /* addr of the variable systemcfg */ + li r27,SYSTEMCFG_PHYS_ADDR + std r27,0(r6) /* set the value of systemcfg */ + /* setup the naca pointer which is needed by *tab_initialize */ LOADADDR(r6,naca) sub r6,r6,r26 /* addr of the variable naca */ - li r27,0x4000 + li r27,NACA_PHYS_ADDR std r27,0(r6) /* set the value of naca */ #ifdef CONFIG_HMT @@ -1709,15 +1756,12 @@ sub r13,r13,r26 /* convert to physical addr */ mtspr SPRG3,r13 /* PPPBBB: Temp... -Peter */ - li r3,0x5000 - std r3,PACASTABREAL(r13) - LOADADDR(r24, __start_stab) - std r24,PACASTABVIRT(r13) + ld r3,PACASTABREAL(r13) ori r4,r3,1 /* turn on valid bit */ /* set the ASR */ - addi r3,0,0x4000 /* r3 = ptr to naca */ - lhz r3,PLATFORM(r3) /* r3 = platform flags */ + li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES_LPAR bne 98f mfspr r3,PVR @@ -1741,8 +1785,8 @@ bl .stab_initialize bl .htab_initialize - addi r3,0,0x4000 /* r3 = ptr to naca */ - lhz r3,PLATFORM(r3) /* r3 = platform flags */ + li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ + lwz r3,PLATFORM(r3) /* r3 = platform flags */ cmpldi r3,PLATFORM_PSERIES bne 98f LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ @@ -1791,11 +1835,14 @@ addi r2,r2,0x4000 addi r2,r2,0x4000 - /* setup the naca pointer */ - LOADADDR(r9,naca) + /* setup the systemcfg pointer */ + LOADADDR(r9,systemcfg) + SET_REG_TO_CONST(r8, SYSTEMCFG_VIRT_ADDR) + std r8,0(r9) - SET_REG_TO_CONST(r8, KERNELBASE) - addi r8,r8,0x4000 + /* setup the naca pointer */ + LOADADDR(r9,naca) + SET_REG_TO_CONST(r8, NACA_VIRT_ADDR) std r8,0(r9) /* set the value of the naca ptr */ LOADADDR(r26, boot_cpuid) @@ -1946,7 +1993,7 @@ hardware_int_paca0: .space 8*4096 -/* 1 page segment table per cpu (max 48) */ +/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */ .globl stab_array stab_array: .space 4096 * 48 diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c --- a/arch/ppc64/kernel/htab.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/htab.c Mon May 12 20:55:47 2003 @@ -101,7 +101,7 @@ hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP); - if (naca->platform == PLATFORM_PSERIES_LPAR) + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) ret = pSeries_lpar_hpte_insert(hpteg, va, (unsigned long)__v2a(addr) >> PAGE_SHIFT, 0, mode, 1, large); @@ -140,7 +140,7 @@ htab_data.htab_num_ptegs = pteg_count; htab_data.htab_hash_mask = pteg_count - 1; - if (naca->platform == PLATFORM_PSERIES) { + if (systemcfg->platform == PLATFORM_PSERIES) { /* Find storage for the HPT. Must be contiguous in * the absolute address space. */ @@ -165,15 +165,15 @@ mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; /* XXX we currently map kernel text rw, should fix this */ - if (cpu_has_largepage() && naca->physicalMemorySize > 256*MB) { + if (cpu_has_largepage() && systemcfg->physicalMemorySize > 256*MB) { create_pte_mapping((unsigned long)KERNELBASE, KERNELBASE + 256*MB, mode_rw, 0); create_pte_mapping((unsigned long)KERNELBASE + 256*MB, - KERNELBASE + (naca->physicalMemorySize), + KERNELBASE + (systemcfg->physicalMemorySize), mode_rw, 1); } else { create_pte_mapping((unsigned long)KERNELBASE, - KERNELBASE+(naca->physicalMemorySize), + KERNELBASE+(systemcfg->physicalMemorySize), mode_rw, 0); } } diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c --- a/arch/ppc64/kernel/iSeries_setup.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/iSeries_setup.c Mon May 12 20:55:48 2003 @@ -561,13 +561,13 @@ * which should be equal to * nextPhysChunk */ - naca->physicalMemorySize = chunk_to_addr(nextPhysChunk); + systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk); /* Bolt kernel mappings for all of memory */ - iSeries_bolt_kernel( 0, naca->physicalMemorySize ); + iSeries_bolt_kernel( 0, systemcfg->physicalMemorySize ); lmb_init(); - lmb_add( 0, naca->physicalMemorySize ); + lmb_add( 0, systemcfg->physicalMemorySize ); lmb_analyze(); /* ?? */ lmb_reserve( 0, __pa(klimit)); @@ -584,29 +584,28 @@ static void __init setup_iSeries_cache_sizes(void) { - unsigned i,n; - unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex; + unsigned int i, n; + unsigned int procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex; + + systemcfg->iCacheL1Size = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024; + systemcfg->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize; + systemcfg->dCacheL1Size = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024; + systemcfg->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize; + naca->iCacheL1LinesPerPage = PAGE_SIZE / systemcfg->iCacheL1LineSize; + naca->dCacheL1LinesPerPage = PAGE_SIZE / systemcfg->dCacheL1LineSize; - naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize; - naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize; - naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize; - naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize; - i = naca->iCacheL1LineSize; + i = systemcfg->iCacheL1LineSize; n = 0; while ((i=(i/2))) ++n; naca->iCacheL1LogLineSize = n; - i = naca->dCacheL1LineSize; + + i = systemcfg->dCacheL1LineSize; n = 0; while ((i=(i/2))) ++n; naca->dCacheL1LogLineSize = n; - printk( "D-cache line size = %d (log = %d)\n", - (unsigned)naca->dCacheL1LineSize, - (unsigned)naca->dCacheL1LogLineSize ); - printk( "I-cache line size = %d (log = %d)\n", - (unsigned)naca->iCacheL1LineSize, - (unsigned)naca->iCacheL1LogLineSize ); - + printk( "D-cache line size = %d\n", (unsigned int)systemcfg->dCacheL1LineSize); + printk( "I-cache line size = %d\n", (unsigned int)systemcfg->iCacheL1LineSize); } /* @@ -648,6 +647,11 @@ void * eventStack; unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex; + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + systemcfg->version.major = SYSTEMCFG_MAJOR; + systemcfg->version.minor = SYSTEMCFG_MINOR; + /* Setup the Lp Event Queue */ /* Allocate a page for the Event Stack @@ -696,8 +700,8 @@ printk("Time base frequency = %lu.%02lu\n", tbFreqMhz, tbFreqMhzHundreths ); - printk("Processor version = %x\n", - xIoHriProcessorVpd[procIx].xPVR ); + systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR; + printk("Processor version = %x\n", systemcfg->processor); } @@ -726,9 +730,9 @@ seq_printf(m,"time base\t: %lu.%02luMHz\n", tbFreqMhz, tbFreqMhzHundreths ); seq_printf(m,"i-cache\t\t: %d\n", - naca->iCacheL1LineSize); + systemcfg->iCacheL1LineSize); seq_printf(m,"d-cache\t\t: %d\n", - naca->dCacheL1LineSize); + systemcfg->dCacheL1LineSize); } diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c --- a/arch/ppc64/kernel/ioctl32.c Mon May 12 20:55:49 2003 +++ b/arch/ppc64/kernel/ioctl32.c Mon May 12 20:55:49 2003 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -577,6 +579,17 @@ len += sizeof(struct ethtool_regs); break; } + case ETHTOOL_GEEPROM: + case ETHTOOL_SEEPROM: { + struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data); + /* darned variable size arguments */ + if (get_user(len, (u32 *)&promaddr->len)) { + err = -EFAULT; + goto out; + } + len += sizeof(struct ethtool_eeprom); + break; + } case ETHTOOL_GSET: case ETHTOOL_SSET: len = sizeof(struct ethtool_cmd); break; default: @@ -659,6 +672,47 @@ return err; } +static inline void *alloc_user_space(long len) +{ + struct pt_regs *regs = current->thread.regs; + unsigned long usp = regs->gpr[1]; + + /* + * We cant access below the stack pointer in the 32bit ABI and + * can access 288 bytes in the 64bit ABI + */ + if (!(test_thread_flag(TIF_32BIT))) + usp -= 288; + + return (void *) (usp - len); +} + +int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq *u_ifreq64; + struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg; + char tmp_buf[IFNAMSIZ]; + void __user *data64; + u32 data32; + + if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), + IFNAMSIZ)) + return -EFAULT; + if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + return -EFAULT; + data64 = A(data32); + + u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64)); + + /* Don't check these user accesses, just let that get trapped + * in the ioctl handler instead. + */ + copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); + __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); + + return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); +} + static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifreq ifr; @@ -3643,670 +3697,32 @@ #define BNEPGETCONNLIST _IOR('B', 210, int) #define BNEPGETCONNINFO _IOR('B', 211, int) -struct ioctl_trans { - unsigned long cmd; - unsigned long handler; - unsigned long next; -}; - -#define COMPATIBLE_IOCTL(cmd) { cmd, (unsigned long)sys_ioctl, 0 }, +#define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, 0 }, +#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl) -#define HANDLE_IOCTL(cmd,handler) { cmd, (unsigned long)handler, 0 }, +#define IOCTL_TABLE_START \ + struct ioctl_trans ioctl_start[] = { +#define IOCTL_TABLE_END \ + }; struct ioctl_trans ioctl_end[0]; #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) -static struct ioctl_trans ioctl_translations[] = { - /* List here explicitly which ioctl's need translation, - * all others default to calling sys_ioctl(). - */ -/* Big T */ -COMPATIBLE_IOCTL(TCGETA) -COMPATIBLE_IOCTL(TCSETA) -COMPATIBLE_IOCTL(TCSETAW) -COMPATIBLE_IOCTL(TCSETAF) -COMPATIBLE_IOCTL(TCSBRK) +IOCTL_TABLE_START +#include COMPATIBLE_IOCTL(TCSBRKP) -COMPATIBLE_IOCTL(TCXONC) -COMPATIBLE_IOCTL(TCFLSH) -COMPATIBLE_IOCTL(TCGETS) -COMPATIBLE_IOCTL(TCSETS) -COMPATIBLE_IOCTL(TCSETSW) -COMPATIBLE_IOCTL(TCSETSF) -COMPATIBLE_IOCTL(TIOCLINUX) COMPATIBLE_IOCTL(TIOCSTART) COMPATIBLE_IOCTL(TIOCSTOP) -/* Little t */ -COMPATIBLE_IOCTL(TIOCGETD) -COMPATIBLE_IOCTL(TIOCSETD) -COMPATIBLE_IOCTL(TIOCEXCL) -COMPATIBLE_IOCTL(TIOCNXCL) -COMPATIBLE_IOCTL(TIOCCONS) -COMPATIBLE_IOCTL(TIOCGSOFTCAR) -COMPATIBLE_IOCTL(TIOCSSOFTCAR) -COMPATIBLE_IOCTL(TIOCSWINSZ) -COMPATIBLE_IOCTL(TIOCGWINSZ) -COMPATIBLE_IOCTL(TIOCMGET) -COMPATIBLE_IOCTL(TIOCMBIC) -COMPATIBLE_IOCTL(TIOCMBIS) -COMPATIBLE_IOCTL(TIOCMSET) -COMPATIBLE_IOCTL(TIOCPKT) -COMPATIBLE_IOCTL(TIOCNOTTY) -COMPATIBLE_IOCTL(TIOCSTI) -COMPATIBLE_IOCTL(TIOCOUTQ) -COMPATIBLE_IOCTL(TIOCSPGRP) -COMPATIBLE_IOCTL(TIOCGPGRP) -COMPATIBLE_IOCTL(TIOCSCTTY) -COMPATIBLE_IOCTL(TIOCGPTN) -COMPATIBLE_IOCTL(TIOCSPTLCK) COMPATIBLE_IOCTL(TIOCGSERIAL) COMPATIBLE_IOCTL(TIOCSSERIAL) -COMPATIBLE_IOCTL(TIOCSERGETLSR) COMPATIBLE_IOCTL(TIOCSLTC) -/* Big F */ -COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO) -COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO) -COMPATIBLE_IOCTL(FBIOPAN_DISPLAY) -COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP) -COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP) #if 0 COMPATIBLE_IOCTL(FBIOBLANK) #endif -/* Little f */ -COMPATIBLE_IOCTL(FIOCLEX) -COMPATIBLE_IOCTL(FIONCLEX) -COMPATIBLE_IOCTL(FIOASYNC) -COMPATIBLE_IOCTL(FIONBIO) -COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ -/* 0x00 */ -COMPATIBLE_IOCTL(FIBMAP) -COMPATIBLE_IOCTL(FIGETBSZ) -/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. - * Some need translations, these do not. - */ -COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) -COMPATIBLE_IOCTL(HDIO_SET_DMA) -COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR) -COMPATIBLE_IOCTL(HDIO_SET_NOWERR) -COMPATIBLE_IOCTL(HDIO_SET_32BIT) -COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT) -COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) -COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE) -COMPATIBLE_IOCTL(HDIO_SET_NICE) -/* 0x02 -- Floppy ioctls */ -COMPATIBLE_IOCTL(FDMSGON) -COMPATIBLE_IOCTL(FDMSGOFF) -COMPATIBLE_IOCTL(FDSETEMSGTRESH) -COMPATIBLE_IOCTL(FDFLUSH) -COMPATIBLE_IOCTL(FDWERRORCLR) -COMPATIBLE_IOCTL(FDSETMAXERRS) -COMPATIBLE_IOCTL(FDGETMAXERRS) -COMPATIBLE_IOCTL(FDGETDRVTYP) -COMPATIBLE_IOCTL(FDEJECT) -COMPATIBLE_IOCTL(FDCLRPRM) -COMPATIBLE_IOCTL(FDFMTBEG) -COMPATIBLE_IOCTL(FDFMTEND) -COMPATIBLE_IOCTL(FDRESET) -COMPATIBLE_IOCTL(FDTWADDLE) -COMPATIBLE_IOCTL(FDFMTTRK) -COMPATIBLE_IOCTL(FDRAWCMD) -/* 0x12 */ -COMPATIBLE_IOCTL(BLKROSET) -COMPATIBLE_IOCTL(BLKROGET) -COMPATIBLE_IOCTL(BLKRRPART) -COMPATIBLE_IOCTL(BLKFLSBUF) -COMPATIBLE_IOCTL(BLKSECTSET) -COMPATIBLE_IOCTL(BLKSSZGET) -COMPATIBLE_IOCTL(BLKRASET) -COMPATIBLE_IOCTL(BLKFRASET) -/* RAID */ -COMPATIBLE_IOCTL(RAID_VERSION) -COMPATIBLE_IOCTL(GET_ARRAY_INFO) -COMPATIBLE_IOCTL(GET_DISK_INFO) -COMPATIBLE_IOCTL(PRINT_RAID_DEBUG) -COMPATIBLE_IOCTL(CLEAR_ARRAY) -COMPATIBLE_IOCTL(ADD_NEW_DISK) -COMPATIBLE_IOCTL(HOT_REMOVE_DISK) -COMPATIBLE_IOCTL(SET_ARRAY_INFO) -COMPATIBLE_IOCTL(SET_DISK_INFO) -COMPATIBLE_IOCTL(WRITE_RAID_INFO) -COMPATIBLE_IOCTL(UNPROTECT_ARRAY) -COMPATIBLE_IOCTL(PROTECT_ARRAY) -COMPATIBLE_IOCTL(HOT_ADD_DISK) -COMPATIBLE_IOCTL(SET_DISK_FAULTY) -COMPATIBLE_IOCTL(RUN_ARRAY) -COMPATIBLE_IOCTL(START_ARRAY) -COMPATIBLE_IOCTL(STOP_ARRAY) -COMPATIBLE_IOCTL(STOP_ARRAY_RO) -COMPATIBLE_IOCTL(RESTART_ARRAY_RW) -/* Big K */ -COMPATIBLE_IOCTL(PIO_FONT) -COMPATIBLE_IOCTL(GIO_FONT) -COMPATIBLE_IOCTL(KDSIGACCEPT) -COMPATIBLE_IOCTL(KDGETKEYCODE) -COMPATIBLE_IOCTL(KDSETKEYCODE) -COMPATIBLE_IOCTL(KIOCSOUND) -COMPATIBLE_IOCTL(KDMKTONE) -COMPATIBLE_IOCTL(KDGKBTYPE) -COMPATIBLE_IOCTL(KDSETMODE) -COMPATIBLE_IOCTL(KDGETMODE) -COMPATIBLE_IOCTL(KDSKBMODE) -COMPATIBLE_IOCTL(KDGKBMODE) -COMPATIBLE_IOCTL(KDSKBMETA) -COMPATIBLE_IOCTL(KDGKBMETA) -COMPATIBLE_IOCTL(KDGKBENT) -COMPATIBLE_IOCTL(KDSKBENT) -COMPATIBLE_IOCTL(KDGKBSENT) -COMPATIBLE_IOCTL(KDSKBSENT) -COMPATIBLE_IOCTL(KDGKBDIACR) -COMPATIBLE_IOCTL(KDKBDREP) -COMPATIBLE_IOCTL(KDSKBDIACR) -COMPATIBLE_IOCTL(KDGKBLED) -COMPATIBLE_IOCTL(KDSKBLED) -COMPATIBLE_IOCTL(KDGETLED) -COMPATIBLE_IOCTL(KDSETLED) -COMPATIBLE_IOCTL(GIO_SCRNMAP) -COMPATIBLE_IOCTL(PIO_SCRNMAP) -COMPATIBLE_IOCTL(GIO_UNISCRNMAP) -COMPATIBLE_IOCTL(PIO_UNISCRNMAP) -COMPATIBLE_IOCTL(PIO_FONTRESET) -COMPATIBLE_IOCTL(PIO_UNIMAPCLR) -/* Big S */ -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN) -COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST) -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK) -COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK) -COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY) -COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE) -COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE) -COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER) -COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) -/* Big T */ -COMPATIBLE_IOCTL(TUNSETNOCSUM) -COMPATIBLE_IOCTL(TUNSETDEBUG) -COMPATIBLE_IOCTL(TUNSETIFF) -COMPATIBLE_IOCTL(TUNSETPERSIST) -COMPATIBLE_IOCTL(TUNSETOWNER) -/* Big V */ -COMPATIBLE_IOCTL(VT_SETMODE) -COMPATIBLE_IOCTL(VT_GETMODE) -COMPATIBLE_IOCTL(VT_GETSTATE) -COMPATIBLE_IOCTL(VT_OPENQRY) -COMPATIBLE_IOCTL(VT_ACTIVATE) -COMPATIBLE_IOCTL(VT_WAITACTIVE) -COMPATIBLE_IOCTL(VT_RELDISP) -COMPATIBLE_IOCTL(VT_DISALLOCATE) -COMPATIBLE_IOCTL(VT_RESIZE) -COMPATIBLE_IOCTL(VT_RESIZEX) -COMPATIBLE_IOCTL(VT_LOCKSWITCH) -COMPATIBLE_IOCTL(VT_UNLOCKSWITCH) -/* Little v, the video4linux ioctls */ -COMPATIBLE_IOCTL(VIDIOCGCAP) -COMPATIBLE_IOCTL(VIDIOCGCHAN) -COMPATIBLE_IOCTL(VIDIOCSCHAN) -COMPATIBLE_IOCTL(VIDIOCGPICT) -COMPATIBLE_IOCTL(VIDIOCSPICT) -COMPATIBLE_IOCTL(VIDIOCCAPTURE) -COMPATIBLE_IOCTL(VIDIOCKEY) -COMPATIBLE_IOCTL(VIDIOCGAUDIO) -COMPATIBLE_IOCTL(VIDIOCSAUDIO) -COMPATIBLE_IOCTL(VIDIOCSYNC) -COMPATIBLE_IOCTL(VIDIOCMCAPTURE) -COMPATIBLE_IOCTL(VIDIOCGMBUF) -COMPATIBLE_IOCTL(VIDIOCGUNIT) -COMPATIBLE_IOCTL(VIDIOCGCAPTURE) -COMPATIBLE_IOCTL(VIDIOCSCAPTURE) -/* BTTV specific... */ -COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256])) -COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256])) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)) -COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */ -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)) -COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)) /* Little p (/dev/rtc, /dev/envctrl, etc.) */ COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ -COMPATIBLE_IOCTL(RTC_AIE_ON) -COMPATIBLE_IOCTL(RTC_AIE_OFF) -COMPATIBLE_IOCTL(RTC_UIE_ON) -COMPATIBLE_IOCTL(RTC_UIE_OFF) -COMPATIBLE_IOCTL(RTC_PIE_ON) -COMPATIBLE_IOCTL(RTC_PIE_OFF) -COMPATIBLE_IOCTL(RTC_WIE_ON) -COMPATIBLE_IOCTL(RTC_WIE_OFF) -COMPATIBLE_IOCTL(RTC_ALM_SET) -COMPATIBLE_IOCTL(RTC_ALM_READ) -COMPATIBLE_IOCTL(RTC_RD_TIME) -COMPATIBLE_IOCTL(RTC_SET_TIME) -COMPATIBLE_IOCTL(RTC_WKALM_SET) -COMPATIBLE_IOCTL(RTC_WKALM_RD) -/* Little m */ -COMPATIBLE_IOCTL(MTIOCTOP) -/* Socket level stuff */ -COMPATIBLE_IOCTL(FIOSETOWN) -COMPATIBLE_IOCTL(SIOCSPGRP) -COMPATIBLE_IOCTL(FIOGETOWN) -COMPATIBLE_IOCTL(SIOCGPGRP) -COMPATIBLE_IOCTL(SIOCATMARK) -COMPATIBLE_IOCTL(SIOCSIFLINK) -COMPATIBLE_IOCTL(SIOCSIFENCAP) -COMPATIBLE_IOCTL(SIOCGIFENCAP) -COMPATIBLE_IOCTL(SIOCSIFBR) -COMPATIBLE_IOCTL(SIOCGIFBR) -COMPATIBLE_IOCTL(SIOCSARP) -COMPATIBLE_IOCTL(SIOCGARP) -COMPATIBLE_IOCTL(SIOCDARP) -COMPATIBLE_IOCTL(SIOCSRARP) -COMPATIBLE_IOCTL(SIOCGRARP) -COMPATIBLE_IOCTL(SIOCDRARP) -COMPATIBLE_IOCTL(SIOCADDDLCI) -COMPATIBLE_IOCTL(SIOCDELDLCI) -COMPATIBLE_IOCTL(SIOCGMIIPHY) -COMPATIBLE_IOCTL(SIOCGMIIREG) -COMPATIBLE_IOCTL(SIOCSMIIREG) -COMPATIBLE_IOCTL(SIOCGIFVLAN) -COMPATIBLE_IOCTL(SIOCSIFVLAN) -/* SG stuff */ -COMPATIBLE_IOCTL(SG_SET_TIMEOUT) -COMPATIBLE_IOCTL(SG_GET_TIMEOUT) -COMPATIBLE_IOCTL(SG_EMULATED_HOST) -COMPATIBLE_IOCTL(SG_SET_TRANSFORM) -COMPATIBLE_IOCTL(SG_GET_TRANSFORM) -COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE) -COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE) -COMPATIBLE_IOCTL(SG_GET_SCSI_ID) -COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA) -COMPATIBLE_IOCTL(SG_GET_LOW_DMA) -COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID) -COMPATIBLE_IOCTL(SG_GET_PACK_ID) -COMPATIBLE_IOCTL(SG_GET_NUM_WAITING) -COMPATIBLE_IOCTL(SG_SET_DEBUG) -COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE) -COMPATIBLE_IOCTL(SG_GET_COMMAND_Q) -COMPATIBLE_IOCTL(SG_SET_COMMAND_Q) -COMPATIBLE_IOCTL(SG_GET_VERSION_NUM) -COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN) -COMPATIBLE_IOCTL(SG_SCSI_RESET) -COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE) -COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN) -COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN) -/* PPP stuff */ -COMPATIBLE_IOCTL(PPPIOCGFLAGS) -COMPATIBLE_IOCTL(PPPIOCSFLAGS) -COMPATIBLE_IOCTL(PPPIOCGASYNCMAP) -COMPATIBLE_IOCTL(PPPIOCSASYNCMAP) -COMPATIBLE_IOCTL(PPPIOCGUNIT) -COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP) -COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP) -COMPATIBLE_IOCTL(PPPIOCGMRU) -COMPATIBLE_IOCTL(PPPIOCSMRU) -COMPATIBLE_IOCTL(PPPIOCSMAXCID) -COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP) -COMPATIBLE_IOCTL(LPGETSTATUS) -COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP) -COMPATIBLE_IOCTL(PPPIOCXFERUNIT) -COMPATIBLE_IOCTL(PPPIOCGNPMODE) -COMPATIBLE_IOCTL(PPPIOCSNPMODE) -COMPATIBLE_IOCTL(PPPIOCGDEBUG) -COMPATIBLE_IOCTL(PPPIOCSDEBUG) -COMPATIBLE_IOCTL(PPPIOCNEWUNIT) -COMPATIBLE_IOCTL(PPPIOCATTACH) -COMPATIBLE_IOCTL(PPPIOCDETACH) -COMPATIBLE_IOCTL(PPPIOCSMRRU) -COMPATIBLE_IOCTL(PPPIOCCONNECT) -COMPATIBLE_IOCTL(PPPIOCDISCONN) -COMPATIBLE_IOCTL(PPPIOCATTCHAN) -COMPATIBLE_IOCTL(PPPIOCGCHAN) -/* PPPOX */ -COMPATIBLE_IOCTL(PPPOEIOCSFWD) -COMPATIBLE_IOCTL(PPPOEIOCDFWD) -/* CDROM stuff */ -COMPATIBLE_IOCTL(CDROMPAUSE) -COMPATIBLE_IOCTL(CDROMRESUME) -COMPATIBLE_IOCTL(CDROMPLAYMSF) -COMPATIBLE_IOCTL(CDROMPLAYTRKIND) -COMPATIBLE_IOCTL(CDROMREADTOCHDR) -COMPATIBLE_IOCTL(CDROMREADTOCENTRY) -COMPATIBLE_IOCTL(CDROMSTOP) -COMPATIBLE_IOCTL(CDROMSTART) -COMPATIBLE_IOCTL(CDROMEJECT) -COMPATIBLE_IOCTL(CDROMVOLCTRL) -COMPATIBLE_IOCTL(CDROMSUBCHNL) -COMPATIBLE_IOCTL(CDROMEJECT_SW) -COMPATIBLE_IOCTL(CDROMMULTISESSION) -COMPATIBLE_IOCTL(CDROM_GET_MCN) -COMPATIBLE_IOCTL(CDROMRESET) -COMPATIBLE_IOCTL(CDROMVOLREAD) -COMPATIBLE_IOCTL(CDROMSEEK) -COMPATIBLE_IOCTL(CDROMPLAYBLK) -COMPATIBLE_IOCTL(CDROMCLOSETRAY) -COMPATIBLE_IOCTL(CDROM_SET_OPTIONS) -COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS) -COMPATIBLE_IOCTL(CDROM_SELECT_SPEED) -COMPATIBLE_IOCTL(CDROM_SELECT_DISC) -COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED) -COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS) -COMPATIBLE_IOCTL(CDROM_DISC_STATUS) -COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS) -COMPATIBLE_IOCTL(CDROM_LOCKDOOR) -COMPATIBLE_IOCTL(CDROM_DEBUG) -COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) -/* DVD ioctls */ -COMPATIBLE_IOCTL(DVD_READ_STRUCT) -COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) -COMPATIBLE_IOCTL(DVD_AUTH) -/* Big L */ -COMPATIBLE_IOCTL(LOOP_SET_FD) -COMPATIBLE_IOCTL(LOOP_CLR_FD) -/* Big Q for sound/OSS */ -COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET) -COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC) -COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO) -COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE) -COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT) -COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT) -COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE) -COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR) -COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI) -COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES) -COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS) -COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS) -COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO) -COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD) -COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL) -COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE) -COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC) -COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND) -COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME) -COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID) -COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL) -COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE) -/* Big T for sound/OSS */ -COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE) -COMPATIBLE_IOCTL(SNDCTL_TMR_START) -COMPATIBLE_IOCTL(SNDCTL_TMR_STOP) -COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE) -COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO) -COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE) -COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME) -COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT) -/* Little m for sound/OSS */ -COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME) -COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE) -COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD) -/* Big P for sound/OSS */ -COMPATIBLE_IOCTL(SNDCTL_DSP_RESET) -COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC) -COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED) -COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE) -COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS) -COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER) -COMPATIBLE_IOCTL(SNDCTL_DSP_POST) -COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE) -COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS) -COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE) -COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER) -COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR) -/* SNDCTL_DSP_MAPINBUF, XXX needs translation */ -/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */ -COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO) -COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX) -COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY) -COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE) -COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE) -COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS) -COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS) -COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER) -/* Big C for sound/OSS */ -COMPATIBLE_IOCTL(SNDCTL_COPR_RESET) -COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD) -COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA) -COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE) -COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA) -COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE) -COMPATIBLE_IOCTL(SNDCTL_COPR_RUN) -COMPATIBLE_IOCTL(SNDCTL_COPR_HALT) -COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG) -COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG) -/* Big M for sound/OSS */ -COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO)) -COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR)) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE) -/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */ -/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */ -COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS) -COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO)) -COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR)) -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE) -/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */ -/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */ -COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC) -COMPATIBLE_IOCTL(SOUND_MIXER_INFO) -COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO) -COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS) -COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1) -COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2) -COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3) -COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4) -COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5) -COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) -COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) -COMPATIBLE_IOCTL(OSS_GETVERSION) -/* AUTOFS */ -COMPATIBLE_IOCTL(AUTOFS_IOC_READY) -COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL) -COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) -COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) -COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) -/* DEVFS */ -COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK) -COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK) -/* Raw devices */ -COMPATIBLE_IOCTL(RAW_SETBIND) -COMPATIBLE_IOCTL(RAW_GETBIND) -/* SMB ioctls which do not need any translations */ -COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) -/* NCP ioctls which do not need any translations */ -COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN) -COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT) -COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED) -COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED) -COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK) -COMPATIBLE_IOCTL(NCP_IOC_GETROOT) -COMPATIBLE_IOCTL(NCP_IOC_SETROOT) -COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS) -COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS) -COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL) -COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL) -/* Little a */ -COMPATIBLE_IOCTL(ATMSIGD_CTRL) -COMPATIBLE_IOCTL(ATMARPD_CTRL) -COMPATIBLE_IOCTL(ATMLEC_CTRL) -COMPATIBLE_IOCTL(ATMLEC_MCAST) -COMPATIBLE_IOCTL(ATMLEC_DATA) -COMPATIBLE_IOCTL(ATM_SETSC) -COMPATIBLE_IOCTL(SIOCSIFATMTCP) -COMPATIBLE_IOCTL(SIOCMKCLIP) -COMPATIBLE_IOCTL(ATMARP_MKIP) -COMPATIBLE_IOCTL(ATMARP_SETENTRY) -COMPATIBLE_IOCTL(ATMARP_ENCAP) -COMPATIBLE_IOCTL(ATMTCP_CREATE) -COMPATIBLE_IOCTL(ATMTCP_REMOVE) -COMPATIBLE_IOCTL(ATMMPC_CTRL) -COMPATIBLE_IOCTL(ATMMPC_DATA) -#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) -COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC) -COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID) -COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC) -COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS) -COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW) -COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW) -COMPATIBLE_IOCTL(DRM_IOCTL_LOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_FINISH) -#endif /* DRM */ -/* Big W */ -/* WIOC_GETSUPPORT not yet implemented -E */ -COMPATIBLE_IOCTL(WDIOC_GETSTATUS) -COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS) -COMPATIBLE_IOCTL(WDIOC_GETTEMP) -COMPATIBLE_IOCTL(WDIOC_SETOPTIONS) -COMPATIBLE_IOCTL(WDIOC_KEEPALIVE) -/* Big R */ -COMPATIBLE_IOCTL(RNDGETENTCNT) -COMPATIBLE_IOCTL(RNDADDTOENTCNT) -COMPATIBLE_IOCTL(RNDGETPOOL) -COMPATIBLE_IOCTL(RNDADDENTROPY) -COMPATIBLE_IOCTL(RNDZAPENTCNT) -COMPATIBLE_IOCTL(RNDCLEARPOOL) -/* Bluetooth ioctls */ -COMPATIBLE_IOCTL(HCIDEVUP) -COMPATIBLE_IOCTL(HCIDEVDOWN) -COMPATIBLE_IOCTL(HCIDEVRESET) -COMPATIBLE_IOCTL(HCIDEVRESTAT) -COMPATIBLE_IOCTL(HCIGETDEVLIST) -COMPATIBLE_IOCTL(HCIGETDEVINFO) -COMPATIBLE_IOCTL(HCIGETCONNLIST) -COMPATIBLE_IOCTL(HCIGETCONNINFO) -COMPATIBLE_IOCTL(HCISETRAW) -COMPATIBLE_IOCTL(HCISETSCAN) -COMPATIBLE_IOCTL(HCISETAUTH) -COMPATIBLE_IOCTL(HCISETENCRYPT) -COMPATIBLE_IOCTL(HCISETPTYPE) -COMPATIBLE_IOCTL(HCISETLINKPOL) -COMPATIBLE_IOCTL(HCISETLINKMODE) -COMPATIBLE_IOCTL(HCISETACLMTU) -COMPATIBLE_IOCTL(HCISETSCOMTU) -COMPATIBLE_IOCTL(HCIINQUIRY) -COMPATIBLE_IOCTL(HCIUARTSETPROTO) -COMPATIBLE_IOCTL(HCIUARTGETPROTO) -COMPATIBLE_IOCTL(RFCOMMCREATEDEV) -COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) -COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) -COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) -COMPATIBLE_IOCTL(RFCOMMSTEALDLC) -COMPATIBLE_IOCTL(BNEPCONNADD) -COMPATIBLE_IOCTL(BNEPCONNDEL) -COMPATIBLE_IOCTL(BNEPGETCONNLIST) -COMPATIBLE_IOCTL(BNEPGETCONNINFO) -COMPATIBLE_IOCTL(PCIIOC_CONTROLLER) -COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO) -COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM) -COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE) -/* USB */ -COMPATIBLE_IOCTL(USBDEVFS_RESETEP) -COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE) -COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION) -COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER) -COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB) -COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE) -COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE) -COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO) -COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO) -COMPATIBLE_IOCTL(USBDEVFS_RESET) -COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) -/* MTD */ -COMPATIBLE_IOCTL(MEMGETINFO) -COMPATIBLE_IOCTL(MEMERASE) -COMPATIBLE_IOCTL(MEMLOCK) -COMPATIBLE_IOCTL(MEMUNLOCK) -COMPATIBLE_IOCTL(MEMGETREGIONCOUNT) -COMPATIBLE_IOCTL(MEMGETREGIONINFO) -/* NBD */ -COMPATIBLE_IOCTL(NBD_SET_SOCK) -COMPATIBLE_IOCTL(NBD_SET_BLKSIZE) -COMPATIBLE_IOCTL(NBD_SET_SIZE) -COMPATIBLE_IOCTL(NBD_DO_IT) -COMPATIBLE_IOCTL(NBD_CLEAR_SOCK) -COMPATIBLE_IOCTL(NBD_CLEAR_QUE) -COMPATIBLE_IOCTL(NBD_PRINT_DEBUG) -COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS) -COMPATIBLE_IOCTL(NBD_DISCONNECT) -/* device-mapper */ -COMPATIBLE_IOCTL(DM_VERSION) -COMPATIBLE_IOCTL(DM_REMOVE_ALL) -COMPATIBLE_IOCTL(DM_DEV_CREATE) -COMPATIBLE_IOCTL(DM_DEV_REMOVE) -COMPATIBLE_IOCTL(DM_DEV_RELOAD) -COMPATIBLE_IOCTL(DM_DEV_SUSPEND) -COMPATIBLE_IOCTL(DM_DEV_RENAME) -COMPATIBLE_IOCTL(DM_DEV_DEPS) -COMPATIBLE_IOCTL(DM_DEV_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_STATUS) -COMPATIBLE_IOCTL(DM_TARGET_WAIT) + /* And these ioctls need translation */ HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) @@ -4473,4 +3889,4 @@ HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) -}; +IOCTL_TABLE_END diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c --- a/arch/ppc64/kernel/irq.c Mon May 12 20:55:46 2003 +++ b/arch/ppc64/kernel/irq.c Mon May 12 20:55:46 2003 @@ -212,7 +212,8 @@ return -ENOENT; } -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction *action; @@ -695,7 +696,7 @@ struct proc_dir_entry *entry; char name [MAX_NAMELEN]; - if (!root_irq_dir || (irq_desc[irq].handler == NULL)) + if (!root_irq_dir || (irq_desc[irq].handler == NULL) || irq_dir[irq]) return; memset(name, 0, MAX_NAMELEN); @@ -743,6 +744,7 @@ } } -void no_action(int irq, void *dev, struct pt_regs *regs) +irqreturn_t no_action(int irq, void *dev, struct pt_regs *regs) { + return IRQ_NONE; } diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/misc.S Mon May 12 20:55:48 2003 @@ -170,12 +170,14 @@ */ LOADADDR(r10,naca) /* Get Naca address */ ld r10,0(r10) - lhz r7,DCACHEL1LINESIZE(r10) /* Get cache line size */ + LOADADDR(r11,systemcfg) /* Get systemcfg address */ + ld r11,0(r11) + lwz r7,DCACHEL1LINESIZE(r11)/* Get cache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ - lhz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ + lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r8 @@ -186,12 +188,12 @@ /* Now invalidate the instruction cache */ - lhz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */ + lwz r7,ICACHEL1LINESIZE(r11) /* Get Icache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 - lhz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ + lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r8 @@ -217,12 +219,14 @@ */ LOADADDR(r10,naca) /* Get Naca address */ ld r10,0(r10) - lhz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */ + LOADADDR(r11,systemcfg) /* Get systemcfg address */ + ld r11,0(r11) + lwz r7,DCACHEL1LINESIZE(r11) /* Get dcache line size */ addi r5,r7,-1 andc r6,r3,r5 /* round low to line bdy */ subf r8,r6,r4 /* compute length */ add r8,r8,r5 /* ensure we get enough */ - lhz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ + lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */ srw. r8,r8,r9 /* compute line count */ beqlr /* nothing to do? */ mtctr r8 @@ -249,9 +253,11 @@ /* Flush the dcache */ LOADADDR(r7,naca) ld r7,0(r7) + LOADADDR(r8,systemcfg) /* Get systemcfg address */ + ld r8,0(r8) clrrdi r3,r3,12 /* Page align */ - lhz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ - lhz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */ + lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */ + lwz r5,DCACHEL1LINESIZE(r8) /* Get dcache line size */ mr r6,r3 mtctr r4 0: dcbst 0,r6 @@ -261,8 +267,8 @@ /* Now invalidate the icache */ - lhz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ - lhz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */ + lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */ + lwz r5,ICACHEL1LINESIZE(r8) /* Get icache line size */ mtctr r4 1: icbi 0,r3 add r3,r3,r5 @@ -574,7 +580,7 @@ .llong .sys32_ssetmask .llong .sys_setreuid /* 70 */ .llong .sys_setregid - .llong .sys_sigsuspend + .llong .sys32_sigsuspend .llong .compat_sys_sigpending .llong .sys32_sethostname .llong .compat_sys_setrlimit /* 75 */ @@ -737,7 +743,7 @@ .llong .sys_set_tid_address .llong .ppc32_fadvise64 .llong .sys_exit_group - .llong .ppc32_lookup_dcookie /* 245 */ + .llong .ppc32_lookup_dcookie /* 235 */ .llong .sys_epoll_create .llong .sys_epoll_ctl .llong .sys_epoll_wait @@ -812,13 +818,13 @@ .llong .sys_getppid .llong .sys_getpgrp /* 65 */ .llong .sys_setsid - .llong .sys_sigaction + .llong .sys_ni_syscall .llong .sys_sgetmask .llong .sys_ssetmask .llong .sys_setreuid /* 70 */ .llong .sys_setregid - .llong .sys_sigsuspend - .llong .sys_sigpending + .llong .sys_ni_syscall + .llong .sys_ni_syscall .llong .sys_sethostname .llong .sys_setrlimit /* 75 */ .llong .sys_ni_syscall /* old getrlimit syscall */ @@ -864,14 +870,14 @@ .llong .sys_sysinfo .llong .sys_ipc .llong .sys_fsync - .llong .ppc64_sigreturn + .llong .sys_ni_syscall .llong .sys_clone /* 120 */ .llong .sys_setdomainname .llong .ppc64_newuname .llong .sys_ni_syscall /* old modify_ldt syscall */ .llong .sys_adjtimex .llong .sys_mprotect /* 125 */ - .llong .sys_sigprocmask + .llong .sys_ni_syscall .llong .sys_ni_syscall /* old create_module syscall */ .llong .sys_init_module .llong .sys_delete_module diff -Nru a/arch/ppc64/kernel/module.c b/arch/ppc64/kernel/module.c --- a/arch/ppc64/kernel/module.c Mon May 12 20:55:49 2003 +++ b/arch/ppc64/kernel/module.c Mon May 12 20:55:49 2003 @@ -20,6 +20,8 @@ #include #include #include +#include +#include /* FIXME: We don't do .init separately. To do this, we'd need to have a separate r2 value in the init and core section, and stub between @@ -374,15 +376,11 @@ return 0; } -/* In arch/ppc64/mm/extable.c */ -extern void sort_ex_table(struct exception_table_entry *start, - struct exception_table_entry *finish); - int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *me) + const Elf_Shdr *sechdrs, struct module *me) { - sort_ex_table(me->extable.entry, - me->extable.entry + me->extable.num_entries); + sort_ex_table((struct exception_table_entry *)me->extable, + (struct exception_table_entry *)me->extable + + me->num_exentries); return 0; } diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c --- a/arch/ppc64/kernel/open_pic.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/open_pic.c Mon May 12 20:55:47 2003 @@ -111,7 +111,6 @@ * data has probably been corrupted and we're going to panic or deadlock later * anyway --Troy */ -extern unsigned long* _get_SP(void); #define check_arg_irq(irq) \ if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \ printk(KERN_ERR "open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \ @@ -765,9 +764,11 @@ openpic_eoi(); } -static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) +static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, + struct pt_regs *regs) { smp_message_recv(cpl-openpic_vec_ipi, regs); + return IRQ_HANDLED; } #endif /* CONFIG_SMP */ diff -Nru a/arch/ppc64/kernel/open_pic_defs.h b/arch/ppc64/kernel/open_pic_defs.h --- a/arch/ppc64/kernel/open_pic_defs.h Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/open_pic_defs.h Mon May 12 20:55:47 2003 @@ -298,7 +298,8 @@ #ifdef CONFIG_SMP /* Interprocessor Interrupts */ static void openpic_initipi(u_int ipi, u_int pri, u_int vector); -static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); +static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, + struct pt_regs *regs); #endif /* Timer Interrupts */ diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c --- a/arch/ppc64/kernel/pSeries_lpar.c Mon May 12 20:55:49 2003 +++ b/arch/ppc64/kernel/pSeries_lpar.c Mon May 12 20:55:49 2003 @@ -110,29 +110,6 @@ lbuf[0], lbuf[1], &dummy, &dummy, &dummy); } -long plpar_eoi(unsigned long xirr) -{ - return plpar_hcall_norets(H_EOI, xirr); -} - -long plpar_cppr(unsigned long cppr) -{ - return plpar_hcall_norets(H_CPPR, cppr); -} - -long plpar_ipi(unsigned long servernum, - unsigned long mfrr) -{ - return plpar_hcall_norets(H_IPI, servernum, mfrr); -} - -long plpar_xirr(unsigned long *xirr_ret) -{ - unsigned long dummy; - return plpar_hcall(H_XIRR, 0, 0, 0, 0, - xirr_ret, &dummy, &dummy); -} - static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, unsigned long uaddr, int direction ) { @@ -179,66 +156,6 @@ } } - -/* PowerPC Interrupts for lpar. */ -/* NOTE: this typedef is duplicated (for now) from xics.c! */ -typedef struct { - int (*xirr_info_get)(int cpu); - void (*xirr_info_set)(int cpu, int val); - void (*cppr_info)(int cpu, u8 val); - void (*qirr_info)(int cpu, u8 val); -} xics_ops; -static int pSeriesLP_xirr_info_get(int n_cpu) -{ - unsigned long lpar_rc; - unsigned long return_value; - - lpar_rc = plpar_xirr(&return_value); - if (lpar_rc != H_Success) { - panic(" bad return code xirr - rc = %lx \n", lpar_rc); - } - return ((int)(return_value)); -} - -static void pSeriesLP_xirr_info_set(int n_cpu, int value) -{ - unsigned long lpar_rc; - unsigned long val64 = value & 0xffffffff; - - lpar_rc = plpar_eoi(val64); - if (lpar_rc != H_Success) { - panic(" bad return code EOI - rc = %ld, value=%lx \n", lpar_rc, val64); - } -} - -static void pSeriesLP_cppr_info(int n_cpu, u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_cppr(value); - if (lpar_rc != H_Success) { - panic(" bad return code cppr - rc = %lx \n", lpar_rc); - } -} - -static void pSeriesLP_qirr_info(int n_cpu , u8 value) -{ - unsigned long lpar_rc; - - lpar_rc = plpar_ipi(n_cpu, value); - if (lpar_rc != H_Success) { - panic(" bad return code qirr -ipi - rc = %lx \n", lpar_rc); - } -} - -xics_ops pSeriesLP_ops = { - pSeriesLP_xirr_info_get, - pSeriesLP_xirr_info_set, - pSeriesLP_cppr_info, - pSeriesLP_qirr_info -}; -/* end TAI-LPAR */ - int vtermno; /* virtual terminal# for udbg */ diff -Nru a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c --- a/arch/ppc64/kernel/pacaData.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/pacaData.c Mon May 12 20:55:48 2003 @@ -20,6 +20,7 @@ #include struct naca_struct *naca; +struct systemcfg *systemcfg; /* The Paca is an array with one entry per processor. Each contains an * ItLpPaca, which contains the information shared between the @@ -65,9 +66,9 @@ struct paca_struct paca[MAX_PACAS] __page_aligned = { #ifdef CONFIG_PPC_ISERIES - PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000), + PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR), #else - PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000), + PACAINITDATA( 0, 1, 0, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR), #endif PACAINITDATA( 1, 0, 0, 0, 0), PACAINITDATA( 2, 0, 0, 0, 0), diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c --- a/arch/ppc64/kernel/pci.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/pci.c Mon May 12 20:55:48 2003 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c --- a/arch/ppc64/kernel/pci_dma.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/pci_dma.c Mon May 12 20:55:47 2003 @@ -134,7 +134,7 @@ dev = ppc64_isabridge_dev; if (!dev) return NULL; - if (naca->platform == PLATFORM_ISERIES_LPAR) { + if (systemcfg->platform == PLATFORM_ISERIES_LPAR) { return ISERIES_DEVNODE(dev)->DevTceTable; } else { return PCI_GET_DN(dev)->tce_table; @@ -723,8 +723,8 @@ */ busdn->bussubno = bus->number; create_pci_bus_tce_table((unsigned long)busdn); - } else - create_tce_tables_for_busesLP(&bus->children); + } + create_tce_tables_for_busesLP(&bus->children); } } @@ -732,7 +732,7 @@ struct pci_dev *dev; struct device_node *dn, *mydn; - if (naca->platform == PLATFORM_PSERIES_LPAR) { + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { create_tce_tables_for_busesLP(&pci_root_buses); } else { @@ -773,7 +773,7 @@ /* - Tce Table Share between buses, */ /* - Tce Table per logical slot. */ /*****************************************************************/ - if(naca->platform == PLATFORM_ISERIES_LPAR) { + if(systemcfg->platform == PLATFORM_ISERIES_LPAR) { struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token; getTceTableParmsiSeries(DevNode,newTceTable); @@ -797,7 +797,7 @@ dn = (struct device_node *)token; phb = dn->phb; - if (naca->platform == PLATFORM_PSERIES) + if (systemcfg->platform == PLATFORM_PSERIES) getTceTableParmsPSeries(phb, dn, newTceTable); else getTceTableParmsPSeriesLP(phb, dn, newTceTable); @@ -1135,7 +1135,8 @@ /* Client asked for way to much space. This is checked later anyway */ /* It is easier to debug here for the drivers than in the tce tables.*/ if(order >= NUM_TCE_LEVELS) { - printk("PCI_DMA: pci_unmap_single 0x%lx size to large: 0x%lx \n",dma_handle,size); + printk("PCI_DMA: pci_unmap_single 0x%lx size too" + " large: 0x%lx \n", (long)dma_handle, (long)size); return; } diff -Nru a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc64/kernel/proc_ppc64.c Mon May 12 20:55:49 2003 @@ -0,0 +1,177 @@ +/* + * arch/ppc64/kernel/proc_ppc64.c + * + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * Change Activity: + * 2001 : mikec : Created + * 2001/06/05 : engebret : Software event count support. + * 2003/02/13 : bergner : Move PMC code to pmc.c + * End Change Activity + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct proc_ppc64_t proc_ppc64; + +void proc_ppc64_create_paca(int num); + +static loff_t page_map_seek( struct file *file, loff_t off, int whence); +static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos); +static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); + +static struct file_operations page_map_fops = { + llseek: page_map_seek, + read: page_map_read, + mmap: page_map_mmap +}; + + +static int __init proc_ppc64_init(void) +{ + + printk(KERN_INFO "proc_ppc64: Creating /proc/ppc64/\n"); + + proc_ppc64.root = proc_mkdir("ppc64", 0); + if (!proc_ppc64.root) + return 0; + + proc_ppc64.naca = create_proc_entry("naca", S_IRUSR, proc_ppc64.root); + if ( proc_ppc64.naca ) { + proc_ppc64.naca->nlink = 1; + proc_ppc64.naca->data = naca; + proc_ppc64.naca->size = 4096; + proc_ppc64.naca->proc_fops = &page_map_fops; + } + + proc_ppc64.systemcfg = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64.root); + if ( proc_ppc64.systemcfg ) { + proc_ppc64.systemcfg->nlink = 1; + proc_ppc64.systemcfg->data = systemcfg; + proc_ppc64.systemcfg->size = 4096; + proc_ppc64.systemcfg->proc_fops = &page_map_fops; + } + + /* /proc/ppc64/paca/XX -- raw paca contents. Only readable to root */ + proc_ppc64.paca = proc_mkdir("paca", proc_ppc64.root); + if (proc_ppc64.paca) { + unsigned long i; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + proc_ppc64_create_paca(i); + } + } + + /* Placeholder for rtas interfaces. */ + proc_ppc64.rtas = proc_mkdir("rtas", proc_ppc64.root); + + return 0; +} + + +/* + * NOTE: since paca data is always in flux the values will never be a consistant set. + * In theory it could be made consistent if we made the corresponding cpu + * copy the page for us (via an IPI). Probably not worth it. + * + */ +void proc_ppc64_create_paca(int num) +{ + struct proc_dir_entry *ent; + struct paca_struct *lpaca = paca + num; + char buf[16]; + + sprintf(buf, "%02x", num); + ent = create_proc_entry(buf, S_IRUSR, proc_ppc64.paca); + if ( ent ) { + ent->nlink = 1; + ent->data = lpaca; + ent->size = 4096; + ent->proc_fops = &page_map_fops; + } +} + + +static loff_t page_map_seek( struct file *file, loff_t off, int whence) +{ + loff_t new; + struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); + + switch(whence) { + case 0: + new = off; + break; + case 1: + new = file->f_pos + off; + break; + case 2: + new = dp->size + off; + break; + default: + return -EINVAL; + } + if ( new < 0 || new > dp->size ) + return -EINVAL; + return (file->f_pos = new); +} + +static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + unsigned pos = *ppos; + struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); + + if ( pos >= dp->size ) + return 0; + if ( nbytes >= dp->size ) + nbytes = dp->size; + if ( pos + nbytes > dp->size ) + nbytes = dp->size - pos; + + copy_to_user( buf, (char *)dp->data + pos, nbytes ); + *ppos = pos + nbytes; + return nbytes; +} + +static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) +{ + struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); + + vma->vm_flags |= VM_SHM | VM_LOCKED; + + if ((vma->vm_end - vma->vm_start) > dp->size) + return -EINVAL; + + remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot ); + return 0; +} + +fs_initcall(proc_ppc64_init); + diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/process.c Mon May 12 20:55:47 2003 @@ -533,8 +533,6 @@ } while (count++ < 32); } -extern unsigned long *_get_SP(void); - void dump_stack(void) { show_tsk_stack(current, (unsigned long)_get_SP()); diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c --- a/arch/ppc64/kernel/prom.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/prom.c Mon May 12 20:55:48 2003 @@ -118,7 +118,6 @@ #define FB_MAX 8 #endif -static int ppc64_is_smp; struct prom_t prom = { 0, /* entry */ @@ -301,7 +300,9 @@ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct naca_struct *_naca = RELOC(naca); + struct systemcfg *_systemcfg = RELOC(systemcfg); + /* NOTE: _naca->debug_switch is already initialized. */ #ifdef DEBUG_PROM prom_print(RELOC("prom_initialize_naca: start...\n")); #endif @@ -320,25 +321,35 @@ * d-cache and i-cache sizes... -Peter */ if ( num_cpus == 1 ) { - u32 size; + u32 size, lsize; call_prom(RELOC("getprop"), 4, 1, node, - RELOC("d-cache-line-size"), + RELOC("d-cache-size"), &size, sizeof(size)); - _naca->dCacheL1LineSize = size; - _naca->dCacheL1LogLineSize = __ilog2(size); - _naca->dCacheL1LinesPerPage = PAGE_SIZE / size; + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("d-cache-line-size"), + &lsize, sizeof(lsize)); + + _systemcfg->dCacheL1Size = size; + _systemcfg->dCacheL1LineSize = lsize; + _naca->dCacheL1LogLineSize = __ilog2(lsize); + _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize; call_prom(RELOC("getprop"), 4, 1, node, - RELOC("i-cache-line-size"), + RELOC("i-cache-size"), &size, sizeof(size)); - _naca->iCacheL1LineSize = size; - _naca->iCacheL1LogLineSize = __ilog2(size); - _naca->iCacheL1LinesPerPage = PAGE_SIZE / size; + call_prom(RELOC("getprop"), 4, 1, node, + RELOC("i-cache-line-size"), + &lsize, sizeof(lsize)); - if (_naca->platform == PLATFORM_PSERIES_LPAR) { + _systemcfg->iCacheL1Size = size; + _systemcfg->iCacheL1LineSize = lsize; + _naca->iCacheL1LogLineSize = __ilog2(lsize); + _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize; + + if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) { u32 pft_size[2]; call_prom(RELOC("getprop"), 4, 1, node, RELOC("ibm,pft-size"), @@ -408,20 +419,17 @@ } /* We gotta have at least 1 cpu... */ - if (num_cpus < 1) + if ( (_systemcfg->processorCount = num_cpus) < 1 ) PROM_BUG(); - if (num_cpus > 1) - RELOC(ppc64_is_smp) = 1; - - _naca->physicalMemorySize = lmb_phys_mem_size(); + _systemcfg->physicalMemorySize = lmb_phys_mem_size(); - if (_naca->platform == PLATFORM_PSERIES) { + if (_systemcfg->platform == PLATFORM_PSERIES) { unsigned long rnd_mem_size, pteg_count; /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize); - if (rnd_mem_size < _naca->physicalMemorySize) + rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize); + if (rnd_mem_size < _systemcfg->physicalMemorySize) rnd_mem_size <<= 1; /* # pages / 2 */ @@ -442,49 +450,43 @@ */ _naca->slb_size = 64; -#ifdef DEBUG_PROM - prom_print(RELOC("naca->physicalMemorySize = 0x")); - prom_print_hex(_naca->physicalMemorySize); - prom_print_nl(); - - prom_print(RELOC("naca->pftSize = 0x")); - prom_print_hex(_naca->pftSize); - prom_print_nl(); - - prom_print(RELOC("naca->dCacheL1LineSize = 0x")); - prom_print_hex(_naca->dCacheL1LineSize); - prom_print_nl(); + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64")); + _systemcfg->version.major = SYSTEMCFG_MAJOR; + _systemcfg->version.minor = SYSTEMCFG_MINOR; + _systemcfg->processor = _get_PVR(); - prom_print(RELOC("naca->dCacheL1LogLineSize = 0x")); - prom_print_hex(_naca->dCacheL1LogLineSize); +#ifdef DEBUG_PROM + prom_print(RELOC("systemcfg->processorCount = 0x")); + prom_print_hex(_systemcfg->processorCount); prom_print_nl(); - prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x")); - prom_print_hex(_naca->dCacheL1LinesPerPage); + prom_print(RELOC("systemcfg->physicalMemorySize = 0x")); + prom_print_hex(_systemcfg->physicalMemorySize); prom_print_nl(); - prom_print(RELOC("naca->iCacheL1LineSize = 0x")); - prom_print_hex(_naca->iCacheL1LineSize); + prom_print(RELOC("naca->pftSize = 0x")); + prom_print_hex(_naca->pftSize); prom_print_nl(); - prom_print(RELOC("naca->iCacheL1LogLineSize = 0x")); - prom_print_hex(_naca->iCacheL1LogLineSize); + prom_print(RELOC("systemcfg->dCacheL1LineSize = 0x")); + prom_print_hex(_systemcfg->dCacheL1LineSize); prom_print_nl(); - prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x")); - prom_print_hex(_naca->iCacheL1LinesPerPage); + prom_print(RELOC("systemcfg->iCacheL1LineSize = 0x")); + prom_print_hex(_systemcfg->iCacheL1LineSize); prom_print_nl(); - prom_print(RELOC("naca->serialPortAddr = 0x")); + prom_print(RELOC("naca->serialPortAddr = 0x")); prom_print_hex(_naca->serialPortAddr); prom_print_nl(); - prom_print(RELOC("naca->interrupt_controller = 0x")); + prom_print(RELOC("naca->interrupt_controller = 0x")); prom_print_hex(_naca->interrupt_controller); prom_print_nl(); - prom_print(RELOC("naca->platform = 0x")); - prom_print_hex(_naca->platform); + prom_print(RELOC("systemcfg->platform = 0x")); + prom_print_hex(_systemcfg->platform); prom_print_nl(); prom_print(RELOC("prom_initialize_naca: end...\n")); @@ -549,7 +551,7 @@ unsigned long offset = reloc_offset(); struct prom_t *_prom = PTRRELOC(&prom); struct rtas_t *_rtas = PTRRELOC(&rtas); - struct naca_struct *_naca = RELOC(naca); + struct systemcfg *_systemcfg = RELOC(systemcfg); ihandle prom_rtas; u32 getprop_rval; @@ -565,7 +567,7 @@ RELOC("ibm,hypertas-functions"), hypertas_funcs, sizeof(hypertas_funcs))) > 0) { - _naca->platform = PLATFORM_PSERIES_LPAR; + _systemcfg->platform = PLATFORM_PSERIES_LPAR; } call_prom(RELOC("getprop"), @@ -582,7 +584,7 @@ * of physical memory (or within the RMO region) because RTAS * runs in 32-bit mode and relocate off. */ - if ( _naca->platform == PLATFORM_PSERIES_LPAR ) { + if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) { struct lmb *_lmb = PTRRELOC(&lmb); rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX); } @@ -767,13 +769,21 @@ * By doing this, we avoid the pitfalls of trying to DMA to * MMIO space and the DMA alias hole. */ - minsize = 4UL << 20; + /* + * On POWER4, firmware sets the TCE region by assuming + * each TCE table is 8MB. Using this memory for anything + * else will impact performance, so we always allocate 8MB. + * Anton + * + * XXX FIXME use a cpu feature here + */ + minsize = 8UL << 20; /* Align to the greater of the align or size */ - align = (minalign < minsize) ? minsize : minalign; + align = max(minalign, minsize); /* Carve out storage for the TCE table. */ - base = lmb_alloc(8UL << 20, 8UL << 20); + base = lmb_alloc(minsize, align); if ( !base ) { prom_print(RELOC("ERROR, cannot find space for TCE table.\n")); @@ -875,7 +885,7 @@ prom_hold_cpus(unsigned long mem) { unsigned long i; - unsigned int reg; + unsigned int cpuid; phandle node; unsigned long offset = reloc_offset(); char type[64], *path; @@ -885,9 +895,13 @@ unsigned long *spinloop = __v2a(&__secondary_hold_spinloop); unsigned long *acknowledge = __v2a(&__secondary_hold_acknowledge); unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold)); + struct systemcfg *_systemcfg = RELOC(systemcfg); struct paca_struct *_xPaca = PTRRELOC(&paca[0]); struct prom_t *_prom = PTRRELOC(&prom); + /* Initially, we must have one active CPU. */ + _systemcfg->processorCount = 1; + #ifdef DEBUG_PROM prom_print(RELOC("prom_hold_cpus: start...\n")); prom_print(RELOC(" 1) spinloop = 0x")); @@ -933,12 +947,12 @@ if (strcmp(type, RELOC("okay")) != 0) continue; - reg = -1; + cpuid = -1; call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"), - ®, sizeof(reg)); + &cpuid, sizeof(cpuid)); /* Only need to start secondary procs, not ourself. */ - if ( reg == _prom->cpu ) + if ( cpuid == _prom->cpu ) continue; path = (char *) mem; @@ -950,7 +964,7 @@ #ifdef DEBUG_PROM prom_print_nl(); prom_print(RELOC("cpu hw idx = 0x")); - prom_print_hex(reg); + prom_print_hex(cpuid); prom_print_nl(); #endif prom_print(RELOC("starting cpu ")); @@ -978,9 +992,8 @@ prom_print(RELOC(" 3) secondary_hold = 0x")); prom_print_hex(secondary_hold); prom_print_nl(); - prom_print_nl(); #endif - call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, reg); + call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid); prom_print(RELOC("...")); for ( i = 0 ; (i < 100000000) && (*acknowledge == ((unsigned long)-1)); i++ ) ; @@ -992,10 +1005,11 @@ prom_print_nl(); } #endif - if (*acknowledge == reg) { + if (*acknowledge == cpuid) { prom_print(RELOC("ok\n")); /* Set the number of active processors. */ - _xPaca[reg].active = 1; + _systemcfg->processorCount++; + _xPaca[cpuid].active = 1; } else { prom_print(RELOC("failed: ")); prom_print_hex(*acknowledge); @@ -1024,8 +1038,8 @@ } } _xPaca[i+1].active = 1; - RELOC(hmt_thread_data)[i].threadid = i+1; } + _systemcfg->processorCount *= 2; } else { prom_print(RELOC("Processor is not HMT capable\n")); } @@ -1046,20 +1060,21 @@ prom_init(unsigned long r3, unsigned long r4, unsigned long pp, unsigned long r6, unsigned long r7) { + int chrp = 0; unsigned long mem; - ihandle prom_root, prom_cpu; + ihandle prom_mmu, prom_op, prom_root, prom_cpu; phandle cpu_pkg; unsigned long offset = reloc_offset(); - long l; + long l, sz; char *p, *d; unsigned long phys; u32 getprop_rval; - struct naca_struct *_naca = RELOC(naca); + struct systemcfg *_systemcfg = RELOC(systemcfg); struct paca_struct *_xPaca = PTRRELOC(&paca[0]); struct prom_t *_prom = PTRRELOC(&prom); /* Default machine type. */ - _naca->platform = PLATFORM_PSERIES; + _systemcfg->platform = PLATFORM_PSERIES; #if 0 /* Reset klimit to take into account the embedded system map */ @@ -1149,6 +1164,8 @@ mem = prom_bi_rec_reserve(mem); + mem = check_display(mem); + prom_instantiate_rtas(); /* Initialize some system info into the Naca early... */ @@ -1158,11 +1175,9 @@ * following, regardless of whether we have an SMP * kernel or not. */ - if (RELOC(ppc64_is_smp)) + if (_systemcfg->processorCount > 1) prom_hold_cpus(mem); - mem = check_display(mem); - #ifdef DEBUG_PROM prom_print(RELOC("copying OF device tree...\n")); #endif @@ -1172,7 +1187,7 @@ lmb_reserve(0, __pa(RELOC(klimit))); - if (_naca->platform == PLATFORM_PSERIES) + if (_systemcfg->platform == PLATFORM_PSERIES) prom_initialize_tce_table(); prom_print(RELOC("Calling quiesce ...\n")); diff -Nru a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c --- a/arch/ppc64/kernel/ras.c Mon May 12 20:55:45 2003 +++ b/arch/ppc64/kernel/ras.c Mon May 12 20:55:45 2003 @@ -54,8 +54,10 @@ #include #include -static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t ras_epow_interrupt(int irq, void *dev_id, + struct pt_regs * regs); +static irqreturn_t ras_error_interrupt(int irq, void *dev_id, + struct pt_regs * regs); void init_ras_IRQ(void); /* #define DEBUG */ @@ -73,7 +75,7 @@ &len))) { for(i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, - &ras_error_interrupt, 0, + ras_error_interrupt, 0, "RAS_ERROR", NULL); ireg++; } @@ -84,7 +86,7 @@ &len))) { for(i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, - &ras_epow_interrupt, 0, + ras_epow_interrupt, 0, "RAS_EPOW", NULL); ireg++; } @@ -98,7 +100,7 @@ * to examine the type of power failure and take appropriate action where * the time horizon permits something useful to be done. */ -static void +static irqreturn_t ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; @@ -114,7 +116,8 @@ udbg_printf("EPOW <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING - "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); + "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); + return IRQ_HANDLED; } /* @@ -125,7 +128,7 @@ * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure. */ -static void +static irqreturn_t ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; @@ -158,7 +161,6 @@ printk(KERN_WARNING "Warning: Recoverable hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); - - return; } + return IRQ_HANDLED; } diff -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c --- a/arch/ppc64/kernel/rtas-proc.c Mon May 12 20:55:46 2003 +++ b/arch/ppc64/kernel/rtas-proc.c Mon May 12 20:55:46 2003 @@ -201,7 +201,7 @@ struct proc_dir_entry *entry; rtas_node = find_devices("rtas"); - if ((rtas_node == NULL) || (naca->platform == PLATFORM_ISERIES_LPAR)) { + if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) { return; } @@ -506,21 +506,27 @@ int error, char * buf) { /* Defined return vales */ - const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", "Mainenance" }; + const char * key_switch[] = { "Off\t", "Normal\t", "Secure\t", + "Maintenance" }; const char * enclosure_switch[] = { "Closed", "Open" }; const char * lid_status[] = { " ", "Open", "Closed" }; - const char * power_source[] = { "AC\t", "Battery", "AC & Battery" }; + const char * power_source[] = { "AC\t", "Battery", + "AC & Battery" }; const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" }; const char * epow_sensor[] = { "EPOW Reset", "Cooling warning", "Power warning", "System shutdown", "System halt", "EPOW main enclosure", "EPOW power off" }; - const char * battery_cyclestate[] = { "None", "In progress", "Requested" }; - const char * battery_charging[] = { "Charging", "Discharching", "No current flow" }; - const char * ibm_drconnector[] = { "Empty", "Present" }; + const char * battery_cyclestate[] = { "None", "In progress", + "Requested" }; + const char * battery_charging[] = { "Charging", "Discharching", + "No current flow" }; + const char * ibm_drconnector[] = { "Empty", "Present", "Unusable", + "Exchange" }; const char * ibm_intqueue[] = { "Disabled", "Enabled" }; int have_strings = 0; + int num_states = 0; int temperature = 0; int unknown = 0; int n = 0; @@ -530,13 +536,20 @@ switch (s.token) { case KEY_SWITCH: n += sprintf(buf+n, "Key switch:\t"); - n += sprintf(buf+n, "%s\t", key_switch[state]); - have_strings = 1; + num_states = sizeof(key_switch) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", key_switch[state]); + have_strings = 1; + } break; case ENCLOSURE_SWITCH: n += sprintf(buf+n, "Enclosure switch:\t"); - n += sprintf(buf+n, "%s\t", enclosure_switch[state]); - have_strings = 1; + num_states = sizeof(enclosure_switch) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + enclosure_switch[state]); + have_strings = 1; + } break; case THERMAL_SENSOR: n += sprintf(buf+n, "Temp. (°C/°F):\t"); @@ -544,39 +557,63 @@ break; case LID_STATUS: n += sprintf(buf+n, "Lid status:\t"); - n += sprintf(buf+n, "%s\t", lid_status[state]); - have_strings = 1; + num_states = sizeof(lid_status) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", lid_status[state]); + have_strings = 1; + } break; case POWER_SOURCE: n += sprintf(buf+n, "Power source:\t"); - n += sprintf(buf+n, "%s\t", power_source[state]); - have_strings = 1; + num_states = sizeof(power_source) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + power_source[state]); + have_strings = 1; + } break; case BATTERY_VOLTAGE: n += sprintf(buf+n, "Battery voltage:\t"); break; case BATTERY_REMAINING: n += sprintf(buf+n, "Battery remaining:\t"); - n += sprintf(buf+n, "%s\t", battery_remaining[state]); - have_strings = 1; + num_states = sizeof(battery_remaining) / sizeof(char *); + if (state < num_states) + { + n += sprintf(buf+n, "%s\t", + battery_remaining[state]); + have_strings = 1; + } break; case BATTERY_PERCENTAGE: n += sprintf(buf+n, "Battery percentage:\t"); break; case EPOW_SENSOR: n += sprintf(buf+n, "EPOW Sensor:\t"); - n += sprintf(buf+n, "%s\t", epow_sensor[state]); - have_strings = 1; + num_states = sizeof(epow_sensor) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", epow_sensor[state]); + have_strings = 1; + } break; case BATTERY_CYCLESTATE: n += sprintf(buf+n, "Battery cyclestate:\t"); - n += sprintf(buf+n, "%s\t", battery_cyclestate[state]); - have_strings = 1; + num_states = sizeof(battery_cyclestate) / + sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + battery_cyclestate[state]); + have_strings = 1; + } break; case BATTERY_CHARGING: n += sprintf(buf+n, "Battery Charging:\t"); - n += sprintf(buf+n, "%s\t", battery_charging[state]); - have_strings = 1; + num_states = sizeof(battery_charging) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + battery_charging[state]); + have_strings = 1; + } break; case IBM_SURVEILLANCE: n += sprintf(buf+n, "Surveillance:\t"); @@ -589,16 +626,24 @@ break; case IBM_DRCONNECTOR: n += sprintf(buf+n, "DR connector:\t"); - n += sprintf(buf+n, "%s\t", ibm_drconnector[state]); - have_strings = 1; + num_states = sizeof(ibm_drconnector) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + ibm_drconnector[state]); + have_strings = 1; + } break; case IBM_POWERSUPPLY: n += sprintf(buf+n, "Powersupply:\t"); break; case IBM_INTQUEUE: n += sprintf(buf+n, "Interrupt queue:\t"); - n += sprintf(buf+n, "%s\t", ibm_intqueue[state]); - have_strings = 1; + num_states = sizeof(ibm_intqueue) / sizeof(char *); + if (state < num_states) { + n += sprintf(buf+n, "%s\t", + ibm_intqueue[state]); + have_strings = 1; + } break; default: n += sprintf(buf+n, "Unkown sensor (type %d), ignoring it\n", diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c --- a/arch/ppc64/kernel/rtas.c Mon May 12 20:55:45 2003 +++ b/arch/ppc64/kernel/rtas.c Mon May 12 20:55:45 2003 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include -struct proc_dir_entry *rtas_proc_dir; /* /proc/ppc64/rtas dir */ struct flash_block_list_header rtas_firmware_flash_list = {0, 0}; /* @@ -216,7 +216,11 @@ image_size += f->blocks[i].length; } next = f->next; - f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next); + /* Don't translate NULL pointer for last entry */ + if(f->next) + f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next); + else + f->next = 0LL; /* make num_blocks into the version/length field */ f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16); } @@ -283,7 +287,7 @@ rtas_power_off(); } -EXPORT_SYMBOL(rtas_proc_dir); +EXPORT_SYMBOL(proc_ppc64); EXPORT_SYMBOL(rtas_firmware_flash_list); EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); diff -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c --- a/arch/ppc64/kernel/rtas_flash.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/rtas_flash.c Mon May 12 20:55:48 2003 @@ -210,7 +210,7 @@ { struct proc_dir_entry *ent = NULL; - if (!rtas_proc_dir) { + if (!proc_ppc64.rtas) { printk(KERN_WARNING "rtas proc dir does not already exist"); return -ENOENT; } @@ -218,7 +218,7 @@ if (rtas_token("ibm,update-flash-64-and-reboot") != RTAS_UNKNOWN_SERVICE) flash_possible = 1; - if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, rtas_proc_dir)) != NULL) { + if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, proc_ppc64.rtas)) != NULL) { ent->nlink = 1; ent->proc_fops = &rtas_flash_operations; ent->owner = THIS_MODULE; @@ -228,9 +228,9 @@ void __exit rtas_flash_cleanup(void) { - if (!rtas_proc_dir) + if (!proc_ppc64.rtas) return; - remove_proc_entry(FIRMWARE_FLASH_NAME, rtas_proc_dir); + remove_proc_entry(FIRMWARE_FLASH_NAME, proc_ppc64.rtas); } module_init(rtas_flash_init); diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c --- a/arch/ppc64/kernel/setup.c Mon May 12 20:55:46 2003 +++ b/arch/ppc64/kernel/setup.c Mon May 12 20:55:46 2003 @@ -142,9 +142,6 @@ void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - /* This should be fixed properly in kernel/resource.c */ - iomem_resource.end = MEM_SPACE_LIMIT; - #ifdef CONFIG_XMON_DEFAULT debugger = xmon; debugger_bpt = xmon_bpt; @@ -156,10 +153,10 @@ #ifdef CONFIG_PPC_ISERIES /* pSeries systems are identified in prom.c via OF. */ if ( itLpNaca.xLparInstalled == 1 ) - naca->platform = PLATFORM_ISERIES_LPAR; + systemcfg->platform = PLATFORM_ISERIES_LPAR; #endif - switch (naca->platform) { + switch (systemcfg->platform) { #ifdef CONFIG_PPC_ISERIES case PLATFORM_ISERIES_LPAR: iSeries_init_early(); @@ -185,7 +182,7 @@ #endif } - if (naca->platform & PLATFORM_PSERIES) { + if (systemcfg->platform & PLATFORM_PSERIES) { early_console_initialized = 1; register_console(&udbg_console); } @@ -193,32 +190,27 @@ printk("Starting Linux PPC64 %s\n", UTS_RELEASE); printk("-----------------------------------------------------\n"); - printk("naca = 0x%p\n", naca); -#if 0 - printk("naca->processorCount = 0x%x\n", naca->processorCount); -#endif - printk("naca->physicalMemorySize = 0x%lx\n", naca->physicalMemorySize); - printk("naca->dCacheL1LineSize = 0x%x\n", naca->dCacheL1LineSize); - printk("naca->dCacheL1LogLineSize = 0x%x\n", naca->dCacheL1LogLineSize); - printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage); - printk("naca->iCacheL1LineSize = 0x%x\n", naca->iCacheL1LineSize); - printk("naca->iCacheL1LogLineSize = 0x%x\n", naca->iCacheL1LogLineSize); - printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage); - printk("naca->pftSize = 0x%lx\n", naca->pftSize); - printk("naca->debug_switch = 0x%lx\n", naca->debug_switch); - printk("naca->interrupt_controller = 0x%d\n", naca->interrupt_controller); - printk("htab_data.htab = 0x%p\n", htab_data.htab); - printk("htab_data.num_ptegs = 0x%lx\n", htab_data.htab_num_ptegs); + printk("naca = 0x%p\n", naca); + printk("naca->pftSize = 0x%lx\n", naca->pftSize); + printk("naca->debug_switch = 0x%lx\n", naca->debug_switch); + printk("naca->interrupt_controller = 0x%d\n", naca->interrupt_controller); + printk("systemcf = 0x%p\n", systemcfg); + printk("systemcfg->processorCount = 0x%x\n", systemcfg->processorCount); + printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); + printk("systemcfg->dCacheL1LineSize = 0x%x\n", systemcfg->dCacheL1LineSize); + printk("systemcfg->iCacheL1LineSize = 0x%x\n", systemcfg->iCacheL1LineSize); + printk("htab_data.htab = 0x%p\n", htab_data.htab); + printk("htab_data.num_ptegs = 0x%lx\n", htab_data.htab_num_ptegs); printk("-----------------------------------------------------\n"); - if (naca->platform & PLATFORM_PSERIES) { + if (systemcfg->platform & PLATFORM_PSERIES) { finish_device_tree(); chrp_init(r3, r4, r5, r6, r7); } mm_init_ppc64(); - switch (naca->platform) { + switch (systemcfg->platform) { #ifdef CONFIG_PPC_ISERIES case PLATFORM_ISERIES_LPAR: iSeries_init(); @@ -312,7 +304,7 @@ * Assume here that all clock rates are the same in a * smp system. -- Cort */ - if (naca->platform != PLATFORM_ISERIES_LPAR) { + if (systemcfg->platform != PLATFORM_ISERIES_LPAR) { struct device_node *cpu_node; int *fp; @@ -516,8 +508,8 @@ * Systems with OF can look in the properties on the cpu node(s) * for a possibly more accurate value. */ - dcache_bsize = naca->dCacheL1LineSize; - icache_bsize = naca->iCacheL1LineSize; + dcache_bsize = systemcfg->dCacheL1LineSize; + icache_bsize = systemcfg->iCacheL1LineSize; /* reboot on panic */ panic_timeout = 180; diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c --- a/arch/ppc64/kernel/signal.c Mon May 12 20:55:44 2003 +++ b/arch/ppc64/kernel/signal.c Mon May 12 20:55:44 2003 @@ -43,57 +43,29 @@ #endif #define GP_REGS_SIZE MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs)) +#define FP_REGS_SIZE sizeof(elf_fpregset_t) -/* - * These are the flags in the MSR that the user is allowed to change - * by modifying the saved value of the MSR on the stack. SE and BE - * should not be in this list since gdb may want to change these. I.e, - * you should be able to step out of a signal handler to see what - * instruction executes next after the signal handler completes. - * Alternately, if you stepped into a signal handler, you should be - * able to continue 'til the next breakpoint from within the signal - * handler, even if the handler returns. - */ -#if 0 -#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1) -#else -/* - * glibc tries to set FE0/FE1 via a signal handler. Since it only ever - * sets both bits and this is the default setting we now disable this - * behaviour. This is done to insure the new prctl which alters FE0/FE1 does - * not get overriden by glibc. Setting and clearing FE0/FE1 via signal - * handler has always been bogus since load_up_fpu used to set FE0/FE1 - * unconditionally. - */ -#define MSR_USERCHANGE 0 -#endif +#define TRAMP_TRACEBACK 3 +#define TRAMP_SIZE 6 /* - * When we have signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * a sigregs struct - * one or more sigcontext structs with - * a gap of __SIGNAL_FRAMESIZE bytes - * - * Each of these things must be a multiple of 16 bytes in size. - * + * When we have signals to deliver, we set up on the user stack, + * going down from the original stack pointer: + * 1) a rt_sigframe struct which contains the ucontext + * 2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller + * frame for the signal handler. */ -struct sigregs { - elf_gregset_t gp_regs; - double fp_regs[ELF_NFPREG]; - unsigned int tramp[2]; - /* 64 bit API allows for 288 bytes below sp before - decrementing it. */ - int abigap[72]; -}; -struct rt_sigframe -{ - unsigned long _unused[2]; +struct rt_sigframe { + /* sys_rt_sigreturn requires the ucontext be the first field */ + struct ucontext uc; + unsigned long _unused[2]; + unsigned int tramp[TRAMP_SIZE]; struct siginfo *pinfo; void *puc; struct siginfo info; - struct ucontext uc; + /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ + char abigap[288]; }; @@ -102,37 +74,6 @@ /* * Atomically swap in the new signal mask, and wait for a signal. */ -long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, - struct pt_regs *regs) -{ - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->result = -EINTR; - regs->gpr[3] = EINTR; - regs->ccr |= 0x10000000; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs)) - /* - * If a signal handler needs to be called, - * do_signal() has set R3 to the signal number (the - * first argument of the signal handler), so don't - * overwrite that with EINTR ! - * In the other cases, do_signal() doesn't touch - * R3, so it's still set to -EINTR (see above). - */ - return regs->gpr[3]; - } -} - long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs) { @@ -170,339 +111,232 @@ return do_sigaltstack(uss, uoss, regs->gpr[1]); } -long sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) + +/* + * Set up the sigcontext for the signal frame. + */ + +static int +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + int signr, sigset_t *set, unsigned long handler) { - struct k_sigaction new_ka, old_ka; - int ret; + int err = 0; - if (act) { - old_sigset_t mask; + if (regs->msr & MSR_FP) + giveup_fpu(current); - if (verify_area(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } + current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1); + regs->msr = current->thread.saved_msr | current->thread.fpexc_mode; + current->thread.saved_softe = regs->softe; + + err |= __put_user(&sc->gp_regs, &sc->regs); + err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); + err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); + err |= __put_user(signr, &sc->signal); + err |= __put_user(handler, &sc->handler); + if (set != NULL) + err |= __put_user(set->sig[0], &sc->oldmask); - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); + current->thread.fpscr = 0; - return ret; + return err; } /* - * When we have rt signals to deliver, we set up on the - * user stack, going down from the original stack pointer: - * a sigregs struct - * one rt_sigframe struct (siginfo + ucontext) - * a gap of __SIGNAL_FRAMESIZE bytes - * - * Each of these things must be a multiple of 16 bytes in size. - * + * Restore the sigcontext from the signal frame. */ -int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) +static int +restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc) { - struct rt_sigframe *rt_sf; - struct sigcontext sigctx; - struct sigregs *sr; - elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ - sigset_t set; - stack_t st; + unsigned int err = 0; - rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); - if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) - || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) - || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) - goto badframe; - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); if (regs->msr & MSR_FP) giveup_fpu(current); - /* restore registers - - * sigctx is initialized to point to the - * preamble frame (where registers are stored) - * see handle_signal() - */ - sr = (struct sigregs *)sigctx.regs; - if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) - goto badframe; - saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) - | (saved_regs[PT_MSR] & MSR_USERCHANGE); - saved_regs[PT_SOFTE] = regs->softe; - memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->thread.fpr, &sr->fp_regs, - sizeof(sr->fp_regs))) - goto badframe; - /* This function sets back the stack flags into - the current task structure. */ - sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs); + err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE); + err |= __copy_from_user(¤t->thread.fpr, &sc->fp_regs, FP_REGS_SIZE); + current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1); + if (set != NULL) + err |= __get_user(set->sig[0], &sc->oldmask); + + /* Don't allow the signal handler to change these modulo FE{0,1} */ + regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1); + regs->softe = current->thread.saved_softe; - return regs->result; - -badframe: - do_exit(SIGSEGV); + return err; } -static void setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, - signed long newsp) +/* + * Allocate space for the signal frame + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) { - struct rt_sigframe *rt_sf = (struct rt_sigframe *)newsp; - /* Handler is *really* a pointer to the function descriptor for - * the signal routine. The first entry in the function - * descriptor is the entry address of signal and the second - * entry is the TOC value we need to use. - */ - struct funct_descr_entry { - unsigned long entry; - unsigned long toc; - }; - - struct funct_descr_entry * funct_desc_ptr; - unsigned long temp_ptr; + unsigned long newsp; - /* Set up preamble frame */ - if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) - goto badframe; - if (regs->msr & MSR_FP) - giveup_fpu(current); - if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) - || __copy_to_user(&frame->fp_regs, current->thread.fpr, - ELF_NFPREG * sizeof(double)) - /* li r0, __NR_rt_sigreturn */ - || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0]) - /* sc */ - || __put_user(0x44000002UL, &frame->tramp[1])) - goto badframe; - flush_icache_range((unsigned long)&frame->tramp[0], - (unsigned long)&frame->tramp[2]); - current->thread.fpscr = 0; /* turn off all fp exceptions */ - - /* Retrieve rt_sigframe from stack and - set up registers for signal handler - */ - newsp -= __SIGNAL_FRAMESIZE; + /* Default to using normal stack */ + newsp = regs->gpr[1]; - if (get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) { - goto badframe; + if (ka->sa.sa_flags & SA_ONSTACK) { + if (! on_sig_stack(regs->gpr[1])) + newsp = (current->sas_ss_sp + current->sas_ss_size); } - funct_desc_ptr = (struct funct_descr_entry *)temp_ptr; - - if (put_user(regs->gpr[1], (unsigned long *)newsp) - || get_user(regs->nip, &funct_desc_ptr->entry) - || get_user(regs->gpr[2], &funct_desc_ptr->toc) - || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) - || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) - || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) - goto badframe; + return (void *)((newsp - frame_size) & -8ul); +} - regs->gpr[1] = newsp; - regs->gpr[6] = (unsigned long)rt_sf; - regs->link = (unsigned long)frame->tramp; +static int +setup_trampoline(unsigned int syscall, unsigned int *tramp) +{ + int i, err = 0; - return; + /* addi r1, r1, __SIGNAL_FRAMESIZE # Pop the dummy stackframe */ + err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]); + /* li r0, __NR_[rt_]sigreturn| */ + err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]); + /* sc */ + err |= __put_user(0x44000002UL, &tramp[2]); + + /* Minimal traceback info */ + for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++) + err |= __put_user(0, &tramp[i]); + + if (!err) + flush_icache_range((unsigned long) &tramp[0], + (unsigned long) &tramp[TRAMP_SIZE]); -badframe: -#if DEBUG_SIG - printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", - regs, frame, newsp); -#endif - do_exit(SIGSEGV); + return err; } /* * Do a signal return; undo the signal stack. */ -long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, unsigned long r8, - struct pt_regs *regs) -{ - struct sigcontext *sc, sigctx; - struct sigregs *sr; - elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + +int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7, unsigned long r8, + struct pt_regs *regs) +{ + struct ucontext *uc = (struct ucontext *)regs->gpr[1]; sigset_t set; + stack_t st; - sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); - if (copy_from_user(&sigctx, sc, sizeof(sigctx))) + if (verify_area(VERIFY_READ, uc, sizeof(*uc))) goto badframe; - set.sig[0] = sigctx.oldmask; -#if _NSIG_WORDS > 1 - set.sig[1] = sigctx._unused[3]; -#endif + if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) + goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (regs->msr & MSR_FP) - giveup_fpu(current); - /* restore registers */ - sr = (struct sigregs *)sigctx.regs; - if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) + if (restore_sigcontext(regs, NULL, &uc->uc_mcontext)) goto badframe; - saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) - | (saved_regs[PT_MSR] & MSR_USERCHANGE); - saved_regs[PT_SOFTE] = regs->softe; - memcpy(regs, saved_regs, GP_REGS_SIZE); - if (copy_from_user(current->thread.fpr, &sr->fp_regs, - sizeof(sr->fp_regs))) + if (__copy_from_user(&st, &uc->uc_stack, sizeof(st))) goto badframe; + /* This function sets back the stack flags into + the current task structure. */ + sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs); return regs->result; badframe: +#if DEBUG_SIG + printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n", + regs, uc, &uc->uc_mcontext); +#endif do_exit(SIGSEGV); -} +} -/* - * Set up a signal frame. - */ -static void setup_frame(struct pt_regs *regs, struct sigregs *frame, - unsigned long newsp) +static void +setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) { - /* Handler is *really* a pointer to the function descriptor for * the signal routine. The first entry in the function * descriptor is the entry address of signal and the second * entry is the TOC value we need to use. */ - struct funct_descr_entry { - unsigned long entry; - unsigned long toc; - }; - - struct funct_descr_entry * funct_desc_ptr; - unsigned long temp_ptr; + func_descr_t *funct_desc_ptr; + struct rt_sigframe *frame; + unsigned long newsp = 0; + int err = 0; - struct sigcontext *sc = (struct sigcontext *)newsp; - - if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) - goto badframe; - if (regs->msr & MSR_FP) - giveup_fpu(current); - if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) - || __copy_to_user(&frame->fp_regs, current->thread.fpr, - ELF_NFPREG * sizeof(double)) - /* li r0, __NR_sigreturn */ - || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0]) - /* sc */ - || __put_user(0x44000002UL, &frame->tramp[1])) - goto badframe; - flush_icache_range((unsigned long)&frame->tramp[0], - (unsigned long)&frame->tramp[2]); - current->thread.fpscr = 0; /* turn off all fp exceptions */ + frame = get_sigframe(ka, regs, sizeof(*frame)); - newsp -= __SIGNAL_FRAMESIZE; - if (get_user(temp_ptr, &sc->handler)) + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto badframe; - - funct_desc_ptr = (struct funct_descr_entry *)temp_ptr; - if (put_user(regs->gpr[1], (unsigned long *)newsp) - || get_user(regs->nip, &funct_desc_ptr ->entry) - || get_user(regs->gpr[2],&funct_desc_ptr->toc) - || get_user(regs->gpr[3], &sc->signal)) - goto badframe; + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto badframe; + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->gpr[1]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL, + (unsigned long)ka->sa.sa_handler); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + if (err) + goto badframe; + + /* Set up to return from userspace. */ + err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); + if (err) + goto badframe; + + funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler; + + /* Allocate a dummy caller frame for the signal handler. */ + newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE; + err |= put_user(0, (unsigned long *)newsp); + + /* Set up "regs" so we "return" to the signal handler. */ + err |= get_user(regs->nip, &funct_desc_ptr->entry); + regs->link = (unsigned long) &frame->tramp[0]; regs->gpr[1] = newsp; - regs->gpr[4] = (unsigned long)sc; - regs->link = (unsigned long)frame->tramp; + err |= get_user(regs->gpr[2], &funct_desc_ptr->toc); + regs->gpr[3] = signr; + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo); + err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc); + regs->gpr[6] = (unsigned long) frame; + } else { + regs->gpr[4] = (unsigned long)&frame->uc.uc_mcontext; + } + if (err) + goto badframe; return; badframe: #if DEBUG_SIG - printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", + printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif do_exit(SIGSEGV); } + /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, - struct pt_regs * regs, unsigned long *newspp, unsigned long frame) +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - struct sigcontext *sc; - struct rt_sigframe *rt_sf; - struct k_sigaction *ka = ¤t->sighand->action[sig-1]; - - if (regs->trap == 0x0C00 /* System Call! */ - && ((int)regs->result == -ERESTARTNOHAND || - (int)regs->result == -ERESTART_RESTARTBLOCK || - ((int)regs->result == -ERESTARTSYS && - !(ka->sa.sa_flags & SA_RESTART)))) { - if ((int)regs->result == -ERESTART_RESTARTBLOCK) - current_thread_info()->restart_block.fn - = do_no_restart_syscall; - regs->result = -EINTR; - } - /* Set up Signal Frame */ - if (ka->sa.sa_flags & SA_SIGINFO) { - /* Put a Real Time Context onto stack */ - *newspp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe *)*newspp; - if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) - goto badframe; - - if (__put_user((unsigned long)ka->sa.sa_handler, - &rt_sf->uc.uc_mcontext.handler) - || __put_user(&rt_sf->info, &rt_sf->pinfo) - || __put_user(&rt_sf->uc, &rt_sf->puc) - /* Put the siginfo */ - || copy_siginfo_to_user(&rt_sf->info, info) - /* Create the ucontext */ - || __put_user(0, &rt_sf->uc.uc_flags) - || __put_user(0, &rt_sf->uc.uc_link) - || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) - || __put_user(sas_ss_flags(regs->gpr[1]), - &rt_sf->uc.uc_stack.ss_flags) - || __put_user(current->sas_ss_size, - &rt_sf->uc.uc_stack.ss_size) - || __copy_to_user(&rt_sf->uc.uc_sigmask, - oldset, sizeof(*oldset)) - /* mcontext.regs points to preamble register frame */ - || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) - || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) - goto badframe; - } else { - /* Put a sigcontext on the stack */ - *newspp -= sizeof(*sc); - sc = (struct sigcontext *)*newspp; - if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) - goto badframe; - - if (__put_user((unsigned long)ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) -#if _NSIG_WORDS > 1 - || __put_user(oldset->sig[1], &sc->_unused[3]) -#endif - || __put_user((struct pt_regs *)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; - } + setup_rt_frame(sig, ka, info, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; @@ -515,14 +349,40 @@ spin_unlock_irq(¤t->sighand->siglock); } return; +} -badframe: -#if DEBUG_SIG - printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n", - regs, frame, *newspp); - printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); -#endif - do_exit(SIGSEGV); +static inline void +syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) +{ + switch ((int)regs->result) { + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = do_no_restart_syscall; + /* fallthrough */ + case -ERESTARTNOHAND: + /* ERESTARTNOHAND means that the syscall should only be + * restarted if there was no handler for the signal, and since + * we only get here if there is a handler, we dont restart. + */ + regs->result = -EINTR; + break; + case -ERESTARTSYS: + /* ERESTARTSYS means to restart the syscall if there is no + * handler or the handler was registered with SA_RESTART + */ + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->result = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + /* ERESTARTNOINTR means that the syscall should be + * called again after the signal handler returns. + */ + regs->gpr[3] = regs->orig_gpr3; + regs->nip -= 4; + regs->result = 0; + break; + } } /* @@ -535,8 +395,6 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; - struct k_sigaction *ka; - unsigned long frame, newsp; int signr; /* @@ -549,20 +407,15 @@ if (!oldset) oldset = ¤t->blocked; - newsp = frame = 0; - signr = get_signal_to_deliver(&info, regs, NULL); if (signr > 0) { - ka = ¤t->sighand->action[signr-1]; - if ((ka->sa.sa_flags & SA_ONSTACK) - && (!on_sig_stack(regs->gpr[1]))) - newsp = (current->sas_ss_sp + current->sas_ss_size); - else - newsp = regs->gpr[1]; - newsp = frame = newsp - sizeof(struct sigregs); + struct k_sigaction *ka = ¤t->sighand->action[signr-1]; /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, oldset, regs, &newsp, frame); + if (regs->trap == 0x0C00) + syscall_restart(regs, ka); + handle_signal(signr, ka, &info, oldset, regs); + return 1; } if (regs->trap == 0x0C00) { /* System Call! */ @@ -579,13 +432,8 @@ } } - if (newsp == frame) - return 0; /* no signals delivered */ - - /* Invoke correct stack setup routine */ - if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(regs, (struct sigregs *)frame, newsp); - else - setup_frame(regs, (struct sigregs *)frame, newsp); - return 1; + return 0; } + + + diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c --- a/arch/ppc64/kernel/signal32.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/signal32.c Mon May 12 20:55:48 2003 @@ -114,6 +114,40 @@ * setup_frame32 */ +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, + struct pt_regs *regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->result = -EINTR; + regs->gpr[3] = EINTR; + regs->ccr |= 0x10000000; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal32(&saveset, regs)) + /* + * If a signal handler needs to be called, + * do_signal32() has set R3 to the signal number (the + * first argument of the signal handler), so don't + * overwrite that with EINTR ! + * In the other cases, do_signal32() doesn't touch + * R3, so it's still set to -EINTR (see above). + */ + return regs->gpr[3]; + } +} + long sys32_sigaction(int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { @@ -792,13 +826,13 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal32(&saveset, regs)) /* * If a signal handler needs to be called, - * do_signal() has set R3 to the signal number (the + * do_signal32() has set R3 to the signal number (the * first argument of the signal handler), so don't * overwrite that with EINTR ! - * In the other cases, do_signal() doesn't touch + * In the other cases, do_signal32() doesn't touch * R3, so it's still set to -EINTR (see above). */ return regs->gpr[3]; diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c --- a/arch/ppc64/kernel/smp.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/kernel/smp.c Mon May 12 20:55:48 2003 @@ -46,8 +46,9 @@ #include #include "open_pic.h" #include +#include -int smp_threads_ready = 0; +int smp_threads_ready; unsigned long cache_decay_ticks; /* initialised so it doesn't end up in bss */ @@ -63,18 +64,6 @@ void smp_call_function_interrupt(void); void smp_message_pass(int target, int msg, unsigned long data, int wait); -void xics_setup_cpu(void); -void xics_cause_IPI(int cpu); - -/* - * XICS only has a single IPI, so encode the messages per CPU - */ -struct xics_ipi_struct { - volatile unsigned long value; -} ____cacheline_aligned; - -struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; - #define smp_message_pass(t,m,d,w) smp_ops->message_pass((t),(m),(d),(w)) static inline void set_tb(unsigned int upper, unsigned int lower) @@ -189,7 +178,7 @@ smp_ops->kick_cpu = smp_iSeries_kick_cpu; smp_ops->setup_cpu = smp_iSeries_setup_cpu; #warning fix for iseries - naca->processorCount = smp_iSeries_numProcs(); + systemcfg->processorCount = smp_iSeries_numProcs(); } #endif @@ -353,7 +342,7 @@ smp_ops->probe = smp_xics_probe; } - if (naca->platform == PLATFORM_PSERIES) { + if (systemcfg->platform == PLATFORM_PSERIES) { smp_ops->give_timebase = pSeries_give_timebase; smp_ops->take_timebase = pSeries_take_timebase; } diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c --- a/arch/ppc64/kernel/sys_ppc32.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/sys_ppc32.c Mon May 12 20:55:47 2003 @@ -1801,7 +1801,7 @@ err = do_sys32_shmctl(first, second, (void *)AA(ptr)); break; default: - err = -EINVAL; + err = -ENOSYS; break; } return err; diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c --- a/arch/ppc64/kernel/syscalls.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/syscalls.c Mon May 12 20:55:47 2003 @@ -68,7 +68,7 @@ version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - ret = -EINVAL; + ret = -ENOSYS; switch (call) { case SEMOP: ret = sys_semop (first, (struct sembuf *)ptr, second); diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c --- a/arch/ppc64/kernel/traps.c Mon May 12 20:55:46 2003 +++ b/arch/ppc64/kernel/traps.c Mon May 12 20:55:46 2003 @@ -55,14 +55,12 @@ * Trap & Exception support */ -/* Should we panic on bad kernel exceptions or try to recover */ -#undef PANIC_ON_ERROR - static spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char *str, struct pt_regs *regs, long err) { static int die_counter; + console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); @@ -71,11 +69,16 @@ bust_spinlocks(0); spin_unlock_irq(&die_lock); -#ifdef PANIC_ON_ERROR - panic(str); -#else + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(5 * HZ); + panic("Fatal exception"); + } do_exit(SIGSEGV); -#endif } static void @@ -139,15 +142,13 @@ #ifdef CONFIG_DEBUG_KERNEL if (debugger) debugger(regs); + else #endif + panic("System Reset"); -#ifdef PANIC_ON_ERROR - panic("System Reset"); -#else /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) panic("Unrecoverable System Reset"); -#endif /* What should we do here? We could issue a shutdown or hard reset. */ } @@ -343,6 +344,14 @@ info.si_addr = (void *)regs->nip; _exception(SIGILL, &info, regs); } +} + + void +KernelFPUnavailableException(struct pt_regs *regs) +{ + printk("Illegal floating point used in kernel (task=0x%016lx, pc=0x%016lx, trap=0x%08x)\n", + current, regs->nip, regs->trap); + panic("Unrecoverable FP Unavailable Exception in Kernel"); } void diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c --- a/arch/ppc64/kernel/udbg.c Mon May 12 20:55:44 2003 +++ b/arch/ppc64/kernel/udbg.c Mon May 12 20:55:44 2003 @@ -176,7 +176,7 @@ void udbg_printSP(const char *s) { - if (naca->platform == PLATFORM_PSERIES) { + if (systemcfg->platform == PLATFORM_PSERIES) { unsigned long sp; asm("mr %0,1" : "=r" (sp) :); if (s) diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c --- a/arch/ppc64/kernel/xics.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/kernel/xics.c Mon May 12 20:55:47 2003 @@ -1,5 +1,5 @@ /* - * arch/ppc/kernel/xics.c + * arch/ppc64/kernel/xics.c * * Copyright 2000 IBM Corporation. * @@ -22,10 +22,11 @@ #include #include #include -#include "i8259.h" #include #include -#include +#include + +#include "i8259.h" void xics_enable_irq(u_int irq); void xics_disable_irq(u_int irq); @@ -61,33 +62,39 @@ /* Want a priority other than 0. Various HW issues require this. */ #define DEFAULT_PRIORITY 5 +/* + * Mark IPIs as higher priority so we can take them inside interrupts that + * arent marked SA_INTERRUPT + */ +#define IPI_PRIORITY 4 + struct xics_ipl { union { - u32 word; - u8 bytes[4]; + u32 word; + u8 bytes[4]; } xirr_poll; union { u32 word; - u8 bytes[4]; + u8 bytes[4]; } xirr; - u32 dummy; + u32 dummy; union { - u32 word; - u8 bytes[4]; + u32 word; + u8 bytes[4]; } qirr; }; -struct xics_info { - volatile struct xics_ipl * per_cpu[NR_CPUS]; -}; +static struct xics_ipl *xics_per_cpu[NR_CPUS]; -struct xics_info xics_info; +static int xics_irq_8259_cascade = 0; +static int xics_irq_8259_cascade_real = 0; +static unsigned int default_server = 0xFF; +static unsigned int default_distrib_server = 0; -unsigned long long intr_base = 0; -int xics_irq_8259_cascade = 0; -int xics_irq_8259_cascade_real = 0; -unsigned int default_server = 0xFF; -unsigned int default_distrib_server = 0; +/* + * XICS only has a single IPI, so encode the messages per CPU + */ +struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; /* RTAS service tokens */ int ibm_get_xive; @@ -95,11 +102,6 @@ int ibm_int_on; int ibm_int_off; -struct xics_interrupt_node { - unsigned long long addr; - unsigned long long size; -} inodes[NR_CPUS*2]; - typedef struct { int (*xirr_info_get)(int cpu); void (*xirr_info_set)(int cpu, int val); @@ -108,24 +110,26 @@ } xics_ops; +/* SMP */ + static int pSeries_xirr_info_get(int n_cpu) { - return (xics_info.per_cpu[n_cpu]->xirr.word); + return xics_per_cpu[n_cpu]->xirr.word; } static void pSeries_xirr_info_set(int n_cpu, int value) { - xics_info.per_cpu[n_cpu]->xirr.word = value; + xics_per_cpu[n_cpu]->xirr.word = value; } static void pSeries_cppr_info(int n_cpu, u8 value) { - xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value; + xics_per_cpu[n_cpu]->xirr.bytes[0] = value; } -static void pSeries_qirr_info(int n_cpu , u8 value) +static void pSeries_qirr_info(int n_cpu, u8 value) { - xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value; + xics_per_cpu[n_cpu]->qirr.bytes[0] = value; } static xics_ops pSeries_ops = { @@ -136,113 +140,174 @@ }; static xics_ops *ops = &pSeries_ops; -extern xics_ops pSeriesLP_ops; -void -xics_enable_irq( - u_int virq - ) +/* LPAR */ + +static inline long plpar_eoi(unsigned long xirr) { - u_int irq; - unsigned long status; - long call_status; + return plpar_hcall_norets(H_EOI, xirr); +} + +static inline long plpar_cppr(unsigned long cppr) +{ + return plpar_hcall_norets(H_CPPR, cppr); +} + +static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr) +{ + return plpar_hcall_norets(H_IPI, servernum, mfrr); +} + +static inline long plpar_xirr(unsigned long *xirr_ret) +{ + unsigned long dummy; + return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy); +} + +static int pSeriesLP_xirr_info_get(int n_cpu) +{ + unsigned long lpar_rc; + unsigned long return_value; + + lpar_rc = plpar_xirr(&return_value); + if (lpar_rc != H_Success) + panic(" bad return code xirr - rc = %lx \n", lpar_rc); + return (int)return_value; +} + +static void pSeriesLP_xirr_info_set(int n_cpu, int value) +{ + unsigned long lpar_rc; + unsigned long val64 = value & 0xffffffff; + + lpar_rc = plpar_eoi(val64); + if (lpar_rc != H_Success) + panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, + val64); +} + +static void pSeriesLP_cppr_info(int n_cpu, u8 value) +{ + unsigned long lpar_rc; + + lpar_rc = plpar_cppr(value); + if (lpar_rc != H_Success) + panic("bad return code cppr - rc = %lx\n", lpar_rc); +} + +static void pSeriesLP_qirr_info(int n_cpu , u8 value) +{ + unsigned long lpar_rc; + + lpar_rc = plpar_ipi(n_cpu, value); + if (lpar_rc != H_Success) + panic("bad return code qirr - rc = %lx\n", lpar_rc); +} + +xics_ops pSeriesLP_ops = { + pSeriesLP_xirr_info_get, + pSeriesLP_xirr_info_set, + pSeriesLP_cppr_info, + pSeriesLP_qirr_info +}; + +void xics_enable_irq(u_int virq) +{ + u_int irq; + long call_status; + unsigned int server; virq -= XICS_IRQ_OFFSET; irq = virt_irq_to_real(virq); if (irq == XICS_IPI) return; + #ifdef CONFIG_IRQ_ALL_CPUS - call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status, - irq, smp_threads_ready ? default_distrib_server : default_server, DEFAULT_PRIORITY); + if (smp_threads_ready) + server = default_distrib_server; + else + server = default_server; #else - call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status, - irq, default_server, DEFAULT_PRIORITY); + server = default_server; #endif - if( call_status != 0 ) { - printk("xics_enable_irq: irq=%x: rtas_call failed; retn=%lx, status=%lx\n", - irq, call_status, status); + + call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, + DEFAULT_PRIORITY); + if (call_status != 0) { + printk("xics_enable_irq: irq=%x: ibm_set_xive returned %lx\n", + irq, call_status); return; } + /* Now unmask the interrupt (often a no-op) */ - call_status = rtas_call(ibm_int_on, 1, 1, (unsigned long*)&status, - irq); - if( call_status != 0 ) { - printk("xics_disable_irq on: irq=%x: rtas_call failed, retn=%lx\n", + call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq); + if (call_status != 0) { + printk("xics_enable_irq: irq=%x: ibm_int_on returned %lx\n", irq, call_status); return; } } -void -xics_disable_irq( - u_int virq - ) -{ - u_int irq; - unsigned long status; - long call_status; +void xics_disable_irq(u_int virq) +{ + u_int irq; + long call_status; virq -= XICS_IRQ_OFFSET; irq = virt_irq_to_real(virq); - call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, - irq); - if( call_status != 0 ) { - printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n", + if (irq == XICS_IPI) + return; + + call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq); + if (call_status != 0) { + printk("xics_disable_irq: irq=%x: ibm_int_off returned %lx\n", irq, call_status); return; } } -void -xics_end_irq( - u_int irq - ) +void xics_end_irq(u_int irq) { int cpu = smp_processor_id(); - ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */ - iosync(); - ops->xirr_info_set(cpu, ((0xff<<24) | (virt_irq_to_real(irq-XICS_IRQ_OFFSET)))); iosync(); + ops->xirr_info_set(cpu, ((0xff<<24) | + (virt_irq_to_real(irq-XICS_IRQ_OFFSET)))); } -void -xics_mask_and_ack_irq(u_int irq) +void xics_mask_and_ack_irq(u_int irq) { int cpu = smp_processor_id(); - if( irq < XICS_IRQ_OFFSET ) { + if (irq < XICS_IRQ_OFFSET) { i8259_pic.ack(irq); iosync(); - ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade_real)); - iosync(); - } - else { - ops->cppr_info(cpu, 0xff); + ops->xirr_info_set(cpu, ((0xff<<24) | + xics_irq_8259_cascade_real)); iosync(); } } -int -xics_get_irq(struct pt_regs *regs) +int xics_get_irq(struct pt_regs *regs) { - u_int cpu = smp_processor_id(); - u_int vec; + u_int cpu = smp_processor_id(); + u_int vec; int irq; vec = ops->xirr_info_get(cpu); /* (vec >> 24) == old priority */ vec &= 0x00ffffff; + /* for sanity, this had better be < NR_IRQS - 16 */ - if( vec == xics_irq_8259_cascade_real ) { + if (vec == xics_irq_8259_cascade_real) { irq = i8259_irq(cpu); - if(irq == -1) { + if (irq == -1) { /* Spurious cascaded interrupt. Still must ack xics */ xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade); irq = -1; } - } else if( vec == XICS_IRQ_SPURIOUS ) { + } else if (vec == XICS_IRQ_SPURIOUS) { irq = -1; } else { irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET; @@ -250,45 +315,49 @@ return irq; } -struct xics_ipi_struct { - volatile unsigned long value; -} ____cacheline_aligned; +#ifdef CONFIG_SMP extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; -#ifdef CONFIG_SMP -void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { int cpu = smp_processor_id(); + int handled = 0; ops->qirr_info(cpu, 0xff); while (xics_ipi_message[cpu].value) { - if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu].value)) { + handled = 1; + if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, + &xics_ipi_message[cpu].value)) { mb(); smp_message_recv(PPC_MSG_CALL_FUNCTION, regs); } - if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu].value)) { + if (test_and_clear_bit(PPC_MSG_RESCHEDULE, + &xics_ipi_message[cpu].value)) { mb(); smp_message_recv(PPC_MSG_RESCHEDULE, regs); } #if 0 - if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, &xics_ipi_message[cpu].value)) { + if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, + &xics_ipi_message[cpu].value)) { mb(); smp_message_recv(PPC_MSG_MIGRATE_TASK, regs); } #endif #ifdef CONFIG_XMON - if (test_and_clear_bit(PPC_MSG_XMON_BREAK, &xics_ipi_message[cpu].value)) { + if (test_and_clear_bit(PPC_MSG_XMON_BREAK, + &xics_ipi_message[cpu].value)) { mb(); smp_message_recv(PPC_MSG_XMON_BREAK, regs); } #endif } + return IRQ_RETVAL(handled); } void xics_cause_IPI(int cpu) { - ops->qirr_info(cpu,0) ; + ops->qirr_info(cpu, IPI_PRIORITY); } void xics_setup_cpu(void) @@ -298,15 +367,20 @@ ops->cppr_info(cpu, 0xff); iosync(); } + #endif /* CONFIG_SMP */ -void -xics_init_IRQ( void ) +void xics_init_IRQ(void) { int i; unsigned long intr_size = 0; struct device_node *np; uint *ireg, ilen, indx=0; + unsigned long intr_base = 0; + struct xics_interrupt_node { + unsigned long long addr; + unsigned long long size; + } inodes[NR_CPUS*2]; ppc64_boot_msg(0x20, "XICS Init"); @@ -386,23 +460,24 @@ xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real); } - if (naca->platform == PLATFORM_PSERIES) { + if (systemcfg->platform == PLATFORM_PSERIES) { #ifdef CONFIG_SMP for (i = 0; i < NR_CPUS; ++i) { if (!cpu_possible(i)) continue; - xics_info.per_cpu[i] = - __ioremap((ulong)inodes[i].addr, - (ulong)inodes[i].size, _PAGE_NO_CACHE); + xics_per_cpu[i] = __ioremap((ulong)inodes[i].addr, + (ulong)inodes[i].size, + _PAGE_NO_CACHE); } #else - xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE); + xics_per_cpu[0] = __ioremap((ulong)intr_base, intr_size, + _PAGE_NO_CACHE); #endif /* CONFIG_SMP */ #ifdef CONFIG_PPC_PSERIES /* actually iSeries does not use any of xics...but it has link dependencies * for now, except this new one... */ - } else if (naca->platform == PLATFORM_PSERIES_LPAR) { + } else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { ops = &pSeriesLP_ops; #endif } @@ -417,8 +492,8 @@ ops->cppr_info(boot_cpuid, 0xff); iosync(); if (xics_irq_8259_cascade != -1) { - if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action, - 0, "8259 cascade", 0)) + if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, + no_action, 0, "8259 cascade", 0)) printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n"); i8259_init(); } diff -Nru a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c --- a/arch/ppc64/mm/fault.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/mm/fault.c Mon May 12 20:55:48 2003 @@ -75,8 +75,8 @@ } #endif - /* On an SLB miss we can only check for a valid exception entry */ - if (regs->trap == 0x380) { + /* On a kernel SLB miss we can only check for a valid exception entry */ + if (!user_mode(regs) && (regs->trap == 0x380)) { bad_page_fault(regs, address, SIGSEGV); return; } diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/mm/init.c Mon May 12 20:55:47 2003 @@ -69,8 +69,6 @@ int mem_init_done; unsigned long ioremap_bot = IMALLOC_BASE; -static int boot_mapsize; - extern pgd_t swapper_pg_dir[]; extern char __init_begin, __init_end; extern char _start[], _end[]; @@ -454,6 +452,7 @@ unsigned long i; unsigned long start, bootmap_pages; unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT; + int boot_mapsize; /* * Find an area to use for the bootmem bitmap. Calculate the size of @@ -532,7 +531,7 @@ int nid; for (nid = 0; nid < numnodes; nid++) { - if (numa_node_exists[nid]) { + if (node_data[nid].node_size != 0) { printk("freeing bootmem node %x\n", nid); totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c --- a/arch/ppc64/mm/numa.c Mon May 12 20:55:47 2003 +++ b/arch/ppc64/mm/numa.c Mon May 12 20:55:47 2003 @@ -24,11 +24,18 @@ int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1}; int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] = { [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1}; -int numa_node_exists[MAX_NUMNODES]; +unsigned long numa_cpumask_lookup_table[MAX_NUMNODES]; struct pglist_data node_data[MAX_NUMNODES]; bootmem_data_t plat_node_bdata[MAX_NUMNODES]; +static inline void map_cpu_to_node(int cpu, int node) +{ + dbg("cpu %d maps to domain %d\n", cpu, node); + numa_cpu_lookup_table[cpu] = node; + numa_cpumask_lookup_table[node] |= 1UL << cpu; +} + static int __init parse_numa_properties(void) { struct device_node *cpu; @@ -88,9 +95,7 @@ if (max_domain < numa_domain) max_domain = numa_domain; - numa_cpu_lookup_table[cpu_nr] = numa_domain; - - dbg("cpu %d maps to domain %d\n", cpu_nr, numa_domain); + map_cpu_to_node(cpu_nr, numa_domain); } for (memory = find_type_devices("memory"); memory; @@ -135,7 +140,7 @@ /* FIXME */ if (numa_domain == 0xffff) { - dbg("cpu has no numa doman\n"); + dbg("memory has no numa doman\n"); numa_domain = 0; } @@ -145,7 +150,8 @@ if (max_domain < numa_domain) max_domain = numa_domain; - numa_node_exists[numa_domain] = 1; + node_data[numa_domain].node_start_pfn = start / PAGE_SIZE; + node_data[numa_domain].node_size = size / PAGE_SIZE; for (i = start ; i < (start+size); i += MEMORY_INCREMENT) numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] = @@ -176,27 +182,17 @@ BUG(); for (nid = 0; nid < numnodes; nid++) { - unsigned long start, end; unsigned long start_paddr, end_paddr; int i; unsigned long bootmem_paddr; unsigned long bootmap_pages; - if (!numa_node_exists[nid]) + if (node_data[nid].node_size == 0) continue; - /* Find start and end of this zone */ - start = 0; - while (numa_memory_lookup_table[start] != nid) - start++; - - end = (MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1; - while (numa_memory_lookup_table[end] != nid) - end--; - end++; - - start_paddr = start << MEMORY_INCREMENT_SHIFT; - end_paddr = end << MEMORY_INCREMENT_SHIFT; + start_paddr = node_data[nid].node_start_pfn * PAGE_SIZE; + end_paddr = start_paddr + + (node_data[nid].node_size * PAGE_SIZE); dbg("node %d\n", nid); dbg("start_paddr = %lx\n", start_paddr); @@ -278,7 +274,7 @@ unsigned long start_pfn; unsigned long end_pfn; - if (!numa_node_exists[nid]) + if (node_data[nid].node_size == 0) continue; start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT; diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c --- a/arch/ppc64/xmon/xmon.c Mon May 12 20:55:48 2003 +++ b/arch/ppc64/xmon/xmon.c Mon May 12 20:55:48 2003 @@ -453,7 +453,7 @@ int i; struct bpt *bp; - if (naca->platform != PLATFORM_PSERIES) + if (systemcfg->platform != PLATFORM_PSERIES) return; bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { @@ -469,12 +469,10 @@ } } - if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) { - if (dabr.enabled) - set_dabr(dabr.address); - if (iabr.enabled) - set_iabr(iabr.address); - } + if (cpu_has_dabr() && dabr.enabled) + set_dabr(dabr.address); + if (cpu_has_iabr() && iabr.enabled) + set_iabr(iabr.address); } static void @@ -484,12 +482,13 @@ struct bpt *bp; unsigned instr; - if (naca->platform != PLATFORM_PSERIES) + if (systemcfg->platform != PLATFORM_PSERIES) return; - if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) { + + if (cpu_has_dabr()) set_dabr(0); + if (cpu_has_iabr()) set_iabr(0); - } bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { @@ -778,8 +777,8 @@ cmd = inchar(); switch (cmd) { case 'd': /* bd - hardware data breakpoint */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) { - printf("Not implemented on POWER4\n"); + if (cpu_has_dabr()) { + printf("Not implemented on this cpu\n"); break; } mode = 7; @@ -798,7 +797,7 @@ dabr.address = (dabr.address & ~7) | mode; break; case 'i': /* bi - hardware instr breakpoint */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) { + if (cpu_has_iabr()) { printf("Not implemented on POWER4\n"); break; } diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c --- a/arch/s390/kernel/s390_ksyms.c Mon May 12 20:55:47 2003 +++ b/arch/s390/kernel/s390_ksyms.c Mon May 12 20:55:47 2003 @@ -13,7 +13,7 @@ #include #include #include -#if CONFIG_IP_MULTICAST +#ifdef CONFIG_IP_MULTICAST #include #endif diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c --- a/arch/s390/kernel/traps.c Mon May 12 20:55:45 2003 +++ b/arch/s390/kernel/traps.c Mon May 12 20:55:45 2003 @@ -304,7 +304,7 @@ } else { -#if CONFIG_REMOTE_DEBUG +#ifdef CONFIG_REMOTE_DEBUG if(gdb_stub_initialised) { gdb_stub_handle_exception(regs, signal); diff -Nru a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c --- a/arch/s390/math-emu/math.c Mon May 12 20:55:45 2003 +++ b/arch/s390/math-emu/math.c Mon May 12 20:55:45 2003 @@ -102,7 +102,7 @@ struct pt_regs *regs; __u16 *location; -#if CONFIG_SYSCTL +#ifdef CONFIG_SYSCTL if(sysctl_ieee_emulation_warnings) #endif { diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c --- a/arch/sparc/kernel/process.c Mon May 12 20:55:44 2003 +++ b/arch/sparc/kernel/process.c Mon May 12 20:55:44 2003 @@ -186,18 +186,6 @@ machine_halt(); } -void show_regwindow(struct reg_window *rw) -{ - printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx " - "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n", - rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], - rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); - printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx " - "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n", - rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], - rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); -} - static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED; void __show_backtrace(unsigned long fp) @@ -248,6 +236,7 @@ } #endif +#if 0 void show_stackframe(struct sparc_stackf *sf) { unsigned long size; @@ -275,24 +264,27 @@ printk("s%d: %08lx\n", i++, *stk++); } while ((size -= sizeof(unsigned long))); } +#endif -void show_regs(struct pt_regs * regs) +void show_regs(struct pt_regs *r) { - printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx %s\n", regs->psr, - regs->pc, regs->npc, regs->y, print_tainted()); - printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ", - regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], - regs->u_regs[3]); - printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n", - regs->u_regs[4], regs->u_regs[5], regs->u_regs[6], - regs->u_regs[7]); - printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx ", - regs->u_regs[8], regs->u_regs[9], regs->u_regs[10], - regs->u_regs[11]); - printk("o4: %08lx o5: %08lx sp: %08lx o7: %08lx\n", - regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], - regs->u_regs[15]); - show_regwindow((struct reg_window *)regs->u_regs[14]); + struct reg_window *rw = (struct reg_window *) r->u_regs[14]; + + printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx %s\n", + r->psr, r->pc, r->npc, r->y, print_tainted()); + printk("%%G: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3], + r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]); + printk("%%O: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11], + r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]); + + printk("%%L: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], + rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); + printk("%%I: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", + rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], + rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } void show_trace_task(struct task_struct *tsk) diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c --- a/arch/sparc/kernel/sparc_ksyms.c Mon May 12 20:55:44 2003 +++ b/arch/sparc/kernel/sparc_ksyms.c Mon May 12 20:55:44 2003 @@ -157,7 +157,7 @@ EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(mostek_lock); EXPORT_SYMBOL(mstk48t02_regs); -#if CONFIG_SUN_AUXIO +#ifdef CONFIG_SUN_AUXIO EXPORT_SYMBOL(set_auxio); EXPORT_SYMBOL(get_auxio); #endif @@ -183,7 +183,7 @@ EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl)); EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one)); -#if CONFIG_SBUS +#ifdef CONFIG_SBUS EXPORT_SYMBOL(sbus_root); EXPORT_SYMBOL(dma_chain); EXPORT_SYMBOL(sbus_set_sbus64); @@ -198,7 +198,7 @@ EXPORT_SYMBOL(sbus_iounmap); EXPORT_SYMBOL(sbus_ioremap); #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); EXPORT_SYMBOL(insl); EXPORT_SYMBOL(outsl); diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c --- a/arch/sparc/mm/init.c Mon May 12 20:55:46 2003 +++ b/arch/sparc/mm/init.c Mon May 12 20:55:46 2003 @@ -107,8 +107,6 @@ add_to_free_ctxlist(ctx_list_pool + ctx); } -#define DEBUG_BOOTMEM - extern unsigned long cmdline_memory_size; unsigned long last_valid_pfn; @@ -157,14 +155,11 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) { - unsigned long bootmap_size, start_pfn, max_pfn; + unsigned long bootmap_size, start_pfn; unsigned long end_of_phys_memory = 0UL; unsigned long bootmap_pfn, bytes_avail, size; int i; -#ifdef DEBUG_BOOTMEM - prom_printf("bootmem_init: Scan sp_banks, "); -#endif bytes_avail = 0UL; for (i = 0; sp_banks[i].num_bytes != 0; i++) { end_of_phys_memory = sp_banks[i].base_addr + @@ -234,10 +229,6 @@ } #endif /* Initialize the boot-time allocator. */ -#ifdef DEBUG_BOOTMEM - prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],mlpfn[%lx])\n", - start_pfn, bootmap_pfn, max_low_pfn); -#endif bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, max_low_pfn); /* Now register the available physical memory with the @@ -264,23 +255,14 @@ size = (last_pfn - curr_pfn) << PAGE_SHIFT; *pages_avail += last_pfn - curr_pfn; -#ifdef DEBUG_BOOTMEM - prom_printf("free_bootmem: base[%lx] size[%lx]\n", - sp_banks[i].base_addr, - size); -#endif - free_bootmem(sp_banks[i].base_addr, - size); + + free_bootmem(sp_banks[i].base_addr, size); } #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { - size = initrd_end - initrd_start; -#ifdef DEBUG_BOOTMEM - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - initrd_start, size); -#endif /* Reserve the initrd image area. */ + size = initrd_end - initrd_start; reserve_bootmem(initrd_start, size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -290,9 +272,6 @@ #endif /* Reserve the kernel text/data/bss. */ size = (start_pfn << PAGE_SHIFT) - phys_base; -#ifdef DEBUG_BOOTMEM - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", phys_base, size); -#endif reserve_bootmem(phys_base, size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -301,10 +280,6 @@ * in free_all_bootmem. */ size = bootmap_size; -#ifdef DEBUG_BOOTMEM - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - (bootmap_pfn << PAGE_SHIFT), size); -#endif reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; @@ -448,9 +423,6 @@ max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT); high_memory = __va(max_low_pfn << PAGE_SHIFT); -#ifdef DEBUG_BOOTMEM - prom_printf("mem_init: Calling free_all_bootmem().\n"); -#endif num_physpages = totalram_pages = free_all_bootmem(); for (i = 0; sp_banks[i].num_bytes != 0; i++) { diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c --- a/arch/sparc/mm/srmmu.c Mon May 12 20:55:47 2003 +++ b/arch/sparc/mm/srmmu.c Mon May 12 20:55:47 2003 @@ -1310,7 +1310,7 @@ flush_tlb_all(); poke_srmmu(); -#if CONFIG_SUN_IO +#ifdef CONFIG_SUN_IO srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END); srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END); #endif diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c --- a/arch/sparc64/kernel/power.c Mon May 12 20:55:48 2003 +++ b/arch/sparc64/kernel/power.c Mon May 12 20:55:48 2003 @@ -84,6 +84,16 @@ return 0; } +static int __init has_button_interrupt(struct linux_ebus_device *edev) +{ + if (edev->irqs[0] == PCI_IRQ_NONE) + return 0; + if (!prom_node_has_property(edev->prom_node, "button")) + return 0; + + return 1; +} + void __init power_init(void) { struct linux_ebus *ebus; @@ -106,7 +116,7 @@ power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4); printk("power: Control reg at %016lx ... ", power_reg); poweroff_method = machine_halt; /* able to use the standard halt */ - if (edev->irqs[0] != PCI_IRQ_NONE) { + if (has_button_interrupt(edev)) { if (kernel_thread(powerd, 0, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); return; diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Mon May 12 20:55:48 2003 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Mon May 12 20:55:48 2003 @@ -196,11 +196,11 @@ EXPORT_SYMBOL(mostek_lock); EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq); -#if CONFIG_SUN_AUXIO +#ifdef CONFIG_SUN_AUXIO EXPORT_SYMBOL(auxio_set_led); EXPORT_SYMBOL(auxio_set_lte); #endif -#if CONFIG_SBUS +#ifdef CONFIG_SBUS EXPORT_SYMBOL(sbus_root); EXPORT_SYMBOL(dma_chain); EXPORT_SYMBOL(sbus_set_sbus64); diff -Nru a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c --- a/arch/sparc64/solaris/socksys.c Mon May 12 20:55:45 2003 +++ b/arch/sparc64/solaris/socksys.c Mon May 12 20:55:45 2003 @@ -191,10 +191,9 @@ printk ("Couldn't create socket\n"); return ret; } - devfs_register (NULL, "socksys", DEVFS_FL_DEFAULT, - 30, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &socksys_fops, NULL); + + devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys"); + file = fcheck(ret); /* N.B. Is this valid? Suppose the f_ops are in a module ... */ socksys_file_ops = *file->f_op; diff -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c --- a/arch/um/drivers/mmapper_kern.c Mon May 12 20:55:44 2003 +++ b/arch/um/drivers/mmapper_kern.c Mon May 12 20:55:44 2003 @@ -124,9 +124,7 @@ p_buf = __pa(v_buf); - devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, - 30, 0, S_IFCHR | S_IRUGO | S_IWUGO, - &mmapper_fops, NULL); + devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUGO|S_IWUGO, "mmapper"); devfs_mk_symlink("mmapper0", "mmapper"); return(0); } diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c --- a/arch/um/kernel/irq.c Mon May 12 20:55:48 2003 +++ b/arch/um/kernel/irq.c Mon May 12 20:55:48 2003 @@ -48,7 +48,7 @@ * each architecture has to answer this themselves, it doesn't deserve * a generic callback i think. */ -#if CONFIG_X86 +#ifdef CONFIG_X86 printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -121,7 +121,7 @@ } p += sprintf(p, "\n"); #ifdef notdef -#if CONFIG_SMP +#ifdef CONFIG_SMP p += sprintf(p, "LOC: "); for (j = 0; j < num_online_cpus(); j++) p += sprintf(p, "%10u ", @@ -198,7 +198,7 @@ spin_unlock_irqrestore(&desc->lock, flags); } -#if CONFIG_SMP +#ifdef CONFIG_SMP inline void synchronize_irq(unsigned int irq) { /* is there anything to synchronize with? */ @@ -621,7 +621,7 @@ err = parse_hex_value(buffer, count, &new_value); -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * Do not allow disabling IRQs completely - it's a too easy * way to make the system unusable accidentally :-) At least diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c --- a/arch/um/kernel/mem.c Mon May 12 20:55:46 2003 +++ b/arch/um/kernel/mem.c Mon May 12 20:55:46 2003 @@ -124,7 +124,7 @@ kmem_top = new; } -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM /* Changed during early boot */ pte_t *kmap_pte; pgprot_t kmap_prot; @@ -329,7 +329,7 @@ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir); -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM init_highmem(); setup_highmem(highmem); #endif diff -Nru a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c --- a/arch/um/kernel/sys_call_table.c Mon May 12 20:55:48 2003 +++ b/arch/um/kernel/sys_call_table.c Mon May 12 20:55:48 2003 @@ -236,7 +236,7 @@ extern syscall_handler_t sys_remap_file_pages; extern syscall_handler_t sys_set_tid_address; -#if CONFIG_NFSD +#ifdef CONFIG_NFSD #define NFSSERVCTL sys_nfsservctl #else #define NFSSERVCTL sys_ni_syscall diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c --- a/arch/x86_64/kernel/irq.c Mon May 12 20:55:46 2003 +++ b/arch/x86_64/kernel/irq.c Mon May 12 20:55:46 2003 @@ -90,7 +90,7 @@ * each architecture has to answer this themselves, it doesn't deserve * a generic callback i think. */ -#if CONFIG_X86 +#ifdef CONFIG_X86 printk("unexpected IRQ trap at vector %02x\n", irq); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -171,7 +171,7 @@ if (cpu_online(j)) seq_printf(p, "%10u ", cpu_pda[j].__nmi_count); seq_putc(p, '\n'); -#if CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) @@ -827,7 +827,7 @@ return 0; } -#if CONFIG_SMP +#ifdef CONFIG_SMP static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; @@ -906,7 +906,7 @@ /* create /proc/irq/1234 */ irq_dir[irq] = proc_mkdir(name, root_irq_dir); -#if CONFIG_SMP +#ifdef CONFIG_SMP { struct proc_dir_entry *entry; diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c --- a/arch/x86_64/kernel/reboot.c Mon May 12 20:55:48 2003 +++ b/arch/x86_64/kernel/reboot.c Mon May 12 20:55:48 2003 @@ -68,7 +68,7 @@ void machine_restart(char * __unused) { -#if CONFIG_SMP +#ifdef CONFIG_SMP int cpuid; cpuid = GET_APIC_ID(apic_read(APIC_ID)); diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Mon May 12 20:55:44 2003 +++ b/arch/x86_64/kernel/traps.c Mon May 12 20:55:44 2003 @@ -529,7 +529,7 @@ unsigned char reason = inb(0x61); if (!(reason & 0xc0)) { -#if CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_X86_LOCAL_APIC /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. diff -Nru a/crypto/Kconfig b/crypto/Kconfig --- a/crypto/Kconfig Mon May 12 20:55:48 2003 +++ b/crypto/Kconfig Mon May 12 20:55:48 2003 @@ -6,14 +6,16 @@ config CRYPTO bool "Cryptographic API" - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m + default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ + INET6_ESP=y || INET6_ESP=m help This option provides the core Cryptographic API. config CRYPTO_HMAC bool "HMAC support" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m + default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ + INET6_ESP=y || INET6_ESP=m help HMAC: Keyed-Hashing for Message Authentication (RFC2104). This is required for IPSec. @@ -33,14 +35,16 @@ config CRYPTO_MD5 tristate "MD5 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m + default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ + INET6_ESP=y || INET6_ESP=m help MD5 message digest algorithm (RFC1321). config CRYPTO_SHA1 tristate "SHA1 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m + default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ + INET6_ESP=y || INET6_ESP=m help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). @@ -68,7 +72,7 @@ config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m + default y if INET_ESP=y || INET_ESP=m || INET6_ESP=y || INET6_ESP=m help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Mon May 12 20:55:48 2003 +++ b/drivers/Makefile Mon May 12 20:55:48 2003 @@ -37,6 +37,7 @@ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ +obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_SERIO) += input/serio/ diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c --- a/drivers/acpi/acpi_ksyms.c Mon May 12 20:55:45 2003 +++ b/drivers/acpi/acpi_ksyms.c Mon May 12 20:55:45 2003 @@ -80,6 +80,7 @@ EXPORT_SYMBOL(acpi_get_possible_resources); EXPORT_SYMBOL(acpi_walk_resources); EXPORT_SYMBOL(acpi_set_current_resources); +EXPORT_SYMBOL(acpi_resource_to_address64); EXPORT_SYMBOL(acpi_enable_event); EXPORT_SYMBOL(acpi_disable_event); EXPORT_SYMBOL(acpi_clear_event); diff -Nru a/drivers/atm/Kconfig b/drivers/atm/Kconfig --- a/drivers/atm/Kconfig Mon May 12 20:55:46 2003 +++ b/drivers/atm/Kconfig Mon May 12 20:55:46 2003 @@ -440,5 +440,19 @@ default m if ATM_FORE200E_MAYBE!=y default y if ATM_FORE200E_MAYBE=y +config ATM_HE + tristate "ForeRunner HE Series" + depends on PCI && ATM + help + This is a driver for the Marconi ForeRunner HE-series ATM adapter + cards. It simultaneously supports the 155 and 622 versions. + +config ATM_HE_USE_SUNI + bool "Use S/UNI PHY driver" + depends on ATM_HE + help + Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner + HE cards. This driver provides carrier detection some statistics. + endmenu diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile --- a/drivers/atm/Makefile Mon May 12 20:55:44 2003 +++ b/drivers/atm/Makefile Mon May 12 20:55:44 2003 @@ -49,6 +49,10 @@ CONFIG_ATM_FORE200E_SBA_FW := $(obj)/sba200e_ecd.bin2 endif endif +obj-$(CONFIG_ATM_HE) += he.o +ifeq ($(CONFIG_ATM_HE_USE_SUNI),y) + obj-$(CONFIG_ATM_HE) += suni.o +endif # FORE Systems 200E-series firmware magic $(obj)/fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ diff -Nru a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c --- a/drivers/atm/ambassador.c Mon May 12 20:55:44 2003 +++ b/drivers/atm/ambassador.c Mon May 12 20:55:44 2003 @@ -290,12 +290,11 @@ /********** microcode **********/ #ifdef AMB_NEW_MICROCODE -#define UCODE(x) UCODE1(atmsar12.,x) +#define UCODE(x) UCODE2(atmsar12.x) #else -#define UCODE(x) UCODE1(atmsar11.,x) +#define UCODE(x) UCODE2(atmsar11.x) #endif #define UCODE2(x) #x -#define UCODE1(x,y) UCODE2(x ## y) static u32 __initdata ucode_start = #include UCODE(start) diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c --- a/drivers/atm/eni.c Mon May 12 20:55:45 2003 +++ b/drivers/atm/eni.c Mon May 12 20:55:45 2003 @@ -1100,9 +1100,9 @@ dma_rd = eni_in(MID_DMA_RD_TX); dma_size = 3; /* JK for descriptor and final fill, plus final size mis-alignment fix */ -DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt); - if (!ATM_SKB(skb)->iovcnt) dma_size += 5; - else dma_size += 5*ATM_SKB(skb)->iovcnt; +DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); + if (!skb_shinfo(skb)->nr_frags) dma_size += 5; + else dma_size += 5*(skb_shinfo(skb)->nr_frags+1); if (dma_size > TX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries " "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF); @@ -1123,15 +1123,20 @@ MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | MID_DT_JK; j++; - if (!ATM_SKB(skb)->iovcnt) + if (!skb_shinfo(skb)->nr_frags) if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); else { DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ - for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) - put_dma(tx->index,eni_dev->dma,&j,(unsigned long) - ((struct iovec *) skb->data)[i].iov_base, - ((struct iovec *) skb->data)[i].iov_len); + for (i = -1; i < skb_shinfo(skb)->nr_frags; i++) + if (i == -1) + put_dma(tx->index,eni_dev->dma,&j,(unsigned long) + skb->data, + skb->len - skb->data_len); + else + put_dma(tx->index,eni_dev->dma,&j,(unsigned long) + skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset, + skb_shinfo(skb)->frags[i].size); } if (skb->len & 3) put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3)); diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/atm/he.c Mon May 12 20:55:49 2003 @@ -0,0 +1,3260 @@ +/* $Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $ */ + +/* + + he.c + + ForeRunnerHE ATM Adapter driver for ATM on Linux + Copyright (C) 1999-2001 Naval Research Laboratory + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + + he.c + + ForeRunnerHE ATM Adapter driver for ATM on Linux + Copyright (C) 1999-2001 Naval Research Laboratory + + Permission to use, copy, modify and distribute this software and its + documentation is hereby granted, provided that both the copyright + notice and this permission notice appear in all copies of the software, + derivative works or modified versions, and any portions thereof, and + that both notices appear in supporting documentation. + + NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND + DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER + RESULTING FROM THE USE OF THIS SOFTWARE. + + This driver was written using the "Programmer's Reference Manual for + ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98. + + AUTHORS: + chas williams + eric kinzie + + NOTES: + 4096 supported 'connections' + group 0 is used for all traffic + interrupt queue 0 is used for all interrupts + aal0 support (based on work from ulrich.u.muller@nokia.com) + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifndef ATM_OC12_PCR +#define ATM_OC12_PCR (622080000/1080*1040/8/53) +#endif + +#ifdef BUS_INT_WAR +void sn_add_polled_interrupt(int irq, int interval); +void sn_delete_polled_interrupt(int irq); +#endif + +#define USE_TASKLET +#define USE_HE_FIND_VCC +#undef USE_SCATTERGATHER +#undef USE_CHECKSUM_HW /* still confused about this */ +#define USE_RBPS +#undef USE_RBPS_POOL /* if memory is tight try this */ +#undef USE_RBPL_POOL /* if memory is tight try this */ +#define USE_TPD_POOL +/* #undef CONFIG_ATM_HE_USE_SUNI */ + +/* compatibility */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) +typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) +#define __devexit_p(func) func +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(x) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) +#define pci_set_drvdata(pci_dev, data) (pci_dev)->driver_data = (data) +#define pci_get_drvdata(pci_dev) (pci_dev)->driver_data +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44) +#define pci_pool_create(a, b, c, d, e) pci_pool_create(a, b, c, d, e, SLAB_KERNEL) +#endif + +#include "he.h" + +#include "suni.h" + +#include + +#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number, ##args) + +#undef DEBUG +#ifdef DEBUG +#define HPRINTK(fmt,args...) hprintk(fmt,args) +#else +#define HPRINTK(fmt,args...) do { } while(0) +#endif /* DEBUG */ + + +/* version definition */ + +static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $"; + +/* declarations */ + +static int he_open(struct atm_vcc *vcc, short vpi, int vci); +static void he_close(struct atm_vcc *vcc); +static int he_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size); +static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); +static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs); +static void he_tasklet(unsigned long data); +static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); +static int he_start(struct atm_dev *dev); +static void he_stop(struct he_dev *dev); +static void he_phy_put(struct atm_dev *, unsigned char, unsigned long); +static unsigned char he_phy_get(struct atm_dev *, unsigned long); + +static u8 read_prom_byte(struct he_dev *he_dev, int addr); + +/* globals */ + +struct he_dev *he_devs = NULL; +static short disable64 = -1; +static short nvpibits = -1; +static short nvcibits = -1; +static short rx_skb_reserve = 16; +static short irq_coalesce = 1; +static short sdh = 1; + +static struct atmdev_ops he_ops = +{ + open: he_open, + close: he_close, + ioctl: he_ioctl, + send: he_send, + sg_send: he_sg_send, + phy_put: he_phy_put, + phy_get: he_phy_get, + proc_read: he_proc_read, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1) + owner: THIS_MODULE +#endif +}; + +/* see the comments in he.h about global_lock */ + +#define HE_SPIN_LOCK(dev, flags) spin_lock_irqsave(&(dev)->global_lock, flags) +#define HE_SPIN_UNLOCK(dev, flags) spin_unlock_irqrestore(&(dev)->global_lock, flags) + +#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while(0) +#define he_readl(dev, reg) readl((dev)->membase + (reg)) + +/* section 2.12 connection memory access */ + +static __inline__ void +he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr, + unsigned flags) +{ + he_writel(he_dev, val, CON_DAT); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, CON_DAT); +#endif + he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL); + while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); +} + +#define he_writel_rcm(dev, val, reg) \ + he_writel_internal(dev, val, reg, CON_CTL_RCM) + +#define he_writel_tcm(dev, val, reg) \ + he_writel_internal(dev, val, reg, CON_CTL_TCM) + +#define he_writel_mbox(dev, val, reg) \ + he_writel_internal(dev, val, reg, CON_CTL_MBOX) + +static unsigned +he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) +{ + he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL); + while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); + return he_readl(he_dev, CON_DAT); +} + +#define he_readl_rcm(dev, reg) \ + he_readl_internal(dev, reg, CON_CTL_RCM) + +#define he_readl_tcm(dev, reg) \ + he_readl_internal(dev, reg, CON_CTL_TCM) + +#define he_readl_mbox(dev, reg) \ + he_readl_internal(dev, reg, CON_CTL_MBOX) + + +/* figure 2.2 connection id */ + +#define he_mkcid(dev, vpi, vci) (((vpi<<(dev)->vcibits) | vci) & 0x1fff) + +/* 2.5.1 per connection transmit state registers */ + +#define he_writel_tsr0(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 0) +#define he_readl_tsr0(dev, cid) \ + he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 0) + +#define he_writel_tsr1(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 1) + +#define he_writel_tsr2(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 2) + +#define he_writel_tsr3(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 3) + +#define he_writel_tsr4(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 4) + + /* from page 2-20 + * + * NOTE While the transmit connection is active, bits 23 through 0 + * of this register must not be written by the host. Byte + * enables should be used during normal operation when writing + * the most significant byte. + */ + +#define he_writel_tsr4_upper(dev, val, cid) \ + he_writel_internal(dev, val, CONFIG_TSRA | (cid<<3) | 4, \ + CON_CTL_TCM \ + | CON_BYTE_DISABLE_2 \ + | CON_BYTE_DISABLE_1 \ + | CON_BYTE_DISABLE_0) + +#define he_readl_tsr4(dev, cid) \ + he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 4) + +#define he_writel_tsr5(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 5) + +#define he_writel_tsr6(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 6) + +#define he_writel_tsr7(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 7) + + +#define he_writel_tsr8(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 0) + +#define he_writel_tsr9(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 1) + +#define he_writel_tsr10(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 2) + +#define he_writel_tsr11(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 3) + + +#define he_writel_tsr12(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 0) + +#define he_writel_tsr13(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 1) + + +#define he_writel_tsr14(dev, val, cid) \ + he_writel_tcm(dev, val, CONFIG_TSRD | cid) + +#define he_writel_tsr14_upper(dev, val, cid) \ + he_writel_internal(dev, val, CONFIG_TSRD | cid, \ + CON_CTL_TCM \ + | CON_BYTE_DISABLE_2 \ + | CON_BYTE_DISABLE_1 \ + | CON_BYTE_DISABLE_0) + +/* 2.7.1 per connection receive state registers */ + +#define he_writel_rsr0(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 0) +#define he_readl_rsr0(dev, cid) \ + he_readl_rcm(dev, 0x00000 | (cid<<3) | 0) + +#define he_writel_rsr1(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 1) + +#define he_writel_rsr2(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 2) + +#define he_writel_rsr3(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 3) + +#define he_writel_rsr4(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 4) + +#define he_writel_rsr5(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 5) + +#define he_writel_rsr6(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 6) + +#define he_writel_rsr7(dev, val, cid) \ + he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 7) + +static __inline__ struct atm_vcc* +he_find_vcc(struct he_dev *he_dev, unsigned cid) +{ + struct atm_vcc *vcc; + short vpi; + int vci; + + vpi = cid >> he_dev->vcibits; + vci = cid & ((1<vcibits)-1); + + for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next) + if (vcc->vci == vci && vcc->vpi == vpi + && vcc->qos.rxtp.traffic_class != ATM_NONE) return vcc; + + return NULL; +} + +static int __devinit +he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) +{ + struct atm_dev *atm_dev = NULL; + struct he_dev *he_dev = NULL; + int err = 0; + + printk(KERN_INFO "he: %s\n", version); + + if (pci_enable_device(pci_dev)) return -EIO; + if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0) { + printk(KERN_WARNING "he: no suitable dma available\n"); + err = -EIO; + goto init_one_failure; + } + + atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, 0); + if (!atm_dev) { + err = -ENODEV; + goto init_one_failure; + } + pci_set_drvdata(pci_dev, atm_dev); + + he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev), + GFP_KERNEL); + if (!he_dev) { + err = -ENOMEM; + goto init_one_failure; + } + memset(he_dev, 0, sizeof(struct he_dev)); + + he_dev->pci_dev = pci_dev; + he_dev->atm_dev = atm_dev; + he_dev->atm_dev->dev_data = he_dev; + HE_DEV(atm_dev) = he_dev; + he_dev->number = atm_dev->number; + if (he_start(atm_dev)) { + he_stop(he_dev); + err = -ENODEV; + goto init_one_failure; + } + he_dev->next = NULL; + if (he_devs) he_dev->next = he_devs; + he_devs = he_dev; + return 0; + +init_one_failure: + if (atm_dev) + atm_dev_deregister(atm_dev); + if (he_dev) + kfree(he_dev); + pci_disable_device(pci_dev); + return err; +} + +static void __devexit +he_remove_one (struct pci_dev *pci_dev) +{ + struct atm_dev *atm_dev; + struct he_dev *he_dev; + + atm_dev = pci_get_drvdata(pci_dev); + he_dev = HE_DEV(atm_dev); + + /* need to remove from he_devs */ + + he_stop(he_dev); + atm_dev_deregister(atm_dev); + kfree(he_dev); + + pci_set_drvdata(pci_dev, NULL); + pci_disable_device(pci_dev); +} + + +static unsigned +rate_to_atmf(unsigned rate) /* cps to atm forum format */ +{ +#define NONZERO (1<<14) + + unsigned exp = 0; + + if (rate == 0) return(0); + + rate <<= 9; + while (rate > 0x3ff) + { + ++exp; + rate >>= 1; + } + + return (NONZERO | (exp << 9) | (rate & 0x1ff)); +} + +static void __init +he_init_rx_lbfp0(struct he_dev *he_dev) +{ + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; + + lbufd_index = 0; + lbm_offset = he_readl(he_dev, RCMLBM_BA); + + he_writel(he_dev, lbufd_index, RLBF0_H); + + for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) + { + lbufd_index += 2; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + + he_writel_rcm(he_dev, lbuf_addr, lbm_offset); + he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); + + if (++lbuf_count == lbufs_per_row) + { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } + lbm_offset += 4; + } + + he_writel(he_dev, lbufd_index - 2, RLBF0_T); + he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); +} + +static void __init +he_init_rx_lbfp1(struct he_dev *he_dev) +{ + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; + + lbufd_index = 1; + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + + he_writel(he_dev, lbufd_index, RLBF1_H); + + for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) + { + lbufd_index += 2; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + + he_writel_rcm(he_dev, lbuf_addr, lbm_offset); + he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); + + if (++lbuf_count == lbufs_per_row) + { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } + lbm_offset += 4; + } + + he_writel(he_dev, lbufd_index - 2, RLBF1_T); + he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); +} + +static void __init +he_init_tx_lbfp(struct he_dev *he_dev) +{ + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; + + lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + + he_writel(he_dev, lbufd_index, TLBF_H); + + for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) + { + lbufd_index += 1; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + + he_writel_rcm(he_dev, lbuf_addr, lbm_offset); + he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); + + if (++lbuf_count == lbufs_per_row) + { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } + lbm_offset += 2; + } + + he_writel(he_dev, lbufd_index - 1, TLBF_T); +} + +static int __init +he_init_tpdrq(struct he_dev *he_dev) +{ + he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys); + if (he_dev->tpdrq_base == NULL) + { + hprintk("failed to alloc tpdrq\n"); + return -ENOMEM; + } + memset(he_dev->tpdrq_base, 0, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq)); + + he_dev->tpdrq_tail = he_dev->tpdrq_base; + he_dev->tpdrq_head = he_dev->tpdrq_base; + + he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H); + he_writel(he_dev, 0, TPDRQ_T); + he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S); + + return 0; +} + +static void __init +he_init_cs_block(struct he_dev *he_dev) +{ + unsigned clock, rate, delta; + int reg; + + /* 5.1.7 cs block initialization */ + + for(reg = 0; reg < 0x20; ++reg) + he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg); + + /* rate grid timer reload values */ + + clock = he_is622(he_dev) ? 66667000 : 50000000; + rate = he_dev->atm_dev->link_rate; + delta = rate / 16 / 2; + + for(reg = 0; reg < 0x10; ++reg) + { + /* 2.4 internal transmit function + * + * we initialize the first row in the rate grid. + * values are period (in clock cycles) of timer + */ + unsigned period = clock / rate; + + he_writel_mbox(he_dev, period, CS_TGRLD0 + reg); + rate -= delta; + } + + if (he_is622(he_dev)) + { + /* table 5.2 (4 cells per lbuf) */ + he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0); + he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1); + he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2); + he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3); + he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4); + + /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ + he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0); + he_writel_mbox(he_dev, 0x1801, CS_ERCTL1); + he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2); + he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); + he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1); + he_writel_mbox(he_dev, 0x14585, CS_RTFWR); + + he_writel_mbox(he_dev, 0x4680, CS_RTATR); + + /* table 5.8 */ + he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET); + he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX); + he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN); + he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC); + he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC); + he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL); + + /* table 5.9 */ + he_writel_mbox(he_dev, 0x5, CS_OTPPER); + he_writel_mbox(he_dev, 0x14, CS_OTWPER); + } + else + { + /* table 5.1 (4 cells per lbuf) */ + he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0); + he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1); + he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2); + he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3); + he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4); + + /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ + he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0); + he_writel_mbox(he_dev, 0x4701, CS_ERCTL1); + he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2); + he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); + he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1); + he_writel_mbox(he_dev, 0xf424, CS_RTFWR); + + he_writel_mbox(he_dev, 0x4680, CS_RTATR); + + /* table 5.8 */ + he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET); + he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX); + he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN); + he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC); + he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC); + he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL); + + /* table 5.9 */ + he_writel_mbox(he_dev, 0x6, CS_OTPPER); + he_writel_mbox(he_dev, 0x1e, CS_OTWPER); + + } + + he_writel_mbox(he_dev, 0x8, CS_OTTLIM); + + for(reg = 0; reg < 0x8; ++reg) + he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg); + +} + +static void __init +he_init_cs_block_rcm(struct he_dev *he_dev) +{ + unsigned rategrid[16][16]; + unsigned rate, delta; + int i, j, reg; + + unsigned rate_atmf, exp, man; + unsigned long long rate_cps; + int mult, buf, buf_limit = 4; + + /* initialize rate grid group table */ + + for (reg = 0x0; reg < 0xff; ++reg) + he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); + + /* initialize rate controller groups */ + + for (reg = 0x100; reg < 0x1ff; ++reg) + he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); + + /* initialize tNrm lookup table */ + + /* the manual makes reference to a routine in a sample driver + for proper configuration; fortunately, we only need this + in order to support abr connection */ + + /* initialize rate to group table */ + + rate = he_dev->atm_dev->link_rate; + delta = rate / 32; + + /* + * 2.4 transmit internal functions + * + * we construct a copy of the rate grid used by the scheduler + * in order to construct the rate to group table below + */ + + for (j = 0; j < 16; j++) + { + rategrid[0][j] = rate; + rate -= delta; + } + + for (i = 1; i < 16; i++) + for (j = 0; j < 16; j++) + if (i > 14) + rategrid[i][j] = rategrid[i - 1][j] / 4; + else + rategrid[i][j] = rategrid[i - 1][j] / 2; + + /* + * 2.4 transmit internal function + * + * this table maps the upper 5 bits of exponent and mantissa + * of the atm forum representation of the rate into an index + * on rate grid + */ + + rate_atmf = 0; + while (rate_atmf < 0x400) + { + man = (rate_atmf & 0x1f) << 4; + exp = rate_atmf >> 5; + + /* + instead of '/ 512', use '>> 9' to prevent a call + to divdu3 on x86 platforms + */ + rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9; + + if (rate_cps < 10) rate_cps = 10; + /* 2.2.1 minimum payload rate is 10 cps */ + + for (i = 255; i > 0; i--) + if (rategrid[i/16][i%16] >= rate_cps) break; + /* pick nearest rate instead? */ + + /* + * each table entry is 16 bits: (rate grid index (8 bits) + * and a buffer limit (8 bits) + * there are two table entries in each 32-bit register + */ + +#ifdef notdef + buf = rate_cps * he_dev->tx_numbuffs / + (he_dev->atm_dev->link_rate * 2); +#else + /* this is pretty, but avoids _divdu3 and is mostly correct */ + buf = 0; + mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; + if (rate_cps > (68 * mult)) buf = 1; + if (rate_cps > (136 * mult)) buf = 2; + if (rate_cps > (204 * mult)) buf = 3; + if (rate_cps > (272 * mult)) buf = 4; +#endif + if (buf > buf_limit) buf = buf_limit; + reg = (reg<<16) | ((i<<8) | buf); + +#define RTGTBL_OFFSET 0x400 + + if (rate_atmf & 0x1) + he_writel_rcm(he_dev, reg, + CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf>>1)); + + ++rate_atmf; + } +} + +static int __init +he_init_group(struct he_dev *he_dev, int group) +{ + int i; + +#ifdef USE_RBPS + /* small buffer pool */ +#ifdef USE_RBPS_POOL + he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev, + CONFIG_RBPS_BUFSIZE, 8, 0); + if (he_dev->rbps_pool == NULL) + { + hprintk("unable to create rbps pages\n"); + return -ENOMEM; + } +#else /* !USE_RBPS_POOL */ + he_dev->rbps_pages = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_RBPS_SIZE * CONFIG_RBPS_BUFSIZE, &he_dev->rbps_pages_phys); + if (he_dev->rbps_pages == NULL) { + hprintk("unable to create rbps page pool\n"); + return -ENOMEM; + } +#endif /* USE_RBPS_POOL */ + + he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); + if (he_dev->rbps_base == NULL) + { + hprintk("failed to alloc rbps\n"); + return -ENOMEM; + } + memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); + he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL); + + for (i = 0; i < CONFIG_RBPS_SIZE; ++i) + { + dma_addr_t dma_handle; + void *cpuaddr; + +#ifdef USE_RBPS_POOL + cpuaddr = pci_pool_alloc(he_dev->rbps_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle); + if (cpuaddr == NULL) + return -ENOMEM; +#else + cpuaddr = he_dev->rbps_pages + (i * CONFIG_RBPS_BUFSIZE); + dma_handle = he_dev->rbps_pages_phys + (i * CONFIG_RBPS_BUFSIZE); +#endif + + he_dev->rbps_virt[i].virt = cpuaddr; + he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF); + he_dev->rbps_base[i].phys = dma_handle; + + } + he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE-1]; + + he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32)); + he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), + G0_RBPS_T + (group * 32)); + he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4, + G0_RBPS_BS + (group * 32)); + he_writel(he_dev, + RBP_THRESH(CONFIG_RBPS_THRESH) | + RBP_QSIZE(CONFIG_RBPS_SIZE-1) | + RBP_INT_ENB, + G0_RBPS_QI + (group * 32)); +#else /* !USE_RBPS */ + he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); + he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), + G0_RBPS_BS + (group * 32)); +#endif /* USE_RBPS */ + + /* large buffer pool */ +#ifdef USE_RBPL_POOL + he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, + CONFIG_RBPL_BUFSIZE, 8, 0); + if (he_dev->rbpl_pool == NULL) + { + hprintk("unable to create rbpl pool\n"); + return -ENOMEM; + } +#else /* !USE_RBPL_POOL */ + he_dev->rbpl_pages = (void *) pci_alloc_consistent(he_dev->pci_dev, + CONFIG_RBPL_SIZE * CONFIG_RBPL_BUFSIZE, &he_dev->rbpl_pages_phys); + if (he_dev->rbpl_pages == NULL) + { + hprintk("unable to create rbpl pages\n"); + return -ENOMEM; + } +#endif /* USE_RBPL_POOL */ + + he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); + if (he_dev->rbpl_base == NULL) + { + hprintk("failed to alloc rbpl\n"); + return -ENOMEM; + } + memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); + he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); + + for (i = 0; i < CONFIG_RBPL_SIZE; ++i) + { + dma_addr_t dma_handle; + void *cpuaddr; + +#ifdef USE_RBPL_POOL + cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle); + if (cpuaddr == NULL) + return -ENOMEM; +#else + cpuaddr = he_dev->rbpl_pages + (i * CONFIG_RBPL_BUFSIZE); + dma_handle = he_dev->rbpl_pages_phys + (i * CONFIG_RBPL_BUFSIZE); +#endif + + he_dev->rbpl_virt[i].virt = cpuaddr; + he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); + he_dev->rbpl_base[i].phys = dma_handle; + + } + he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE-1]; + + he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); + he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), + G0_RBPL_T + (group * 32)); + he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4, + G0_RBPL_BS + (group * 32)); + he_writel(he_dev, + RBP_THRESH(CONFIG_RBPL_THRESH) | + RBP_QSIZE(CONFIG_RBPL_SIZE-1) | + RBP_INT_ENB, + G0_RBPL_QI + (group * 32)); + + /* rx buffer ready queue */ + + he_dev->rbrq_base = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); + if (he_dev->rbrq_base == NULL) + { + hprintk("failed to allocate rbrq\n"); + return -ENOMEM; + } + memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq)); + + he_dev->rbrq_head = he_dev->rbrq_base; + he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); + he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); + he_writel(he_dev, + RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1), + G0_RBRQ_Q + (group * 16)); + if (irq_coalesce) + { + hprintk("coalescing interrupts\n"); + he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), + G0_RBRQ_I + (group * 16)); + } + else + he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1), + G0_RBRQ_I + (group * 16)); + + /* tx buffer ready queue */ + + he_dev->tbrq_base = pci_alloc_consistent(he_dev->pci_dev, + CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); + if (he_dev->tbrq_base == NULL) + { + hprintk("failed to allocate tbrq\n"); + return -ENOMEM; + } + memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq)); + + he_dev->tbrq_head = he_dev->tbrq_base; + + he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16)); + he_writel(he_dev, 0, G0_TBRQ_H + (group * 16)); + he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16)); + he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); + + return 0; +} + +static int __init +he_init_irq(struct he_dev *he_dev) +{ + int i; + + /* 2.9.3.5 tail offset for each interrupt queue is located after the + end of the interrupt queue */ + + he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, + (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); + if (he_dev->irq_base == NULL) + { + hprintk("failed to allocate irq\n"); + return -ENOMEM; + } + he_dev->irq_tailoffset = (unsigned *) + &he_dev->irq_base[CONFIG_IRQ_SIZE]; + *he_dev->irq_tailoffset = 0; + he_dev->irq_head = he_dev->irq_base; + he_dev->irq_tail = he_dev->irq_base; + + for(i=0; i < CONFIG_IRQ_SIZE; ++i) + he_dev->irq_base[i].isw = ITYPE_INVALID; + + he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); + he_writel(he_dev, + IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH), + IRQ0_HEAD); + he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL); + he_writel(he_dev, 0x0, IRQ0_DATA); + + he_writel(he_dev, 0x0, IRQ1_BASE); + he_writel(he_dev, 0x0, IRQ1_HEAD); + he_writel(he_dev, 0x0, IRQ1_CNTL); + he_writel(he_dev, 0x0, IRQ1_DATA); + + he_writel(he_dev, 0x0, IRQ2_BASE); + he_writel(he_dev, 0x0, IRQ2_HEAD); + he_writel(he_dev, 0x0, IRQ2_CNTL); + he_writel(he_dev, 0x0, IRQ2_DATA); + + he_writel(he_dev, 0x0, IRQ3_BASE); + he_writel(he_dev, 0x0, IRQ3_HEAD); + he_writel(he_dev, 0x0, IRQ3_CNTL); + he_writel(he_dev, 0x0, IRQ3_DATA); + + /* 2.9.3.2 interrupt queue mapping registers */ + + he_writel(he_dev, 0x0, GRP_10_MAP); + he_writel(he_dev, 0x0, GRP_32_MAP); + he_writel(he_dev, 0x0, GRP_54_MAP); + he_writel(he_dev, 0x0, GRP_76_MAP); + + if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev)) + { + hprintk("irq %d already in use\n", he_dev->pci_dev->irq); + return -EINVAL; + } + + he_dev->irq = he_dev->pci_dev->irq; + +#ifdef BUS_INT_WAR + HPRINTK("sn_add_polled_interrupt(irq %d, 1)\n", he_dev->irq); + sn_add_polled_interrupt(he_dev->irq, 1); +#endif + + return 0; +} + +static int __init +he_start(struct atm_dev *dev) +{ + struct he_dev *he_dev; + struct pci_dev *pci_dev; + + u16 command; + u32 gen_cntl_0, host_cntl, lb_swap; + u8 cache_size, timer; + + unsigned err; + unsigned int status, reg; + int i, group; + + he_dev = HE_DEV(dev); + pci_dev = he_dev->pci_dev; + + he_dev->membase = pci_dev->resource[0].start; + HPRINTK("membase = 0x%lx irq = %d.\n", he_dev->membase, pci_dev->irq); + + /* + * pci bus controller initialization + */ + + /* 4.3 pci bus controller-specific initialization */ + if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) + { + hprintk("can't read GEN_CNTL_0\n"); + return -EINVAL; + } + gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); + if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) + { + hprintk("can't write GEN_CNTL_0.\n"); + return -EINVAL; + } + + if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) + { + hprintk("can't read PCI_COMMAND.\n"); + return -EINVAL; + } + + command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); + if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) + { + hprintk("can't enable memory.\n"); + return -EINVAL; + } + + if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) + { + hprintk("can't read cache line size?\n"); + return -EINVAL; + } + + if (cache_size < 16) + { + cache_size = 16; + if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size)) + hprintk("can't set cache line size to %d\n", cache_size); + } + + if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) + { + hprintk("can't read latency timer?\n"); + return -EINVAL; + } + + /* from table 3.9 + * + * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE + * + * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles] + * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles] + * + */ +#define LAT_TIMER 209 + if (timer < LAT_TIMER) + { + HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER); + timer = LAT_TIMER; + if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer)) + hprintk("can't set latency timer to %d\n", timer); + } + + if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) { + hprintk("can't set up page mapping\n"); + return -EINVAL; + } + + /* 4.4 card reset */ + he_writel(he_dev, 0x0, RESET_CNTL); + he_writel(he_dev, 0xff, RESET_CNTL); + + udelay(16*1000); /* 16 ms */ + status = he_readl(he_dev, RESET_CNTL); + if ((status & BOARD_RST_STATUS) == 0) + { + hprintk("reset failed\n"); + return -EINVAL; + } + + /* 4.5 set bus width */ + host_cntl = he_readl(he_dev, HOST_CNTL); + if (host_cntl & PCI_BUS_SIZE64) + gen_cntl_0 |= ENBL_64; + else + gen_cntl_0 &= ~ENBL_64; + + if (disable64 == 1) + { + hprintk("disabling 64-bit pci bus transfers\n"); + gen_cntl_0 &= ~ENBL_64; + } + + if (gen_cntl_0 & ENBL_64) hprintk("64-bit transfers enabled\n"); + + pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); + + /* 4.7 read prom contents */ + for(i=0; iprod_id[i] = read_prom_byte(he_dev, PROD_ID + i); + + he_dev->media = read_prom_byte(he_dev, MEDIA); + + for(i=0; i<6; ++i) + dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); + + hprintk("%s%s, %x:%x:%x:%x:%x:%x\n", + he_dev->prod_id, + he_dev->media & 0x40 ? "SM" : "MM", + dev->esi[0], + dev->esi[1], + dev->esi[2], + dev->esi[3], + dev->esi[4], + dev->esi[5]); + he_dev->atm_dev->link_rate = he_is622(he_dev) ? + ATM_OC12_PCR : ATM_OC3_PCR; + + /* 4.6 set host endianess */ + lb_swap = he_readl(he_dev, LB_SWAP); + if (he_is622(he_dev)) + lb_swap &= ~XFER_SIZE; /* 4 cells */ + else + lb_swap |= XFER_SIZE; /* 8 cells */ +#ifdef __BIG_ENDIAN + lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST; +#else + lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST | + DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP); +#endif /* __BIG_ENDIAN */ + he_writel(he_dev, lb_swap, LB_SWAP); + + /* 4.8 sdram controller initialization */ + he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL); + + /* 4.9 initialize rnum value */ + lb_swap |= SWAP_RNUM_MAX(0xf); + he_writel(he_dev, lb_swap, LB_SWAP); + + /* 4.10 initialize the interrupt queues */ + if ((err = he_init_irq(he_dev)) != 0) return err; + +#ifdef USE_TASKLET + tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); +#endif + spin_lock_init(&he_dev->global_lock); + + /* 4.11 enable pci bus controller state machines */ + host_cntl |= (OUTFF_ENB | CMDFF_ENB | + QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB); + he_writel(he_dev, host_cntl, HOST_CNTL); + + gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB; + pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); + + /* + * atm network controller initialization + */ + + /* 5.1.1 generic configuration state */ + + /* + * local (cell) buffer memory map + * + * HE155 HE622 + * + * 0 ____________1023 bytes 0 _______________________2047 bytes + * | | | | | + * | utility | | rx0 | | + * 5|____________| 255|___________________| u | + * 6| | 256| | t | + * | | | | i | + * | rx0 | row | tx | l | + * | | | | i | + * | | 767|___________________| t | + * 517|____________| 768| | y | + * row 518| | | rx1 | | + * | | 1023|___________________|___| + * | | + * | tx | + * | | + * | | + * 1535|____________| + * 1536| | + * | rx1 | + * 2047|____________| + * + */ + + /* total 4096 connections */ + he_dev->vcibits = CONFIG_DEFAULT_VCIBITS; + he_dev->vpibits = CONFIG_DEFAULT_VPIBITS; + + if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) + { + hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS); + return -ENODEV; + } + + if (nvpibits != -1) + { + he_dev->vpibits = nvpibits; + he_dev->vcibits = HE_MAXCIDBITS - nvpibits; + } + + if (nvcibits != -1) + { + he_dev->vcibits = nvcibits; + he_dev->vpibits = HE_MAXCIDBITS - nvcibits; + } + + + if (he_is622(he_dev)) + { + he_dev->cells_per_row = 40; + he_dev->bytes_per_row = 2048; + he_dev->r0_numrows = 256; + he_dev->tx_numrows = 512; + he_dev->r1_numrows = 256; + he_dev->r0_startrow = 0; + he_dev->tx_startrow = 256; + he_dev->r1_startrow = 768; + } + else + { + he_dev->cells_per_row = 20; + he_dev->bytes_per_row = 1024; + he_dev->r0_numrows = 512; + he_dev->tx_numrows = 1018; + he_dev->r1_numrows = 512; + he_dev->r0_startrow = 6; + he_dev->tx_startrow = 518; + he_dev->r1_startrow = 1536; + } + + he_dev->cells_per_lbuf = 4; + he_dev->buffer_limit = 4; + he_dev->r0_numbuffs = he_dev->r0_numrows * + he_dev->cells_per_row / he_dev->cells_per_lbuf; + if (he_dev->r0_numbuffs > 2560) he_dev->r0_numbuffs = 2560; + + he_dev->r1_numbuffs = he_dev->r1_numrows * + he_dev->cells_per_row / he_dev->cells_per_lbuf; + if (he_dev->r1_numbuffs > 2560) he_dev->r1_numbuffs = 2560; + + he_dev->tx_numbuffs = he_dev->tx_numrows * + he_dev->cells_per_row / he_dev->cells_per_lbuf; + if (he_dev->tx_numbuffs > 5120) he_dev->tx_numbuffs = 5120; + + /* 5.1.2 configure hardware dependent registers */ + + he_writel(he_dev, + SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) | + RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) | + (he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) | + (he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)), + LBARB); + + he_writel(he_dev, BANK_ON | + (he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)), + SDRAMCON); + + he_writel(he_dev, + (he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) | + RM_RW_WAIT(1), RCMCONFIG); + he_writel(he_dev, + (he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) | + TM_RW_WAIT(1), TCMCONFIG); + + he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG); + + he_writel(he_dev, + (he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) | + (he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) | + RX_VALVP(he_dev->vpibits) | + RX_VALVC(he_dev->vcibits), RC_CONFIG); + + he_writel(he_dev, DRF_THRESH(0x20) | + (he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) | + TX_VCI_MASK(he_dev->vcibits) | + LBFREE_CNT(he_dev->tx_numbuffs), TX_CONFIG); + + he_writel(he_dev, 0x0, TXAAL5_PROTO); + + he_writel(he_dev, PHY_INT_ENB | + (he_is622(he_dev) ? PTMR_PRE(67-1) : PTMR_PRE(50-1)), + RH_CONFIG); + + /* 5.1.3 initialize connection memory */ + + for(i=0; i < TCM_MEM_SIZE; ++i) + he_writel_tcm(he_dev, 0, i); + + for(i=0; i < RCM_MEM_SIZE; ++i) + he_writel_rcm(he_dev, 0, i); + + /* + * transmit connection memory map + * + * tx memory + * 0x0 ___________________ + * | | + * | | + * | TSRa | + * | | + * | | + * 0x8000|___________________| + * | | + * | TSRb | + * 0xc000|___________________| + * | | + * | TSRc | + * 0xe000|___________________| + * | TSRd | + * 0xf000|___________________| + * | tmABR | + * 0x10000|___________________| + * | | + * | tmTPD | + * |___________________| + * | | + * .... + * 0x1ffff|___________________| + * + * + */ + + he_writel(he_dev, CONFIG_TSRB, TSRB_BA); + he_writel(he_dev, CONFIG_TSRC, TSRC_BA); + he_writel(he_dev, CONFIG_TSRD, TSRD_BA); + he_writel(he_dev, CONFIG_TMABR, TMABR_BA); + he_writel(he_dev, CONFIG_TPDBA, TPD_BA); + + + /* + * receive connection memory map + * + * 0x0 ___________________ + * | | + * | | + * | RSRa | + * | | + * | | + * 0x8000|___________________| + * | | + * | rx0/1 | + * | LBM | link lists of local + * | tx | buffer memory + * | | + * 0xd000|___________________| + * | | + * | rmABR | + * 0xe000|___________________| + * | | + * | RSRb | + * |___________________| + * | | + * .... + * 0xffff|___________________| + */ + + he_writel(he_dev, 0x08000, RCMLBM_BA); + he_writel(he_dev, 0x0e000, RCMRSRB_BA); + he_writel(he_dev, 0x0d800, RCMABR_BA); + + /* 5.1.4 initialize local buffer free pools linked lists */ + + he_init_rx_lbfp0(he_dev); + he_init_rx_lbfp1(he_dev); + + he_writel(he_dev, 0x0, RLBC_H); + he_writel(he_dev, 0x0, RLBC_T); + he_writel(he_dev, 0x0, RLBC_H2); + + he_writel(he_dev, 512, RXTHRSH); /* 10% of r0+r1 buffers */ + he_writel(he_dev, 256, LITHRSH); /* 5% of r0+r1 buffers */ + + he_init_tx_lbfp(he_dev); + + he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA); + + /* 5.1.5 initialize intermediate receive queues */ + + if (he_is622(he_dev)) + { + he_writel(he_dev, 0x000f, G0_INMQ_S); + he_writel(he_dev, 0x200f, G0_INMQ_L); + + he_writel(he_dev, 0x001f, G1_INMQ_S); + he_writel(he_dev, 0x201f, G1_INMQ_L); + + he_writel(he_dev, 0x002f, G2_INMQ_S); + he_writel(he_dev, 0x202f, G2_INMQ_L); + + he_writel(he_dev, 0x003f, G3_INMQ_S); + he_writel(he_dev, 0x203f, G3_INMQ_L); + + he_writel(he_dev, 0x004f, G4_INMQ_S); + he_writel(he_dev, 0x204f, G4_INMQ_L); + + he_writel(he_dev, 0x005f, G5_INMQ_S); + he_writel(he_dev, 0x205f, G5_INMQ_L); + + he_writel(he_dev, 0x006f, G6_INMQ_S); + he_writel(he_dev, 0x206f, G6_INMQ_L); + + he_writel(he_dev, 0x007f, G7_INMQ_S); + he_writel(he_dev, 0x207f, G7_INMQ_L); + } + else + { + he_writel(he_dev, 0x0000, G0_INMQ_S); + he_writel(he_dev, 0x0008, G0_INMQ_L); + + he_writel(he_dev, 0x0001, G1_INMQ_S); + he_writel(he_dev, 0x0009, G1_INMQ_L); + + he_writel(he_dev, 0x0002, G2_INMQ_S); + he_writel(he_dev, 0x000a, G2_INMQ_L); + + he_writel(he_dev, 0x0003, G3_INMQ_S); + he_writel(he_dev, 0x000b, G3_INMQ_L); + + he_writel(he_dev, 0x0004, G4_INMQ_S); + he_writel(he_dev, 0x000c, G4_INMQ_L); + + he_writel(he_dev, 0x0005, G5_INMQ_S); + he_writel(he_dev, 0x000d, G5_INMQ_L); + + he_writel(he_dev, 0x0006, G6_INMQ_S); + he_writel(he_dev, 0x000e, G6_INMQ_L); + + he_writel(he_dev, 0x0007, G7_INMQ_S); + he_writel(he_dev, 0x000f, G7_INMQ_L); + } + + /* 5.1.6 application tunable parameters */ + + he_writel(he_dev, 0x0, MCC); + he_writel(he_dev, 0x0, OEC); + he_writel(he_dev, 0x0, DCC); + he_writel(he_dev, 0x0, CEC); + + /* 5.1.7 cs block initialization */ + + he_init_cs_block(he_dev); + + /* 5.1.8 cs block connection memory initialization */ + + he_init_cs_block_rcm(he_dev); + + /* 5.1.10 initialize host structures */ + + he_init_tpdrq(he_dev); + +#ifdef USE_TPD_POOL + he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, + sizeof(struct he_tpd), TPD_ALIGNMENT, 0); + if (he_dev->tpd_pool == NULL) + { + hprintk("unable to create tpd pci_pool\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&he_dev->outstanding_tpds); +#else + he_dev->tpd_base = (void *) pci_alloc_consistent(he_dev->pci_dev, + CONFIG_NUMTPDS * sizeof(struct he_tpd), &he_dev->tpd_base_phys); + if (!he_dev->tpd_base) + return -ENOMEM; + + for(i = 0; i < CONFIG_NUMTPDS; ++i) + { + he_dev->tpd_base[i].status = (i << TPD_ADDR_SHIFT); + he_dev->tpd_base[i].inuse = 0; + } + + he_dev->tpd_head = he_dev->tpd_base; + he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS-1]; +#endif + + if (he_init_group(he_dev, 0) != 0) + return -ENOMEM; + + for (group = 1; group < HE_NUM_GROUPS; ++group) + { + he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); + he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), + G0_RBPS_BS + (group * 32)); + + he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32)); + he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), + G0_RBPL_QI + (group * 32)); + he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32)); + + he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16)); + he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16)); + he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0), + G0_RBRQ_Q + (group * 16)); + he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16)); + + he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16)); + he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16)); + he_writel(he_dev, TBRQ_THRESH(0x1), + G0_TBRQ_THRESH + (group * 16)); + he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16)); + } + + /* host status page */ + + he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev, + sizeof(struct he_hsp), &he_dev->hsp_phys); + if (he_dev->hsp == NULL) + { + hprintk("failed to allocate host status page\n"); + return -ENOMEM; + } + memset(he_dev->hsp, 0, sizeof(struct he_hsp)); + he_writel(he_dev, he_dev->hsp_phys, HSP_BA); + + /* initialize framer */ + +#ifdef CONFIG_ATM_HE_USE_SUNI + suni_init(he_dev->atm_dev); + if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start) + he_dev->atm_dev->phy->start(he_dev->atm_dev); +#endif /* CONFIG_ATM_HE_USE_SUNI */ + + if (sdh) + { + /* this really should be in suni.c but for now... */ + + int val; + + val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM); + val = (val & ~SUNI_TPOP_APM_S) | ( 0x2 << SUNI_TPOP_APM_S_SHIFT); + he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM); + } + + /* 5.1.12 enable transmit and receive */ + + reg = he_readl_mbox(he_dev, CS_ERCTL0); + reg |= TX_ENABLE|ER_ENABLE; + he_writel_mbox(he_dev, reg, CS_ERCTL0); + + reg = he_readl(he_dev, RC_CONFIG); + reg |= RX_ENABLE; + he_writel(he_dev, reg, RC_CONFIG); + +#ifndef USE_HE_FIND_VCC + he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * + (1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL); + if (he_dev->he_vcc_table == NULL) + { + hprintk("failed to alloc he_vcc_table\n"); + return -ENOMEM; + } + memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) * + (1 << (he_dev->vcibits + he_dev->vpibits))); +#endif + + for (i = 0; i < HE_NUM_CS_STPER; ++i) + { + he_dev->cs_stper[i].inuse = 0; + he_dev->cs_stper[i].pcr = -1; + } + he_dev->total_bw = 0; + + + /* atm linux initialization */ + + he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits; + he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits; + + he_dev->irq_peak = 0; + he_dev->rbrq_peak = 0; + he_dev->rbpl_peak = 0; + he_dev->tbrq_peak = 0; + + HPRINTK("hell bent for leather!\n"); + + return 0; +} + +static void +he_stop(struct he_dev *he_dev) +{ + u16 command; + u32 gen_cntl_0, reg; + struct pci_dev *pci_dev; + + pci_dev = he_dev->pci_dev; + + /* disable interrupts */ + + if (he_dev->membase) + { + pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0); + gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); + pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); + +#ifdef USE_TASKLET + tasklet_disable(&he_dev->tasklet); +#endif + + /* disable recv and transmit */ + + reg = he_readl_mbox(he_dev, CS_ERCTL0); + reg &= ~(TX_ENABLE|ER_ENABLE); + he_writel_mbox(he_dev, reg, CS_ERCTL0); + + reg = he_readl(he_dev, RC_CONFIG); + reg &= ~(RX_ENABLE); + he_writel(he_dev, reg, RC_CONFIG); + } + +#ifdef CONFIG_ATM_HE_USE_SUNI + if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop) + he_dev->atm_dev->phy->stop(he_dev->atm_dev); +#endif /* CONFIG_ATM_HE_USE_SUNI */ + + if (he_dev->irq) + { +#ifdef BUS_INT_WAR + sn_delete_polled_interrupt(he_dev->irq); +#endif + free_irq(he_dev->irq, he_dev); + } + + if (he_dev->irq_base) + pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) + * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); + + if (he_dev->hsp) + pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp), + he_dev->hsp, he_dev->hsp_phys); + + if (he_dev->rbpl_base) + { +#ifdef USE_RBPL_POOL + for (i=0; irbpl_virt[i].virt; + dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; + + pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle); + } +#else + pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE + * CONFIG_RBPL_BUFSIZE, he_dev->rbpl_pages, he_dev->rbpl_pages_phys); +#endif + pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE + * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); + } + +#ifdef USE_RBPL_POOL + if (he_dev->rbpl_pool) + pci_pool_destroy(he_dev->rbpl_pool); +#endif + +#ifdef USE_RBPS + if (he_dev->rbps_base) + { +#ifdef USE_RBPS_POOL + for (i=0; irbps_virt[i].virt; + dma_addr_t dma_handle = he_dev->rbps_base[i].phys; + + pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle); + } +#else + pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE + * CONFIG_RBPS_BUFSIZE, he_dev->rbps_pages, he_dev->rbps_pages_phys); +#endif + pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE + * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys); + } + +#ifdef USE_RBPS_POOL + if (he_dev->rbps_pool) + pci_pool_destroy(he_dev->rbps_pool); +#endif + +#endif /* USE_RBPS */ + + if (he_dev->rbrq_base) + pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), + he_dev->rbrq_base, he_dev->rbrq_phys); + + if (he_dev->tbrq_base) + pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + he_dev->tbrq_base, he_dev->tbrq_phys); + + if (he_dev->tpdrq_base) + pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + he_dev->tpdrq_base, he_dev->tpdrq_phys); + +#ifdef USE_TPD_POOL + if (he_dev->tpd_pool) + pci_pool_destroy(he_dev->tpd_pool); +#else + if (he_dev->tpd_base) + pci_free_consistent(he_dev->pci_dev, CONFIG_NUMTPDS * sizeof(struct he_tpd), + he_dev->tpd_base, he_dev->tpd_base_phys); +#endif + +#ifndef USE_HE_FIND_VCC + if (he_dev->he_vcc_table) + kfree(he_dev->he_vcc_table); +#endif + + if (he_dev->pci_dev) + { + pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); + command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command); + } + + if (he_dev->membase) iounmap((void *) he_dev->membase); +} + +static struct he_tpd * +__alloc_tpd(struct he_dev *he_dev) +{ +#ifdef USE_TPD_POOL + struct he_tpd *tpd; + dma_addr_t dma_handle; + + tpd = pci_pool_alloc(he_dev->tpd_pool, SLAB_ATOMIC|SLAB_DMA, &dma_handle); + if (tpd == NULL) + return NULL; + + tpd->status = TPD_ADDR(dma_handle); + tpd->reserved = 0; + tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0; + tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0; + tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0; + + return tpd; +#else + int i; + + for(i = 0; i < CONFIG_NUMTPDS; ++i) + { + ++he_dev->tpd_head; + if (he_dev->tpd_head > he_dev->tpd_end) { + he_dev->tpd_head = he_dev->tpd_base; + } + + if (!he_dev->tpd_head->inuse) { + he_dev->tpd_head->inuse = 1; + he_dev->tpd_head->status &= TPD_MASK; + he_dev->tpd_head->iovec[0].addr = 0; he_dev->tpd_head->iovec[0].len = 0; + he_dev->tpd_head->iovec[1].addr = 0; he_dev->tpd_head->iovec[1].len = 0; + he_dev->tpd_head->iovec[2].addr = 0; he_dev->tpd_head->iovec[2].len = 0; + return he_dev->tpd_head; + } + } + hprintk("out of tpds -- increase CONFIG_NUMTPDS (%d)\n", CONFIG_NUMTPDS); + return NULL; +#endif +} + +#define AAL5_LEN(buf,len) \ + ((((unsigned char *)(buf))[(len)-6]<<8) | \ + (((unsigned char *)(buf))[(len)-5])) + +/* 2.10.1.2 receive + * + * aal5 packets can optionally return the tcp checksum in the lower + * 16 bits of the crc (RSR0_TCP_CKSUM) + */ + +#define TCP_CKSUM(buf,len) \ + ((((unsigned char *)(buf))[(len)-2]<<8) | \ + (((unsigned char *)(buf))[(len-1)])) + +static int +he_service_rbrq(struct he_dev *he_dev, int group) +{ + struct he_rbrq *rbrq_tail = (struct he_rbrq *) + ((unsigned long)he_dev->rbrq_base | + he_dev->hsp->group[group].rbrq_tail); + struct he_rbp *rbp = NULL; + unsigned cid, lastcid = -1; + unsigned buf_len = 0; + struct sk_buff *skb; + struct atm_vcc *vcc = NULL; + struct he_vcc *he_vcc; + struct he_iovec *iov; + int pdus_assembled = 0; + int updated = 0; + + while (he_dev->rbrq_head != rbrq_tail) + { + ++updated; + + HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n", + he_dev->rbrq_head, group, + RBRQ_ADDR(he_dev->rbrq_head), + RBRQ_BUFLEN(he_dev->rbrq_head), + RBRQ_CID(he_dev->rbrq_head), + RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "", + RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "", + RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "", + RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "", + RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", + RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); + +#ifdef USE_RBPS + if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF) + rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; + else +#endif + rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))]; + + buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; + cid = RBRQ_CID(he_dev->rbrq_head); + +#ifdef USE_HE_FIND_VCC + if (cid != lastcid) + vcc = he_find_vcc(he_dev, cid); + lastcid = cid; +#else + vcc = HE_LOOKUP_VCC(he_dev, cid); +#endif + if (vcc == NULL) + { + hprintk("vcc == NULL (cid 0x%x)\n", cid); + if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) + rbp->status &= ~RBP_LOANED; + + goto next_rbrq_entry; + } + + he_vcc = HE_VCC(vcc); + if (he_vcc == NULL) + { + hprintk("he_vcc == NULL (cid 0x%x)\n", cid); + if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) + rbp->status &= ~RBP_LOANED; + goto next_rbrq_entry; + } + + if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) + { + hprintk("HBUF_ERR! (cid 0x%x)\n", cid); + atomic_inc(&vcc->stats->rx_drop); + goto return_host_buffers; + } + + he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head); + he_vcc->iov_tail->iov_len = buf_len; + he_vcc->pdu_len += buf_len; + ++he_vcc->iov_tail; + + if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) + { + lastcid = -1; + HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid); + wake_up(&he_vcc->rx_waitq); + goto return_host_buffers; + } + +#ifdef notdef + if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) + { + hprintk("iovec full! cid 0x%x\n", cid); + goto return_host_buffers; + } +#endif + if (!RBRQ_END_PDU(he_dev->rbrq_head)) goto next_rbrq_entry; + + if (RBRQ_LEN_ERR(he_dev->rbrq_head) + || RBRQ_CRC_ERR(he_dev->rbrq_head)) + { + HPRINTK("%s%s (%d.%d)\n", + RBRQ_CRC_ERR(he_dev->rbrq_head) + ? "CRC_ERR " : "", + RBRQ_LEN_ERR(he_dev->rbrq_head) + ? "LEN_ERR" : "", + vcc->vpi, vcc->vci); + atomic_inc(&vcc->stats->rx_err); + goto return_host_buffers; + } + + skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve, + GFP_ATOMIC); + if (!skb) + { + HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci); + goto return_host_buffers; + } + + if (rx_skb_reserve > 0) skb_reserve(skb, rx_skb_reserve); + + do_gettimeofday(&skb->stamp); + + for(iov = he_vcc->iov_head; + iov < he_vcc->iov_tail; ++iov) + { +#ifdef USE_RBPS + if (iov->iov_base & RBP_SMALLBUF) + memcpy(skb_put(skb, iov->iov_len), + he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); + else +#endif + memcpy(skb_put(skb, iov->iov_len), + he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); + } + + switch(vcc->qos.aal) + { + case ATM_AAL0: + /* 2.10.1.5 raw cell receive */ + skb->len = ATM_AAL0_SDU; + skb->tail = skb->data + skb->len; + break; + case ATM_AAL5: + /* 2.10.1.2 aal5 receive */ + + skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); + skb->tail = skb->data + skb->len; +#ifdef USE_CHECKSUM_HW + if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) + { + skb->ip_summed = CHECKSUM_HW; + skb->csum = TCP_CKSUM(skb->data, + he_vcc->pdu_len); + } +#endif + break; + } + +#ifdef should_never_happen + if (skb->len > vcc->qos.rxtp.max_sdu) + hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)! cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid); +#endif + +#ifdef notdef + ATM_SKB(skb)->vcc = vcc; +#endif + vcc->push(vcc, skb); + + atomic_inc(&vcc->stats->rx); + +return_host_buffers: + ++pdus_assembled; + + for(iov = he_vcc->iov_head; + iov < he_vcc->iov_tail; ++iov) + { +#ifdef USE_RBPS + if (iov->iov_base & RBP_SMALLBUF) + rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)]; + else +#endif + rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)]; + + rbp->status &= ~RBP_LOANED; + } + + he_vcc->iov_tail = he_vcc->iov_head; + he_vcc->pdu_len = 0; + +next_rbrq_entry: + he_dev->rbrq_head = (struct he_rbrq *) + ((unsigned long) he_dev->rbrq_base | + RBRQ_MASK(++he_dev->rbrq_head)); + + } + + if (updated) + { + if (updated > he_dev->rbrq_peak) he_dev->rbrq_peak = updated; + + he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head), + G0_RBRQ_H + (group * 16)); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, G0_RBRQ_H + (group * 16)); +#endif + } + + return pdus_assembled; +} + +static void +he_service_tbrq(struct he_dev *he_dev, int group) +{ + struct he_tbrq *tbrq_tail = (struct he_tbrq *) + ((unsigned long)he_dev->tbrq_base | + he_dev->hsp->group[group].tbrq_tail); + struct he_tpd *tpd; + int slot, updated = 0; +#ifdef USE_TPD_POOL + struct list_head *p; +#endif + + /* 2.1.6 transmit buffer return queue */ + + while (he_dev->tbrq_head != tbrq_tail) + { + ++updated; + + HPRINTK("tbrq%d 0x%x%s%s\n", + group, + TBRQ_TPD(he_dev->tbrq_head), + TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "", + TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); +#ifdef USE_TPD_POOL + tpd = NULL; + p = &he_dev->outstanding_tpds; + while ((p = p->next) != &he_dev->outstanding_tpds) + { + struct he_tpd *__tpd = list_entry(p, struct he_tpd, entry); + if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) + { + tpd = __tpd; + list_del(&__tpd->entry); + break; + } + } + + if (tpd == NULL) + { + hprintk("unable to locate tpd for dma buffer %x\n", + TBRQ_TPD(he_dev->tbrq_head)); + goto next_tbrq_entry; + } +#else + tpd = &he_dev->tpd_base[ TPD_INDEX(TBRQ_TPD(he_dev->tbrq_head)) ]; +#endif + + if (TBRQ_EOS(he_dev->tbrq_head)) + { + HPRINTK("wake_up(tx_waitq) cid 0x%x\n", + he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci)); + if (tpd->vcc) + wake_up(&HE_VCC(tpd->vcc)->tx_waitq); + + goto next_tbrq_entry; + } + + for(slot = 0; slot < TPD_MAXIOV; ++slot) + { + if (tpd->iovec[slot].addr) + pci_unmap_single(he_dev->pci_dev, + tpd->iovec[slot].addr, + tpd->iovec[slot].len & TPD_LEN_MASK, + PCI_DMA_TODEVICE); + if (tpd->iovec[slot].len & TPD_LST) break; + + } + + if (tpd->skb) /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ + { + if (tpd->vcc && tpd->vcc->pop) + tpd->vcc->pop(tpd->vcc, tpd->skb); + else + dev_kfree_skb_any(tpd->skb); + } + +next_tbrq_entry: +#ifdef USE_TPD_POOL + if (tpd) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); +#else + tpd->inuse = 0; +#endif + he_dev->tbrq_head = (struct he_tbrq *) + ((unsigned long) he_dev->tbrq_base | + TBRQ_MASK(++he_dev->tbrq_head)); + } + + if (updated) + { + if (updated > he_dev->tbrq_peak) he_dev->tbrq_peak = updated; + + he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head), + G0_TBRQ_H + (group * 16)); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, G0_TBRQ_H + (group * 16)); +#endif + } +} + + +static void +he_service_rbpl(struct he_dev *he_dev, int group) +{ + struct he_rbp *newtail; + struct he_rbp *rbpl_head; + int moved = 0; + + rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | + RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); + + for(;;) + { + newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | + RBPL_MASK(he_dev->rbpl_tail+1)); + + /* table 3.42 -- rbpl_tail should never be set to rbpl_head */ + if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED)) + break; + + newtail->status |= RBP_LOANED; + he_dev->rbpl_tail = newtail; + ++moved; + + } + + if (moved) { + he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, G0_RBPL_T); +#endif + } +} + +#ifdef USE_RBPS +static void +he_service_rbps(struct he_dev *he_dev, int group) +{ + struct he_rbp *newtail; + struct he_rbp *rbps_head; + int moved = 0; + + rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | + RBPS_MASK(he_readl(he_dev, G0_RBPS_S))); + + for(;;) + { + newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | + RBPS_MASK(he_dev->rbps_tail+1)); + + /* table 3.42 -- rbps_tail should never be set to rbps_head */ + if ((newtail == rbps_head) || (newtail->status & RBP_LOANED)) + break; + + newtail->status |= RBP_LOANED; + he_dev->rbps_tail = newtail; + ++moved; + + } + + if (moved) { + he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, G0_RBPS_T); +#endif + } +} +#endif /* USE_RBPS */ + +static void +he_tasklet(unsigned long data) +{ + unsigned long flags; + struct he_dev *he_dev = (struct he_dev *) data; + int group, type; + int updated = 0; + + HPRINTK("tasklet (0x%lx)\n", data); +#ifdef USE_TASKLET + HE_SPIN_LOCK(he_dev, flags); +#endif + + while(he_dev->irq_head != he_dev->irq_tail) + { + ++updated; + + type = ITYPE_TYPE(he_dev->irq_head->isw); + group = ITYPE_GROUP(he_dev->irq_head->isw); + + switch (type) + { + case ITYPE_RBRQ_THRESH: + hprintk("rbrq%d threshold\n", group); + case ITYPE_RBRQ_TIMER: + if (he_service_rbrq(he_dev, group)) + { + he_service_rbpl(he_dev, group); +#ifdef USE_RBPS + he_service_rbps(he_dev, group); +#endif /* USE_RBPS */ + } + break; + case ITYPE_TBRQ_THRESH: + hprintk("tbrq%d threshold\n", group); + case ITYPE_TPD_COMPLETE: + he_service_tbrq(he_dev, group); + break; + case ITYPE_RBPL_THRESH: + he_service_rbpl(he_dev, group); + break; + case ITYPE_RBPS_THRESH: +#ifdef USE_RBPS + he_service_rbps(he_dev, group); +#endif /* USE_RBPS */ + break; + case ITYPE_PHY: +#ifdef CONFIG_ATM_HE_USE_SUNI + HE_SPIN_UNLOCK(he_dev, flags); + if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) + he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); + HE_SPIN_LOCK(he_dev, flags); +#endif + HPRINTK("phy interrupt\n"); + break; + case ITYPE_OTHER: + switch (type|group) + { + case ITYPE_PARITY: + hprintk("parity error\n"); + break; + case ITYPE_ABORT: + hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR)); + break; + } + break; + default: + if (he_dev->irq_head->isw == ITYPE_INVALID) + { + /* see 8.1.1 -- check all queues */ + + HPRINTK("isw not updated 0x%x\n", + he_dev->irq_head->isw); + + he_service_rbrq(he_dev, 0); + he_service_rbpl(he_dev, 0); +#ifdef USE_RBPS + he_service_rbps(he_dev, 0); +#endif /* USE_RBPS */ + he_service_tbrq(he_dev, 0); + } + else + hprintk("bad isw = 0x%x?\n", + he_dev->irq_head->isw); + } + + he_dev->irq_head->isw = ITYPE_INVALID; + + he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK); + } + + if (updated) + { + if (updated > he_dev->irq_peak) he_dev->irq_peak = updated; + + he_writel(he_dev, + IRQ_SIZE(CONFIG_IRQ_SIZE) | + IRQ_THRESH(CONFIG_IRQ_THRESH) | + IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD); + (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ + } +#ifdef USE_TASKLET + HE_SPIN_UNLOCK(he_dev, flags); +#endif +} + +static irqreturn_t +he_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + struct he_dev *he_dev = (struct he_dev * )dev_id; + int handled = 0; + + if (he_dev == NULL) + return IRQ_NONE; + + HE_SPIN_LOCK(he_dev, flags); + + he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | + (*he_dev->irq_tailoffset << 2)); + + if (he_dev->irq_tail == he_dev->irq_head) + { + HPRINTK("tailoffset not updated?\n"); + he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | + ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); + (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ + } + +#ifdef DEBUG + if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */) + hprintk("spurious (or shared) interrupt?\n"); +#endif + + if (he_dev->irq_head != he_dev->irq_tail) + { + handled = 1; +#ifdef USE_TASKLET + tasklet_schedule(&he_dev->tasklet); +#else + he_tasklet((unsigned long) he_dev); +#endif + he_writel(he_dev, INT_CLEAR_A, INT_FIFO); + /* clear interrupt */ +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, INT_FIFO); +#endif + } + HE_SPIN_UNLOCK(he_dev, flags); + return IRQ_RETVAL(handled); + +} + +static __inline__ void +__enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) +{ + struct he_tpdrq *new_tail; + + HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n", + tpd, cid, he_dev->tpdrq_tail); + + /* new_tail = he_dev->tpdrq_tail; */ + new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base | + TPDRQ_MASK(he_dev->tpdrq_tail+1)); + + /* + * check to see if we are about to set the tail == head + * if true, update the head pointer from the adapter + * to see if this is really the case (reading the queue + * head for every enqueue would be unnecessarily slow) + */ + + if (new_tail == he_dev->tpdrq_head) + { + he_dev->tpdrq_head = (struct he_tpdrq *) + (((unsigned long)he_dev->tpdrq_base) | + TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H))); + + if (new_tail == he_dev->tpdrq_head) + { + hprintk("tpdrq full (cid 0x%x)\n", cid); + /* + * FIXME + * push tpd onto a transmit backlog queue + * after service_tbrq, service the backlog + * for now, we just drop the pdu + */ + if (tpd->skb) + { + if (tpd->vcc->pop) + tpd->vcc->pop(tpd->vcc, tpd->skb); + else + dev_kfree_skb_any(tpd->skb); + atomic_inc(&tpd->vcc->stats->tx_err); + } +#ifdef USE_TPD_POOL + pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); +#else + tpd->inuse = 0; +#endif + return; + } + } + + /* 2.1.5 transmit packet descriptor ready queue */ +#ifdef USE_TPD_POOL + list_add_tail(&tpd->entry, &he_dev->outstanding_tpds); + he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status); +#else + he_dev->tpdrq_tail->tpd = he_dev->tpd_base_phys + + (TPD_INDEX(tpd->status) * sizeof(struct he_tpd)); +#endif + he_dev->tpdrq_tail->cid = cid; + wmb(); + + he_dev->tpdrq_tail = new_tail; + + he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, TPDRQ_T); +#endif +} + +static int +he_open(struct atm_vcc *vcc, short vpi, int vci) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(vcc->dev); + struct he_vcc *he_vcc; + int err = 0; + unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock; + + + if ((err = atm_find_ci(vcc, &vpi, &vci))) + { + HPRINTK("atm_find_ci err = %d\n", err); + return err; + } + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; + vcc->vpi = vpi; + vcc->vci = vci; + + HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci); + + set_bit(ATM_VF_ADDR, &vcc->flags); + + cid = he_mkcid(he_dev, vpi, vci); + + he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC); + if (he_vcc == NULL) + { + hprintk("unable to allocate he_vcc during open\n"); + return -ENOMEM; + } + + he_vcc->iov_tail = he_vcc->iov_head; + he_vcc->pdu_len = 0; + he_vcc->rc_index = -1; + + init_waitqueue_head(&he_vcc->rx_waitq); + init_waitqueue_head(&he_vcc->tx_waitq); + + HE_VCC(vcc) = he_vcc; + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + int pcr_goal; + + pcr_goal = atm_pcr_goal(&vcc->qos.txtp); + if (pcr_goal == 0) + pcr_goal = he_dev->atm_dev->link_rate; + if (pcr_goal < 0) /* means round down, technically */ + pcr_goal = -pcr_goal; + + HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); + + switch (vcc->qos.aal) + { + case ATM_AAL5: + tsr0_aal = TSR0_AAL5; + tsr4 = TSR4_AAL5; + break; + case ATM_AAL0: + tsr0_aal = TSR0_AAL0_SDU; + tsr4 = TSR4_AAL0_SDU; + break; + default: + err = -EINVAL; + goto open_failed; + } + + HE_SPIN_LOCK(he_dev, flags); + tsr0 = he_readl_tsr0(he_dev, cid); + HE_SPIN_UNLOCK(he_dev, flags); + + if (TSR0_CONN_STATE(tsr0) != 0) + { + hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); + err = -EBUSY; + goto open_failed; + } + + switch(vcc->qos.txtp.traffic_class) + { + case ATM_UBR: + /* 2.3.3.1 open connection ubr */ + + tsr0 = TSR0_UBR | TSR0_GROUP(0) | tsr0_aal | + TSR0_USE_WMIN | TSR0_UPDATE_GER; + break; + + case ATM_CBR: + /* 2.3.3.2 open connection cbr */ + + /* 8.2.3 cbr scheduler wrap problem -- limit to 90% total link rate */ + if ((he_dev->total_bw + pcr_goal) + > (he_dev->atm_dev->link_rate * 9 / 10)) + { + err = -EBUSY; + goto open_failed; + } + + HE_SPIN_LOCK(he_dev, flags); /* also protects he_dev->cs_stper[] */ + + /* find an unused cs_stper register */ + for(reg = 0; reg < HE_NUM_CS_STPER; ++reg) + if (he_dev->cs_stper[reg].inuse == 0 || + he_dev->cs_stper[reg].pcr == pcr_goal) + break; + + if (reg == HE_NUM_CS_STPER) + { + err = -EBUSY; + HE_SPIN_UNLOCK(he_dev, flags); + goto open_failed; + } + + he_dev->total_bw += pcr_goal; + + he_vcc->rc_index = reg; + ++he_dev->cs_stper[reg].inuse; + he_dev->cs_stper[reg].pcr = pcr_goal; + + clock = he_is622(he_dev) ? 66667000 : 50000000; + period = clock / pcr_goal; + + HPRINTK("rc_index = %d period = %d\n", + reg, period); + + he_writel_mbox(he_dev, rate_to_atmf(period/2), + CS_STPER0 + reg); + HE_SPIN_UNLOCK(he_dev, flags); + + tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | + TSR0_RC_INDEX(reg); + + break; + default: + err = -EINVAL; + goto open_failed; + } + + HE_SPIN_LOCK(he_dev, flags); + + he_writel_tsr0(he_dev, tsr0, cid); + he_writel_tsr4(he_dev, tsr4 | 1, cid); + he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) | + TSR1_PCR(rate_to_atmf(pcr_goal)), cid); + he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid); + he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid); + + he_writel_tsr3(he_dev, 0x0, cid); + he_writel_tsr5(he_dev, 0x0, cid); + he_writel_tsr6(he_dev, 0x0, cid); + he_writel_tsr7(he_dev, 0x0, cid); + he_writel_tsr8(he_dev, 0x0, cid); + he_writel_tsr10(he_dev, 0x0, cid); + he_writel_tsr11(he_dev, 0x0, cid); + he_writel_tsr12(he_dev, 0x0, cid); + he_writel_tsr13(he_dev, 0x0, cid); + he_writel_tsr14(he_dev, 0x0, cid); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl_tsr0(he_dev, cid); +#endif + HE_SPIN_UNLOCK(he_dev, flags); + } + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + unsigned aal; + + HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid, + &HE_VCC(vcc)->rx_waitq); + + switch (vcc->qos.aal) + { + case ATM_AAL5: + aal = RSR0_AAL5; + break; + case ATM_AAL0: + aal = RSR0_RAWCELL; + break; + default: + err = -EINVAL; + goto open_failed; + } + + HE_SPIN_LOCK(he_dev, flags); + + rsr0 = he_readl_rsr0(he_dev, cid); + if (rsr0 & RSR0_OPEN_CONN) + { + HE_SPIN_UNLOCK(he_dev, flags); + + hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); + err = -EBUSY; + goto open_failed; + } + +#ifdef USE_RBPS + rsr1 = RSR1_GROUP(0); + rsr4 = RSR4_GROUP(0); +#else /* !USE_RBPS */ + rsr1 = RSR1_GROUP(0)|RSR1_RBPL_ONLY; + rsr4 = RSR4_GROUP(0)|RSR4_RBPL_ONLY; +#endif /* USE_RBPS */ + rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? + (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; + +#ifdef USE_CHECKSUM_HW + if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) rsr0 |= RSR0_TCP_CKSUM; +#endif + + he_writel_rsr4(he_dev, rsr4, cid); + he_writel_rsr1(he_dev, rsr1, cid); + /* 5.1.11 last parameter initialized should be + the open/closed indication in rsr0 */ + he_writel_rsr0(he_dev, + rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl_rsr0(he_dev, cid); +#endif + + HE_SPIN_UNLOCK(he_dev, flags); + +#ifndef USE_HE_FIND_VCC + HE_LOOKUP_VCC(he_dev, cid) = vcc; +#endif + } + +open_failed: + + if (err) + { + if (he_vcc) kfree(he_vcc); + clear_bit(ATM_VF_ADDR, &vcc->flags); + } + else + set_bit(ATM_VF_READY, &vcc->flags); + + return err; +} + +static void +he_close(struct atm_vcc *vcc) +{ + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + struct he_dev *he_dev = HE_DEV(vcc->dev); + struct he_tpd *tpd; + unsigned cid; + struct he_vcc *he_vcc = HE_VCC(vcc); +#define MAX_RETRY 30 + int retry = 0, sleep = 1, tx_inuse; + + HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci); + + clear_bit(ATM_VF_READY, &vcc->flags); + cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) + { + int timeout; + + HPRINTK("close rx cid 0x%x\n", cid); + + /* 2.7.2.2 close receive operation */ + + /* wait for previous close (if any) to finish */ + + HE_SPIN_LOCK(he_dev, flags); + while(he_readl(he_dev, RCC_STAT) & RCC_BUSY) + { + HPRINTK("close cid 0x%x RCC_BUSY\n", cid); + udelay(250); + } + + add_wait_queue(&he_vcc->rx_waitq, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + + he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl_rsr0(he_dev, cid); +#endif + he_writel_mbox(he_dev, cid, RXCON_CLOSE); + HE_SPIN_UNLOCK(he_dev, flags); + + timeout = schedule_timeout(30*HZ); + + remove_wait_queue(&he_vcc->rx_waitq, &wait); + set_current_state(TASK_RUNNING); + + if (timeout == 0) + hprintk("close rx timeout cid 0x%x\n", cid); + +#ifndef USE_HE_FIND_VCC + HE_LOOKUP_VCC(he_dev, cid) = NULL; +#endif + HPRINTK("close rx cid 0x%x complete\n", cid); + + } + + if (vcc->qos.txtp.traffic_class != ATM_NONE) + { + volatile unsigned tsr4, tsr0; + int timeout; + + HPRINTK("close tx cid 0x%x\n", cid); + + /* 2.1.2 + * + * ... the host must first stop queueing packets to the TPDRQ + * on the connection to be closed, then wait for all outstanding + * packets to be transmitted and their buffers returned to the + * TBRQ. When the last packet on the connection arrives in the + * TBRQ, the host issues the close command to the adapter. + */ + + while (((tx_inuse = atomic_read(&vcc->sk->wmem_alloc)) > 0) + && (retry < MAX_RETRY)) + { + set_current_state(TASK_UNINTERRUPTIBLE); + (void) schedule_timeout(sleep); + set_current_state(TASK_RUNNING); + if (sleep < HZ) sleep = sleep * 2; + + ++retry; + } + + if (tx_inuse) hprintk("close tx cid 0x%x tx_inuse = %d\n", + cid, tx_inuse); + + /* 2.3.1.1 generic close operations with flush */ + + HE_SPIN_LOCK(he_dev, flags); + he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); + /* also clears TSR4_SESSION_ENDED */ +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl_tsr4(he_dev, cid); +#endif + + switch(vcc->qos.txtp.traffic_class) + { + case ATM_UBR: + he_writel_tsr1(he_dev, + TSR1_MCR(rate_to_atmf(200000)) + | TSR1_PCR(0), cid); + break; + case ATM_CBR: + he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid); + break; + } + + + tpd = __alloc_tpd(he_dev); + if (tpd == NULL) + { + hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid); + goto close_tx_incomplete; + } + tpd->status |= TPD_EOS | TPD_INT; + tpd->skb = NULL; + tpd->vcc = vcc; + wmb(); + + add_wait_queue(&he_vcc->tx_waitq, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + __enqueue_tpd(he_dev, tpd, cid); + HE_SPIN_UNLOCK(he_dev, flags); + + timeout = schedule_timeout(30*HZ); + + remove_wait_queue(&he_vcc->tx_waitq, &wait); + set_current_state(TASK_RUNNING); + + if (timeout == 0) + { + hprintk("close tx timeout cid 0x%x\n", cid); + goto close_tx_incomplete; + } + + HE_SPIN_LOCK(he_dev, flags); + while (!((tsr4 = he_readl_tsr4(he_dev, cid)) + & TSR4_SESSION_ENDED)) + { + HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); + udelay(250); + } + + while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) + { + HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0); + udelay(250); + } + +close_tx_incomplete: + + if (vcc->qos.txtp.traffic_class == ATM_CBR) + { + int reg = he_vcc->rc_index; + + HPRINTK("cs_stper reg = %d\n", reg); + + if (he_dev->cs_stper[reg].inuse == 0) + hprintk("cs_stper[%d].inuse = 0!\n", reg); + else + --he_dev->cs_stper[reg].inuse; + + he_dev->total_bw -= he_dev->cs_stper[reg].pcr; + } + HE_SPIN_UNLOCK(he_dev, flags); + + HPRINTK("close tx cid 0x%x complete\n", cid); + } + + kfree(he_vcc); + + clear_bit(ATM_VF_ADDR, &vcc->flags); +} + +static int +he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size) +{ +#ifdef USE_SCATTERGATHER + return 1; +#else + return 0; +#endif +} + +static int +he_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(vcc->dev); + unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); + struct he_tpd *tpd; +#ifdef USE_SCATTERGATHER + int i, slot = 0; +#endif + +#define HE_TPD_BUFSIZE 0xffff + + HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci); + + if ((skb->len > HE_TPD_BUFSIZE) || + ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) + { + hprintk("buffer too large (or small) -- %d bytes\n", skb->len ); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); + atomic_inc(&vcc->stats->tx_err); + return -EINVAL; + } + +#ifndef USE_SCATTERGATHER + if (skb_shinfo(skb)->nr_frags) + { + hprintk("no scatter/gather support\n"); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); + atomic_inc(&vcc->stats->tx_err); + return -EINVAL; + } +#endif + HE_SPIN_LOCK(he_dev, flags); + + tpd = __alloc_tpd(he_dev); + if (tpd == NULL) + { + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); + atomic_inc(&vcc->stats->tx_err); + HE_SPIN_UNLOCK(he_dev, flags); + return -ENOMEM; + } + + if (vcc->qos.aal == ATM_AAL5) + tpd->status |= TPD_CELLTYPE(TPD_USERCELL); + else + { + char *pti_clp = (void *) (skb->data + 3); + int clp, pti; + + pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + clp = (*pti_clp & ATM_HDR_CLP); + tpd->status |= TPD_CELLTYPE(pti); + if (clp) tpd->status |= TPD_CLP; + + skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD); + } + +#ifdef USE_SCATTERGATHER + tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data, + skb->len - skb->data_len, PCI_DMA_TODEVICE); + tpd->iovec[slot].len = skb->len - skb->data_len; + ++slot; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + if (slot == TPD_MAXIOV) /* send tpd; start new tpd */ + { + tpd->vcc = vcc; + tpd->skb = NULL; /* not the last fragment + so dont ->push() yet */ + wmb(); + + __enqueue_tpd(he_dev, tpd, cid); + tpd = __alloc_tpd(he_dev); + if (tpd == NULL) + { + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); + atomic_inc(&vcc->stats->tx_err); + HE_SPIN_UNLOCK(he_dev, flags); + return -ENOMEM; + } + tpd->status |= TPD_USERCELL; + slot = 0; + } + + tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, + (void *) page_address(frag->page) + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + tpd->iovec[slot].len = frag->size; + ++slot; + + } + + tpd->iovec[slot-1].len |= TPD_LST; +#else + tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + tpd->length0 = skb->len | TPD_LST; +#endif + tpd->status |= TPD_INT; + + tpd->vcc = vcc; + tpd->skb = skb; + wmb(); + ATM_SKB(skb)->vcc = vcc; + + __enqueue_tpd(he_dev, tpd, cid); + HE_SPIN_UNLOCK(he_dev, flags); + + atomic_inc(&vcc->stats->tx); + + return 0; +} + +static int +he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(atm_dev); + struct he_ioctl_reg reg; + int err = 0; + + switch (cmd) + { + case HE_GET_REG: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + + copy_from_user(®, (struct he_ioctl_reg *) arg, + sizeof(struct he_ioctl_reg)); + HE_SPIN_LOCK(he_dev, flags); + switch (reg.type) + { + case HE_REGTYPE_PCI: + reg.val = he_readl(he_dev, reg.addr); + break; + case HE_REGTYPE_RCM: + reg.val = + he_readl_rcm(he_dev, reg.addr); + break; + case HE_REGTYPE_TCM: + reg.val = + he_readl_tcm(he_dev, reg.addr); + break; + case HE_REGTYPE_MBOX: + reg.val = + he_readl_mbox(he_dev, reg.addr); + break; + default: + err = -EINVAL; + break; + } + HE_SPIN_UNLOCK(he_dev, flags); + if (err == 0) copy_to_user((struct he_ioctl_reg *) arg, ®, + sizeof(struct he_ioctl_reg)); + break; + default: +#ifdef CONFIG_ATM_HE_USE_SUNI + if (atm_dev->phy && atm_dev->phy->ioctl) + err = atm_dev->phy->ioctl(atm_dev, cmd, arg); +#else /* CONFIG_ATM_HE_USE_SUNI */ + return -EINVAL; +#endif /* CONFIG_ATM_HE_USE_SUNI */ + break; + } + + return err; +} + +static void +he_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(atm_dev); + + HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); + + HE_SPIN_LOCK(he_dev, flags); + he_writel(he_dev, val, FRAMER + (addr*4)); +#ifdef CONFIG_IA64_SGI_SN2 + (void) he_readl(he_dev, FRAMER + (addr*4)); +#endif + HE_SPIN_UNLOCK(he_dev, flags); +} + + +static unsigned char +he_phy_get(struct atm_dev *atm_dev, unsigned long addr) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(atm_dev); + unsigned reg; + + HE_SPIN_LOCK(he_dev, flags); + reg = he_readl(he_dev, FRAMER + (addr*4)); + HE_SPIN_UNLOCK(he_dev, flags); + + HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); + return reg; +} + +static int +he_proc_read(struct atm_dev *dev, loff_t *pos, char *page) +{ + unsigned long flags; + struct he_dev *he_dev = HE_DEV(dev); + int left, i; +#ifdef notdef + struct he_rbrq *rbrq_tail; + struct he_tpdrq *tpdrq_head; + int rbpl_head, rbpl_tail; +#endif + static long mcc = 0, oec = 0, dcc = 0, cec = 0; + + + left = *pos; + if (!left--) + return sprintf(page, "%s\n", version); + + if (!left--) + return sprintf(page, "%s%s\n\n", + he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM"); + + if (!left--) + return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); + + HE_SPIN_LOCK(he_dev, flags); + mcc += he_readl(he_dev, MCC); + oec += he_readl(he_dev, OEC); + dcc += he_readl(he_dev, DCC); + cec += he_readl(he_dev, CEC); + HE_SPIN_UNLOCK(he_dev, flags); + + if (!left--) + return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", + mcc, oec, dcc, cec); + + if (!left--) + return sprintf(page, "irq_size = %d inuse = ? peak = %d\n", + CONFIG_IRQ_SIZE, he_dev->irq_peak); + + if (!left--) + return sprintf(page, "tpdrq_size = %d inuse = ?\n", + CONFIG_TPDRQ_SIZE); + + if (!left--) + return sprintf(page, "rbrq_size = %d inuse = ? peak = %d\n", + CONFIG_RBRQ_SIZE, he_dev->rbrq_peak); + + if (!left--) + return sprintf(page, "tbrq_size = %d peak = %d\n", + CONFIG_TBRQ_SIZE, he_dev->tbrq_peak); + + +#ifdef notdef + rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); + rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); + + inuse = rbpl_head - rbpl_tail; + if (inuse < 0) inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); + inuse /= sizeof(struct he_rbp); + + if (!left--) + return sprintf(page, "rbpl_size = %d inuse = %d\n\n", + CONFIG_RBPL_SIZE, inuse); +#endif + + if (!left--) + return sprintf(page, "rate controller periods (cbr)\n pcr #vc\n"); + + for (i = 0; i < HE_NUM_CS_STPER; ++i) + if (!left--) + return sprintf(page, "cs_stper%-2d %8ld %3d\n", i, + he_dev->cs_stper[i].pcr, + he_dev->cs_stper[i].inuse); + + if (!left--) + return sprintf(page, "total bw (cbr): %d (limit %d)\n", + he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9); + + return 0; +} + +/* eeprom routines -- see 4.7 */ + +u8 +read_prom_byte(struct he_dev *he_dev, int addr) +{ + u32 val = 0, tmp_read = 0; + int i, j = 0; + u8 byte_read = 0; + + val = readl(he_dev->membase + HOST_CNTL); + val &= 0xFFFFE0FF; + + /* Turn on write enable */ + val |= 0x800; + he_writel(he_dev, val, HOST_CNTL); + + /* Send READ instruction */ + for (i=0; i=0; i--) { + he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); + udelay(EEPROM_DELAY); + he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); + udelay(EEPROM_DELAY); + } + + j=0; + + val &= 0xFFFFF7FF; /* Turn off write enable */ + he_writel(he_dev, val, HOST_CNTL); + + /* Now, we can read data from the EEPROM by clocking it in */ + for (i=7; i>=0; i--) { + he_writel(he_dev, val | clocktab[j++], HOST_CNTL); + udelay(EEPROM_DELAY); + tmp_read = he_readl(he_dev, HOST_CNTL); + byte_read |= (unsigned char) + ((tmp_read & ID_DOUT) + >> ID_DOFFSET << i); + he_writel(he_dev, val | clocktab[j++], HOST_CNTL); + udelay(EEPROM_DELAY); + } + + he_writel(he_dev, val | ID_CS, HOST_CNTL); + udelay(EEPROM_DELAY); + + return (byte_read); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("chas williams "); +MODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver"); +MODULE_PARM(disable64, "h"); +MODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers"); +MODULE_PARM(nvpibits, "i"); +MODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)"); +MODULE_PARM(nvcibits, "i"); +MODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)"); +MODULE_PARM(rx_skb_reserve, "i"); +MODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)"); +MODULE_PARM(irq_coalesce, "i"); +MODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)"); +MODULE_PARM(sdh, "i"); +MODULE_PARM_DESC(sdh, "use SDH framing (default 0)"); + +static struct pci_device_id he_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID, + 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver he_driver = { + .name = "he", + .probe = he_init_one, + .remove = __devexit_p(he_remove_one), + .id_table = he_pci_tbl, +}; + +static int __init he_init(void) +{ + return pci_module_init(&he_driver); +} + +static void __exit he_cleanup(void) +{ + pci_unregister_driver(&he_driver); +} + +module_init(he_init); +module_exit(he_cleanup); diff -Nru a/drivers/atm/he.h b/drivers/atm/he.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/atm/he.h Mon May 12 20:55:49 2003 @@ -0,0 +1,938 @@ +/* $Id: he.h,v 1.4 2003/05/06 22:48:00 chas Exp $ */ + +/* + + he.h + + ForeRunnerHE ATM Adapter driver for ATM on Linux + Copyright (C) 1999-2001 Naval Research Laboratory + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + + he.h + + ForeRunnerHE ATM Adapter driver for ATM on Linux + Copyright (C) 1999-2000 Naval Research Laboratory + + Permission to use, copy, modify and distribute this software and its + documentation is hereby granted, provided that both the copyright + notice and this permission notice appear in all copies of the software, + derivative works or modified versions, and any portions thereof, and + that both notices appear in supporting documentation. + + NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND + DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER + RESULTING FROM THE USE OF THIS SOFTWARE. + + */ + +#ifndef _HE_H_ +#define _HE_H_ + +#define DEV_LABEL "he" + +#define CONFIG_DEFAULT_VCIBITS 12 +#define CONFIG_DEFAULT_VPIBITS 0 + +#define CONFIG_IRQ_SIZE 128 +#define CONFIG_IRQ_THRESH (CONFIG_IRQ_SIZE/2) + +#define CONFIG_NUMTPDS 256 + +#define CONFIG_TPDRQ_SIZE 512 +#define TPDRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TPDRQ_SIZE<<3)-1)) + +#define CONFIG_RBRQ_SIZE 512 +#define CONFIG_RBRQ_THRESH 400 +#define RBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_RBRQ_SIZE<<3)-1)) + +#define CONFIG_TBRQ_SIZE 512 +#define CONFIG_TBRQ_THRESH 400 +#define TBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TBRQ_SIZE<<2)-1)) + +#define CONFIG_RBPL_SIZE 512 +#define CONFIG_RBPL_THRESH 64 +#define CONFIG_RBPL_BUFSIZE 4096 +#define RBPL_MASK(x) (((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1)) + +#define CONFIG_RBPS_SIZE 1024 +#define CONFIG_RBPS_THRESH 64 +#define CONFIG_RBPS_BUFSIZE 128 +#define RBPS_MASK(x) (((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1)) + +/* 5.1.3 initialize connection memory */ + +#define CONFIG_RSRA 0x00000 +#define CONFIG_RCMLBM 0x08000 +#define CONFIG_RCMABR 0x0d800 +#define CONFIG_RSRB 0x0e000 + +#define CONFIG_TSRA 0x00000 +#define CONFIG_TSRB 0x08000 +#define CONFIG_TSRC 0x0c000 +#define CONFIG_TSRD 0x0e000 +#define CONFIG_TMABR 0x0f000 +#define CONFIG_TPDBA 0x10000 + +#define HE_MAXCIDBITS 12 + +/* 2.9.3.3 interrupt encodings */ + +struct he_irq { + volatile u32 isw; +}; + +#define IRQ_ALIGNMENT 0x1000 + +#define NEXT_ENTRY(base, tail, mask) \ + (((unsigned long)base)|(((unsigned long)(tail+1))&mask)) + +#define ITYPE_INVALID 0xffffffff +#define ITYPE_TBRQ_THRESH (0<<3) +#define ITYPE_TPD_COMPLETE (1<<3) +#define ITYPE_RBPS_THRESH (2<<3) +#define ITYPE_RBPL_THRESH (3<<3) +#define ITYPE_RBRQ_THRESH (4<<3) +#define ITYPE_RBRQ_TIMER (5<<3) +#define ITYPE_PHY (6<<3) +#define ITYPE_OTHER 0x80 +#define ITYPE_PARITY 0x81 +#define ITYPE_ABORT 0x82 + +#define ITYPE_GROUP(x) (x & 0x7) +#define ITYPE_TYPE(x) (x & 0xf8) + +#define HE_NUM_GROUPS 8 + +/* 2.1.4 transmit packet descriptor */ + +struct he_tpd { + + /* read by the adapter */ + + volatile u32 status; + volatile u32 reserved; + +#define TPD_MAXIOV 3 + struct { + u32 addr, len; + } iovec[TPD_MAXIOV]; + +#define address0 iovec[0].addr +#define length0 iovec[0].len + + /* linux-atm extensions */ + + struct sk_buff *skb; + struct atm_vcc *vcc; + +#ifdef USE_TPD_POOL + struct list_head entry; +#else + u32 inuse; + char padding[32 - sizeof(u32) - (2*sizeof(void*))]; +#endif +}; + +#define TPD_ALIGNMENT 64 +#define TPD_LEN_MASK 0xffff + +#define TPD_ADDR_SHIFT 6 +#define TPD_MASK 0xffffffc0 +#define TPD_ADDR(x) ((x) & TPD_MASK) +#define TPD_INDEX(x) (TPD_ADDR(x) >> TPD_ADDR_SHIFT) + + +/* table 2.3 transmit buffer return elements */ + +struct he_tbrq { + volatile u32 tbre; +}; + +#define TBRQ_ALIGNMENT CONFIG_TBRQ_SIZE + +#define TBRQ_TPD(tbrq) ((tbrq)->tbre & 0xffffffc0) +#define TBRQ_EOS(tbrq) ((tbrq)->tbre & (1<<3)) +#define TBRQ_MULTIPLE(tbrq) ((tbrq)->tbre & (1)) + +/* table 2.21 receive buffer return queue element field organization */ + +struct he_rbrq { + volatile u32 addr; + volatile u32 cidlen; +}; + +#define RBRQ_ALIGNMENT CONFIG_RBRQ_SIZE + +#define RBRQ_ADDR(rbrq) ((rbrq)->addr & 0xffffffc0) +#define RBRQ_CRC_ERR(rbrq) ((rbrq)->addr & (1<<5)) +#define RBRQ_LEN_ERR(rbrq) ((rbrq)->addr & (1<<4)) +#define RBRQ_END_PDU(rbrq) ((rbrq)->addr & (1<<3)) +#define RBRQ_AAL5_PROT(rbrq) ((rbrq)->addr & (1<<2)) +#define RBRQ_CON_CLOSED(rbrq) ((rbrq)->addr & (1<<1)) +#define RBRQ_HBUF_ERR(rbrq) ((rbrq)->addr & 1) +#define RBRQ_CID(rbrq) (((rbrq)->cidlen >> 16) & 0x1fff) +#define RBRQ_BUFLEN(rbrq) ((rbrq)->cidlen & 0xffff) + +/* figure 2.3 transmit packet descriptor ready queue */ + +struct he_tpdrq { + volatile u32 tpd; + volatile u32 cid; +}; + +#define TPDRQ_ALIGNMENT CONFIG_TPDRQ_SIZE + +/* table 2.30 host status page detail */ + +#define HSP_ALIGNMENT 0x400 /* must align on 1k boundary */ + +struct he_hsp { + struct he_hsp_entry { + volatile u32 tbrq_tail; + volatile u32 reserved1[15]; + volatile u32 rbrq_tail; + volatile u32 reserved2[15]; + } group[HE_NUM_GROUPS]; +}; + +/* figure 2.9 receive buffer pools */ + +struct he_rbp { + volatile u32 phys; + volatile u32 status; +}; + +/* NOTE: it is suggested that virt be the virtual address of the host + buffer. on a 64-bit machine, this would not work. Instead, we + store the real virtual address in another list, and store an index + (and buffer status) in the virt member. +*/ + +#define RBP_INDEX_OFF 6 +#define RBP_INDEX(x) (((long)(x) >> RBP_INDEX_OFF) & 0xffff) +#define RBP_LOANED 0x80000000 +#define RBP_SMALLBUF 0x40000000 + +struct he_virt { + void *virt; +}; + +#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE +#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE + +#ifdef notyet +struct he_group { + u32 rpbs_size, rpbs_qsize; + struct he_rbp rbps_ba; + + u32 rpbl_size, rpbl_qsize; + struct he_rpb_entry *rbpl_ba; +}; +#endif + +#define HE_LOOKUP_VCC(dev, cid) ((dev)->he_vcc_table[(cid)].vcc) + +struct he_vcc_table +{ + struct atm_vcc *vcc; +}; + +struct he_cs_stper +{ + long pcr; + int inuse; +}; + +#define HE_NUM_CS_STPER 16 + +struct he_dev { + unsigned int number; + unsigned int irq; + unsigned long membase; + + char prod_id[30]; + char mac_addr[6]; + int media; /* + * 0x26 = HE155 MM + * 0x27 = HE622 MM + * 0x46 = HE155 SM + * 0x47 = HE622 SM + */ + + + unsigned int vcibits, vpibits; + unsigned int cells_per_row; + unsigned int bytes_per_row; + unsigned int cells_per_lbuf; + unsigned int r0_numrows, r0_startrow, r0_numbuffs; + unsigned int r1_numrows, r1_startrow, r1_numbuffs; + unsigned int tx_numrows, tx_startrow, tx_numbuffs; + unsigned int buffer_limit; + + struct he_vcc_table *he_vcc_table; + +#ifdef notyet + struct he_group group[HE_NUM_GROUPS]; +#endif + struct he_cs_stper cs_stper[HE_NUM_CS_STPER]; + unsigned total_bw; + + dma_addr_t irq_phys; + struct he_irq *irq_base, *irq_head, *irq_tail; + volatile unsigned *irq_tailoffset; + int irq_peak; + +#ifdef USE_TASKLET + struct tasklet_struct tasklet; +#endif +#ifdef USE_TPD_POOL + struct pci_pool *tpd_pool; + struct list_head outstanding_tpds; +#else + struct he_tpd *tpd_head, *tpd_base, *tpd_end; + dma_addr_t tpd_base_phys; +#endif + + dma_addr_t tpdrq_phys; + struct he_tpdrq *tpdrq_base, *tpdrq_tail, *tpdrq_head; + + spinlock_t global_lock; /* 8.1.5 pci transaction ordering + error problem */ + dma_addr_t rbrq_phys; + struct he_rbrq *rbrq_base, *rbrq_head; + int rbrq_peak; + +#ifdef USE_RBPL_POOL + struct pci_pool *rbpl_pool; +#else + void *rbpl_pages; + dma_addr_t rbpl_pages_phys; +#endif + dma_addr_t rbpl_phys; + struct he_rbp *rbpl_base, *rbpl_tail; + struct he_virt *rbpl_virt; + int rbpl_peak; + +#ifdef USE_RBPS +#ifdef USE_RBPS_POOL + struct pci_pool *rbps_pool; +#else + void *rbps_pages; + dma_addr_t rbps_pages_phys; +#endif +#endif + dma_addr_t rbps_phys; + struct he_rbp *rbps_base, *rbps_tail; + struct he_virt *rbps_virt; + int rbps_peak; + + dma_addr_t tbrq_phys; + struct he_tbrq *tbrq_base, *tbrq_head; + int tbrq_peak; + + dma_addr_t hsp_phys; + struct he_hsp *hsp; + + struct pci_dev *pci_dev; + struct atm_dev *atm_dev; + struct he_dev *next; +}; + +struct he_iovec +{ + u32 iov_base; + u32 iov_len; +}; + +#define HE_MAXIOV 20 + +struct he_vcc +{ + struct he_iovec iov_head[HE_MAXIOV]; + struct he_iovec *iov_tail; + int pdu_len; + + int rc_index; + + wait_queue_head_t rx_waitq; + wait_queue_head_t tx_waitq; +}; + +#define HE_VCC(vcc) ((struct he_vcc *)(vcc->dev_data)) + +#define PCI_VENDOR_ID_FORE 0x1127 +#define PCI_DEVICE_ID_FORE_HE 0x400 + +#define HE_DMA_MASK 0xffffffff + +#define GEN_CNTL_0 0x40 +#define INT_PROC_ENBL (1<<25) +#define SLAVE_ENDIAN_MODE (1<<16) +#define MRL_ENB (1<<5) +#define MRM_ENB (1<<4) +#define INIT_ENB (1<<2) +#define IGNORE_TIMEOUT (1<<1) +#define ENBL_64 (1<<0) + +#define MIN_PCI_LATENCY 32 /* errata 8.1.3 */ + +#define HE_DEV(dev) ((struct he_dev *) (dev)->dev_data) + +#define he_is622(dev) ((dev)->media & 0x1) + +#define HE_REGMAP_SIZE 0x100000 + +#define RESET_CNTL 0x80000 +#define BOARD_RST_STATUS (1<<6) + +#define HOST_CNTL 0x80004 +#define PCI_BUS_SIZE64 (1<<27) +#define DESC_RD_STATIC_64 (1<<26) +#define DATA_RD_STATIC_64 (1<<25) +#define DATA_WR_STATIC_64 (1<<24) +#define ID_CS (1<<12) +#define ID_WREN (1<<11) +#define ID_DOUT (1<<10) +#define ID_DOFFSET 10 +#define ID_DIN (1<<9) +#define ID_CLOCK (1<<8) +#define QUICK_RD_RETRY (1<<7) +#define QUICK_WR_RETRY (1<<6) +#define OUTFF_ENB (1<<5) +#define CMDFF_ENB (1<<4) +#define PERR_INT_ENB (1<<2) +#define IGNORE_INTR (1<<0) + +#define LB_SWAP 0x80008 +#define SWAP_RNUM_MAX(x) (x<<27) +#define DATA_WR_SWAP (1<<20) +#define DESC_RD_SWAP (1<<19) +#define DATA_RD_SWAP (1<<18) +#define INTR_SWAP (1<<17) +#define DESC_WR_SWAP (1<<16) +#define SDRAM_INIT (1<<15) +#define BIG_ENDIAN_HOST (1<<14) +#define XFER_SIZE (1<<7) + +#define LB_MEM_ADDR 0x8000c +#define LB_MEM_DATA 0x80010 + +#define LB_MEM_ACCESS 0x80014 +#define LB_MEM_HNDSHK (1<<30) +#define LM_MEM_WRITE (0x7) +#define LM_MEM_READ (0x3) + +#define SDRAM_CTL 0x80018 +#define LB_64_ENB (1<<3) +#define LB_TWR (1<<2) +#define LB_TRP (1<<1) +#define LB_TRAS (1<<0) + +#define INT_FIFO 0x8001c +#define INT_MASK_D (1<<15) +#define INT_MASK_C (1<<14) +#define INT_MASK_B (1<<13) +#define INT_MASK_A (1<<12) +#define INT_CLEAR_D (1<<11) +#define INT_CLEAR_C (1<<10) +#define INT_CLEAR_B (1<<9) +#define INT_CLEAR_A (1<<8) + +#define ABORT_ADDR 0x80020 + +#define IRQ0_BASE 0x80080 +#define IRQ_BASE(x) (x<<12) +#define IRQ_MASK ((CONFIG_IRQ_SIZE<<2)-1) /* was 0x3ff */ +#define IRQ_TAIL(x) (((unsigned long)(x)) & IRQ_MASK) +#define IRQ0_HEAD 0x80084 +#define IRQ_SIZE(x) (x<<22) +#define IRQ_THRESH(x) (x<<12) +#define IRQ_HEAD(x) (x<<2) +/* #define IRQ_PENDING (1) conflict with linux/irq.h */ +#define IRQ0_CNTL 0x80088 +#define IRQ_ADDRSEL(x) (x<<2) +#define IRQ_INT_A (0<<2) +#define IRQ_INT_B (1<<2) +#define IRQ_INT_C (2<<2) +#define IRQ_INT_D (3<<2) +#define IRQ_TYPE_ADDR 0x1 +#define IRQ_TYPE_LINE 0x0 +#define IRQ0_DATA 0x8008c + +#define IRQ1_BASE 0x80090 +#define IRQ1_HEAD 0x80094 +#define IRQ1_CNTL 0x80098 +#define IRQ1_DATA 0x8009c + +#define IRQ2_BASE 0x800a0 +#define IRQ2_HEAD 0x800a4 +#define IRQ2_CNTL 0x800a8 +#define IRQ2_DATA 0x800ac + +#define IRQ3_BASE 0x800b0 +#define IRQ3_HEAD 0x800b4 +#define IRQ3_CNTL 0x800b8 +#define IRQ3_DATA 0x800bc + +#define GRP_10_MAP 0x800c0 +#define GRP_32_MAP 0x800c4 +#define GRP_54_MAP 0x800c8 +#define GRP_76_MAP 0x800cc + +#define G0_RBPS_S 0x80400 +#define G0_RBPS_T 0x80404 +#define RBP_TAIL(x) ((x)<<3) +#define RBP_MASK(x) ((x)|0x1fff) +#define G0_RBPS_QI 0x80408 +#define RBP_QSIZE(x) ((x)<<14) +#define RBP_INT_ENB (1<<13) +#define RBP_THRESH(x) (x) +#define G0_RBPS_BS 0x8040c +#define G0_RBPL_S 0x80410 +#define G0_RBPL_T 0x80414 +#define G0_RBPL_QI 0x80418 +#define G0_RBPL_BS 0x8041c + +#define G1_RBPS_S 0x80420 +#define G1_RBPS_T 0x80424 +#define G1_RBPS_QI 0x80428 +#define G1_RBPS_BS 0x8042c +#define G1_RBPL_S 0x80430 +#define G1_RBPL_T 0x80434 +#define G1_RBPL_QI 0x80438 +#define G1_RBPL_BS 0x8043c + +#define G2_RBPS_S 0x80440 +#define G2_RBPS_T 0x80444 +#define G2_RBPS_QI 0x80448 +#define G2_RBPS_BS 0x8044c +#define G2_RBPL_S 0x80450 +#define G2_RBPL_T 0x80454 +#define G2_RBPL_QI 0x80458 +#define G2_RBPL_BS 0x8045c + +#define G3_RBPS_S 0x80460 +#define G3_RBPS_T 0x80464 +#define G3_RBPS_QI 0x80468 +#define G3_RBPS_BS 0x8046c +#define G3_RBPL_S 0x80470 +#define G3_RBPL_T 0x80474 +#define G3_RBPL_QI 0x80478 +#define G3_RBPL_BS 0x8047c + +#define G4_RBPS_S 0x80480 +#define G4_RBPS_T 0x80484 +#define G4_RBPS_QI 0x80488 +#define G4_RBPS_BS 0x8048c +#define G4_RBPL_S 0x80490 +#define G4_RBPL_T 0x80494 +#define G4_RBPL_QI 0x80498 +#define G4_RBPL_BS 0x8049c + +#define G5_RBPS_S 0x804a0 +#define G5_RBPS_T 0x804a4 +#define G5_RBPS_QI 0x804a8 +#define G5_RBPS_BS 0x804ac +#define G5_RBPL_S 0x804b0 +#define G5_RBPL_T 0x804b4 +#define G5_RBPL_QI 0x804b8 +#define G5_RBPL_BS 0x804bc + +#define G6_RBPS_S 0x804c0 +#define G6_RBPS_T 0x804c4 +#define G6_RBPS_QI 0x804c8 +#define G6_RBPS_BS 0x804cc +#define G6_RBPL_S 0x804d0 +#define G6_RBPL_T 0x804d4 +#define G6_RBPL_QI 0x804d8 +#define G6_RBPL_BS 0x804dc + +#define G7_RBPS_S 0x804e0 +#define G7_RBPS_T 0x804e4 +#define G7_RBPS_QI 0x804e8 +#define G7_RBPS_BS 0x804ec + +#define G7_RBPL_S 0x804f0 +#define G7_RBPL_T 0x804f4 +#define G7_RBPL_QI 0x804f8 +#define G7_RBPL_BS 0x804fc + +#define G0_RBRQ_ST 0x80500 +#define G0_RBRQ_H 0x80504 +#define G0_RBRQ_Q 0x80508 +#define RBRQ_THRESH(x) ((x)<<13) +#define RBRQ_SIZE(x) (x) +#define G0_RBRQ_I 0x8050c +#define RBRQ_TIME(x) ((x)<<8) +#define RBRQ_COUNT(x) (x) + +/* fill in 1 ... 7 later */ + +#define G0_TBRQ_B_T 0x80600 +#define G0_TBRQ_H 0x80604 +#define G0_TBRQ_S 0x80608 +#define G0_TBRQ_THRESH 0x8060c +#define TBRQ_THRESH(x) (x) + +/* fill in 1 ... 7 later */ + +#define RH_CONFIG 0x805c0 +#define PHY_INT_ENB (1<<10) +#define OAM_GID(x) (x<<7) +#define PTMR_PRE(x) (x) + +#define G0_INMQ_S 0x80580 +#define G0_INMQ_L 0x80584 +#define G1_INMQ_S 0x80588 +#define G1_INMQ_L 0x8058c +#define G2_INMQ_S 0x80590 +#define G2_INMQ_L 0x80594 +#define G3_INMQ_S 0x80598 +#define G3_INMQ_L 0x8059c +#define G4_INMQ_S 0x805a0 +#define G4_INMQ_L 0x805a4 +#define G5_INMQ_S 0x805a8 +#define G5_INMQ_L 0x805ac +#define G6_INMQ_S 0x805b0 +#define G6_INMQ_L 0x805b4 +#define G7_INMQ_S 0x805b8 +#define G7_INMQ_L 0x805bc + +#define TPDRQ_B_H 0x80680 +#define TPDRQ_T 0x80684 +#define TPDRQ_S 0x80688 + +#define UBUFF_BA 0x8068c + +#define RLBF0_H 0x806c0 +#define RLBF0_T 0x806c4 +#define RLBF1_H 0x806c8 +#define RLBF1_T 0x806cc +#define RLBC_H 0x806d0 +#define RLBC_T 0x806d4 +#define RLBC_H2 0x806d8 +#define TLBF_H 0x806e0 +#define TLBF_T 0x806e4 +#define RLBF0_C 0x806e8 +#define RLBF1_C 0x806ec +#define RXTHRSH 0x806f0 +#define LITHRSH 0x806f4 + +#define LBARB 0x80700 +#define SLICE_X(x) (x<<28) +#define ARB_RNUM_MAX(x) (x<<23) +#define TH_PRTY(x) (x<<21) +#define RH_PRTY(x) (x<<19) +#define TL_PRTY(x) (x<<17) +#define RL_PRTY(x) (x<<15) +#define BUS_MULTI(x) (x<<8) +#define NET_PREF(x) (x) + +#define SDRAMCON 0x80704 +#define BANK_ON (1<<14) +#define WIDE_DATA (1<<13) +#define TWR_WAIT (1<<12) +#define TRP_WAIT (1<<11) +#define TRAS_WAIT (1<<10) +#define REF_RATE(x) (x) + +#define LBSTAT 0x80708 + +#define RCC_STAT 0x8070c +#define RCC_BUSY (1) + +#define TCMCONFIG 0x80740 +#define TM_DESL2 (1<<10) +#define TM_BANK_WAIT(x) (x<<6) +#define TM_ADD_BANK4(x) (x<<4) +#define TM_PAR_CHECK(x) (x<<3) +#define TM_RW_WAIT(x) (x<<2) +#define TM_SRAM_TYPE(x) (x) + +#define TSRB_BA 0x80744 +#define TSRC_BA 0x80748 +#define TMABR_BA 0x8074c +#define TPD_BA 0x80750 +#define TSRD_BA 0x80758 + +#define TX_CONFIG 0x80760 +#define DRF_THRESH(x) (x<<22) +#define TX_UT_MODE(x) (x<<21) +#define TX_VCI_MASK(x) (x<<17) +#define LBFREE_CNT(x) (x) + +#define TXAAL5_PROTO 0x80764 +#define CPCS_UU(x) (x<<8) +#define CPI(x) (x) + +#define RCMCONFIG 0x80780 +#define RM_DESL2(x) (x<<10) +#define RM_BANK_WAIT(x) (x<<6) +#define RM_ADD_BANK(x) (x<<4) +#define RM_PAR_CHECK(x) (x<<3) +#define RM_RW_WAIT(x) (x<<2) +#define RM_SRAM_TYPE(x) (x) + +#define RCMRSRB_BA 0x80784 +#define RCMLBM_BA 0x80788 +#define RCMABR_BA 0x8078c + +#define RC_CONFIG 0x807c0 +#define UT_RD_DELAY(x) (x<<11) +#define WRAP_MODE(x) (x<<10) +#define RC_UT_MODE(x) (x<<9) +#define RX_ENABLE (1<<8) +#define RX_VALVP(x) (x<<4) +#define RX_VALVC(x) (x) + +#define MCC 0x807c4 +#define OEC 0x807c8 +#define DCC 0x807cc +#define CEC 0x807d0 + +#define HSP_BA 0x807f0 + +#define LB_CONFIG 0x807f4 +#define LB_SIZE(x) (x) + +#define CON_DAT 0x807f8 +#define CON_CTL 0x807fc +#define CON_CTL_MBOX (2<<30) +#define CON_CTL_TCM (1<<30) +#define CON_CTL_RCM (0<<30) +#define CON_CTL_WRITE (1<<29) +#define CON_CTL_READ (0<<29) +#define CON_CTL_BUSY (1<<28) +#define CON_BYTE_DISABLE_3 (1<<22) /* 24..31 */ +#define CON_BYTE_DISABLE_2 (1<<21) /* 16..23 */ +#define CON_BYTE_DISABLE_1 (1<<20) /* 8..15 */ +#define CON_BYTE_DISABLE_0 (1<<19) /* 0..7 */ +#define CON_CTL_ADDR(x) (x) + +#define FRAMER 0x80800 /* to 0x80bfc */ + +/* 3.3 network controller (internal) mailbox registers */ + +#define CS_STPER0 0x0 + /* ... */ +#define CS_STPER31 0x01f + +#define CS_STTIM0 0x020 + /* ... */ +#define CS_STTIM31 0x03f + +#define CS_TGRLD0 0x040 + /* ... */ +#define CS_TGRLD15 0x04f + +#define CS_ERTHR0 0x050 +#define CS_ERTHR1 0x051 +#define CS_ERTHR2 0x052 +#define CS_ERTHR3 0x053 +#define CS_ERTHR4 0x054 +#define CS_ERCTL0 0x055 +#define TX_ENABLE (1<<28) +#define ER_ENABLE (1<<27) +#define CS_ERCTL1 0x056 +#define CS_ERCTL2 0x057 +#define CS_ERSTAT0 0x058 +#define CS_ERSTAT1 0x059 + +#define CS_RTCCT 0x060 +#define CS_RTFWC 0x061 +#define CS_RTFWR 0x062 +#define CS_RTFTC 0x063 +#define CS_RTATR 0x064 + +#define CS_TFBSET 0x070 +#define CS_TFBADD 0x071 +#define CS_TFBSUB 0x072 +#define CS_WCRMAX 0x073 +#define CS_WCRMIN 0x074 +#define CS_WCRINC 0x075 +#define CS_WCRDEC 0x076 +#define CS_WCRCEIL 0x077 +#define CS_BWDCNT 0x078 + +#define CS_OTPPER 0x080 +#define CS_OTWPER 0x081 +#define CS_OTTLIM 0x082 +#define CS_OTTCNT 0x083 + +#define CS_HGRRT0 0x090 + /* ... */ +#define CS_HGRRT7 0x097 + +#define CS_ORPTRS 0x0a0 + +#define RXCON_CLOSE 0x100 + + +#define RCM_MEM_SIZE 0x10000 /* 1M of 32-bit registers */ +#define TCM_MEM_SIZE 0x20000 /* 2M of 32-bit registers */ + +/* 2.5 transmit connection memory registers */ + +#define TSR0_CONN_STATE(x) ((x>>28) & 0x7) +#define TSR0_USE_WMIN (1<<23) +#define TSR0_GROUP(x) ((x & 0x7)<<18) +#define TSR0_ABR (2<<16) +#define TSR0_UBR (1<<16) +#define TSR0_CBR (0<<16) +#define TSR0_PROT (1<<15) +#define TSR0_AAL0_SDU (2<<12) +#define TSR0_AAL0 (1<<12) +#define TSR0_AAL5 (0<<12) +#define TSR0_HALT_ER (1<<11) +#define TSR0_MARK_CI (1<<10) +#define TSR0_MARK_ER (1<<9) +#define TSR0_UPDATE_GER (1<<8) +#define TSR0_RC_INDEX(x) (x & 0x1F) + +#define TSR1_PCR(x) ((x & 0x7FFF)<<16) +#define TSR1_MCR(x) (x & 0x7FFF) + +#define TSR2_ACR(x) ((x & 0x7FFF)<<16) + +#define TSR3_NRM_CNT(x) ((x & 0xFF)<<24) +#define TSR3_CRM_CNT(x) (x & 0xFFFF) + +#define TSR4_FLUSH_CONN (1<<31) +#define TSR4_SESSION_ENDED (1<<30) +#define TSR4_CRC10 (1<<28) +#define TSR4_NULL_CRC10 (1<<27) +#define TSR4_PROT (1<<26) +#define TSR4_AAL0_SDU (2<<23) +#define TSR4_AAL0 (1<<23) +#define TSR4_AAL5 (0<<23) + +#define TSR9_OPEN_CONN (1<<20) + +#define TSR11_ICR(x) ((x & 0x7FFF)<<16) +#define TSR11_TRM(x) ((x & 0x7)<<13) +#define TSR11_NRM(x) ((x & 0x7)<<10) +#define TSR11_ADTF(x) (x & 0x3FF) + +#define TSR13_RDF(x) ((x & 0xF)<<23) +#define TSR13_RIF(x) ((x & 0xF)<<19) +#define TSR13_CDF(x) ((x & 0x7)<<16) +#define TSR13_CRM(x) (x & 0xFFFF) + +#define TSR14_DELETE (1<<31) +#define TSR14_ABR_CLOSE (1<<16) + +/* 2.7.1 per connection receieve state registers */ + +#define RSR0_START_PDU (1<<10) +#define RSR0_OPEN_CONN (1<<6) +#define RSR0_CLOSE_CONN (0<<6) +#define RSR0_PPD_ENABLE (1<<5) +#define RSR0_EPD_ENABLE (1<<4) +#define RSR0_TCP_CKSUM (1<<3) +#define RSR0_AAL5 (0) +#define RSR0_AAL0 (1) +#define RSR0_AAL0_SDU (2) +#define RSR0_RAWCELL (3) +#define RSR0_RAWCELL_CRC10 (4) + +#define RSR1_AQI_ENABLE (1<<20) +#define RSR1_RBPL_ONLY (1<<19) +#define RSR1_GROUP(x) ((x)<<16) + +#define RSR4_AQI_ENABLE (1<<30) +#define RSR4_GROUP(x) ((x)<<27) +#define RSR4_RBPL_ONLY (1<<26) + +/* 2.1.4 transmit packet descriptor */ + +#define TPD_USERCELL 0x0 +#define TPD_SEGMENT_OAMF5 0x4 +#define TPD_END2END_OAMF5 0x5 +#define TPD_RMCELL 0x6 +#define TPD_CELLTYPE(x) (x<<3) +#define TPD_EOS (1<<2) +#define TPD_CLP (1<<1) +#define TPD_INT (1<<0) +#define TPD_LST (1<<31) + +/* table 4.3 serial eeprom information */ + +#define PROD_ID 0x08 /* char[] */ +#define PROD_ID_LEN 30 +#define HW_REV 0x26 /* char[] */ +#define M_SN 0x3a /* integer */ +#define MEDIA 0x3e /* integer */ +#define HE155MM 0x26 +#define HE155SM 0x27 +#define HE622MM 0x46 +#define HE622SM 0x47 +#define MAC_ADDR 0x42 /* char[] */ + +#define CS_LOW 0x0 +#define CS_HIGH ID_CS /* HOST_CNTL_ID_PROM_SEL */ +#define CLK_LOW 0x0 +#define CLK_HIGH ID_CLOCK /* HOST_CNTL_ID_PROM_CLOCK */ +#define SI_HIGH ID_DIN /* HOST_CNTL_ID_PROM_DATA_IN */ +#define EEPROM_DELAY 400 /* microseconds */ + +/* Read from EEPROM = 0000 0011b */ +unsigned int readtab[] = { + CS_HIGH | CLK_HIGH, + CS_LOW | CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW, + CLK_HIGH, /* 0 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH, /* 1 */ + CLK_LOW | SI_HIGH, + CLK_HIGH | SI_HIGH /* 1 */ +}; + +/* Clock to read from/write to the EEPROM */ +unsigned int clocktab[] = { + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW, + CLK_HIGH, + CLK_LOW +}; + + +#endif /* _HE_H_ */ diff -Nru a/drivers/atm/horizon.c b/drivers/atm/horizon.c --- a/drivers/atm/horizon.c Mon May 12 20:55:44 2003 +++ b/drivers/atm/horizon.c Mon May 12 20:55:44 2003 @@ -1768,17 +1768,20 @@ { unsigned int tx_len = skb->len; - unsigned int tx_iovcnt = ATM_SKB(skb)->iovcnt; + unsigned int tx_iovcnt = skb_shinfo(skb)->nr_frags; // remember this so we can free it later dev->tx_skb = skb; if (tx_iovcnt) { // scatter gather transfer dev->tx_regions = tx_iovcnt; - dev->tx_iovec = (struct iovec *) skb->data; + dev->tx_iovec = 0; /* @@@ needs rewritten */ dev->tx_bytes = 0; PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", skb->data, tx_len); + tx_release (dev); + hrz_kfree_skb (skb); + return -EIO; } else { // simple transfer dev->tx_regions = 0; diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c --- a/drivers/atm/idt77252.c Mon May 12 20:55:46 2003 +++ b/drivers/atm/idt77252.c Mon May 12 20:55:46 2003 @@ -1986,7 +1986,7 @@ return -EINVAL; } - if (ATM_SKB(skb)->iovcnt != 0) { + if (skb_shinfo(skb)->nr_frags != 0) { printk("%s: No scatter-gather yet.\n", card->name); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); @@ -2023,8 +2023,7 @@ atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } - atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; + atomic_add(skb->truesize, &vcc->sk->wmem_alloc); memcpy(skb_put(skb, 52), cell, 52); diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c --- a/drivers/atm/iphase.c Mon May 12 20:55:49 2003 +++ b/drivers/atm/iphase.c Mon May 12 20:55:49 2003 @@ -1167,7 +1167,6 @@ skb_put(skb,len); // pwang_test ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->iovcnt = 0; ATM_DESC(skb) = desc; skb_queue_tail(&iadev->rx_dma_q, skb); @@ -2778,7 +2777,7 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; tmps = (u16 *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) - if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT; + if(put_user((u16)(readl(iadev->seg_reg+i) & 0xffff), tmps)) return -EFAULT; ia_cmds.status = 0; ia_cmds.len = 0x80; break; @@ -2786,26 +2785,33 @@ if (!capable(CAP_NET_ADMIN)) return -EPERM; tmps = (u16 *)ia_cmds.buf; for(i=0; i<0x80; i+=2, tmps++) - if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT; + if(put_user((u16)(readl(iadev->reass_reg+i) & 0xffff), tmps)) return -EFAULT; ia_cmds.status = 0; ia_cmds.len = 0x80; break; case MEMDUMP_FFL: { - ia_regs_t regs_local; - ffredn_t *ffL = ®s_local.ffredn; - rfredn_t *rfL = ®s_local.rfredn; + ia_regs_t *regs_local; + ffredn_t *ffL; + rfredn_t *rfL; if (!capable(CAP_NET_ADMIN)) return -EPERM; + regs_local = kmalloc(sizeof(*regs_local), GFP_KERNEL); + if (!regs_local) return -ENOMEM; + ffL = ®s_local->ffredn; + rfL = ®s_local->rfredn; /* Copy real rfred registers into the local copy */ for (i=0; i<(sizeof (rfredn_t))/4; i++) - ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff; + ((u_int *)rfL)[i] = readl(iadev->reass_reg + i) & 0xffff; /* Copy real ffred registers into the local copy */ for (i=0; i<(sizeof (ffredn_t))/4; i++) - ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff; + ((u_int *)ffL)[i] = readl(iadev->seg_reg + i) & 0xffff; - if (copy_to_user(ia_cmds.buf, ®s_local,sizeof(ia_regs_t))) + if (copy_to_user(ia_cmds.buf, regs_local,sizeof(ia_regs_t))) { + kfree(regs_local); return -EFAULT; + } + kfree(regs_local); printk("Board %d registers dumped\n", board); ia_cmds.status = 0; } diff -Nru a/drivers/atm/lanai.c b/drivers/atm/lanai.c --- a/drivers/atm/lanai.c Mon May 12 20:55:45 2003 +++ b/drivers/atm/lanai.c Mon May 12 20:55:45 2003 @@ -2846,7 +2846,6 @@ .phy_get = NULL, .feedback = NULL, .change_qos = lanai_change_qos, - .free_rx_skb = NULL, .proc_read = lanai_proc_read }; diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c --- a/drivers/atm/nicstar.c Mon May 12 20:55:45 2003 +++ b/drivers/atm/nicstar.c Mon May 12 20:55:45 2003 @@ -882,9 +882,14 @@ return error; } - if (ns_parse_mac(mac[i], card->atmdev->esi)) + if (ns_parse_mac(mac[i], card->atmdev->esi)) { nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, card->atmdev->esi, 6); + if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) { + nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, + card->atmdev->esi, 6); + } + } printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], @@ -1601,9 +1606,9 @@ card->index); iovb = vc->rx_iov; recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); - ATM_SKB(iovb)->iovcnt = 0; - ATM_SKB(iovb)->vcc = NULL; + NS_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->vcc = NULL; ns_grab_int_lock(card, flags); recycle_iov_buf(card, iovb); spin_unlock_irqrestore(&card->int_lock, flags); @@ -1801,7 +1806,7 @@ return -EINVAL; } - if (ATM_SKB(skb)->iovcnt != 0) + if (skb_shinfo(skb)->nr_frags != 0) { printk("nicstar%d: No scatter-gather yet.\n", card->index); atomic_inc(&vcc->stats->tx_err); @@ -2226,30 +2231,30 @@ } } vc->rx_iov = iovb; - ATM_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; iovb->tail = iovb->data = iovb->head; - ATM_SKB(iovb)->vcc = vcc; + NS_SKB(iovb)->vcc = vcc; /* IMPORTANT: a pointer to the sk_buff containing the small or large buffer is stored as iovec base, NOT a pointer to the small or large buffer itself. */ } - else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) + else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS) { printk("nicstar%d: received too big AAL5 SDU.\n", card->index); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); - ATM_SKB(iovb)->iovcnt = 0; + NS_SKB(iovb)->iovcnt = 0; iovb->len = 0; iovb->tail = iovb->data = iovb->head; - ATM_SKB(iovb)->vcc = vcc; + NS_SKB(iovb)->vcc = vcc; } - iov = &((struct iovec *) iovb->data)[ATM_SKB(iovb)->iovcnt++]; + iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++]; iov->iov_base = (void *) skb; iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; iovb->len += iov->iov_len; - if (ATM_SKB(iovb)->iovcnt == 1) + if (NS_SKB(iovb)->iovcnt == 1) { if (skb->list != &card->sbpool.queue) { @@ -2263,7 +2268,7 @@ return; } } - else /* ATM_SKB(iovb)->iovcnt >= 2 */ + else /* NS_SKB(iovb)->iovcnt >= 2 */ { if (skb->list != &card->lbpool.queue) { @@ -2272,7 +2277,7 @@ which_list(card, skb); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2296,7 +2301,7 @@ printk(".\n"); atomic_inc(&vcc->stats->rx_err); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2304,7 +2309,7 @@ /* By this point we (hopefully) have a complete SDU without errors. */ - if (ATM_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ + if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */ { /* skb points to a small buffer */ if (!atm_charge(vcc, skb->truesize)) @@ -2326,7 +2331,7 @@ atomic_inc(&vcc->stats->rx); } } - else if (ATM_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ + else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */ { struct sk_buff *sb; @@ -2403,7 +2408,7 @@ printk("nicstar%d: Out of huge buffers.\n", card->index); atomic_inc(&vcc->stats->rx_drop); recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - ATM_SKB(iovb)->iovcnt); + NS_SKB(iovb)->iovcnt); vc->rx_iov = NULL; recycle_iov_buf(card, iovb); return; @@ -2441,7 +2446,7 @@ if (!atm_charge(vcc, hb->truesize)) { - recycle_iovec_rx_bufs(card, iov, ATM_SKB(iovb)->iovcnt); + recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt); if (card->hbpool.count < card->hbnr.max) { skb_queue_tail(&card->hbpool.queue, hb); @@ -2464,7 +2469,7 @@ 0, 0); /* Copy all large buffers to the huge buffer and free them */ - for (j = 1; j < ATM_SKB(iovb)->iovcnt; j++) + for (j = 1; j < NS_SKB(iovb)->iovcnt; j++) { lb = (struct sk_buff *) iov->iov_base; tocopy = MIN(remaining, iov->iov_len); diff -Nru a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h --- a/drivers/atm/nicstar.h Mon May 12 20:55:45 2003 +++ b/drivers/atm/nicstar.h Mon May 12 20:55:45 2003 @@ -96,6 +96,7 @@ /* ESI stuff ******************************************************************/ #define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C +#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6 /* #defines *******************************************************************/ @@ -747,6 +748,15 @@ SCD. 0x00000000 for UBR/VBR/ABR */ int tbd_count; } vc_map; + + +struct ns_skb_data +{ + struct atm_vcc *vcc; + int iovcnt; +}; + +#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb)) typedef struct ns_dev diff -Nru a/drivers/atm/zatm.c b/drivers/atm/zatm.c --- a/drivers/atm/zatm.c Mon May 12 20:55:45 2003 +++ b/drivers/atm/zatm.c Mon May 12 20:55:45 2003 @@ -827,10 +827,10 @@ vcc = ATM_SKB(skb)->vcc; zatm_dev = ZATM_DEV(vcc->dev); zatm_vcc = ZATM_VCC(vcc); - EVENT("iovcnt=%d\n",ATM_SKB(skb)->iovcnt,0); + EVENT("iovcnt=%d\n",skb_shinfo(skb)->nr_frags,0); save_flags(flags); cli(); - if (!ATM_SKB(skb)->iovcnt) { + if (!skb_shinfo(skb)->nr_frags) { if (zatm_vcc->txing == RING_ENTRIES-1) { restore_flags(flags); return RING_BUSY; diff -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c Mon May 12 20:55:49 2003 +++ b/drivers/base/class.c Mon May 12 20:55:49 2003 @@ -133,6 +133,21 @@ sysfs_remove_link(&class_dev->kobj, "device"); } +static int class_device_driver_link(struct class_device * class_dev) +{ + if ((class_dev->dev) && (class_dev->dev->driver)) + return sysfs_create_link(&class_dev->kobj, + &class_dev->dev->driver->kobj, "driver"); + return 0; +} + +static void class_device_driver_unlink(struct class_device * class_dev) +{ + if ((class_dev->dev) && (class_dev->dev->driver)) + sysfs_remove_link(&class_dev->kobj, "driver"); +} + + #define to_class_dev(obj) container_of(obj,struct class_device,kobj) #define to_class_dev_attr(_attr) container_of(_attr,struct class_device_attribute,attr) @@ -244,7 +259,6 @@ /* first, register with generic layer. */ strncpy(class_dev->kobj.name, class_dev->class_id, KOBJ_NAME_LEN); - kobj_set_kset_s(class_dev, class_subsys); kobj_set_kset_s(class_dev, class_obj_subsys); if (parent) class_dev->kobj.parent = &parent->subsys.kset.kobj; @@ -265,6 +279,7 @@ } class_device_dev_link(class_dev); + class_device_driver_link(class_dev); register_done: if (error && parent) @@ -298,6 +313,7 @@ if (class_dev->dev) { class_device_dev_unlink(class_dev); + class_device_driver_unlink(class_dev); put_device(class_dev->dev); } diff -Nru a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c --- a/drivers/block/acsi_slm.c Mon May 12 20:55:44 2003 +++ b/drivers/block/acsi_slm.c Mon May 12 20:55:44 2003 @@ -1008,11 +1008,8 @@ devfs_mk_dir("slm"); for (i = 0; i < MAX_SLM; i++) { - char name[16]; - sprintf(name, "slm/%d", i); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - ACSI_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR, - &slm_fops, NULL); + devfs_mk_cdev(MKDEV(ACSI_MAJOR, i), + S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i); } return 0; } diff -Nru a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c --- a/drivers/block/deadline-iosched.c Mon May 12 20:55:48 2003 +++ b/drivers/block/deadline-iosched.c Mon May 12 20:55:48 2003 @@ -28,7 +28,7 @@ static int fifo_batch = 16; /* # of sequential requests treated as one by the above parameters. For throughput. */ -static const int deadline_hash_shift = 10; +static const int deadline_hash_shift = 5; #define DL_HASH_BLOCK(sec) ((sec) >> 3) #define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift)) #define DL_HASH_ENTRIES (1 << deadline_hash_shift) @@ -71,6 +71,8 @@ int fifo_batch; int writes_starved; int front_merges; + + mempool_t *drq_pool; }; /* @@ -130,6 +132,21 @@ list_add(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]); } +/* + * move hot entry to front of chain + */ +static inline void +deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) +{ + struct request *rq = drq->request; + struct list_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))]; + + if (ON_HASH(drq) && drq->hash.prev != head) { + list_del(&drq->hash); + list_add(&drq->hash, head); + } +} + static struct request * deadline_find_drq_hash(struct deadline_data *dd, sector_t offset) { @@ -353,6 +370,8 @@ out: q->last_merge = &__rq->queuelist; out_insert: + if (ret) + deadline_hot_drq_hash(dd, RQ_DATA(__rq)); *insert = &__rq->queuelist; return ret; } @@ -673,28 +692,11 @@ static void deadline_exit(request_queue_t *q, elevator_t *e) { struct deadline_data *dd = e->elevator_data; - struct deadline_rq *drq; - struct request *rq; - int i; BUG_ON(!list_empty(&dd->fifo_list[READ])); BUG_ON(!list_empty(&dd->fifo_list[WRITE])); - for (i = READ; i <= WRITE; i++) { - struct request_list *rl = &q->rq[i]; - struct list_head *entry; - - list_for_each(entry, &rl->free) { - rq = list_entry_rq(entry); - - if ((drq = RQ_DATA(rq)) == NULL) - continue; - - rq->elevator_private = NULL; - kmem_cache_free(drq_pool, drq); - } - } - + mempool_destroy(dd->drq_pool); kfree(dd->hash); kfree(dd); } @@ -706,9 +708,7 @@ static int deadline_init(request_queue_t *q, elevator_t *e) { struct deadline_data *dd; - struct deadline_rq *drq; - struct request *rq; - int i, ret = 0; + int i; if (!drq_pool) return -ENOMEM; @@ -724,6 +724,13 @@ return -ENOMEM; } + dd->drq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, drq_pool); + if (!dd->drq_pool) { + kfree(dd->hash); + kfree(dd); + return -ENOMEM; + } + for (i = 0; i < DL_HASH_ENTRIES; i++) INIT_LIST_HEAD(&dd->hash[i]); @@ -739,33 +746,41 @@ dd->front_merges = 1; dd->fifo_batch = fifo_batch; e->elevator_data = dd; + return 0; +} - for (i = READ; i <= WRITE; i++) { - struct request_list *rl = &q->rq[i]; - struct list_head *entry; - - list_for_each(entry, &rl->free) { - rq = list_entry_rq(entry); - - drq = kmem_cache_alloc(drq_pool, GFP_KERNEL); - if (!drq) { - ret = -ENOMEM; - break; - } +static void deadline_put_request(request_queue_t *q, struct request *rq) +{ + struct deadline_data *dd = q->elevator.elevator_data; + struct deadline_rq *drq = RQ_DATA(rq); - memset(drq, 0, sizeof(*drq)); - INIT_LIST_HEAD(&drq->fifo); - INIT_LIST_HEAD(&drq->hash); - RB_CLEAR(&drq->rb_node); - drq->request = rq; - rq->elevator_private = drq; - } + if (drq) { + mempool_free(drq, dd->drq_pool); + rq->elevator_private = NULL; } +} - if (ret) - deadline_exit(q, e); +static int +deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask) +{ + struct deadline_data *dd = q->elevator.elevator_data; + struct deadline_rq *drq; - return ret; + drq = mempool_alloc(dd->drq_pool, gfp_mask); + if (drq) { + RB_CLEAR(&drq->rb_node); + drq->request = rq; + + INIT_LIST_HEAD(&drq->hash); + drq->hash_valid_count = 0; + + INIT_LIST_HEAD(&drq->fifo); + + rq->elevator_private = drq; + return 0; + } + + return 1; } /* @@ -916,6 +931,8 @@ .elevator_queue_empty_fn = deadline_queue_empty, .elevator_former_req_fn = deadline_former_request, .elevator_latter_req_fn = deadline_latter_request, + .elevator_set_req_fn = deadline_set_request, + .elevator_put_req_fn = deadline_put_request, .elevator_init_fn = deadline_init, .elevator_exit_fn = deadline_exit, diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c --- a/drivers/block/elevator.c Mon May 12 20:55:48 2003 +++ b/drivers/block/elevator.c Mon May 12 20:55:48 2003 @@ -408,6 +408,25 @@ return NULL; } +int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_set_req_fn) + return e->elevator_set_req_fn(q, rq, gfp_mask); + + rq->elevator_private = NULL; + return 0; +} + +void elv_put_request(request_queue_t *q, struct request *rq) +{ + elevator_t *e = &q->elevator; + + if (e->elevator_put_req_fn) + e->elevator_put_req_fn(q, rq); +} + int elv_register_queue(struct gendisk *disk) { request_queue_t *q = disk->queue; diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Mon May 12 20:55:44 2003 +++ b/drivers/block/ll_rw_blk.c Mon May 12 20:55:44 2003 @@ -48,12 +48,6 @@ */ static int queue_nr_requests; -/* - * How many free requests must be available before we wake a process which - * is waiting for a request? - */ -static int batch_requests; - unsigned long blk_max_low_pfn, blk_max_pfn; int blk_nohighio = 0; @@ -419,7 +413,7 @@ { struct blk_queue_tag *bqt = q->queue_tags; - if(unlikely(bqt == NULL || bqt->max_depth < tag)) + if (unlikely(bqt == NULL || bqt->max_depth < tag)) return NULL; return bqt->tag_index[tag]; @@ -1122,26 +1116,6 @@ spin_unlock_irq(&blk_plug_lock); } -static int __blk_cleanup_queue(struct request_list *list) -{ - struct list_head *head = &list->free; - struct request *rq; - int i = 0; - - while (!list_empty(head)) { - rq = list_entry(head->next, struct request, queuelist); - list_del_init(&rq->queuelist); - kmem_cache_free(request_cachep, rq); - i++; - } - - if (i != list->count) - printk("request list leak!\n"); - - list->count = 0; - return i; -} - /** * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed * @q: the request queue to be released @@ -1158,18 +1132,14 @@ **/ void blk_cleanup_queue(request_queue_t * q) { - int count = (queue_nr_requests*2); + struct request_list *rl = &q->rq; elevator_exit(q); - count -= __blk_cleanup_queue(&q->rq[READ]); - count -= __blk_cleanup_queue(&q->rq[WRITE]); - del_timer_sync(&q->unplug_timer); flush_scheduled_work(); - if (count) - printk("blk_cleanup_queue: leaked requests (%d)\n", count); + mempool_destroy(rl->rq_pool); if (blk_queue_tagged(q)) blk_queue_free_tags(q); @@ -1179,42 +1149,16 @@ static int blk_init_free_list(request_queue_t *q) { - struct request_list *rl; - struct request *rq; - int i; + struct request_list *rl = &q->rq; - INIT_LIST_HEAD(&q->rq[READ].free); - INIT_LIST_HEAD(&q->rq[WRITE].free); - q->rq[READ].count = 0; - q->rq[WRITE].count = 0; + rl->count[READ] = rl->count[WRITE] = 0; - /* - * Divide requests in half between read and write - */ - rl = &q->rq[READ]; - for (i = 0; i < (queue_nr_requests*2); i++) { - rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL); - if (!rq) - goto nomem; + rl->rq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep); - /* - * half way through, switch to WRITE list - */ - if (i == queue_nr_requests) - rl = &q->rq[WRITE]; - - memset(rq, 0, sizeof(struct request)); - rq->rq_status = RQ_INACTIVE; - list_add(&rq->queuelist, &rl->free); - rl->count++; - } + if (!rl->rq_pool) + return -ENOMEM; - init_waitqueue_head(&q->rq[READ].wait); - init_waitqueue_head(&q->rq[WRITE].wait); return 0; -nomem: - blk_cleanup_queue(q); - return 1; } static int __make_request(request_queue_t *, struct bio *); @@ -1276,41 +1220,79 @@ blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS); blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); - INIT_LIST_HEAD(&q->plug_list); - return 0; } +static inline void blk_free_request(request_queue_t *q, struct request *rq) +{ + elv_put_request(q, rq); + mempool_free(rq, q->rq.rq_pool); +} + +static inline struct request *blk_alloc_request(request_queue_t *q,int gfp_mask) +{ + struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); + + if (!rq) + return NULL; + + if (!elv_set_request(q, rq, gfp_mask)) + return rq; + + mempool_free(rq, q->rq.rq_pool); + return NULL; +} + #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) /* - * Get a free request. queue lock must be held and interrupts - * disabled on the way in. + * Get a free request, queue_lock must not be held */ -static struct request *get_request(request_queue_t *q, int rw) +static struct request *get_request(request_queue_t *q, int rw, int gfp_mask) { struct request *rq = NULL; - struct request_list *rl = q->rq + rw; + struct request_list *rl = &q->rq; - if (!list_empty(&rl->free)) { - rq = blkdev_free_rq(&rl->free); - list_del_init(&rq->queuelist); - rq->ref_count = 1; - rl->count--; - if (rl->count < queue_congestion_on_threshold()) - set_queue_congested(q, rw); - rq->flags = 0; - rq->rq_status = RQ_ACTIVE; - rq->errors = 0; - rq->special = NULL; - rq->buffer = NULL; - rq->data = NULL; - rq->sense = NULL; - rq->waiting = NULL; - rq->bio = rq->biotail = NULL; - rq->q = q; - rq->rl = rl; + spin_lock_irq(q->queue_lock); + if (rl->count[rw] == BLKDEV_MAX_RQ) { + spin_unlock_irq(q->queue_lock); + goto out; } + rl->count[rw]++; + if ((BLKDEV_MAX_RQ - rl->count[rw]) < queue_congestion_on_threshold()) + set_queue_congested(q, rw); + spin_unlock_irq(q->queue_lock); + rq = blk_alloc_request(q, gfp_mask); + if (!rq) { + spin_lock_irq(q->queue_lock); + rl->count[rw]--; + if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold()) + clear_queue_congested(q, rw); + spin_unlock_irq(q->queue_lock); + goto out; + } + + INIT_LIST_HEAD(&rq->queuelist); + + /* + * first three bits are identical in rq->flags and bio->bi_rw, + * see bio.h and blkdev.h + */ + rq->flags = rw; + + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + rq->bio = rq->biotail = NULL; + rq->buffer = NULL; + rq->ref_count = 1; + rq->q = q; + rq->rl = rl; + rq->waiting = NULL; + rq->special = NULL; + rq->data = NULL; + rq->sense = NULL; + +out: return rq; } @@ -1319,31 +1301,16 @@ */ static struct request *get_request_wait(request_queue_t *q, int rw) { - DEFINE_WAIT(wait); - struct request_list *rl = &q->rq[rw]; struct request *rq; - spin_lock_prefetch(q->queue_lock); - generic_unplug_device(q); do { - int block = 0; - - prepare_to_wait_exclusive(&rl->wait, &wait, - TASK_UNINTERRUPTIBLE); - spin_lock_irq(q->queue_lock); - if (!rl->count) - block = 1; - spin_unlock_irq(q->queue_lock); + rq = get_request(q, rw, GFP_NOIO); - if (block) - io_schedule(); - finish_wait(&rl->wait, &wait); + if (!rq) + blk_congestion_wait(rw, HZ / 50); + } while (!rq); - spin_lock_irq(q->queue_lock); - rq = get_request(q, rw); - spin_unlock_irq(q->queue_lock); - } while (rq == NULL); return rq; } @@ -1353,39 +1320,11 @@ BUG_ON(rw != READ && rw != WRITE); - spin_lock_irq(q->queue_lock); - rq = get_request(q, rw); - spin_unlock_irq(q->queue_lock); + rq = get_request(q, rw, gfp_mask); if (!rq && (gfp_mask & __GFP_WAIT)) rq = get_request_wait(q, rw); - if (rq) { - rq->flags = 0; - rq->buffer = NULL; - rq->bio = rq->biotail = NULL; - rq->waiting = NULL; - } - return rq; -} - -/* - * Non-locking blk_get_request variant, for special requests from drivers. - */ -struct request *__blk_get_request(request_queue_t *q, int rw) -{ - struct request *rq; - - BUG_ON(rw != READ && rw != WRITE); - - rq = get_request(q, rw); - - if (rq) { - rq->flags = 0; - rq->buffer = NULL; - rq->bio = rq->biotail = NULL; - rq->waiting = NULL; - } return rq; } @@ -1503,14 +1442,17 @@ disk->stamp_idle = now; } +/* + * queue lock must be held + */ void __blk_put_request(request_queue_t *q, struct request *req) { struct request_list *rl = req->rl; - if (unlikely(--req->ref_count)) - return; if (unlikely(!q)) return; + if (unlikely(--req->ref_count)) + return; req->rq_status = RQ_INACTIVE; req->q = NULL; @@ -1521,24 +1463,15 @@ * it didn't come out of our reserved rq pools */ if (rl) { - int rw = 0; + int rw = rq_data_dir(req); BUG_ON(!list_empty(&req->queuelist)); - list_add(&req->queuelist, &rl->free); + blk_free_request(q, req); - if (rl == &q->rq[WRITE]) - rw = WRITE; - else if (rl == &q->rq[READ]) - rw = READ; - else - BUG(); - - rl->count++; - if (rl->count >= queue_congestion_off_threshold()) + rl->count[rw]--; + if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold()) clear_queue_congested(q, rw); - if (rl->count >= batch_requests && waitqueue_active(&rl->wait)) - wake_up(&rl->wait); } } @@ -1605,24 +1538,23 @@ * will have updated segment counts, update sector * counts here. */ - if (q->merge_requests_fn(q, req, next)) { - req->biotail->bi_next = next->bio; - req->biotail = next->biotail; + if (!q->merge_requests_fn(q, req, next)) + return 0; - req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; + req->biotail->bi_next = next->bio; + req->biotail = next->biotail; - elv_merge_requests(q, req, next); + req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; - if (req->rq_disk) { - disk_round_stats(req->rq_disk); - disk_stat_dec(req->rq_disk, in_flight); - } + elv_merge_requests(q, req, next); - __blk_put_request(q, next); - return 1; + if (req->rq_disk) { + disk_round_stats(req->rq_disk); + disk_stat_dec(req->rq_disk, in_flight); } - return 0; + __blk_put_request(q, next); + return 1; } static inline int attempt_back_merge(request_queue_t *q, struct request *rq) @@ -1698,9 +1630,9 @@ barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); - spin_lock_irq(q->queue_lock); again: insert_here = NULL; + spin_lock_irq(q->queue_lock); if (elv_queue_empty(q)) { blk_plug_device(q); @@ -1776,17 +1708,17 @@ if (freereq) { req = freereq; freereq = NULL; - } else if ((req = get_request(q, rw)) == NULL) { + } else { spin_unlock_irq(q->queue_lock); - - /* - * READA bit set - */ - if (bio_flagged(bio, BIO_RW_AHEAD)) - goto end_io; - - freereq = get_request_wait(q, rw); - spin_lock_irq(q->queue_lock); + if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) { + /* + * READA bit set + */ + if (bio_flagged(bio, BIO_RW_AHEAD)) + goto end_io; + + freereq = get_request_wait(q, rw); + } goto again; } @@ -1813,14 +1745,15 @@ req->bio = req->biotail = bio; req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; + add_request(q, req, insert_here); out: if (freereq) __blk_put_request(q, freereq); if (blk_queue_plugged(q)) { - int nr_queued = (queue_nr_requests - q->rq[0].count) + - (queue_nr_requests - q->rq[1].count); + int nr_queued = q->rq.count[0] + q->rq.count[1]; + if (nr_queued == q->unplug_thresh) __generic_unplug_device(q); } @@ -2213,7 +2146,6 @@ int __init blk_dev_init(void) { - int total_ram = nr_free_pages() << (PAGE_SHIFT - 10); int i; request_cachep = kmem_cache_create("blkdev_requests", @@ -2221,24 +2153,11 @@ if (!request_cachep) panic("Can't create request pool slab cache\n"); - /* - * Free request slots per queue. One per quarter-megabyte. - * We use this many requests for reads, and this many for writes. - */ - queue_nr_requests = (total_ram >> 9) & ~7; - if (queue_nr_requests < 16) - queue_nr_requests = 16; - if (queue_nr_requests > 128) - queue_nr_requests = 128; - - batch_requests = queue_nr_requests / 8; - if (batch_requests > 8) - batch_requests = 8; + queue_nr_requests = BLKDEV_MAX_RQ; printk("block request queues:\n"); - printk(" %d requests per read queue\n", queue_nr_requests); - printk(" %d requests per write queue\n", queue_nr_requests); - printk(" %d requests per batch\n", batch_requests); + printk(" %d/%d requests per read queue\n", BLKDEV_MIN_RQ, queue_nr_requests); + printk(" %d/%d requests per write queue\n", BLKDEV_MIN_RQ, queue_nr_requests); printk(" enter congestion at %d\n", queue_congestion_on_threshold()); printk(" exit congestion at %d\n", queue_congestion_off_threshold()); @@ -2281,7 +2200,6 @@ EXPORT_SYMBOL(blk_phys_contig_segment); EXPORT_SYMBOL(blk_hw_contig_segment); EXPORT_SYMBOL(blk_get_request); -EXPORT_SYMBOL(__blk_get_request); EXPORT_SYMBOL(blk_put_request); EXPORT_SYMBOL(blk_insert_request); diff -Nru a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c --- a/drivers/block/paride/pg.c Mon May 12 20:55:48 2003 +++ b/drivers/block/paride/pg.c Mon May 12 20:55:48 2003 @@ -652,11 +652,8 @@ devfs_mk_dir ("pg"); for (unit=0; unitudev, husb->bulk_out_ep->desc.bEndpointAddress); usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, hci_usb_tx_complete, husb); - urb->transfer_flags = USB_ZERO_PACKET; + urb->transfer_flags = URB_ZERO_PACKET; BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); diff -Nru a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig --- a/drivers/char/agp/Kconfig Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/Kconfig Mon May 12 20:55:47 2003 @@ -1,6 +1,6 @@ config AGP tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU - default AGP_GART if GART_IOMMU + default y if GART_IOMMU ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to connect graphics cards to the rest of the system. @@ -25,54 +25,66 @@ a module, say M here and read . The module will be called agpgart. -config AGP_GART - bool "/dev/agpgart (AGP Support)" - depends on GART_IOMMU - -config AGP_INTEL - tristate "Intel 440LX/BX/GX, I8xx and E7x05 support" - depends on AGP && !X86_64 - help +config AGP_ALI + tristate "ALI chipset support" + depends on AGP && X86 && !X86_64 + ---help--- This option gives you AGP support for the GLX component of the - XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860 - E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G, - 852GM, 855GM and 865G integrated graphics chipsets. + XFree86 4.x on the following ALi chipsets. The supported chipsets + include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. + For the ALi-chipset question, ALi suggests you refer to + . - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI, or if you have any Intel integrated graphics - chipsets. If unsure, say Y. + The M1541 chipset can do AGP 1x and 2x, but note that there is an + acknowledged incompatibility with Matrox G200 cards. Due to + timing issues, this chipset cannot do AGP 2x with the G200. + This is a hardware limitation. AGP 1x seems to be fine, though. -#config AGP_I810 -# tristate "Intel I810/I815/I830M (on-board) support" -# depends on AGP && !X86_64 -# help -# This option gives you AGP support for the Xserver on the Intel 810 -# 815 and 830m chipset boards for their on-board integrated graphics. This -# is required to do any useful video modes with these boards. + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. -config AGP_VIA - tristate "VIA chipset support" - depends on AGP && !X86_64 +config AGP_AMD + tristate "AMD Irongate, 761, and 762 chipset support" + depends on AGP && X86 && !X86_64 help This option gives you AGP support for the GLX component of the - XFree86 4.x on VIA MPV3/Apollo Pro chipsets. + XFree86 4.x on AMD Irongate, 761, and 762 chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. -config AGP_AMD - tristate "AMD Irongate, 761, and 762 support" - depends on AGP && !X86_64 +config AGP_AMD_8151 + tristate "AMD 8151 chipset support" + depends on AGP && X86 + default GART_IOMMU + help + Say Y here to support the AMD 8151 AGP bridge and the builtin + GART on the AMD Athlon64/Opteron ("Hammer") CPUs. + +config AGP_INTEL + tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support" + depends on AGP && X86 && !X86_64 help This option gives you AGP support for the GLX component of the - XFree86 4.x on AMD Irongate, 761, and 762 chipsets. + XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860 + E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G, + 852GM, 855GM and 865G integrated graphics chipsets. You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. + use GLX or DRI, or if you have any Intel integrated graphics + chipsets. If unsure, say Y. + +config AGP_NVIDIA + tristate "NVIDIA nForce/nForce2 chipset support" + depends on AGP && X86 && !X86_64 + help + This option gives you AGP support for the GLX component of the + XFree86 4.x on the following NVIDIA chipsets. The supported chipsets + include nForce and nForce2 config AGP_SIS - tristate "Generic SiS support" - depends on AGP && !X86_64 + tristate "SiS chipset support" + depends on AGP && X86 && !X86_64 help This option gives you AGP support for the GLX component of the "soon to be released" XFree86 4.x on Silicon Integrated Systems [SiS] @@ -83,55 +95,39 @@ You should say Y here if you use XFree86 3.3.6 or 4.x and want to use GLX or DRI. If unsure, say N. -config AGP_ALI - tristate "ALI chipset support" - depends on AGP && !X86_64 - ---help--- - This option gives you AGP support for the GLX component of the - XFree86 4.x on the following ALi chipsets. The supported chipsets - include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. - For the ALi-chipset question, ALi suggests you refer to - . - - The M1541 chipset can do AGP 1x and 2x, but note that there is an - acknowledged incompatibility with Matrox G200 cards. Due to - timing issues, this chipset cannot do AGP 2x with the G200. - This is a hardware limitation. AGP 1x seems to be fine, though. - - You should say Y here if you use XFree86 3.3.6 or 4.x and want to - use GLX or DRI. If unsure, say N. - config AGP_SWORKS - tristate "Serverworks LE/HE support" - depends on AGP && !X86_64 + tristate "Serverworks LE/HE chipset support" + depends on AGP && X86 && !X86_64 help Say Y here to support the Serverworks AGP card. See for product descriptions and images. -config AGP_AMD_8151 - tristate "AMD 8151 support" - depends on AGP - default GART_IOMMU +config AGP_VIA + tristate "VIA chipset support" + depends on AGP && X86 && !X86_64 help - Say Y here to support the AMD 8151 AGP bridge and the builtin - GART on the AMD Athlon64/Opteron ("Hammer") CPUs. + This option gives you AGP support for the GLX component of the + XFree86 4.x on VIA MPV3/Apollo Pro chipsets. + + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. config AGP_I460 - tristate "Intel 460GX support" + tristate "Intel 460GX chipset support" depends on AGP && IA64 help This option gives you AGP GART support for the Intel 460GX chipset for IA64 processors. config AGP_HP_ZX1 - tristate "HP ZX1 AGP support" + tristate "HP ZX1 chipset AGP support" depends on AGP && IA64 help This option gives you AGP GART support for the HP ZX1 chipset for IA64 processors. config AGP_ALPHA_CORE - tristate + tristate "Alpha AGP support" depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL) default AGP diff -Nru a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile --- a/drivers/char/agp/Makefile Mon May 12 20:55:45 2003 +++ b/drivers/char/agp/Makefile Mon May 12 20:55:45 2003 @@ -1,21 +1,15 @@ -# -# Makefile for the agpgart device driver. This driver adds a user -# space ioctl interface to use agp memory. It also adds a kernel interface -# that other drivers could use to manipulate agp memory. - agpgart-y := backend.o frontend.o generic.o generic-3.0.o -agpgart-objs := $(agpgart-y) -obj-$(CONFIG_AGP) += agpgart.o -obj-$(CONFIG_AGP_INTEL) += intel-agp.o -obj-$(CONFIG_AGP_VIA) += via-agp.o -obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o -obj-$(CONFIG_AGP_SIS) += sis-agp.o +obj-$(CONFIG_AGP) += agpgart.o obj-$(CONFIG_AGP_ALI) += ali-agp.o -obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o -obj-$(CONFIG_AGP_I460) += i460-agp.o -obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o +obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o obj-$(CONFIG_AGP_AMD_8151) += amd-k8-agp.o obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o - +obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o +obj-$(CONFIG_AGP_I460) += i460-agp.o +obj-$(CONFIG_AGP_INTEL) += intel-agp.o +obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o +obj-$(CONFIG_AGP_SIS) += sis-agp.o +obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o +obj-$(CONFIG_AGP_VIA) += via-agp.o diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h --- a/drivers/char/agp/agp.h Mon May 12 20:55:46 2003 +++ b/drivers/char/agp/agp.h Mon May 12 20:55:46 2003 @@ -30,27 +30,16 @@ #include /* for flush_agp_cache() */ -extern struct agp_bridge_data *agp_bridge; - #define PFX "agpgart: " -#ifdef CONFIG_SMP -static void ipi_handler(void *null) -{ - flush_agp_cache(); -} - -static void __attribute__((unused)) global_cache_flush(void) -{ - if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0) - panic(PFX "timed out waiting for the other CPUs!\n"); -} +//#define AGP_DEBUG 1 +#ifdef AGP_DEBUG +#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y) #else -static void global_cache_flush(void) -{ - flush_agp_cache(); -} -#endif /* !CONFIG_SMP */ +#define DBG(x,y...) do { } while (0) +#endif + +extern struct agp_bridge_data *agp_bridge; enum aper_size_type { U8_APER_SIZE, @@ -101,14 +90,41 @@ int page_order; }; +struct agp_bridge_driver { + struct module *owner; + void *aperture_sizes; + int num_aperture_sizes; + enum aper_size_type size_type; + int cant_use_aperture; + int needs_scratch_page; + struct gatt_mask *masks; + int (*fetch_size)(void); + int (*configure)(void); + void (*agp_enable)(u32); + void (*cleanup)(void); + void (*tlb_flush)(agp_memory *); + unsigned long (*mask_memory)(unsigned long, int); + void (*cache_flush)(void); + int (*create_gatt_table)(void); + int (*free_gatt_table)(void); + int (*insert_memory)(agp_memory *, off_t, int); + int (*remove_memory)(agp_memory *, off_t, int); + agp_memory *(*alloc_by_type) (size_t, int); + void (*free_by_type)(agp_memory *); + void *(*agp_alloc_page)(void); + void (*agp_destroy_page)(void *); + int (*suspend)(void); + void (*resume)(void); +}; + struct agp_bridge_data { struct agp_version *version; - void *aperture_sizes; + struct agp_bridge_driver *driver; + struct vm_operations_struct *vm_ops; void *previous_size; void *current_size; void *dev_private_data; struct pci_dev *dev; - struct gatt_mask *masks; u32 *gatt_table; u32 *gatt_table_real; unsigned long scratch_page; @@ -117,38 +133,12 @@ unsigned long gatt_bus_addr; u32 mode; enum chipset_type type; - enum aper_size_type size_type; unsigned long *key_list; atomic_t current_memory_agp; atomic_t agp_in_use; int max_memory_agp; /* in number of pages */ - int needs_scratch_page; int aperture_size_idx; - int num_aperture_sizes; int capndx; - int cant_use_aperture; - struct vm_operations_struct *vm_ops; - - /* Links to driver specific functions */ - - int (*fetch_size) (void); - int (*configure) (void); - void (*agp_enable) (u32); - void (*cleanup) (void); - void (*tlb_flush) (agp_memory *); - unsigned long (*mask_memory) (unsigned long, int); - void (*cache_flush) (void); - int (*create_gatt_table) (void); - int (*free_gatt_table) (void); - int (*insert_memory) (agp_memory *, off_t, int); - int (*remove_memory) (agp_memory *, off_t, int); - agp_memory *(*alloc_by_type) (size_t, int); - void (*free_by_type) (agp_memory *); - void *(*agp_alloc_page) (void); - void (*agp_destroy_page) (void *); - int (*suspend)(void); - void (*resume)(void); - }; #define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr)) @@ -165,20 +155,17 @@ #define MB(x) (KB (KB (x))) #define GB(x) (MB (KB (x))) -#define CACHE_FLUSH agp_bridge->cache_flush #define A_SIZE_8(x) ((struct aper_size_info_8 *) x) #define A_SIZE_16(x) ((struct aper_size_info_16 *) x) #define A_SIZE_32(x) ((struct aper_size_info_32 *) x) #define A_SIZE_LVL2(x) ((struct aper_size_info_lvl2 *) x) #define A_SIZE_FIX(x) ((struct aper_size_info_fixed *) x) -#define A_IDX8() (A_SIZE_8(agp_bridge->aperture_sizes) + i) -#define A_IDX16() (A_SIZE_16(agp_bridge->aperture_sizes) + i) -#define A_IDX32() (A_SIZE_32(agp_bridge->aperture_sizes) + i) -#define A_IDXLVL2() (A_SIZE_LVL2(agp_bridge->aperture_sizes) + i) -#define A_IDXFIX() (A_SIZE_FIX(agp_bridge->aperture_sizes) + i) +#define A_IDX8(bridge) (A_SIZE_8((bridge)->driver->aperture_sizes) + i) +#define A_IDX16(bridge) (A_SIZE_16((bridge)->driver->aperture_sizes) + i) +#define A_IDX32(bridge) (A_SIZE_32((bridge)->driver->aperture_sizes) + i) #define MAXKEY (4096 * 32) -#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge->scratch_page) +#define PGE_EMPTY(b, p) (!(p) || (p) == (unsigned long) (b)->scratch_page) /* intel register */ #define INTEL_APBASE 0x10 @@ -374,11 +361,15 @@ int (*chipset_setup) (struct pci_dev *pdev); /* used to override generic */ }; -struct agp_driver { - struct module *owner; - struct pci_dev *dev; -}; - +/* Driver registration */ +struct agp_bridge_data *agp_alloc_bridge(void); +void agp_put_bridge(struct agp_bridge_data *bridge); +int agp_add_bridge(struct agp_bridge_data *bridge); +void agp_remove_bridge(struct agp_bridge_data *bridge); + +/* Frontend routines. */ +int agp_frontend_initialize(void); +void agp_frontend_cleanup(void); /* Generic routines. */ void agp_generic_enable(u32 mode); @@ -395,10 +386,29 @@ void agp_generic_resume(void); void agp_free_key(int key); int agp_num_entries(void); -int agp_register_driver (struct agp_driver *drv); -int agp_unregister_driver(struct agp_driver *drv); u32 agp_collect_device_status(u32 mode, u32 command); void agp_device_command(u32 command, int agp_v3); -int agp_3_0_node_enable(u32 mode, u32 minor); +int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor); +void global_cache_flush(void); + +/* Standard agp registers */ +#define AGPSTAT 0x4 +#define AGPCMD 0x8 +#define AGPNEPG 0x16 + +#define AGP_MAJOR_VERSION_SHIFT (20) +#define AGP_MINOR_VERSION_SHIFT (16) + +#define AGPSTAT_RQ_DEPTH (0xff000000) + +#define AGPSTAT_ARQSZ_SHIFT 13 + +#define AGPSTAT_AGP_ENABLE (1<<8) +#define AGPSTAT_SBA (1<<9) + +#define AGPSTAT2_1X (1<<0) +#define AGPSTAT2_2X (1<<1) +#define AGPSTAT2_4X (1<<2) +#define AGPSTAT_FW (1<<4) #endif /* _AGP_BACKEND_PRIV_H */ diff -Nru a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c --- a/drivers/char/agp/ali-agp.c Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/ali-agp.c Mon May 12 20:55:47 2003 @@ -19,9 +19,9 @@ pci_read_config_dword(agp_bridge->dev, ALI_ATTBASE, &temp); temp &= ~(0xfffffff0); - values = A_SIZE_32(agp_bridge->aperture_sizes); + values = A_SIZE_32(agp_bridge->driver->aperture_sizes); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -118,47 +118,51 @@ { /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } -static void ali_cache_flush(void) +static void m1541_cache_flush(void) { - global_cache_flush(); + int i, page_count; + u32 temp; - if (agp_bridge->type == ALI_M1541) { - int i, page_count; - u32 temp; + global_cache_flush(); - page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order; - for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { - pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - (agp_bridge->gatt_bus_addr + i)) | - ALI_CACHE_FLUSH_EN)); - } + page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order; + for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) { + pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, + &temp); + pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + (agp_bridge->gatt_bus_addr + i)) | + ALI_CACHE_FLUSH_EN)); } } -static void *ali_alloc_page(void) +static void *m1541_alloc_page(void) { - void *adr = agp_generic_alloc_page(); + void *addr = agp_generic_alloc_page(); u32 temp; - if (adr == 0) - return 0; + if (!addr) + return NULL; + + pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + virt_to_phys(addr)) | ALI_CACHE_FLUSH_EN )); + return addr; +} - if (agp_bridge->type == ALI_M1541) { - pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_phys(adr)) | - ALI_CACHE_FLUSH_EN )); +static void ali_destroy_page(void * addr) +{ + if (addr) { + global_cache_flush(); /* is this really needed? --hch */ + agp_generic_destroy_page(addr); } - return adr; } -static void ali_destroy_page(void * addr) +static void m1541_destroy_page(void * addr) { u32 temp; @@ -167,17 +171,14 @@ global_cache_flush(); - if (agp_bridge->type == ALI_M1541) { - pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); - pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, - (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_phys(addr)) | - ALI_CACHE_FLUSH_EN)); - } - + pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); + pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, + (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | + virt_to_phys(addr)) | ALI_CACHE_FLUSH_EN)); agp_generic_destroy_page(addr); } + /* Setup function */ static struct gatt_mask ali_generic_masks[] = { @@ -195,170 +196,185 @@ {4, 1024, 0, 3} }; -static int __init ali_generic_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = ali_generic_masks; - agp_bridge->aperture_sizes = (void *) ali_generic_sizes; - agp_bridge->size_type = U32_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = ali_configure; - agp_bridge->fetch_size = ali_fetch_size; - agp_bridge->cleanup = ali_cleanup; - agp_bridge->tlb_flush = ali_tlbflush; - agp_bridge->mask_memory = ali_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = ali_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = ali_alloc_page; - agp_bridge->agp_destroy_page = ali_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver ali_generic_bridge = { + .owner = THIS_MODULE, + .masks = ali_generic_masks, + .aperture_sizes = ali_generic_sizes, + .size_type = U32_APER_SIZE, + .num_aperture_sizes = 7, + .configure = ali_configure, + .fetch_size = ali_fetch_size, + .cleanup = ali_cleanup, + .tlb_flush = ali_tlbflush, + .mask_memory = ali_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = ali_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + +struct agp_bridge_driver ali_m1541_bridge = { + .owner = THIS_MODULE, + .masks = ali_generic_masks, + .aperture_sizes = ali_generic_sizes, + .size_type = U32_APER_SIZE, + .num_aperture_sizes = 7, + .configure = ali_configure, + .fetch_size = ali_fetch_size, + .cleanup = ali_cleanup, + .tlb_flush = ali_tlbflush, + .mask_memory = ali_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = m1541_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = m1541_alloc_page, + .agp_destroy_page = m1541_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + struct agp_device_ids ali_agp_device_ids[] __initdata = { { .device_id = PCI_DEVICE_ID_AL_M1541, - .chipset = ALI_M1541, .chipset_name = "M1541", }, { .device_id = PCI_DEVICE_ID_AL_M1621, - .chipset = ALI_M1621, .chipset_name = "M1621", }, { .device_id = PCI_DEVICE_ID_AL_M1631, - .chipset = ALI_M1631, .chipset_name = "M1631", }, { .device_id = PCI_DEVICE_ID_AL_M1632, - .chipset = ALI_M1632, .chipset_name = "M1632", }, { .device_id = PCI_DEVICE_ID_AL_M1641, - .chipset = ALI_M1641, .chipset_name = "M1641", }, { .device_id = PCI_DEVICE_ID_AL_M1644, - .chipset = ALI_M1644, .chipset_name = "M1644", }, { .device_id = PCI_DEVICE_ID_AL_M1647, - .chipset = ALI_M1647, .chipset_name = "M1647", }, { .device_id = PCI_DEVICE_ID_AL_M1651, - .chipset = ALI_M1651, .chipset_name = "M1651", }, { .device_id = PCI_DEVICE_ID_AL_M1671, - .chipset = ALI_M1671, .chipset_name = "M1671", }, { }, /* dummy final entry, always present */ }; -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +static int __init agp_ali_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int j=0; - struct agp_device_ids *devs; - - devs = ali_agp_device_ids; + struct agp_device_ids *devs = ali_agp_device_ids; + struct agp_bridge_data *bridge; + u8 hidden_1621_id, cap_ptr; + int j; - while (devs[j].chipset_name != NULL) { - if (pdev->device == devs[j].device_id) { - if (pdev->device == PCI_DEVICE_ID_AL_M1621) { - u8 hidden_1621_id; - - pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); - switch (hidden_1621_id) { - case 0x31: - devs[j].chipset_name="M1631"; - break; - case 0x32: - devs[j].chipset_name="M1632"; - break; - case 0x41: - devs[j].chipset_name="M1641"; - break; - case 0x43: - break; - case 0x47: - devs[j].chipset_name="M1647"; - break; - case 0x51: - devs[j].chipset_name="M1651"; - break; - default: - break; - } - } - - printk (KERN_INFO PFX "Detected ALi %s chipset\n", - devs[j].chipset_name); - agp_bridge->type = devs[j].chipset; - - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return ali_generic_setup(pdev); - } - j++; + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; + + /* probe for known chipsets */ + for (j = 0; devs[j].chipset_name; j++) { + if (pdev->device == devs[j].device_id) + goto found; } - /* try init anyway, if user requests it */ - if (agp_try_unsupported) { - printk(KERN_WARNING PFX "Trying generic ALi routines" - " for device id: %04x\n", pdev->device); - agp_bridge->type = ALI_GENERIC; - return ali_generic_setup(pdev); + if (!agp_try_unsupported) { + printk(KERN_ERR PFX + "Unsupported ALi chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; } - printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x)," - " you might want to try agp_try_unsupported=1.\n", pdev->device); - return -ENODEV; -} + printk(KERN_WARNING PFX "Trying generic ALi routines" + " for device id: %04x\n", pdev->device); -static struct agp_driver ali_agp_driver = { - .owner = THIS_MODULE, -}; +found: + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + bridge->dev = pdev; + bridge->capndx = cap_ptr; + + switch (pdev->device) { + case PCI_DEVICE_ID_AL_M1541: + bridge->driver = &ali_m1541_bridge; + break; + case PCI_DEVICE_ID_AL_M1621: + pci_read_config_byte(pdev, 0xFB, &hidden_1621_id); + switch (hidden_1621_id) { + case 0x31: + devs[j].chipset_name = "M1631"; + break; + case 0x32: + devs[j].chipset_name = "M1632"; + break; + case 0x41: + devs[j].chipset_name = "M1641"; + break; + case 0x43: + break; + case 0x47: + devs[j].chipset_name = "M1647"; + break; + case 0x51: + devs[j].chipset_name = "M1651"; + break; + default: + break; + } + /*FALLTHROUGH*/ + default: + bridge->driver = &ali_generic_bridge; + } -static int __init agp_ali_probe (struct pci_dev *dev, const struct pci_device_id *ent) -{ - u8 cap_ptr = 0; + printk(KERN_INFO PFX "Detected ALi %s chipset\n", + devs[j].chipset_name); - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); - /* probe for known chipsets */ - if (agp_lookup_host_bridge(dev) != -ENODEV) { - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - ali_agp_driver.dev = dev; - agp_register_driver(&ali_agp_driver); - return 0; - } - return -ENODEV; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} + +static void __devexit agp_ali_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_ali_pci_table[] __initdata = { @@ -379,22 +395,16 @@ .name = "agpgart-ali", .id_table = agp_ali_pci_table, .probe = agp_ali_probe, + .remove = agp_ali_remove, }; static int __init agp_ali_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_ali_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_ali_pci_driver); } static void __exit agp_ali_cleanup(void) { - agp_unregister_driver(&ali_agp_driver); pci_unregister_driver(&agp_ali_pci_driver); } diff -Nru a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c --- a/drivers/char/agp/alpha-agp.c Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/alpha-agp.c Mon May 12 20:55:47 2003 @@ -81,7 +81,7 @@ static unsigned long alpha_core_agp_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } static void alpha_core_agp_enable(u32 mode) @@ -109,7 +109,7 @@ status = agp->ops->bind(agp, pg_start, mem); mb(); - agp_bridge->tlb_flush(mem); + alpha_core_agp_tlbflush(mem); return status; } @@ -121,29 +121,57 @@ int status; status = agp->ops->unbind(agp, pg_start, mem); - agp_bridge->tlb_flush(mem); + alpha_core_agp_tlbflush(mem); return status; } - -static struct agp_driver alpha_core_agp_driver = { - .owner = THIS_MODULE, +struct agp_bridge_driver alpha_core_agp_driver = { + .owner = THIS_MODULE, + .masks = alpha_core_agp_masks, + .aperture_sizes = aper_size, + .current_size = aper_size, /* only one entry */ + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 1, + .configure = alpha_core_agp_configure, + .fetch_size = alpha_core_agp_fetch_size, + .cleanup = alpha_core_agp_cleanup, + .tlb_flush = alpha_core_agp_tlbflush, + .mask_memory = alpha_core_agp_mask_memory, + .agp_enable = alpha_core_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = alpha_core_agp_nop, + .free_gatt_table = alpha_core_agp_nop, + .insert_memory = alpha_core_agp_insert_memory, + .remove_memory = alpha_core_agp_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .mode = agp->capability.lw, + .cant_use_aperture = 1, + .vm_ops = &alpha_core_agp_vm_ops, }; +struct agp_bridge_data *alpha_bridge; + int __init alpha_core_agp_setup(void) { alpha_agp_info *agp = alpha_mv.agp_info(); + struct pci_dev *pdev; /* faked */ struct aper_size_info_fixed *aper_size; - if (!agp) return -ENODEV; - if (agp->ops->setup(agp)) return -ENODEV; + if (!agp) + return -ENODEV; + if (agp->ops->setup(agp)) + return -ENODEV; /* * Build the aperture size descriptor */ aper_size = alpha_core_agp_sizes; - if (!aper_size) return -ENOMEM; + if (!aper_size) + return -ENOMEM; aper_size->size = agp->aperture.size / (1024 * 1024); aper_size->num_entries = agp->aperture.size / PAGE_SIZE; aper_size->page_order = ffs(aper_size->num_entries / 1024) - 1; @@ -151,63 +179,40 @@ /* * Build a fake pci_dev struct */ - if (!(agp_bridge->dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL))) { + pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + if (!pdev) return -ENOMEM; - } - agp_bridge->dev->vendor = 0xffff; - agp_bridge->dev->device = 0xffff; - agp_bridge->dev->sysdata = agp->hose; - - /* - * Fill in the rest of the agp_bridge struct - */ - agp_bridge->masks = alpha_core_agp_masks; - agp_bridge->aperture_sizes = aper_size; - agp_bridge->current_size = aper_size; /* only one entry */ - agp_bridge->size_type = FIXED_APER_SIZE; - agp_bridge->num_aperture_sizes = 1; - agp_bridge->dev_private_data = agp; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = alpha_core_agp_configure; - agp_bridge->fetch_size = alpha_core_agp_fetch_size; - agp_bridge->cleanup = alpha_core_agp_cleanup; - agp_bridge->tlb_flush = alpha_core_agp_tlbflush; - agp_bridge->mask_memory = alpha_core_agp_mask_memory; - agp_bridge->agp_enable = alpha_core_agp_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = alpha_core_agp_nop; - agp_bridge->free_gatt_table = alpha_core_agp_nop; - agp_bridge->insert_memory = alpha_core_agp_insert_memory; - agp_bridge->remove_memory = alpha_core_agp_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->mode = agp->capability.lw; - agp_bridge->cant_use_aperture = 1; - agp_bridge->vm_ops = &alpha_core_agp_vm_ops; + pdev->vendor = 0xffff; + pdev->device = 0xffff; + pdev->sysdata = agp->hose; + + alpha_bridge = agp_alloc_bridge(); + if (!alpha_bridge) + goto fail; + + alpha_bridge->driver = &alpha_core_agp_driver; + alpha_bridge->dev_private_data = agp; + alpha_bridge->dev = pdev; - alpha_core_agp_driver.dev = agp_bridge->dev; - agp_register_driver(&alpha_core_agp_driver); printk(KERN_INFO "Detected AGP on hose %d\n", agp->hose->index); - return 0; + return agp_add_bridge(alpha_bridge); + + fail: + kfree(pdev); + return -ENOMEM; } static int __init agp_alpha_core_init(void) { - int ret_val = -ENODEV; - if (alpha_mv.agp_info) { - agp_bridge->type = ALPHA_CORE_AGP; - ret_val = alpha_core_agp_setup(); - } - - return ret_val; + if (alpha_mv.agp_info) + return alpha_core_agp_setup(); + return -ENODEV; } static void __exit agp_alpha_core_cleanup(void) { - agp_unregister_driver(&alpha_core_agp_driver); - /* no pci driver for core */ + agp_remove_bridge(alpha_bridge); + agp_put_bridge(alpha_bridge); } module_init(agp_alpha_core_init); diff -Nru a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c --- a/drivers/char/agp/amd-k7-agp.c Mon May 12 20:55:49 2003 +++ b/drivers/char/agp/amd-k7-agp.c Mon May 12 20:55:49 2003 @@ -33,7 +33,7 @@ return -ENOMEM; } SetPageReserved(virt_to_page(page_map->real)); - CACHE_FLUSH(); + global_cache_flush(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { @@ -42,7 +42,7 @@ page_map->real = NULL; return -ENOMEM; } - CACHE_FLUSH(); + global_cache_flush(); for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { page_map->remapped[i] = agp_bridge->scratch_page; @@ -75,6 +75,7 @@ } } kfree(tables); + amd_irongate_private.gatt_pages = NULL; } static int amd_create_gatt_pages(int nr_tables) @@ -184,8 +185,8 @@ pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp); temp = (temp & 0x0000000e); - values = A_SIZE_LVL2(agp_bridge->aperture_sizes); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes); + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -274,7 +275,7 @@ { /* Only type 0 is supported by the irongate */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } static int amd_insert_memory(agp_memory * mem, @@ -297,14 +298,13 @@ while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) return -EBUSY; - } j++; } if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); + global_cache_flush(); mem->is_flushed = TRUE; } @@ -312,9 +312,9 @@ addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->mask_memory(mem->memory[i], mem->type); + amd_irongate_mask_memory(mem->memory[i], mem->type); } - agp_bridge->tlb_flush(mem); + amd_irongate_tlbflush(mem); return 0; } @@ -335,7 +335,7 @@ (unsigned long) agp_bridge->scratch_page; } - agp_bridge->tlb_flush(mem); + amd_irongate_tlbflush(mem); return 0; } @@ -355,115 +355,104 @@ {.mask = 0x00000001, .type = 0} }; -static int __init amd_irongate_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = amd_irongate_masks; - agp_bridge->aperture_sizes = (void *) amd_irongate_sizes; - agp_bridge->size_type = LVL2_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = (void *) &amd_irongate_private; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = amd_irongate_configure; - agp_bridge->fetch_size = amd_irongate_fetch_size; - agp_bridge->cleanup = amd_irongate_cleanup; - agp_bridge->tlb_flush = amd_irongate_tlbflush; - agp_bridge->mask_memory = amd_irongate_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = amd_create_gatt_table; - agp_bridge->free_gatt_table = amd_free_gatt_table; - agp_bridge->insert_memory = amd_insert_memory; - agp_bridge->remove_memory = amd_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver amd_irongate_driver = { + .owner = THIS_MODULE, + .masks = amd_irongate_masks, + .aperture_sizes = amd_irongate_sizes, + .size_type = LVL2_APER_SIZE, + .num_aperture_sizes = 7, + .configure = amd_irongate_configure, + .fetch_size = amd_irongate_fetch_size, + .cleanup = amd_irongate_cleanup, + .tlb_flush = amd_irongate_tlbflush, + .mask_memory = amd_irongate_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = amd_create_gatt_table, + .free_gatt_table = amd_free_gatt_table, + .insert_memory = amd_insert_memory, + .remove_memory = amd_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; struct agp_device_ids amd_agp_device_ids[] __initdata = { { .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, - .chipset = AMD_IRONGATE, .chipset_name = "Irongate", }, { .device_id = PCI_DEVICE_ID_AMD_FE_GATE_700E, - .chipset = AMD_761, .chipset_name = "761", }, { .device_id = PCI_DEVICE_ID_AMD_FE_GATE_700C, - .chipset = AMD_762, .chipset_name = "760MP", }, { }, /* dummy final entry, always present */ }; - -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +static int __init agp_amdk7_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int j=0; - struct agp_device_ids *devs; - - devs = amd_agp_device_ids; + struct agp_device_ids *devs = amd_agp_device_ids; + struct agp_bridge_data *bridge; + u8 cap_ptr; + int j; - while (devs[j].chipset_name != NULL) { - if (pdev->device == devs[j].device_id) { - printk (KERN_INFO PFX "Detected AMD %s chipset\n", devs[j].chipset_name); - agp_bridge->type = devs[j].chipset; + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return amd_irongate_setup(pdev); + for (j = 0; devs[j].chipset_name; j++) { + if (pdev->device == devs[j].device_id) { + printk (KERN_INFO PFX "Detected AMD %s chipset\n", + devs[j].chipset_name); + goto found; } - j++; } - /* try init anyway, if user requests it */ - if (agp_try_unsupported) { - printk(KERN_WARNING PFX "Trying generic AMD routines" - " for device id: %04x\n", pdev->device); - agp_bridge->type = AMD_GENERIC; - return amd_irongate_setup(pdev); + if (!agp_try_unsupported) { + printk(KERN_ERR PFX + "Unsupported AMD chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; } - printk(KERN_ERR PFX "Unsupported AMD chipset (device id: %04x)," - " you might want to try agp_try_unsupported=1.\n", pdev->device); - return -ENODEV; -} + printk(KERN_WARNING PFX "Trying generic AMD routines" + " for device id: %04x\n", pdev->device); +found: + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; -static struct agp_driver amd_k7_agp_driver = { - .owner = THIS_MODULE, -}; + bridge->driver = &amd_irongate_driver; + bridge->dev_private_data = &amd_irongate_private, + bridge->dev = pdev; + bridge->capndx = cap_ptr; -/* Supported Device Scanning routine */ + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); -static int __init agp_amdk7_probe (struct pci_dev *dev, const struct pci_device_id *ent) -{ - u8 cap_ptr = 0; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; +static void __devexit agp_amdk7_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - if (agp_lookup_host_bridge(dev) != -ENODEV) { - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - amd_k7_agp_driver.dev = dev; - agp_register_driver(&amd_k7_agp_driver); - return 0; - } - return -ENODEV; + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_amdk7_pci_table[] __initdata = { @@ -484,22 +473,16 @@ .name = "agpgart-amdk7", .id_table = agp_amdk7_pci_table, .probe = agp_amdk7_probe, + .remove = agp_amdk7_remove, }; static int __init agp_amdk7_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_amdk7_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_amdk7_pci_driver); } static void __exit agp_amdk7_cleanup(void) { - agp_unregister_driver(&amd_k7_agp_driver); pci_unregister_driver(&agp_amdk7_pci_driver); } @@ -508,4 +491,3 @@ MODULE_PARM(agp_try_unsupported, "1i"); MODULE_LICENSE("GPL and additional rights"); - diff -Nru a/drivers/char/agp/amd-k8-agp.c b/drivers/char/agp/amd-k8-agp.c --- a/drivers/char/agp/amd-k8-agp.c Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/amd-k8-agp.c Mon May 12 20:55:47 2003 @@ -29,6 +29,21 @@ static int gart_iterator; #define for_each_nb() for(gart_iterator=0;gart_iteratorpage_count)) { - if (!PGE_EMPTY(agp_bridge->gatt_table[j])) + if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) return -EBUSY; j++; } if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); + global_cache_flush(); mem->is_flushed = TRUE; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - addr = agp_bridge->mask_memory(mem->memory[i], mem->type); + addr = agp_bridge->driver->mask_memory(mem->memory[i], mem->type); tmp = addr; BUG_ON(tmp & 0xffffff0000000ffc); @@ -71,7 +86,7 @@ agp_bridge->gatt_table[j] = pte; } - agp_bridge->tlb_flush(mem); + amd_x86_64_tlbflush(mem); return 0; } @@ -113,7 +128,7 @@ temp = (temp & 0xe); values = A_SIZE_32(x86_64_aperture_sizes); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -125,25 +140,6 @@ return 0; } - -static void flush_x86_64_tlb(struct pci_dev *dev) -{ - u32 tmp; - - pci_read_config_dword (dev, AMD_X86_64_GARTCACHECTL, &tmp); - tmp |= 1<<0; - pci_write_config_dword (dev, AMD_X86_64_GARTCACHECTL, tmp); -} - - -static void amd_x86_64_tlbflush(agp_memory * temp) -{ - for_each_nb() { - flush_x86_64_tlb (hammers[gart_iterator]); - } -} - - /* * In a multiprocessor x86-64 system, this function gets * called once for each CPU. @@ -218,7 +214,7 @@ static unsigned long amd_8151_mask_memory(unsigned long addr, int type) { - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } @@ -227,130 +223,84 @@ {.mask = 0x00000001, .type = 0} }; +struct agp_bridge_driver amd_8151_driver = { + .owner = THIS_MODULE, + .masks = amd_8151_masks, + .aperture_sizes = amd_8151_sizes, + .size_type = U32_APER_SIZE, + .num_aperture_sizes = 7, + .configure = amd_8151_configure, + .fetch_size = amd_x86_64_fetch_size, + .cleanup = amd_8151_cleanup, + .tlb_flush = amd_x86_64_tlbflush, + .mask_memory = amd_8151_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = x86_64_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -/* - * Try to configure an AGP v3 capable setup. - * If we fail (typically because we don't have an AGP v3 - * card in the system) we fall back to the generic AGP v2 - * routines. - */ -static void agp_x86_64_agp_enable(u32 mode) +static int __init agp_amdk8_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct pci_dev *device = NULL; - u32 command, scratch; + struct agp_bridge_data *bridge; + struct pci_dev *loop_dev; u8 cap_ptr; - u8 v3_devs=0; - - /* FIXME: If 'mode' is x1/x2/x4 should we call the AGPv2 routines directly ? - * Messy, as some AGPv3 cards can only do x4 as a minimum. - */ - - /* PASS1: Count # of devs capable of AGPv3 mode. */ - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - pci_read_config_dword(device, cap_ptr, &scratch); - scratch &= (1<<20|1<<21|1<<22|1<<23); - scratch = scratch>>20; - /* AGP v3 capable ? */ - if (scratch>=3) { - v3_devs++; - printk (KERN_INFO "AGP: Found AGPv3 capable device at %d:%d:%d\n", - device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn)); - } else { - printk (KERN_INFO "AGP: Meh. version %x AGP device found.\n", scratch); - } - } - } - /* If not enough, go to AGP v2 setup */ - if (v3_devs<2) { - printk (KERN_INFO "AGP: Only %d devices found, not enough, trying AGPv2\n", v3_devs); - return agp_generic_enable(mode); - } else { - printk (KERN_INFO "AGP: Enough AGPv3 devices found, setting up...\n"); - } - - - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &command); - - command = agp_collect_device_status(mode, command); - command |= 0x100; - - pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_COMMAND, command); - - agp_device_command(command, 1); -} + int i = 0; + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; -static int __init amd_8151_setup (struct pci_dev *pdev) -{ - struct pci_dev *dev; - int i=0; + printk(KERN_INFO PFX "Detected Opteron/Athlon64 on-CPU GART\n"); - agp_bridge->masks = amd_8151_masks; - agp_bridge->aperture_sizes = (void *) amd_8151_sizes; - agp_bridge->size_type = U32_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = amd_8151_configure; - agp_bridge->fetch_size = amd_x86_64_fetch_size; - agp_bridge->cleanup = amd_8151_cleanup; - agp_bridge->tlb_flush = amd_x86_64_tlbflush; - agp_bridge->mask_memory = amd_8151_mask_memory; - agp_bridge->agp_enable = agp_x86_64_agp_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = x86_64_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + bridge->driver = &amd_8151_driver; + bridge->dev = pdev; + bridge->capndx = cap_ptr; + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); /* cache pci_devs of northbridges. */ - pci_for_each_dev(dev) { - if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 && - (PCI_SLOT(dev->devfn) >=24) && (PCI_SLOT(dev->devfn) <=31)) { - - hammers[i++] = dev; + pci_for_each_dev(loop_dev) { + if (loop_dev->bus->number == 0 && + PCI_FUNC(loop_dev->devfn) == 3 && + PCI_SLOT(loop_dev->devfn) >=24 && + PCI_SLOT(loop_dev->devfn) <=31) { + hammers[i++] = loop_dev; nr_garts = i; - if (i==MAX_HAMMER_GARTS) - return 0; + if (i == MAX_HAMMER_GARTS) + goto out_free; } } - return 0; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); + out_free: + agp_put_bridge(bridge); + return -ENOMEM; } -static struct agp_driver amd_k8_agp_driver = { - .owner = THIS_MODULE, -}; - -static int __init agp_amdk8_probe (struct pci_dev *dev, const struct pci_device_id *ent) +static void __devexit agp_amdk8_remove(struct pci_dev *pdev) { - u8 cap_ptr = 0; - - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - printk (KERN_INFO PFX "Detected Opteron/Athlon64 on-CPU GART\n"); - - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - amd_8151_setup(dev); - amd_k8_agp_driver.dev = dev; - agp_register_driver(&amd_k8_agp_driver); - return 0; + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_amdk8_pci_table[] __initdata = { @@ -371,25 +321,17 @@ .name = "agpgart-amd-k8", .id_table = agp_amdk8_pci_table, .probe = agp_amdk8_probe, + .remove = agp_amdk8_remove, }; /* Not static due to IOMMU code calling it early. */ int __init agp_amdk8_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_amdk8_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - agp_bridge->type = AMD_8151; - - return ret_val; + return pci_module_init(&agp_amdk8_pci_driver); } static void __exit agp_amdk8_cleanup(void) { - agp_unregister_driver(&amd_k8_agp_driver); pci_unregister_driver(&agp_amdk8_pci_driver); } diff -Nru a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c --- a/drivers/char/agp/backend.c Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/backend.c Mon May 12 20:55:47 2003 @@ -43,37 +43,54 @@ * past 0.99 at all due to some boolean logic error. */ #define AGPGART_VERSION_MAJOR 0 #define AGPGART_VERSION_MINOR 100 +static struct agp_version agp_current_version = +{ + .major = AGPGART_VERSION_MAJOR, + .minor = AGPGART_VERSION_MINOR, +}; + +static int agp_count=0; struct agp_bridge_data agp_bridge_dummy = { .type = NOT_SUPPORTED }; struct agp_bridge_data *agp_bridge = &agp_bridge_dummy; +EXPORT_SYMBOL(agp_bridge); + +/** + * agp_backend_acquire - attempt to acquire the agp backend. + * + * returns -EBUSY if agp is in use, + * returns 0 if the caller owns the agp backend + */ int agp_backend_acquire(void) { if (agp_bridge->type == NOT_SUPPORTED) return -EINVAL; - - if (atomic_read(&agp_bridge->agp_in_use) != 0) + if (atomic_read(&agp_bridge->agp_in_use)) return -EBUSY; - atomic_inc(&agp_bridge->agp_in_use); return 0; } +EXPORT_SYMBOL(agp_backend_acquire); + +/** + * agp_backend_release - release the lock on the agp backend. + * + * The caller must insure that the graphics aperture translation table + * is read for use by another entity. + * + * (Ensure that all memory it bound is unbound.) + */ void agp_backend_release(void) { - if (agp_bridge->type == NOT_SUPPORTED) - return; - - atomic_dec(&agp_bridge->agp_in_use); + if (agp_bridge->type != NOT_SUPPORTED) + atomic_dec(&agp_bridge->agp_in_use); } +EXPORT_SYMBOL(agp_backend_release); -struct agp_max_table { - int mem; - int agp; -}; -static struct agp_max_table maxes_table[9] = -{ +struct { int mem, agp; } maxes_table[] = { {0, 0}, {32, 4}, {64, 28}, @@ -85,7 +102,7 @@ {4096, 3932} }; -static int agp_find_max (void) +static int agp_find_max(void) { long memory, index, result; @@ -105,48 +122,43 @@ return result; } -static struct agp_version agp_current_version = -{ - .major = AGPGART_VERSION_MAJOR, - .minor = AGPGART_VERSION_MINOR, -}; -static int agp_backend_initialize(struct pci_dev *dev) +static int agp_backend_initialize(struct agp_bridge_data *bridge) { int size_value, rc, got_gatt=0, got_keylist=0; - agp_bridge->max_memory_agp = agp_find_max(); - agp_bridge->version = &agp_current_version; + bridge->max_memory_agp = agp_find_max(); + bridge->version = &agp_current_version; - if (agp_bridge->needs_scratch_page == TRUE) { - void *addr; - addr = agp_bridge->agp_alloc_page(); + if (bridge->driver->needs_scratch_page) { + void *addr = bridge->driver->agp_alloc_page(); - if (addr == NULL) { + if (!addr) { printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); return -ENOMEM; } - agp_bridge->scratch_page_real = virt_to_phys(addr); - agp_bridge->scratch_page = - agp_bridge->mask_memory(agp_bridge->scratch_page_real, 0); - } - size_value = agp_bridge->fetch_size(); + bridge->scratch_page_real = virt_to_phys(addr); + bridge->scratch_page = + bridge->driver->mask_memory(bridge->scratch_page_real, 0); + } + size_value = bridge->driver->fetch_size(); if (size_value == 0) { printk(KERN_ERR PFX "unable to determine aperture size.\n"); rc = -EINVAL; goto err_out; } - if (agp_bridge->create_gatt_table()) { - printk(KERN_ERR PFX "unable to get memory for graphics translation table.\n"); + if (bridge->driver->create_gatt_table()) { + printk(KERN_ERR PFX + "unable to get memory for graphics translation table.\n"); rc = -ENOMEM; goto err_out; } got_gatt = 1; - agp_bridge->key_list = vmalloc(PAGE_SIZE * 4); - if (agp_bridge->key_list == NULL) { + bridge->key_list = vmalloc(PAGE_SIZE * 4); + if (bridge->key_list == NULL) { printk(KERN_ERR PFX "error allocating memory for key lists.\n"); rc = -ENOMEM; goto err_out; @@ -154,61 +166,62 @@ got_keylist = 1; /* FIXME vmalloc'd memory not guaranteed contiguous */ - memset(agp_bridge->key_list, 0, PAGE_SIZE * 4); + memset(bridge->key_list, 0, PAGE_SIZE * 4); - if (agp_bridge->configure()) { + if (bridge->driver->configure()) { printk(KERN_ERR PFX "error configuring host chipset.\n"); rc = -EINVAL; goto err_out; } printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", - size_value, agp_bridge->gart_bus_addr); + size_value, bridge->gart_bus_addr); return 0; err_out: - if (agp_bridge->needs_scratch_page == TRUE) { - agp_bridge->agp_destroy_page(phys_to_virt(agp_bridge->scratch_page_real)); - } + if (bridge->driver->needs_scratch_page) + bridge->driver->agp_destroy_page( + phys_to_virt(bridge->scratch_page_real)); if (got_gatt) - agp_bridge->free_gatt_table(); - if (got_keylist) - vfree(agp_bridge->key_list); + bridge->driver->free_gatt_table(); + if (got_keylist) { + vfree(bridge->key_list); + bridge->key_list = NULL; + } return rc; } - /* cannot be __exit b/c as it could be called from __init code */ -static void agp_backend_cleanup(void) +static void agp_backend_cleanup(struct agp_bridge_data *bridge) { - if (agp_bridge->cleanup != NULL) - agp_bridge->cleanup(); - if (agp_bridge->free_gatt_table != NULL) - agp_bridge->free_gatt_table(); - if (agp_bridge->key_list) - vfree(agp_bridge->key_list); - - if ((agp_bridge->agp_destroy_page!=NULL) && - (agp_bridge->needs_scratch_page == TRUE)) - agp_bridge->agp_destroy_page(phys_to_virt(agp_bridge->scratch_page_real)); + if (bridge->driver->cleanup) + bridge->driver->cleanup(); + if (bridge->driver->free_gatt_table) + bridge->driver->free_gatt_table(); + if (bridge->key_list) { + vfree(bridge->key_list); + bridge->key_list = NULL; + } + + if (bridge->driver->agp_destroy_page && + bridge->driver->needs_scratch_page) + bridge->driver->agp_destroy_page( + phys_to_virt(bridge->scratch_page_real)); } static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data) { - switch(rq) - { + switch(rq) { case PM_SUSPEND: - return agp_bridge->suspend(); + return agp_bridge->driver->suspend(); case PM_RESUME: - agp_bridge->resume(); + agp_bridge->driver->resume(); return 0; } return 0; } -extern int agp_frontend_initialize(void); -extern void agp_frontend_cleanup(void); static const drm_agp_t drm_agp = { &agp_free_memory, @@ -221,78 +234,81 @@ &agp_copy_info }; -static int agp_count=0; +/* XXX Kludge alert: agpgart isn't ready for multiple bridges yet */ +struct agp_bridge_data *agp_alloc_bridge(void) +{ + return agp_bridge; +} +EXPORT_SYMBOL(agp_alloc_bridge); + + +void agp_put_bridge(struct agp_bridge_data *bridge) +{ +} +EXPORT_SYMBOL(agp_put_bridge); -int agp_register_driver (struct agp_driver *drv) + +int agp_add_bridge(struct agp_bridge_data *bridge) { - int ret_val; + int error; - if (drv->dev == NULL) { - printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n"); + if (!bridge->dev) { + printk(KERN_DEBUG PFX "Erk, registering with no pci_dev!\n"); return -EINVAL; } - if (agp_count==1) { - printk (KERN_DEBUG PFX "Only one agpgart device currently supported.\n"); + if (agp_count) { + printk(KERN_DEBUG PFX + "Only one agpgart device currently supported.\n"); return -ENODEV; } /* Grab reference on the chipset driver. */ - if (!try_module_get(drv->owner)) + if (!try_module_get(bridge->driver->owner)) return -EINVAL; - ret_val = agp_backend_initialize(drv->dev); - if (ret_val) + bridge->type = SUPPORTED; + + error = agp_backend_initialize(agp_bridge); + if (error) goto err_out; - ret_val = agp_frontend_initialize(); - if (ret_val) + error = agp_frontend_initialize(); + if (error) goto frontend_err; /* FIXME: What to do with this? */ inter_module_register("drm_agp", THIS_MODULE, &drm_agp); - pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge->dev), agp_power); + pm_register(PM_PCI_DEV, PM_PCI_ID(bridge->dev), agp_power); agp_count++; return 0; frontend_err: - agp_backend_cleanup(); + agp_backend_cleanup(agp_bridge); err_out: - agp_bridge->type = NOT_SUPPORTED; - module_put(drv->owner); - drv->dev = NULL; - return ret_val; + bridge->type = NOT_SUPPORTED; + module_put(bridge->driver->owner); + return error; } +EXPORT_SYMBOL_GPL(agp_add_bridge); -int agp_unregister_driver(struct agp_driver *drv) -{ - if (drv->dev==NULL) - return -ENODEV; - agp_bridge->type = NOT_SUPPORTED; +void agp_remove_bridge(struct agp_bridge_data *bridge) +{ + bridge->type = NOT_SUPPORTED; pm_unregister_all(agp_power); agp_frontend_cleanup(); - agp_backend_cleanup(); + agp_backend_cleanup(bridge); inter_module_unregister("drm_agp"); agp_count--; - module_put(drv->owner); - return 0; + module_put(bridge->driver->owner); } +EXPORT_SYMBOL_GPL(agp_remove_bridge); -int __init agp_init(void) +static int __init agp_init(void) { - static int already_initialised=0; - - if (already_initialised!=0) - return 0; - - already_initialised = 1; - - memset(agp_bridge, 0, sizeof(struct agp_bridge_data)); - agp_bridge->type = NOT_SUPPORTED; - printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Dave Jones\n", AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); return 0; @@ -300,19 +316,13 @@ void __exit agp_exit(void) { - if (agp_count!=0) - BUG(); } -#ifndef CONFIG_GART_IOMMU -module_init(agp_init); -module_exit(agp_exit); -#endif - -EXPORT_SYMBOL(agp_backend_acquire); -EXPORT_SYMBOL(agp_backend_release); -EXPORT_SYMBOL_GPL(agp_register_driver); -EXPORT_SYMBOL_GPL(agp_unregister_driver); MODULE_AUTHOR("Dave Jones "); +MODULE_DESCRIPTION("AGP GART driver"); MODULE_LICENSE("GPL and additional rights"); + +module_init(agp_init); +module_exit(agp_exit); + diff -Nru a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c --- a/drivers/char/agp/frontend.c Mon May 12 20:55:44 2003 +++ b/drivers/char/agp/frontend.c Mon May 12 20:55:44 2003 @@ -53,11 +53,12 @@ while (curr != NULL) { if (curr->key == key) - return curr; + break; curr = curr->next; } - return NULL; + DBG("key=%d -> mem=%p", key, curr); + return curr; } static void agp_remove_from_pool(agp_memory * temp) @@ -67,6 +68,7 @@ /* Check to see if this is even in the memory pool */ + DBG("mem=%p", temp); if (agp_find_mem_by_key(temp->key) != NULL) { next = temp->next; prev = temp->prev; @@ -92,11 +94,12 @@ * to each auth'ed client. */ -static agp_segment_priv *agp_find_seg_in_client(const agp_client * client, +static struct +agp_segment_priv *agp_find_seg_in_client(const struct agp_client *client, unsigned long offset, int size, pgprot_t page_prot) { - agp_segment_priv *seg; + struct agp_segment_priv *seg; int num_segments, i; off_t pg_start; size_t pg_count; @@ -117,25 +120,32 @@ return NULL; } -static void agp_remove_seg_from_client(agp_client * client) +static void agp_remove_seg_from_client(struct agp_client *client) { + DBG("client=%p", client); + if (client->segments != NULL) { - if (*(client->segments) != NULL) + if (*(client->segments) != NULL) { + DBG("Freeing %p from client %p", *(client->segments), client); kfree(*(client->segments)); + } + DBG("Freeing %p from client %p", client->segments, client); kfree(client->segments); + client->segments = NULL; } } -static void agp_add_seg_to_client(agp_client * client, - agp_segment_priv ** seg, int num_segments) +static void agp_add_seg_to_client(struct agp_client *client, + struct agp_segment_priv ** seg, int num_segments) { - agp_segment_priv **prev_seg; + struct agp_segment_priv **prev_seg; prev_seg = client->segments; if (prev_seg != NULL) agp_remove_seg_from_client(client); + DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client); client->num_segments = num_segments; client->segments = seg; } @@ -171,19 +181,20 @@ return temp; } -static int agp_create_segment(agp_client * client, agp_region * region) +static int agp_create_segment(struct agp_client *client, struct agp_region *region) { - agp_segment_priv **ret_seg; - agp_segment_priv *seg; - agp_segment *user_seg; + struct agp_segment_priv **ret_seg; + struct agp_segment_priv *seg; + struct agp_segment *user_seg; size_t i; - seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count), GFP_KERNEL); + seg = kmalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); if (seg == NULL) { kfree(region->seg_list); + region->seg_list = NULL; return -ENOMEM; } - memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count)); + memset(seg, 0, (sizeof(struct agp_segment_priv) * region->seg_count)); user_seg = region->seg_list; for (i = 0; i < region->seg_count; i++) { @@ -191,14 +202,15 @@ seg[i].pg_count = user_seg[i].pg_count; seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); } + kfree(region->seg_list); + region->seg_list = NULL; + ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); if (ret_seg == NULL) { - kfree(region->seg_list); kfree(seg); return -ENOMEM; } *ret_seg = seg; - kfree(region->seg_list); agp_add_seg_to_client(client, ret_seg, region->seg_count); return 0; } @@ -222,9 +234,9 @@ /* File private list routines */ -agp_file_private *agp_find_private(pid_t pid) +struct agp_file_private *agp_find_private(pid_t pid) { - agp_file_private *curr; + struct agp_file_private *curr; curr = agp_fe.file_priv_list; @@ -237,9 +249,9 @@ return NULL; } -void agp_insert_file_private(agp_file_private * priv) +void agp_insert_file_private(struct agp_file_private * priv) { - agp_file_private *prev; + struct agp_file_private *prev; prev = agp_fe.file_priv_list; @@ -249,10 +261,10 @@ agp_fe.file_priv_list = priv; } -void agp_remove_file_private(agp_file_private * priv) +void agp_remove_file_private(struct agp_file_private * priv) { - agp_file_private *next; - agp_file_private *prev; + struct agp_file_private *next; + struct agp_file_private *prev; next = priv->next; prev = priv->prev; @@ -301,9 +313,9 @@ * controllers */ -static agp_controller *agp_find_controller_by_pid(pid_t id) +static struct agp_controller *agp_find_controller_by_pid(pid_t id) { - agp_controller *controller; + struct agp_controller *controller; controller = agp_fe.controllers; @@ -316,24 +328,24 @@ return NULL; } -static agp_controller *agp_create_controller(pid_t id) +static struct agp_controller *agp_create_controller(pid_t id) { - agp_controller *controller; + struct agp_controller *controller; - controller = kmalloc(sizeof(agp_controller), GFP_KERNEL); + controller = kmalloc(sizeof(struct agp_controller), GFP_KERNEL); if (controller == NULL) return NULL; - memset(controller, 0, sizeof(agp_controller)); + memset(controller, 0, sizeof(struct agp_controller)); controller->pid = id; return controller; } -static int agp_insert_controller(agp_controller * controller) +static int agp_insert_controller(struct agp_controller *controller) { - agp_controller *prev_controller; + struct agp_controller *prev_controller; prev_controller = agp_fe.controllers; controller->next = prev_controller; @@ -346,15 +358,15 @@ return 0; } -static void agp_remove_all_clients(agp_controller * controller) +static void agp_remove_all_clients(struct agp_controller *controller) { - agp_client *client; - agp_client *temp; + struct agp_client *client; + struct agp_client *temp; client = controller->clients; while (client) { - agp_file_private *priv; + struct agp_file_private *priv; temp = client; agp_remove_seg_from_client(temp); @@ -369,7 +381,7 @@ } } -static void agp_remove_all_memory(agp_controller * controller) +static void agp_remove_all_memory(struct agp_controller *controller) { agp_memory *memory; agp_memory *temp; @@ -383,10 +395,10 @@ } } -static int agp_remove_controller(agp_controller * controller) +static int agp_remove_controller(struct agp_controller *controller) { - agp_controller *prev_controller; - agp_controller *next_controller; + struct agp_controller *prev_controller; + struct agp_controller *next_controller; prev_controller = controller->prev; next_controller = controller->next; @@ -415,14 +427,14 @@ return 0; } -static void agp_controller_make_current(agp_controller * controller) +static void agp_controller_make_current(struct agp_controller *controller) { - agp_client *clients; + struct agp_client *clients; clients = controller->clients; while (clients != NULL) { - agp_file_private *priv; + struct agp_file_private *priv; priv = agp_find_private(clients->pid); @@ -436,16 +448,16 @@ agp_fe.current_controller = controller; } -static void agp_controller_release_current(agp_controller * controller, - agp_file_private * controller_priv) +static void agp_controller_release_current(struct agp_controller *controller, + struct agp_file_private *controller_priv) { - agp_client *clients; + struct agp_client *clients; clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); clients = controller->clients; while (clients != NULL) { - agp_file_private *priv; + struct agp_file_private *priv; priv = agp_find_private(clients->pid); @@ -465,10 +477,10 @@ * These routines are for managing the list of auth'ed clients. */ -static agp_client *agp_find_client_in_controller(agp_controller * controller, - pid_t id) +static struct agp_client +*agp_find_client_in_controller(struct agp_controller *controller, pid_t id) { - agp_client *client; + struct agp_client *client; if (controller == NULL) return NULL; @@ -484,9 +496,9 @@ return NULL; } -static agp_controller *agp_find_controller_for_client(pid_t id) +static struct agp_controller *agp_find_controller_for_client(pid_t id) { - agp_controller *controller; + struct agp_controller *controller; controller = agp_fe.controllers; @@ -499,9 +511,9 @@ return NULL; } -static agp_client *agp_find_client_by_pid(pid_t id) +static struct agp_client *agp_find_client_by_pid(pid_t id) { - agp_client *temp; + struct agp_client *temp; if (agp_fe.current_controller == NULL) return NULL; @@ -510,9 +522,9 @@ return temp; } -static void agp_insert_client(agp_client * client) +static void agp_insert_client(struct agp_client *client) { - agp_client *prev_client; + struct agp_client *prev_client; prev_client = agp_fe.current_controller->clients; client->next = prev_client; @@ -524,16 +536,16 @@ agp_fe.current_controller->num_clients++; } -static agp_client *agp_create_client(pid_t id) +static struct agp_client *agp_create_client(pid_t id) { - agp_client *new_client; + struct agp_client *new_client; - new_client = kmalloc(sizeof(agp_client), GFP_KERNEL); + new_client = kmalloc(sizeof(struct agp_client), GFP_KERNEL); if (new_client == NULL) return NULL; - memset(new_client, 0, sizeof(agp_client)); + memset(new_client, 0, sizeof(struct agp_client)); new_client->pid = id; agp_insert_client(new_client); return new_client; @@ -541,10 +553,10 @@ static int agp_remove_client(pid_t id) { - agp_client *client; - agp_client *prev_client; - agp_client *next_client; - agp_controller *controller; + struct agp_client *client; + struct agp_client *prev_client; + struct agp_client *next_client; + struct agp_controller *controller; controller = agp_find_controller_for_client(id); if (controller == NULL) @@ -582,11 +594,11 @@ { unsigned int size, current_size; unsigned long offset; - agp_client *client; - agp_file_private *priv = (agp_file_private *) file->private_data; + struct agp_client *client; + struct agp_file_private *priv = file->private_data; agp_kern_info kerninfo; - AGP_LOCK(); + down(&(agp_fe.agp_mutex)); if (agp_fe.backend_acquired != TRUE) goto out_eperm; @@ -599,6 +611,7 @@ current_size = kerninfo.aper_size; current_size = current_size * 0x100000; offset = vma->vm_pgoff << PAGE_SHIFT; + DBG("%lx:%lx", offset, offset+size); if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { if ((size + offset) > current_size) @@ -612,6 +625,7 @@ if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot)) goto out_inval; + DBG("client vm_ops=%p", kerninfo.vm_ops); if (kerninfo.vm_ops) { vma->vm_ops = kerninfo.vm_ops; } else if (remap_page_range(vma, vma->vm_start, @@ -619,7 +633,7 @@ size, vma->vm_page_prot)) { goto out_again; } - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return 0; } @@ -627,6 +641,7 @@ if (size != current_size) goto out_inval; + DBG("controller vm_ops=%p", kerninfo.vm_ops); if (kerninfo.vm_ops) { vma->vm_ops = kerninfo.vm_ops; } else if (remap_page_range(vma, vma->vm_start, @@ -634,68 +649,71 @@ size, vma->vm_page_prot)) { goto out_again; } - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return 0; } out_eperm: - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return -EPERM; out_inval: - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return -EINVAL; out_again: - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return -EAGAIN; } static int agp_release(struct inode *inode, struct file *file) { - agp_file_private *priv = (agp_file_private *) file->private_data; + struct agp_file_private *priv = file->private_data; - AGP_LOCK(); + down(&(agp_fe.agp_mutex)); + + DBG("priv=%p", priv); if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { - agp_controller *controller; + struct agp_controller *controller; controller = agp_find_controller_by_pid(priv->my_pid); if (controller != NULL) { - if (controller == agp_fe.current_controller) { - agp_controller_release_current(controller, - priv); - } + if (controller == agp_fe.current_controller) + agp_controller_release_current(controller, priv); agp_remove_controller(controller); + controller = NULL; } } - if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { + + if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) agp_remove_client(priv->my_pid); - } + agp_remove_file_private(priv); kfree(priv); - AGP_UNLOCK(); + file->private_data = NULL; + up(&(agp_fe.agp_mutex)); return 0; } static int agp_open(struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - agp_file_private *priv; - agp_client *client; + struct agp_file_private *priv; + struct agp_client *client; int rc = -ENXIO; - AGP_LOCK(); + down(&(agp_fe.agp_mutex)); if (minor != AGPGART_MINOR) goto err_out; - priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + priv = kmalloc(sizeof(struct agp_file_private), GFP_KERNEL); if (priv == NULL) goto err_out_nomem; - memset(priv, 0, sizeof(agp_file_private)); + memset(priv, 0, sizeof(struct agp_file_private)); set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; @@ -711,13 +729,14 @@ } file->private_data = (void *) priv; agp_insert_file_private(priv); - AGP_UNLOCK(); + DBG("private=%p, client=%p", priv, client); + up(&(agp_fe.agp_mutex)); return 0; err_out_nomem: rc = -ENOMEM; err_out: - AGP_UNLOCK(); + up(&(agp_fe.agp_mutex)); return rc; } @@ -734,9 +753,9 @@ return -EINVAL; } -static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_info_wrap(struct agp_file_private *priv, unsigned long arg) { - agp_info userinfo; + struct agp_info userinfo; agp_kern_info kerninfo; agp_copy_info(&kerninfo); @@ -751,17 +770,19 @@ userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; userinfo.pg_used = kerninfo.current_memory; - if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info))) + if (copy_to_user((void *) arg, &userinfo, sizeof(struct agp_info))) return -EFAULT; return 0; } -static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_acquire_wrap(struct agp_file_private *priv, unsigned long arg) { int ret; + struct agp_controller *controller; + + DBG(""); - agp_controller *controller; if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) return -EPERM; @@ -795,33 +816,36 @@ return 0; } -static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_release_wrap(struct agp_file_private *priv, unsigned long arg) { + DBG(""); agp_controller_release_current(agp_fe.current_controller, priv); return 0; } -static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_setup_wrap(struct agp_file_private *priv, unsigned long arg) { - agp_setup mode; + struct agp_setup mode; - if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) { + DBG(""); + if (copy_from_user(&mode, (void *) arg, sizeof(struct agp_setup))) return -EFAULT; - } + agp_enable(mode.agp_mode); return 0; } -static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_reserve_wrap(struct agp_file_private *priv, unsigned long arg) { - agp_region reserve; - agp_client *client; - agp_file_private *client_priv; + struct agp_region reserve; + struct agp_client *client; + struct agp_file_private *client_priv; - if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) + DBG(""); + if (copy_from_user(&reserve, (void *) arg, sizeof(struct agp_region))) return -EFAULT; - if ((unsigned) reserve.seg_count >= ~0U/sizeof(agp_segment)) + if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) return -EFAULT; client = agp_find_client_by_pid(reserve.pid); @@ -831,10 +855,8 @@ client_priv = agp_find_private(reserve.pid); if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, - &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, - &client_priv->access_flags); + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); } if (client == NULL) { /* client is already removed */ @@ -842,19 +864,19 @@ } return agp_remove_client(reserve.pid); } else { - agp_segment *segment; + struct agp_segment *segment; if (reserve.seg_count >= 16384) return -EINVAL; - - segment = kmalloc((sizeof(agp_segment) * reserve.seg_count), + + segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count), GFP_KERNEL); if (segment == NULL) return -ENOMEM; if (copy_from_user(segment, (void *) reserve.seg_list, - sizeof(agp_segment) * reserve.seg_count)) { + sizeof(struct agp_segment) * reserve.seg_count)) { kfree(segment); return -EFAULT; } @@ -871,32 +893,30 @@ client_priv = agp_find_private(reserve.pid); if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, - &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, - &client_priv->access_flags); + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); } - return agp_create_segment(client, &reserve); - } else { - return agp_create_segment(client, &reserve); } + return agp_create_segment(client, &reserve); } /* Will never really happen */ return -EINVAL; } -static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_protect_wrap(struct agp_file_private *priv, unsigned long arg) { + DBG(""); /* This function is not currently implemented */ return -EINVAL; } -static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_allocate_wrap(struct agp_file_private *priv, unsigned long arg) { agp_memory *memory; - agp_allocate alloc; + struct agp_allocate alloc; - if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate))) + DBG(""); + if (copy_from_user(&alloc, (void *) arg, sizeof(struct agp_allocate))) return -EFAULT; memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); @@ -907,17 +927,18 @@ alloc.key = memory->key; alloc.physical = memory->physical; - if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) { + if (copy_to_user((void *) arg, &alloc, sizeof(struct agp_allocate))) { agp_free_memory_wrap(memory); return -EFAULT; } return 0; } -static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_deallocate_wrap(struct agp_file_private *priv, unsigned long arg) { agp_memory *memory; + DBG(""); memory = agp_find_mem_by_key((int) arg); if (memory == NULL) @@ -927,12 +948,13 @@ return 0; } -static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_bind_wrap(struct agp_file_private *priv, unsigned long arg) { - agp_bind bind_info; + struct agp_bind bind_info; agp_memory *memory; - if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind))) + DBG(""); + if (copy_from_user(&bind_info, (void *) arg, sizeof(struct agp_bind))) return -EFAULT; memory = agp_find_mem_by_key(bind_info.key); @@ -943,12 +965,13 @@ return agp_bind_memory(memory, bind_info.pg_start); } -static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg) +static int agpioc_unbind_wrap(struct agp_file_private *priv, unsigned long arg) { agp_memory *memory; - agp_unbind unbind; + struct agp_unbind unbind; - if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind))) + DBG(""); + if (copy_from_user(&unbind, (void *) arg, sizeof(struct agp_unbind))) return -EFAULT; memory = agp_find_mem_by_key(unbind.key); @@ -962,10 +985,11 @@ static int agp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - agp_file_private *curr_priv = (agp_file_private *) file->private_data; + struct agp_file_private *curr_priv = file->private_data; int ret_val = -ENOTTY; - AGP_LOCK(); + DBG("priv=%p, cmd=%x", curr_priv, cmd); + down(&(agp_fe.agp_mutex)); if ((agp_fe.current_controller == NULL) && (cmd != AGPIOC_ACQUIRE)) { @@ -1034,7 +1058,8 @@ } ioctl_out: - AGP_UNLOCK(); + DBG("ioctl returns %d\n", ret_val); + up(&(agp_fe.agp_mutex)); return ret_val; } @@ -1060,7 +1085,7 @@ int agp_frontend_initialize(void) { memset(&agp_fe, 0, sizeof(struct agp_front_data)); - AGP_LOCK_INIT(); + sema_init(&(agp_fe.agp_mutex), 1); if (misc_register(&agp_miscdev)) { printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); diff -Nru a/drivers/char/agp/generic-3.0.c b/drivers/char/agp/generic-3.0.c --- a/drivers/char/agp/generic-3.0.c Mon May 12 20:55:45 2003 +++ b/drivers/char/agp/generic-3.0.c Mon May 12 20:55:45 2003 @@ -18,7 +18,7 @@ struct pci_dev *dev; }; -static int agp_3_0_dev_list_insert(struct list_head *head, struct list_head *new) +static void agp_3_0_dev_list_insert(struct list_head *head, struct list_head *new) { struct agp_3_0_dev *cur, *n = list_entry(new, struct agp_3_0_dev, list); struct list_head *pos; @@ -29,11 +29,9 @@ break; } list_add_tail(new, pos); - - return 0; } -static int agp_3_0_dev_list_sort(struct agp_3_0_dev *list, unsigned int ndevs) +static void agp_3_0_dev_list_sort(struct agp_3_0_dev *list, unsigned int ndevs) { struct agp_3_0_dev *cur; struct pci_dev *dev; @@ -53,7 +51,6 @@ pos = pos->next; agp_3_0_dev_list_insert(head, tmp); } - return 0; } /* @@ -62,7 +59,8 @@ * lying behind it...) */ -static int agp_3_0_isochronous_node_enable(struct agp_3_0_dev *dev_list, unsigned int ndevs) +static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge, + struct agp_3_0_dev *dev_list, unsigned int ndevs) { /* * Convenience structure to make the calculations clearer @@ -77,7 +75,7 @@ struct agp_3_0_dev *dev; }; - struct pci_dev *td = agp_bridge->dev, *dev; + struct pci_dev *td = bridge->dev, *dev; struct list_head *head = &dev_list->list, *pos; struct agp_3_0_dev *cur; struct isoch_data *master, target; @@ -114,11 +112,10 @@ * transfers are enabled and consequently whether maxbw will mean * anything. */ - if((ret = agp_3_0_dev_list_sort(dev_list, ndevs)) != 0) - goto free_and_exit; + agp_3_0_dev_list_sort(dev_list, ndevs); - pci_read_config_dword(td, agp_bridge->capndx + 0x0c, &tnistat); - pci_read_config_dword(td, agp_bridge->capndx + 0x04, &tstatus); + pci_read_config_dword(td, bridge->capndx + 0x0c, &tnistat); + pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus); /* Extract power-on defaults from the target */ target.maxbw = (tnistat >> 16) & 0xff; @@ -170,13 +167,13 @@ * in the target's NISTAT register, so we need to do this now * to get an accurate value for ISOCH_N later. */ - pci_read_config_word(td, agp_bridge->capndx + 0x20, &tnicmd); + pci_read_config_word(td, bridge->capndx + 0x20, &tnicmd); tnicmd &= ~(0x3 << 6); tnicmd |= target.y << 6; - pci_write_config_word(td, agp_bridge->capndx + 0x20, tnicmd); + pci_write_config_word(td, bridge->capndx + 0x20, tnicmd); /* Reread the target's ISOCH_N */ - pci_read_config_dword(td, agp_bridge->capndx + 0x0c, &tnistat); + pci_read_config_dword(td, bridge->capndx + 0x0c, &tnistat); target.n = (tnistat >> 8) & 0xff; /* Calculate the minimum ISOCH_N needed by each master */ @@ -260,7 +257,7 @@ ? (rem_async + rem_isoch) : step; pci_read_config_word(dev, cur->capndx + 0x20, &mnicmd); - pci_read_config_dword(dev, cur->capndx + 0x08, &mcmd); + pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd); mnicmd &= ~(0xff << 8); mnicmd &= ~(0x3 << 6); @@ -270,7 +267,7 @@ mnicmd |= master[cdev].y << 6; mcmd |= master[cdev].rq << 24; - pci_write_config_dword(dev, cur->capndx + 0x08, mcmd); + pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd); pci_write_config_word(dev, cur->capndx + 0x20, mnicmd); } @@ -288,7 +285,8 @@ * target by ndevs. Distribute this many slots to each AGP 3.0 device, * giving any left over slots to the last device in dev_list. */ -static int agp_3_0_nonisochronous_node_enable(struct agp_3_0_dev *dev_list, unsigned int ndevs) +static void agp_3_0_nonisochronous_node_enable(struct agp_bridge_data *bridge, + struct agp_3_0_dev *dev_list, unsigned int ndevs) { struct agp_3_0_dev *cur; struct list_head *head = &dev_list->list, *pos; @@ -296,7 +294,7 @@ u32 trq, mrq, rem; unsigned int cdev = 0; - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + 0x04, &tstatus); + pci_read_config_dword(bridge->dev, bridge->capndx + 0x04, &tstatus); trq = (tstatus >> 24) & 0xff; mrq = trq / ndevs; @@ -306,22 +304,20 @@ for(pos = head->next; cdev < ndevs; cdev++, pos = pos->next) { cur = list_entry(pos, struct agp_3_0_dev, list); - pci_read_config_dword(cur->dev, cur->capndx + 0x08, &mcmd); + pci_read_config_dword(cur->dev, cur->capndx+AGPCMD, &mcmd); mcmd &= ~(0xff << 24); mcmd |= ((cdev == ndevs - 1) ? rem : mrq) << 24; - pci_write_config_dword(cur->dev, cur->capndx + 0x08, mcmd); + pci_write_config_dword(cur->dev, cur->capndx+AGPCMD, mcmd); } - - return 0; } /* * Fully configure and enable an AGP 3.0 host bridge and all the devices * lying behind it. */ -int agp_3_0_node_enable(u32 mode, u32 minor) +int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor) { - struct pci_dev *td = agp_bridge->dev, *dev; + struct pci_dev *td = bridge->dev, *dev; u8 mcapndx; u32 isoch, arqsz, cal_cycle, tmp, rate; u32 tstatus, tcmd, mcmd, mstatus, ncapid; @@ -345,12 +341,22 @@ /* Find all AGP devices, and add them to dev_list. */ pci_for_each_dev(dev) { + mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); switch ((dev->class >>8) & 0xff00) { + case 0x0600: /* Bridge */ + /* Skip bridges. We should call this function for each one. */ + continue; + case 0x0001: /* Unclassified device */ + /* Don't know what this is, but log it for investigation. */ + if (mcapndx != 0) { + printk (KERN_INFO PFX "Wacky, found unclassified AGP device. %x:%x\n", + dev->vendor, dev->device); + } + continue; + case 0x0300: /* Display controller */ case 0x0400: /* Multimedia controller */ - case 0x0600: /* Bridge */ - mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); if (mcapndx == 0) continue; @@ -371,7 +377,7 @@ } /* Extract some power-on defaults from the target */ - pci_read_config_dword(td, agp_bridge->capndx + 0x04, &tstatus); + pci_read_config_dword(td, bridge->capndx + 0x04, &tstatus); isoch = (tstatus >> 17) & 0x1; arqsz = (tstatus >> 13) & 0x7; cal_cycle = (tstatus >> 10) & 0x7; @@ -409,8 +415,8 @@ goto free_and_exit; } - mmajor = (ncapid >> 20) & 0xf; - mminor = (ncapid >> 16) & 0xf; + mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; + mminor = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf; if(mmajor < 3) { printk(KERN_ERR PFX "woah! AGP 2.0 device " @@ -463,13 +469,15 @@ * masters. This process is dramatically different depending on * whether isochronous transfers are supported. */ - if(isoch != 0) { - if((ret = agp_3_0_isochronous_node_enable(dev_list, ndevs)) != 0) - goto free_and_exit; - } else { - if((ret = agp_3_0_nonisochronous_node_enable(dev_list,ndevs)) != 0) - goto free_and_exit; + if (isoch) { + ret = agp_3_0_isochronous_node_enable(bridge, dev_list, ndevs); + if (ret) { + printk(KERN_INFO PFX "Something bad happened setting " + "up isochronous xfers. Falling back to " + "non-isochronous xfer mode.\n"); + } } + agp_3_0_nonisochronous_node_enable(bridge, dev_list, ndevs); /* * Set the calculated minimum supported cal_cycle and minimum @@ -477,7 +485,7 @@ * Also set the AGP_ENABLE bit, effectively 'turning on' the * target (this has to be done _before_ turning on the masters). */ - pci_read_config_dword(td, agp_bridge->capndx + 0x08, &tcmd); + pci_read_config_dword(td, bridge->capndx+AGPCMD, &tcmd); tcmd &= ~(0x7 << 10); tcmd &= ~0x7; @@ -486,7 +494,7 @@ tcmd |= 0x1 << 8; tcmd |= rate; - pci_write_config_dword(td, agp_bridge->capndx + 0x08, tcmd); + pci_write_config_dword(td, bridge->capndx+AGPCMD, tcmd); /* * Set the target's advertised arqsz value, the minimum supported @@ -499,16 +507,16 @@ mcapndx = cur->capndx; - pci_read_config_dword(dev, cur->capndx + 0x08, &mcmd); + pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd); - mcmd &= ~(0x7 << 13); + mcmd &= ~(0x7 << AGPSTAT_ARQSZ_SHIFT); mcmd &= ~0x7; mcmd |= arqsz << 13; - mcmd |= 0x1 << 8; + mcmd |= AGPSTAT_AGP_ENABLE; mcmd |= rate; - pci_write_config_dword(dev, cur->capndx + 0x08, mcmd); + pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd); } free_and_exit: diff -Nru a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c --- a/drivers/char/agp/generic.c Mon May 12 20:55:45 2003 +++ b/drivers/char/agp/generic.c Mon May 12 20:55:45 2003 @@ -1,6 +1,6 @@ /* * AGPGART driver. - * Copyright (C) 2002 Dave Jones. + * Copyright (C) 2002-2003 Dave Jones. * Copyright (C) 1999 Jeff Hartmann. * Copyright (C) 1999 Precision Insight, Inc. * Copyright (C) 1999 Xi Graphics, Inc. @@ -42,19 +42,19 @@ /* * Generic routines for handling agp_memory structures - - * They use the basic page allocation routines to do the - * brunt of the work. + * They use the basic page allocation routines to do the brunt of the work. */ void agp_free_key(int key) { - if (key < 0) return; if (key < MAXKEY) clear_bit(key, agp_bridge->key_list); } +EXPORT_SYMBOL(agp_free_key); + static int agp_get_key(void) { @@ -68,6 +68,7 @@ return -1; } + agp_memory *agp_create_memory(int scratch_pages) { agp_memory *new; @@ -94,7 +95,16 @@ new->num_scratch_pages = scratch_pages; return new; } +EXPORT_SYMBOL(agp_create_memory); +/** + * agp_free_memory - free memory associated with an agp_memory pointer. + * + * @curr: agp_memory pointer to be freed. + * + * It is the only function that can be called when the backend is not owned + * by the caller. (So it can free memory on client death.) + */ void agp_free_memory(agp_memory * curr) { size_t i; @@ -106,21 +116,33 @@ agp_unbind_memory(curr); if (curr->type != 0) { - agp_bridge->free_by_type(curr); + agp_bridge->driver->free_by_type(curr); return; } if (curr->page_count != 0) { for (i = 0; i < curr->page_count; i++) { - agp_bridge->agp_destroy_page(phys_to_virt(curr->memory[i])); + agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[i])); } } agp_free_key(curr->key); vfree(curr->memory); kfree(curr); } +EXPORT_SYMBOL(agp_free_memory); #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) +/** + * agp_allocate_memory - allocate a group of pages of a certain type. + * + * @page_count: size_t argument of the number of pages + * @type: u32 argument of the type of memory to be allocated. + * + * Every agp bridge device will allow you to allocate AGP_NORMAL_MEMORY which + * maps to physical ram. Any other type is device dependent. + * + * It returns NULL whenever memory is unavailable. + */ agp_memory *agp_allocate_memory(size_t page_count, u32 type) { int scratch_pages; @@ -134,7 +156,7 @@ return NULL; if (type != 0) { - new = agp_bridge->alloc_by_type(page_count, type); + new = agp_bridge->driver->alloc_by_type(page_count, type); return new; } @@ -146,7 +168,7 @@ return NULL; for (i = 0; i < page_count; i++) { - void *addr = agp_bridge->agp_alloc_page(); + void *addr = agp_bridge->driver->agp_alloc_page(); if (addr == NULL) { agp_free_memory(new); @@ -160,9 +182,12 @@ return new; } +EXPORT_SYMBOL(agp_allocate_memory); + /* End - Generic routines for handling agp_memory structures */ + static int agp_return_size(void) { int current_size; @@ -170,7 +195,7 @@ temp = agp_bridge->current_size; - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: current_size = A_SIZE_8(temp)->size; break; @@ -197,6 +222,7 @@ return current_size; } + int agp_num_entries(void) { int num_entries; @@ -204,7 +230,7 @@ temp = agp_bridge->current_size; - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: num_entries = A_SIZE_8(temp)->num_entries; break; @@ -230,9 +256,17 @@ num_entries = 0; return num_entries; } +EXPORT_SYMBOL_GPL(agp_num_entries); -/* Routine to copy over information structure */ +/** + * agp_copy_info - copy bridge state information + * + * @info: agp_kern_info pointer. The caller should insure that this pointer is valid. + * + * This function copies information about the agp bridge device and the state of + * the agp backend into an agp_kern_info pointer. + */ int agp_copy_info(agp_kern_info * info) { memset(info, 0, sizeof(agp_kern_info)); @@ -249,20 +283,32 @@ info->aper_size = agp_return_size(); info->max_memory = agp_bridge->max_memory_agp; info->current_memory = atomic_read(&agp_bridge->current_memory_agp); - info->cant_use_aperture = agp_bridge->cant_use_aperture; + info->cant_use_aperture = agp_bridge->driver->cant_use_aperture; info->vm_ops = agp_bridge->vm_ops; info->page_mask = ~0UL; return 0; } +EXPORT_SYMBOL(agp_copy_info); + /* End - Routine to copy over information structure */ + /* * Routines for handling swapping of agp_memory into the GATT - * These routines take agp_memory and insert them into the GATT. * They call device specific routines to actually write to the GATT. */ +/** + * agp_bind_memory - Bind an agp_memory structure into the GATT. + * + * @curr: agp_memory pointer + * @pg_start: an offset into the graphics aperture translation table + * + * It returns -EINVAL if the pointer == NULL. + * It returns -EBUSY if the area of the table requested is already in use. + */ int agp_bind_memory(agp_memory * curr, off_t pg_start) { int ret_val; @@ -272,10 +318,10 @@ return -EINVAL; } if (curr->is_flushed == FALSE) { - CACHE_FLUSH(); + agp_bridge->driver->cache_flush(); curr->is_flushed = TRUE; } - ret_val = agp_bridge->insert_memory(curr, pg_start, curr->type); + ret_val = agp_bridge->driver->insert_memory(curr, pg_start, curr->type); if (ret_val != 0) return ret_val; @@ -284,7 +330,17 @@ curr->pg_start = pg_start; return 0; } +EXPORT_SYMBOL(agp_bind_memory); + +/** + * agp_unbind_memory - Removes an agp_memory structure from the GATT + * + * @curr: agp_memory pointer to be removed from the GATT. + * + * It returns -EINVAL if this piece of agp_memory is not currently bound to + * the graphics aperture translation table or if the agp_memory pointer == NULL + */ int agp_unbind_memory(agp_memory * curr) { int ret_val; @@ -295,7 +351,7 @@ if (curr->is_bound != TRUE) return -EINVAL; - ret_val = agp_bridge->remove_memory(curr, curr->pg_start, curr->type); + ret_val = agp_bridge->driver->remove_memory(curr, curr->pg_start, curr->type); if (ret_val != 0) return ret_val; @@ -304,6 +360,7 @@ curr->pg_start = 0; return 0; } +EXPORT_SYMBOL(agp_unbind_memory); /* End - Routines for handling swapping of agp_memory into the GATT */ @@ -328,50 +385,44 @@ pci_read_config_dword(device, agp + PCI_AGP_STATUS, &scratch); /* adjust RQ depth */ - command = ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); + command = ((command & ~AGPSTAT_RQ_DEPTH) | + min_t(u32, (mode & AGPSTAT_RQ_DEPTH), + min_t(u32, (command & AGPSTAT_RQ_DEPTH), + (scratch & AGPSTAT_RQ_DEPTH)))); /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; + if (!((command & AGPSTAT_SBA) && (scratch & AGPSTAT_SBA) && (mode & AGPSTAT_SBA))) + command &= ~AGPSTAT_SBA; /* disable FW if it's not supported */ - if (!((command & 0x00000010) && - (scratch & 0x00000010) && - (mode & 0x00000010))) - command &= ~0x00000010; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; + if (!((command & AGPSTAT_FW) && (scratch & AGPSTAT_FW) && (mode & AGPSTAT_FW))) + command &= ~AGPSTAT_FW; + + /* Set speed */ + if (!((command & AGPSTAT2_4X) && (scratch & AGPSTAT2_4X) && (mode & AGPSTAT2_4X))) + command &= ~AGPSTAT2_4X; + + if (!((command & AGPSTAT2_2X) && (scratch & AGPSTAT2_2X) && (mode & AGPSTAT2_2X))) + command &= ~AGPSTAT2_2X; + + if (!((command & AGPSTAT2_1X) && (scratch & AGPSTAT2_1X) && (mode & AGPSTAT2_1X))) + command &= ~AGPSTAT2_1X; } - if (command & 4) - command &= ~3; /* 4X */ + /* Now we know what mode it should be, clear out the unwanted bits. */ + if (command & AGPSTAT2_4X) + command &= ~(AGPSTAT2_1X | AGPSTAT2_2X); /* 4X */ - if (command & 2) - command &= ~5; /* 2X (8X for AGP3.0) */ + if (command & AGPSTAT2_2X) + command &= ~(AGPSTAT2_1X | AGPSTAT2_4X); /* 2X */ - if (command & 1) - command &= ~6; /* 1X (4X for AGP3.0) */ + if (command & AGPSTAT2_1X) + command &= ~(AGPSTAT2_2X | AGPSTAT2_4X); /* 1Xf */ return command; } +EXPORT_SYMBOL(agp_collect_device_status); + void agp_device_command(u32 command, int agp_v3) { @@ -392,6 +443,8 @@ pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); } } +EXPORT_SYMBOL(agp_device_command); + void agp_generic_enable(u32 mode) { @@ -408,7 +461,7 @@ pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + 0x4, &agp_3_0); /* Check to see if we are operating in 3.0 mode */ if((agp_3_0 >> 3) & 0x1) { - agp_3_0_node_enable(mode, minor); + agp_3_0_node_enable(agp_bridge, mode, minor); return; } else { printk (KERN_INFO PFX "not in AGP 3.0 mode, falling back to 2.x\n"); @@ -420,12 +473,14 @@ agp_bridge->capndx + PCI_AGP_STATUS, &command); command = agp_collect_device_status(mode, command); - command |= 0x100; + command |= AGPSTAT_AGP_ENABLE; pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_COMMAND, command); agp_device_command(command, 0); } +EXPORT_SYMBOL(agp_generic_enable); + int agp_generic_create_gatt_table(void) { @@ -439,7 +494,7 @@ struct page *page; /* The generic routines can't handle 2 level gatt's */ - if (agp_bridge->size_type == LVL2_APER_SIZE) + if (agp_bridge->driver->size_type == LVL2_APER_SIZE) return -EINVAL; table = NULL; @@ -447,9 +502,9 @@ temp = agp_bridge->current_size; size = page_order = num_entries = 0; - if (agp_bridge->size_type != FIXED_APER_SIZE) { + if (agp_bridge->driver->size_type != FIXED_APER_SIZE) { do { - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: size = A_SIZE_8(temp)->size; page_order = @@ -480,19 +535,17 @@ if (table == NULL) { i++; - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: - agp_bridge->current_size = A_IDX8(); + agp_bridge->current_size = A_IDX8(agp_bridge); break; case U16_APER_SIZE: - agp_bridge->current_size = A_IDX16(); + agp_bridge->current_size = A_IDX16(agp_bridge); break; case U32_APER_SIZE: - agp_bridge->current_size = A_IDX32(); + agp_bridge->current_size = A_IDX32(agp_bridge); break; - /* This case will never really - * happen. - */ + /* This case will never really happen. */ case FIXED_APER_SIZE: case LVL2_APER_SIZE: default: @@ -504,7 +557,7 @@ } else { agp_bridge->aperture_size_idx = i; } - } while ((table == NULL) && (i < agp_bridge->num_aperture_sizes)); + } while (!table && (i < agp_bridge->driver->num_aperture_sizes)); } else { size = ((struct aper_size_info_fixed *) temp)->size; page_order = ((struct aper_size_info_fixed *) temp)->page_order; @@ -522,10 +575,11 @@ agp_bridge->gatt_table_real = (u32 *) table; agp_gatt_table = (void *)table; - CACHE_FLUSH(); + + agp_bridge->driver->cache_flush(); agp_bridge->gatt_table = ioremap_nocache(virt_to_phys(table), (PAGE_SIZE * (1 << page_order))); - CACHE_FLUSH(); + agp_bridge->driver->cache_flush(); if (agp_bridge->gatt_table == NULL) { for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) @@ -543,16 +597,21 @@ return 0; } +EXPORT_SYMBOL(agp_generic_create_gatt_table); int agp_generic_suspend(void) { return 0; } +EXPORT_SYMBOL(agp_generic_suspend); + void agp_generic_resume(void) { return; } +EXPORT_SYMBOL(agp_generic_resume); + int agp_generic_free_gatt_table(void) { @@ -563,7 +622,7 @@ temp = agp_bridge->current_size; - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: page_order = A_SIZE_8(temp)->page_order; break; @@ -587,8 +646,7 @@ /* Do not worry about freeing memory, because if this is * called, then all agp memory is deallocated and removed - * from the table. - */ + * from the table. */ iounmap(agp_bridge->gatt_table); table = (char *) agp_bridge->gatt_table_real; @@ -598,8 +656,16 @@ ClearPageReserved(page); free_pages((unsigned long) agp_bridge->gatt_table_real, page_order); + + agp_gatt_table = NULL; + agp_bridge->gatt_table = NULL; + agp_bridge->gatt_table_real = NULL; + agp_bridge->gatt_bus_addr = 0; + return 0; } +EXPORT_SYMBOL(agp_generic_free_gatt_table); + int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type) { @@ -610,7 +676,7 @@ temp = agp_bridge->current_size; - switch (agp_bridge->size_type) { + switch (agp_bridge->driver->size_type) { case U8_APER_SIZE: num_entries = A_SIZE_8(temp)->num_entries; break; @@ -647,24 +713,27 @@ j = pg_start; while (j < (pg_start + mem->page_count)) { - if (!PGE_EMPTY(agp_bridge->gatt_table[j])) { + if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) { return -EBUSY; } j++; } if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); + agp_bridge->driver->cache_flush(); mem->is_flushed = TRUE; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) agp_bridge->gatt_table[j] = - agp_bridge->mask_memory(mem->memory[i], mem->type); + agp_bridge->driver->mask_memory( + mem->memory[i], mem->type); - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return 0; } +EXPORT_SYMBOL(agp_generic_insert_memory); + int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type) { @@ -681,14 +750,18 @@ (unsigned long) agp_bridge->scratch_page; } - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return 0; } +EXPORT_SYMBOL(agp_generic_remove_memory); + agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) { return NULL; } +EXPORT_SYMBOL(agp_generic_alloc_by_type); + void agp_generic_free_by_type(agp_memory * curr) { @@ -698,13 +771,13 @@ agp_free_key(curr->key); kfree(curr); } +EXPORT_SYMBOL(agp_generic_free_by_type); + /* * Basic Page Allocation Routines - - * These routines handle page allocation - * and by default they reserve the allocated - * memory. They also handle incrementing the - * current_memory_agp value, Which is checked + * These routines handle page allocation and by default they reserve the allocated + * memory. They also handle incrementing the current_memory_agp value, Which is checked * against a maximum value. */ @@ -723,6 +796,8 @@ atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); } +EXPORT_SYMBOL(agp_generic_alloc_page); + void agp_generic_destroy_page(void *addr) { @@ -738,41 +813,39 @@ free_page((unsigned long)addr); atomic_dec(&agp_bridge->current_memory_agp); } +EXPORT_SYMBOL(agp_generic_destroy_page); /* End Basic Page Allocation Routines */ + +/** + * agp_enable - initialise the agp point-to-point connection. + * + * @mode: agp mode register value to configure with. + */ void agp_enable(u32 mode) { if (agp_bridge->type == NOT_SUPPORTED) return; - agp_bridge->agp_enable(mode); + agp_bridge->driver->agp_enable(mode); } - -EXPORT_SYMBOL(agp_free_memory); -EXPORT_SYMBOL(agp_allocate_memory); -EXPORT_SYMBOL(agp_copy_info); -EXPORT_SYMBOL(agp_create_memory); -EXPORT_SYMBOL(agp_bind_memory); -EXPORT_SYMBOL(agp_unbind_memory); -EXPORT_SYMBOL(agp_free_key); EXPORT_SYMBOL(agp_enable); -EXPORT_SYMBOL(agp_bridge); - -EXPORT_SYMBOL(agp_generic_alloc_page); -EXPORT_SYMBOL(agp_generic_destroy_page); -EXPORT_SYMBOL(agp_generic_suspend); -EXPORT_SYMBOL(agp_generic_resume); -EXPORT_SYMBOL(agp_generic_enable); -EXPORT_SYMBOL(agp_generic_create_gatt_table); -EXPORT_SYMBOL(agp_generic_free_gatt_table); -EXPORT_SYMBOL(agp_generic_insert_memory); -EXPORT_SYMBOL(agp_generic_remove_memory); -EXPORT_SYMBOL(agp_generic_alloc_by_type); -EXPORT_SYMBOL(agp_generic_free_by_type); -EXPORT_SYMBOL(global_cache_flush); -EXPORT_SYMBOL(agp_device_command); -EXPORT_SYMBOL(agp_collect_device_status); +#ifdef CONFIG_SMP +static void ipi_handler(void *null) +{ + flush_agp_cache(); +} +#endif -EXPORT_SYMBOL_GPL(agp_num_entries); +void global_cache_flush(void) +{ +#ifdef CONFIG_SMP + if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0) + panic(PFX "timed out waiting for the other CPUs!\n"); +#else + flush_agp_cache(); +#endif +} +EXPORT_SYMBOL(global_cache_flush); diff -Nru a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c --- a/drivers/char/agp/hp-agp.c Mon May 12 20:55:48 2003 +++ b/drivers/char/agp/hp-agp.c Mon May 12 20:55:48 2003 @@ -285,7 +285,7 @@ } if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); + global_cache_flush(); mem->is_flushed = TRUE; } @@ -296,11 +296,11 @@ for (k = 0; k < hp->io_pages_per_kpage; k++, j++, paddr += hp->io_page_size) { - hp->gatt[j] = agp_bridge->mask_memory(paddr, type); + hp->gatt[j] = agp_bridge->driver->mask_memory(paddr, type); } } - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return 0; } @@ -319,7 +319,7 @@ hp->gatt[i] = agp_bridge->scratch_page; } - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return 0; } @@ -328,58 +328,62 @@ return HP_ZX1_PDIR_VALID_BIT | addr; } -static int __init hp_zx1_setup (struct pci_dev *pdev __attribute__((unused))) -{ - agp_bridge->masks = hp_zx1_masks; - agp_bridge->dev_private_data = NULL; - agp_bridge->size_type = FIXED_APER_SIZE; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = hp_zx1_configure; - agp_bridge->fetch_size = hp_zx1_fetch_size; - agp_bridge->cleanup = hp_zx1_cleanup; - agp_bridge->tlb_flush = hp_zx1_tlbflush; - agp_bridge->mask_memory = hp_zx1_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = hp_zx1_create_gatt_table; - agp_bridge->free_gatt_table = hp_zx1_free_gatt_table; - agp_bridge->insert_memory = hp_zx1_insert_memory; - agp_bridge->remove_memory = hp_zx1_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->cant_use_aperture = 1; - return hp_zx1_ioc_init(); -} +struct agp_bridge_driver hp_zx1_driver = { + .owner = THIS_MODULE, + .masks = hp_zx1_masks, + .size_type = FIXED_APER_SIZE, + .configure = hp_zx1_configure, + .fetch_size = hp_zx1_fetch_size, + .cleanup = hp_zx1_cleanup, + .tlb_flush = hp_zx1_tlbflush, + .mask_memory = hp_zx1_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = hp_zx1_create_gatt_table, + .free_gatt_table = hp_zx1_free_gatt_table, + .insert_memory = hp_zx1_insert_memory, + .remove_memory = hp_zx1_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .cant_use_aperture = 1, +}; -static int __init agp_find_supported_device(struct pci_dev *dev) +static int __init agp_hp_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - agp_bridge->dev = dev; + struct agp_bridge_data *bridge; + int error; /* ZX1 LBAs can be either PCI or AGP bridges */ - if (pci_find_capability(dev, PCI_CAP_ID_AGP)) { - printk(KERN_INFO PFX "Detected HP ZX1 AGP chipset at %s\n", - dev->slot_name); - agp_bridge->type = HP_ZX1; - agp_bridge->dev = dev; - return hp_zx1_setup(dev); - } - return -ENODEV; -} + if (!pci_find_capability(pdev, PCI_CAP_ID_AGP)) + return -ENODEV; -static struct agp_driver hp_agp_driver = { - .owner = THIS_MODULE, -}; + printk(KERN_INFO PFX "Detected HP ZX1 AGP chipset at %s\n", + pdev->slot_name); + + error = hp_zx1_ioc_init(); + if (error) + return error; + + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; -static int __init agp_hp_probe (struct pci_dev *dev, const struct pci_device_id *ent) + bridge->driver = &hp_zx1_driver; + bridge->dev = pdev; + + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} + +static void __devexit agp_hp_remove(struct pci_dev *pdev) { - if (agp_find_supported_device(dev) == 0) { - hp_agp_driver.dev = dev; - agp_register_driver(&hp_agp_driver); - return 0; - } - return -ENODEV; + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_hp_pci_table[] __initdata = { @@ -400,22 +404,16 @@ .name = "agpgart-hp", .id_table = agp_hp_pci_table, .probe = agp_hp_probe, + .remove = agp_hp_remove, }; static int __init agp_hp_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_hp_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_hp_pci_driver); } static void __exit agp_hp_cleanup(void) { - agp_unregister_driver(&hp_agp_driver); pci_unregister_driver(&agp_hp_pci_driver); } diff -Nru a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c --- a/drivers/char/agp/i460-agp.c Mon May 12 20:55:47 2003 +++ b/drivers/char/agp/i460-agp.c Mon May 12 20:55:47 2003 @@ -69,7 +69,7 @@ } *lp_desc; } i460; -static const struct aper_size_info_8 i460_sizes[3] = +static struct aper_size_info_8 i460_sizes[3] = { /* * The 32GB aperture is only available with a 4M GART page size. Due to the @@ -107,7 +107,7 @@ return 0; } - values = A_SIZE_8(agp_bridge->aperture_sizes); + values = A_SIZE_8(agp_bridge->driver->aperture_sizes); pci_read_config_byte(agp_bridge->dev, INTEL_I460_AGPSIZ, &temp); @@ -130,7 +130,7 @@ else i460.dynamic_apbase = INTEL_I460_APBASE; - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { /* * Dynamically calculate the proper num_entries and page_order values for * the define aperture sizes. Take care not to shift off the end of @@ -140,7 +140,7 @@ values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT); } - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { /* Neglect control bits when matching up size_value */ if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -294,7 +294,7 @@ j = io_pg_start; while (j < (io_pg_start + I460_IOPAGES_PER_KPAGE * mem->page_count)) { - if (!PGE_EMPTY(RD_GATT(j))) { + if (!PGE_EMPTY(agp_bridge, RD_GATT(j))) { pr_debug("i460_insert_memory_small_io_page: GATT[%d]=0x%x is busy\n", j, RD_GATT(j)); return -EBUSY; @@ -306,7 +306,7 @@ for (i = 0, j = io_pg_start; i < mem->page_count; i++) { paddr = mem->memory[i]; for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size) - WR_GATT(j, agp_bridge->mask_memory(paddr, mem->type)); + WR_GATT(j, agp_bridge->driver->mask_memory(paddr, mem->type)); } WR_FLUSH_GATT(j - 1); return 0; @@ -417,7 +417,7 @@ if (i460_alloc_large_page(lp) < 0) return -ENOMEM; pg = lp - i460.lp_desc; - WR_GATT(pg, agp_bridge->mask_memory(lp->paddr, 0)); + WR_GATT(pg, agp_bridge->driver->mask_memory(lp->paddr, 0)); WR_FLUSH_GATT(pg); } @@ -439,7 +439,7 @@ struct lp_desc *start, *end, *lp; void *temp; - temp = agp_bridge->current_size; + temp = agp_bridge->driver->current_size; num_entries = A_SIZE_8(temp)->num_entries; /* Figure out what pg_start means in terms of our large GART pages */ @@ -519,64 +519,71 @@ static unsigned long i460_mask_memory (unsigned long addr, int type) { /* Make sure the returned address is a valid GATT entry */ - return (agp_bridge->masks[0].mask + return (agp_bridge->driver->masks[0].mask | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12)); } -static int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused))) -{ - agp_bridge->masks = i460_masks; - agp_bridge->aperture_sizes = (void *) i460_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 3; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = i460_configure; - agp_bridge->fetch_size = i460_fetch_size; - agp_bridge->cleanup = i460_cleanup; - agp_bridge->tlb_flush = i460_tlb_flush; - agp_bridge->mask_memory = i460_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = i460_create_gatt_table; - agp_bridge->free_gatt_table = i460_free_gatt_table; +struct agp_bridge_driver intel_i460_driver = { + .owner = THIS_MODULE, + .masks = i460_masks, + .aperture_sizes = i460_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 3, + .configure = i460_configure, + .fetch_size = i460_fetch_size, + .cleanup = i460_cleanup, + .tlb_flush = i460_tlb_flush, + .mask_memory = i460_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = i460_create_gatt_table, + .free_gatt_table = i460_free_gatt_table, #if I460_LARGE_IO_PAGES - agp_bridge->insert_memory = i460_insert_memory; - agp_bridge->remove_memory = i460_remove_memory; - agp_bridge->agp_alloc_page = i460_alloc_page; - agp_bridge->agp_destroy_page = i460_destroy_page; + .insert_memory = i460_insert_memory, + .remove_memory = i460_remove_memory, + .agp_alloc_page = i460_alloc_page, + .agp_destroy_page = i460_destroy_page, #else - agp_bridge->insert_memory = i460_insert_memory_small_io_page; - agp_bridge->remove_memory = i460_remove_memory_small_io_page; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; + .insert_memory = i460_insert_memory_small_io_page, + .remove_memory = i460_remove_memory_small_io_page, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, #endif - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 1; - return 0; -} - -static struct agp_driver i460_agp_driver = { - .owner = THIS_MODULE, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, + .cant_use_aperture = 1, }; -static int __init agp_intel_i460_probe (struct pci_dev *dev, const struct pci_device_id *ent) +static int __init agp_intel_i460_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - u8 cap_ptr = 0; + struct agp_bridge_data *bridge; + u8 cap_ptr; - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) return -ENODEV; - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - intel_i460_setup(dev); - i460_agp_driver.dev = dev; - agp_register_driver(&i460_agp_driver); - return 0; + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + bridge->driver = &intel_i460_driver; + bridge->dev = pdev; + bridge->capndx = cap_ptr; + + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} + +static void __devexit agp_intel_i460_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_intel_i460_pci_table[] __initdata = { @@ -597,22 +604,16 @@ .name = "agpgart-intel-i460", .id_table = agp_intel_i460_pci_table, .probe = agp_intel_i460_probe, + .remove = agp_intel_i460_remove, }; static int __init agp_intel_i460_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_intel_i460_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_intel_i460_pci_driver); } static void __exit agp_intel_i460_cleanup(void) { - agp_unregister_driver(&i460_agp_driver); pci_unregister_driver(&agp_intel_i460_pci_driver); } diff -Nru a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c --- a/drivers/char/agp/intel-agp.c Mon May 12 20:55:46 2003 +++ b/drivers/char/agp/intel-agp.c Mon May 12 20:55:46 2003 @@ -45,7 +45,7 @@ struct aper_size_info_fixed *values; pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc); - values = A_SIZE_FIX(agp_bridge->aperture_sizes); + values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { printk(KERN_WARNING PFX "i810 is disabled\n"); @@ -89,9 +89,9 @@ agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - CACHE_FLUSH(); + global_cache_flush(); - if (agp_bridge->needs_scratch_page == TRUE) { + if (agp_bridge->driver->needs_scratch_page) { for (i = 0; i < current_size->num_entries; i++) { OUTREG32(intel_i810_private.registers, I810_PTE_BASE + (i * 4), @@ -130,23 +130,22 @@ return -EINVAL; } for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge->gatt_table[j])) { + if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) return -EBUSY; - } } if (type != 0 || mem->type != 0) { if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { /* special insert */ - CACHE_FLUSH(); + global_cache_flush(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { OUTREG32(intel_i810_private.registers, I810_PTE_BASE + (i * 4), (i * 4096) | I810_PTE_LOCAL | I810_PTE_VALID); } - CACHE_FLUSH(); - agp_bridge->tlb_flush(mem); + global_cache_flush(); + agp_bridge->driver->tlb_flush(mem); return 0; } if((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) @@ -155,15 +154,15 @@ } insert: - CACHE_FLUSH(); + global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { OUTREG32(intel_i810_private.registers, I810_PTE_BASE + (j * 4), - agp_bridge->mask_memory(mem->memory[i], mem->type)); + agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); } - CACHE_FLUSH(); + global_cache_flush(); - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return 0; } @@ -178,58 +177,61 @@ agp_bridge->scratch_page); } - CACHE_FLUSH(); - agp_bridge->tlb_flush(mem); + global_cache_flush(); + agp_bridge->driver->tlb_flush(mem); return 0; } +/* + * The i810/i830 requires a physical address to program its mouse + * pointer into hardware. + * However the Xserver still writes to it through the agp aperture. + */ +static agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) +{ + agp_memory *new; + void *addr; + + if (pg_count != 1) + return NULL; + + addr = agp_bridge->driver->agp_alloc_page(); + if (addr == NULL) + return NULL; + + new = agp_create_memory(1); + if (new == NULL) + return NULL; + + new->memory[0] = virt_to_phys(addr); + new->page_count = 1; + new->num_scratch_pages = 1; + new->type = AGP_PHYS_MEMORY; + new->physical = new->memory[0]; + return new; +} + static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) { agp_memory *new; if (type == AGP_DCACHE_MEMORY) { - if (pg_count != intel_i810_private.num_dcache_entries) { + if (pg_count != intel_i810_private.num_dcache_entries) return NULL; - } - new = agp_create_memory(1); - if (new == NULL) { + new = agp_create_memory(1); + if (new == NULL) return NULL; - } + new->type = AGP_DCACHE_MEMORY; new->page_count = pg_count; new->num_scratch_pages = 0; vfree(new->memory); return new; } - if(type == AGP_PHYS_MEMORY) { - void *addr; - /* The I810 requires a physical address to program - * it's mouse pointer into hardware. However the - * Xserver still writes to it through the agp - * aperture - */ - if (pg_count != 1) - return NULL; - - new = agp_create_memory(1); - if (new == NULL) - return NULL; - - addr = agp_bridge->agp_alloc_page(); + if (type == AGP_PHYS_MEMORY) + return(alloc_agpphysmem_i8xx(pg_count, type)); - if (addr == NULL) { - /* Free this structure */ - agp_free_memory(new); - return NULL; - } - new->memory[0] = virt_to_phys(addr); - new->page_count = 1; - new->num_scratch_pages = 1; - new->type = AGP_PHYS_MEMORY; - new->physical = new->memory[0]; - return new; - } return NULL; } @@ -237,7 +239,7 @@ { agp_free_key(curr->key); if(curr->type == AGP_PHYS_MEMORY) { - agp_bridge->agp_destroy_page(phys_to_virt(curr->memory[0])); + agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0])); vfree(curr->memory); } kfree(curr); @@ -246,39 +248,7 @@ static unsigned long intel_i810_mask_memory(unsigned long addr, int type) { /* Type checking must be done elsewhere */ - return addr | agp_bridge->masks[type].mask; -} - -static int __init intel_i810_setup(struct pci_dev *i810_dev) -{ - intel_i810_private.i810_dev = i810_dev; - - agp_bridge->masks = intel_i810_masks; - agp_bridge->aperture_sizes = (void *) intel_i810_sizes; - agp_bridge->size_type = FIXED_APER_SIZE; - agp_bridge->num_aperture_sizes = 2; - agp_bridge->dev_private_data = (void *) &intel_i810_private; - agp_bridge->needs_scratch_page = TRUE; - agp_bridge->configure = intel_i810_configure; - agp_bridge->fetch_size = intel_i810_fetch_size; - agp_bridge->cleanup = intel_i810_cleanup; - agp_bridge->tlb_flush = intel_i810_tlbflush; - agp_bridge->mask_memory = intel_i810_mask_memory; - agp_bridge->agp_enable = intel_i810_agp_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = intel_i810_insert_entries; - agp_bridge->remove_memory = intel_i810_remove_entries; - agp_bridge->alloc_by_type = intel_i810_alloc_by_type; - agp_bridge->free_by_type = intel_i810_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - - return 0; + return addr | agp_bridge->driver->masks[type].mask; } static struct aper_size_info_fixed intel_i830_sizes[] = @@ -379,10 +349,11 @@ temp &= 0xfff80000; intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) return (-ENOMEM); + if (!intel_i830_private.registers) + return (-ENOMEM); temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000; - CACHE_FLUSH(); + global_cache_flush(); /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); @@ -407,7 +378,7 @@ u16 gmch_ctrl; struct aper_size_info_fixed *values; - values = A_SIZE_FIX(agp_bridge->aperture_sizes); + values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB && agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) { @@ -449,9 +420,9 @@ pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED); - CACHE_FLUSH(); + global_cache_flush(); - if (agp_bridge->needs_scratch_page == TRUE) + if (agp_bridge->driver->needs_scratch_page) for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); @@ -490,15 +461,15 @@ (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) return (-EINVAL); - CACHE_FLUSH(); + global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4), - agp_bridge->mask_memory(mem->memory[i], mem->type)); + agp_bridge->driver->mask_memory(mem->memory[i], mem->type)); - CACHE_FLUSH(); + global_cache_flush(); - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return(0); } @@ -507,7 +478,7 @@ { int i; - CACHE_FLUSH (); + global_cache_flush(); if (pg_start < intel_i830_private.gtt_entries) { printk ("Trying to disable local/stolen memory\n"); @@ -517,90 +488,22 @@ for (i = pg_start; i < (mem->page_count + pg_start); i++) OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page); - CACHE_FLUSH(); + global_cache_flush(); - agp_bridge->tlb_flush(mem); + agp_bridge->driver->tlb_flush(mem); return (0); } static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) { - agp_memory *nw; - - /* always return NULL for now */ - if (type == AGP_DCACHE_MEMORY) return(NULL); - - if (type == AGP_PHYS_MEMORY) { - void *addr; - - /* The i830 requires a physical address to program - * it's mouse pointer into hardware. However the - * Xserver still writes to it through the agp - * aperture - */ - - if (pg_count != 1) return(NULL); - - nw = agp_create_memory(1); - - if (nw == NULL) return(NULL); - - addr = agp_bridge->agp_alloc_page(); - if (addr == NULL) { - /* free this structure */ - agp_free_memory(nw); - return(NULL); - } - - nw->memory[0] = virt_to_phys(addr); - nw->page_count = 1; - nw->num_scratch_pages = 1; - nw->type = AGP_PHYS_MEMORY; - nw->physical = nw->memory[0]; - return(nw); - } + if (type == AGP_PHYS_MEMORY) + return(alloc_agpphysmem_i8xx(pg_count, type)); + /* always return NULL for other allocation types for now */ return(NULL); } -static int __init intel_i830_setup(struct pci_dev *i830_dev) -{ - intel_i830_private.i830_dev = i830_dev; - - agp_bridge->masks = intel_i810_masks; - agp_bridge->aperture_sizes = (void *) intel_i830_sizes; - agp_bridge->size_type = FIXED_APER_SIZE; - agp_bridge->num_aperture_sizes = 2; - - agp_bridge->dev_private_data = (void *) &intel_i830_private; - agp_bridge->needs_scratch_page = TRUE; - - agp_bridge->configure = intel_i830_configure; - agp_bridge->fetch_size = intel_i830_fetch_size; - agp_bridge->cleanup = intel_i830_cleanup; - agp_bridge->tlb_flush = intel_i810_tlbflush; - agp_bridge->mask_memory = intel_i810_mask_memory; - agp_bridge->agp_enable = intel_i810_agp_enable; - agp_bridge->cache_flush = global_cache_flush; - - agp_bridge->create_gatt_table = intel_i830_create_gatt_table; - agp_bridge->free_gatt_table = intel_i830_free_gatt_table; - - agp_bridge->insert_memory = intel_i830_insert_entries; - agp_bridge->remove_memory = intel_i830_remove_entries; - agp_bridge->alloc_by_type = intel_i830_alloc_by_type; - agp_bridge->free_by_type = intel_i810_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - - return(0); -} - static int intel_fetch_size(void) { int i; @@ -608,9 +511,9 @@ struct aper_size_info_16 *values; pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp); - values = A_SIZE_16(agp_bridge->aperture_sizes); + values = A_SIZE_16(agp_bridge->driver->aperture_sizes); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); agp_bridge->aperture_size_idx = i; @@ -621,22 +524,14 @@ return 0; } -static int intel_8xx_fetch_size(void) +static int __intel_8xx_fetch_size(u8 temp) { int i; - u8 temp; struct aper_size_info_8 *values; - pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp); - - /* Intel 815 chipsets have a _weird_ APSIZE register with only - * one non-reserved bit, so mask the others out ... */ - if (agp_bridge->type == INTEL_I815) - temp &= (1 << 3); + values = A_SIZE_8(agp_bridge->driver->aperture_sizes); - values = A_SIZE_8(agp_bridge->aperture_sizes); - - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -647,6 +542,25 @@ return 0; } +static int intel_8xx_fetch_size(void) +{ + u8 temp; + + pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp); + return __intel_8xx_fetch_size(temp); +} + +static int intel_815_fetch_size(void) +{ + u8 temp; + + /* Intel 815 chipsets have a _weird_ APSIZE register with only + * one non-reserved bit, so mask the others out ... */ + pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp); + temp &= (1 << 3); + + return __intel_8xx_fetch_size(temp); +} static void intel_tlbflush(agp_memory * mem) { @@ -991,7 +905,7 @@ static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } static void intel_resume(void) @@ -1041,584 +955,485 @@ {32, 8192, 3, 56} }; -static int __init intel_generic_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_generic_sizes; - agp_bridge->size_type = U16_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_configure; - agp_bridge->fetch_size = intel_fetch_size; - agp_bridge->cleanup = intel_cleanup; - agp_bridge->tlb_flush = intel_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = intel_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_generic_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_generic_sizes, + .size_type = U16_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_configure, + .fetch_size = intel_fetch_size, + .cleanup = intel_cleanup, + .tlb_flush = intel_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = intel_resume, +}; -static int __init intel_815_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_815_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 2; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_815_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_810_driver = { + .owner = THIS_MODULE, + .masks = intel_i810_masks, + .aperture_sizes = intel_i810_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 2, + .needs_scratch_page = TRUE, + .configure = intel_i810_configure, + .fetch_size = intel_i810_fetch_size, + .cleanup = intel_i810_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i810_mask_memory, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = intel_i810_insert_entries, + .remove_memory = intel_i810_remove_entries, + .alloc_by_type = intel_i810_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_820_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_820_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_820_cleanup; - agp_bridge->tlb_flush = intel_820_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_815_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_815_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 2, + .configure = intel_815_configure, + .fetch_size = intel_815_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_830mp_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_830mp_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 4; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_830mp_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_830_driver = { + .owner = THIS_MODULE, + .masks = intel_i810_masks, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 2, + .needs_scratch_page = TRUE, + .configure = intel_i830_configure, + .fetch_size = intel_i830_fetch_size, + .cleanup = intel_i830_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i810_mask_memory, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i830_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i830_insert_entries, + .remove_memory = intel_i830_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_840_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_840_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} -static int __init intel_845_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_845_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = intel_845_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_820_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_820_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_820_cleanup, + .tlb_flush = intel_820_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_850_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_850_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_830mp_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_830mp_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 4, + .configure = intel_830mp_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_860_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_860_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} +struct agp_bridge_driver intel_840_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_840_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init intel_7505_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = intel_generic_masks; - agp_bridge->aperture_sizes = (void *) intel_8xx_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = intel_7505_configure; - agp_bridge->fetch_size = intel_8xx_fetch_size; - agp_bridge->cleanup = intel_8xx_cleanup; - agp_bridge->tlb_flush = intel_8xx_tlbflush; - agp_bridge->mask_memory = intel_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} -struct agp_device_ids intel_agp_device_ids[] __initdata = -{ - { - .device_id = PCI_DEVICE_ID_INTEL_82443LX_0, - .chipset = INTEL_LX, - .chipset_name = "440LX", - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82443BX_0, - .chipset = INTEL_BX, - .chipset_name = "440BX", - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82443GX_0, - .chipset = INTEL_GX, - .chipset_name = "440GX", - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82815_MC, - .chipset = INTEL_I815, - .chipset_name = "i815", - .chipset_setup = intel_815_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82820_HB, - .chipset = INTEL_I820, - .chipset_name = "i820", - .chipset_setup = intel_820_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82820_UP_HB, - .chipset = INTEL_I820, - .chipset_name = "i820", - .chipset_setup = intel_820_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82830_HB, - .chipset = INTEL_I830_M, - .chipset_name = "830M", - .chipset_setup = intel_830mp_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82840_HB, - .chipset = INTEL_I840, - .chipset_name = "i840", - .chipset_setup = intel_840_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82845_HB, - .chipset = INTEL_I845, - .chipset_name = "i845", - .chipset_setup = intel_845_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82845G_HB, - .chipset = INTEL_I845_G, - .chipset_name = "845G", - .chipset_setup = intel_845_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82850_HB, - .chipset = INTEL_I850, - .chipset_name = "i850", - .chipset_setup = intel_850_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82855_HB, - .chipset = INTEL_I855_PM, - .chipset_name = "855PM", - .chipset_setup = intel_845_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82860_HB, - .chipset = INTEL_I860, - .chipset_name = "i860", - .chipset_setup = intel_860_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_82865_HB, - .chipset = INTEL_I865_G, - .chipset_name = "865G", - .chipset_setup = intel_845_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_7505_0, - .chipset = INTEL_E7505, - .chipset_name = "E7505", - .chipset_setup = intel_7505_setup - }, - { - .device_id = PCI_DEVICE_ID_INTEL_7205_0, - .chipset = INTEL_E7505, - .chipset_name = "E7205", - .chipset_setup = intel_7505_setup - }, - { }, /* dummy final entry, always present */ +struct agp_bridge_driver intel_845_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_845_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = intel_845_resume, }; +struct agp_bridge_driver intel_850_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_850_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + +struct agp_bridge_driver intel_860_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_860_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +struct agp_bridge_driver intel_7505_driver = { + .owner = THIS_MODULE, + .masks = intel_generic_masks, + .aperture_sizes = intel_8xx_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = intel_7505_configure, + .fetch_size = intel_8xx_fetch_size, + .cleanup = intel_8xx_cleanup, + .tlb_flush = intel_8xx_tlbflush, + .mask_memory = intel_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + +static int find_i810(u16 device, const char *name) { - int j=0; - struct agp_device_ids *devs; - - devs = intel_agp_device_ids; + struct pci_dev *i810_dev; - while (devs[j].chipset_name != NULL) { - if (pdev->device == devs[j].device_id) { - printk (KERN_INFO PFX "Detected Intel %s chipset\n", - devs[j].chipset_name); - agp_bridge->type = devs[j].chipset; - - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return intel_generic_setup(pdev); - } - j++; + i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (!i810_dev) { + printk(KERN_ERR PFX "Detected an Intel %s Chipset, " + "but could not find the secondary device.\n", + name); + return 0; } - j--; + + intel_i810_private.i810_dev = i810_dev; + return 1; +} - /* try init anyway, if user requests it */ - if (agp_try_unsupported) { - printk(KERN_WARNING PFX "Trying generic Intel routines" - " for device id: %04x\n", pdev->device); - agp_bridge->type = INTEL_GENERIC; - return intel_generic_setup(pdev); - } +static int find_i830(u16 device) +{ + struct pci_dev *i830_dev; - printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x)," - " you might want to try agp_try_unsupported=1.\n", pdev->device); - return -ENODEV; -} + i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { + i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + device, i830_dev); + } + if (!i830_dev) + return 0; -/* Supported Device Scanning routine */ + intel_i830_private.i830_dev = i830_dev; + return 1; +} -static int __init agp_find_supported_device(struct pci_dev *dev) +static int __init agp_intel_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - struct pci_dev *i810_dev; + struct agp_bridge_data *bridge; + char *name = "(unknown)"; u8 cap_ptr = 0; - agp_bridge->dev = dev; + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; - /* This shit needs moving into tables/init-routines. */ - switch (dev->device) { + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_82443LX_0: + bridge->driver = &intel_generic_driver; + name = "440LX"; + break; + case PCI_DEVICE_ID_INTEL_82443BX_0: + bridge->driver = &intel_generic_driver; + name = "440BX"; + break; + case PCI_DEVICE_ID_INTEL_82443GX_0: + bridge->driver = &intel_generic_driver; + name = "440GX"; + break; case PCI_DEVICE_ID_INTEL_82810_MC1: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1, NULL); - if (i810_dev == NULL) { - printk(KERN_ERR PFX "Detected an Intel i810," - " but could not find the secondary device.\n"); - return -ENODEV; - } - printk(KERN_INFO PFX "Detected an Intel i810 Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i810_setup (i810_dev); - + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1, "i810")) + goto fail; + bridge->driver = &intel_810_driver; + name = "i810"; + break; case PCI_DEVICE_ID_INTEL_82810_MC3: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, NULL); - if (i810_dev == NULL) { - printk(KERN_ERR PFX "Detected an Intel i810 DC100, but could not find the " - "secondary device.\n"); - return -ENODEV; - } - printk(KERN_INFO PFX "Detected an Intel i810 DC100 Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i810_setup(i810_dev); - + if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3, "i810 DC100")) + goto fail; + bridge->driver = &intel_810_driver; + name = "i810 DC100"; + break; case PCI_DEVICE_ID_INTEL_82810E_MC: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG, NULL); - if (i810_dev == NULL) { - printk(KERN_ERR PFX "Detected an Intel i810 E" - ", but could not find the secondary device.\n"); - return -ENODEV; - } - printk(KERN_INFO PFX "Detected an Intel i810 E Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i810_setup(i810_dev); - + if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG, "i810 E")) + goto fail; + bridge->driver = &intel_810_driver; + name = "i810 E"; + break; case PCI_DEVICE_ID_INTEL_82815_MC: - /* The i815 can operate either as an i810 style + /* + * The i815 can operate either as an i810 style * integrated device, or as an AGP4X motherboard. - * - * This only addresses the first mode: */ - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, NULL); - if (i810_dev == NULL) { - printk(KERN_ERR PFX "agpgart: Detected an " - "Intel i815, but could not find the" - " secondary device. Assuming a " - "non-integrated video card.\n"); - break; - } - printk(KERN_INFO PFX "agpgart: Detected an Intel i815 Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i810_setup(i810_dev); - - case PCI_DEVICE_ID_INTEL_82845G_HB: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82845G_IG, NULL); - if (i810_dev && PCI_FUNC(i810_dev->devfn) != 0) { - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82845G_IG, i810_dev); - } - - if (i810_dev == NULL) { - /* - * We probably have a I845G chipset with an external graphics - * card. It will be initialized later - */ - agp_bridge->type = INTEL_I845_G; - break; - } - printk(KERN_INFO PFX "Detected an Intel(R) 845G Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i830_setup(i810_dev); - + if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC, "i815")) + bridge->driver = &intel_810_driver; + else + bridge->driver = &intel_815_driver; + name = "i815"; + break; + case PCI_DEVICE_ID_INTEL_82820_HB: + case PCI_DEVICE_ID_INTEL_82820_UP_HB: + bridge->driver = &intel_820_driver; + name = "i820"; + break; case PCI_DEVICE_ID_INTEL_82830_HB: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, NULL); - if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, i810_dev); - - if (i810_dev == NULL) { - /* Intel 830MP with external graphic card */ - /* It will be initialized later */ - agp_bridge->type = INTEL_I830_M; - break; + if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) { + bridge->driver = &intel_830_driver; + } else { + bridge->driver = &intel_830mp_driver; } - printk(KERN_INFO PFX "Detected an Intel(R) 830M Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i830_setup(i810_dev); - - case PCI_DEVICE_ID_INTEL_82855_HB: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855_IG, NULL); - if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855_IG, i810_dev); - - if (i810_dev == NULL) { - /* Intel 855PM with external graphic card */ - /* It will be initialized later */ - agp_bridge->type = INTEL_I855_PM; - break; + name = "830M"; + break; + case PCI_DEVICE_ID_INTEL_82840_HB: + bridge->driver = &intel_840_driver; + name = "i840"; + break; + case PCI_DEVICE_ID_INTEL_82845_HB: + bridge->driver = &intel_845_driver; + name = "i845"; + break; + case PCI_DEVICE_ID_INTEL_82845G_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) { + bridge->driver = &intel_830_driver; + } else { + bridge->driver = &intel_845_driver; } - { - u32 capval = 0; - const char *name = "855GM/852GM"; - pci_read_config_dword(dev, I85X_CAPID, &capval); - switch ((capval >> I85X_VARIANT_SHIFT) & - I85X_VARIANT_MASK) { - case I855_GME: - name = "855GME"; - break; - case I855_GM: - name = "855GM"; - break; - case I852_GME: - name = "852GME"; - break; - case I852_GM: - name = "852GM"; - break; - } - printk(KERN_INFO PFX - "Detected an Intel(R) %s Chipset.\n", name); + name = "845G"; + break; + case PCI_DEVICE_ID_INTEL_82850_HB: + bridge->driver = &intel_850_driver; + name = "i850"; + break; + case PCI_DEVICE_ID_INTEL_82855PM_HB: + bridge->driver = &intel_845_driver; + name = "855PM"; + break; + case PCI_DEVICE_ID_INTEL_82855GM_HB: + if (find_i830(PCI_DEVICE_ID_INTEL_82855GM_IG)) { + bridge->driver = &intel_830_driver; + name = "855"; + } else { + bridge->driver = &intel_845_driver; + name = "855GM"; } - agp_bridge->type = INTEL_I810; - return intel_i830_setup(i810_dev); - + break; + case PCI_DEVICE_ID_INTEL_82860_HB: + bridge->driver = &intel_860_driver; + name = "i860"; + break; case PCI_DEVICE_ID_INTEL_82865_HB: - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82865_IG, NULL); - if (i810_dev && PCI_FUNC(i810_dev->devfn) != 0) { - i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82865_IG, i810_dev); - } - - if (i810_dev == NULL) { - /* - * We probably have a 865G chipset with an external graphics - * card. It will be initialized later - */ - agp_bridge->type = INTEL_I865_G; - break; + if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) { + bridge->driver = &intel_830_driver; + } else { + bridge->driver = &intel_845_driver; } - printk(KERN_INFO PFX "Detected an Intel(R) 865G Chipset.\n"); - agp_bridge->type = INTEL_I810; - return intel_i830_setup(i810_dev); - + name = "865"; + break; + case PCI_DEVICE_ID_INTEL_82875_HB: + bridge->driver = &intel_845_driver; + name = "i875"; + break; + case PCI_DEVICE_ID_INTEL_7505_0: + bridge->driver = &intel_7505_driver; + name = "E7505"; + break; + case PCI_DEVICE_ID_INTEL_7205_0: + bridge->driver = &intel_7505_driver; + name = "E7205"; + break; default: + if (!agp_try_unsupported) { + printk(KERN_ERR PFX + "Unsupported Intel chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; + } + bridge->driver = &intel_generic_driver; break; - } + }; - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; - agp_bridge->capndx = cap_ptr; + bridge->dev = pdev; + bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); + if (bridge->driver == &intel_810_driver) + bridge->dev_private_data = &intel_i810_private; + else if (bridge->driver == &intel_830_driver) + bridge->dev_private_data = &intel_i830_private; - /* probe for known chipsets */ - return agp_lookup_host_bridge(dev); -} + printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name); -static struct agp_driver intel_agp_driver = { - .owner = THIS_MODULE, -}; + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); + + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); + fail: + agp_put_bridge(bridge); + return -ENODEV; +} -static int __init agp_intel_probe (struct pci_dev *dev, const struct pci_device_id *ent) +static void __devexit agp_intel_remove(struct pci_dev *pdev) { - if (agp_find_supported_device(dev) == 0) { - intel_agp_driver.dev = dev; - agp_register_driver(&intel_agp_driver); - return 0; - } - return -ENODEV; + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_intel_pci_table[] __initdata = { @@ -1639,29 +1454,24 @@ .name = "agpgart-intel", .id_table = agp_intel_pci_table, .probe = agp_intel_probe, + .remove = agp_intel_remove, }; /* intel_agp_init() must not be declared static for explicit early initialization to work (ie i810fb) */ int __init agp_intel_init(void) { - int ret_val; static int agp_initialised=0; - if (agp_initialised==1) + if (agp_initialised == 1) return 0; agp_initialised=1; - ret_val = pci_module_init(&agp_intel_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_intel_pci_driver); } static void __exit agp_intel_cleanup(void) { - agp_unregister_driver(&intel_agp_driver); pci_unregister_driver(&agp_intel_pci_driver); } diff -Nru a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/agp/nvidia-agp.c Mon May 12 20:55:49 2003 @@ -0,0 +1,380 @@ +/* + * Nvidia AGPGART routines. + * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up + * to work in 2.5 by Dave Jones + */ + +#include +#include +#include +#include +#include +#include +#include +#include "agp.h" + + +/* registers */ +#define NVIDIA_0_APBASE 0x10 +#define NVIDIA_0_APSIZE 0x80 +#define NVIDIA_1_WBC 0xf0 +#define NVIDIA_2_GARTCTRL 0xd0 +#define NVIDIA_2_APBASE 0xd8 +#define NVIDIA_2_APLIMIT 0xdc +#define NVIDIA_2_ATTBASE(i) (0xe0 + (i) * 4) +#define NVIDIA_3_APBASE 0x50 +#define NVIDIA_3_APLIMIT 0x54 + + +static int agp_try_unsupported __initdata = 0; + +static struct _nvidia_private { + struct pci_dev *dev_1; + struct pci_dev *dev_2; + struct pci_dev *dev_3; + volatile u32 *aperture; + int num_active_entries; + off_t pg_offset; + u32 wbc_mask; +} nvidia_private; + + +static int nvidia_fetch_size(void) +{ + int i; + u8 size_value; + struct aper_size_info_8 *values; + + pci_read_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, &size_value); + size_value &= 0x0f; + values = A_SIZE_8(agp_bridge->driver->aperture_sizes); + + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { + if (size_value == values[i].size_value) { + agp_bridge->previous_size = + agp_bridge->current_size = (void *) (values + i); + agp_bridge->aperture_size_idx = i; + return values[i].size; + } + } + + return 0; +} + + +static int nvidia_configure(void) +{ + int i, num_dirs; + u32 apbase, aplimit; + struct aper_size_info_8 *current_size; + u32 temp; + + current_size = A_SIZE_8(agp_bridge->current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, + current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APBASE, &apbase); + apbase &= PCI_BASE_ADDRESS_MEM_MASK; + agp_bridge->gart_bus_addr = apbase; + aplimit = apbase + (current_size->size * 1024 * 1024) - 1; + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase); + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit); + pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase); + pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit); + + /* directory size is 64k */ + num_dirs = current_size->size / 64; + nvidia_private.num_active_entries = current_size->num_entries; + nvidia_private.pg_offset = 0; + if (num_dirs == 0) { + num_dirs = 1; + nvidia_private.num_active_entries /= (64 / current_size->size); + nvidia_private.pg_offset = (apbase & (64 * 1024 * 1024 - 1) & + ~(current_size->size * 1024 * 1024 - 1)) / PAGE_SIZE; + } + + /* attbase */ + for(i = 0; i < 8; i++) { + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_ATTBASE(i), + (agp_bridge->gatt_bus_addr + (i % num_dirs) * 64 * 1024) | 1); + } + + /* gtlb control */ + pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp | 0x11); + + /* gart control */ + pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp); + pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100); + + /* map aperture */ + nvidia_private.aperture = + (volatile u32 *) ioremap(apbase, 33 * PAGE_SIZE); + + return 0; +} + +static void nvidia_cleanup(void) +{ + struct aper_size_info_8 *previous_size; + u32 temp; + + /* gart control */ + pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp); + pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp & ~(0x100)); + + /* gtlb control */ + pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11)); + + /* unmap aperture */ + iounmap((void *) nvidia_private.aperture); + + /* restore previous aperture size */ + previous_size = A_SIZE_8(agp_bridge->previous_size); + pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, + previous_size->size_value); +} + + +static unsigned long nvidia_mask_memory(unsigned long addr, int type) +{ + /* Memory type is ignored */ + return addr | agp_bridge->driver->masks[0].mask; +} + +#if 0 +extern int agp_memory_reserved; + +static int nvidia_insert_memory(agp_memory * mem, off_t pg_start, int type) +{ + int i, j; + + if ((type != 0) || (mem->type != 0)) + return -EINVAL; + + if ((pg_start + mem->page_count) > + (nvidia_private.num_active_entries - agp_memory_reserved/PAGE_SIZE)) + return -EINVAL; + + for(j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[nvidia_private.pg_offset + j])) + return -EBUSY; + } + + if (mem->is_flushed == FALSE) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) + agp_bridge->gatt_table[nvidia_private.pg_offset + j] = mem->memory[i]; + + agp_bridge->tlb_flush(mem); + return 0; +} + +static int nvidia_remove_memory(agp_memory * mem, off_t pg_start, int type) +{ + int i; + + if ((type != 0) || (mem->type != 0)) + return -EINVAL; + + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + agp_bridge->gatt_table[nvidia_private.pg_offset + i] = + (unsigned long) agp_bridge->scratch_page; + } + + agp_bridge->tlb_flush(mem); + return 0; +} +#endif + + +static void nvidia_tlbflush(agp_memory * mem) +{ + unsigned long end; + u32 wbc_reg, temp; + int i; + + /* flush chipset */ + if (nvidia_private.wbc_mask) { + pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg); + wbc_reg |= nvidia_private.wbc_mask; + pci_write_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, wbc_reg); + + end = jiffies + 3*HZ; + do { + pci_read_config_dword(nvidia_private.dev_1, + NVIDIA_1_WBC, &wbc_reg); + if ((signed)(end - jiffies) <= 0) { + printk(KERN_ERR + "TLB flush took more than 3 seconds.\n"); + } + } while (wbc_reg & nvidia_private.wbc_mask); + } + + /* flush TLB entries */ + for(i = 0; i < 32 + 1; i++) + temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; + for(i = 0; i < 32 + 1; i++) + temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)]; +} + + +static struct aper_size_info_8 nvidia_generic_sizes[5] = +{ + {512, 131072, 7, 0}, + {256, 65536, 6, 8}, + {128, 32768, 5, 12}, + {64, 16384, 4, 14}, + /* The 32M mode still requires a 64k gatt */ + {32, 16384, 4, 15} +}; + + +static struct gatt_mask nvidia_generic_masks[] = +{ + {0x00000001, 0} +}; + + +struct agp_bridge_driver nvidia_driver = { + .owner = THIS_MODULE, + .masks = nvidia_generic_masks, + .aperture_sizes = nvidia_generic_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 5, + .configure = nvidia_configure, + .fetch_size = nvidia_fetch_size, + .cleanup = nvidia_cleanup, + .tlb_flush = nvidia_tlbflush, + .mask_memory = nvidia_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + +static int __init agp_nvidia_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct agp_bridge_data *bridge; + u8 cap_ptr; + + nvidia_private.dev_1 = + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); + nvidia_private.dev_2 = + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); + nvidia_private.dev_3 = + pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); + + if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { + printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " + "nForce/nForce2 chipset, but could not find " + "the secondary devices.\n"); + return -ENODEV; + } + + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; + + switch (pdev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE: + printk(KERN_INFO PFX "Detected NVIDIA nForce chipset\n"); + nvidia_private.wbc_mask = 0x00010000; + break; + case PCI_DEVICE_ID_NVIDIA_NFORCE2: + printk(KERN_INFO PFX "Detected NVIDIA nForce2 chipset\n"); + nvidia_private.wbc_mask = 0x80000000; + break; + default: + if (!agp_try_unsupported) { + printk(KERN_ERR PFX + "Unsupported NVIDIA chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; + } + printk(KERN_WARNING PFX + "Trying generic NVIDIA routines for device id: %04x\n", + pdev->device); + break; + } + + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + bridge->driver = &nvidia_driver; + bridge->dev_private_data = &nvidia_private, + bridge->dev = pdev; + bridge->capndx = cap_ptr; + + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); + + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} + +static void __devexit agp_nvidia_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); +} + +static struct pci_device_id agp_nvidia_pci_table[] __initdata = { + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { } +}; + +MODULE_DEVICE_TABLE(pci, agp_nvidia_pci_table); + +static struct __initdata pci_driver agp_nvidia_pci_driver = { + .name = "agpgart-nvidia", + .id_table = agp_nvidia_pci_table, + .probe = agp_nvidia_probe, + .remove = agp_nvidia_remove, +}; + +static int __init agp_nvidia_init(void) +{ + return pci_module_init(&agp_nvidia_pci_driver); +} + +static void __exit agp_nvidia_cleanup(void) +{ + pci_unregister_driver(&agp_nvidia_pci_driver); +} + +module_init(agp_nvidia_init); +module_exit(agp_nvidia_cleanup); + +MODULE_PARM(agp_try_unsupported, "1i"); +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("NVIDIA Corporation"); + diff -Nru a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c --- a/drivers/char/agp/sis-agp.c Mon May 12 20:55:44 2003 +++ b/drivers/char/agp/sis-agp.c Mon May 12 20:55:44 2003 @@ -17,8 +17,8 @@ struct aper_size_info_8 *values; pci_read_config_byte(agp_bridge->dev, SIS_APSIZE, &temp_size); - values = A_SIZE_8(agp_bridge->aperture_sizes); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + values = A_SIZE_8(agp_bridge->driver->aperture_sizes); + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if ((temp_size == values[i].size_value) || ((temp_size & ~(0x03)) == (values[i].size_value & ~(0x03)))) { @@ -67,7 +67,7 @@ { /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } static struct aper_size_info_8 sis_generic_sizes[7] = @@ -86,164 +86,144 @@ {.mask = 0x00000000, .type = 0} }; -static int __init sis_generic_setup (struct pci_dev *pdev) -{ - agp_bridge->masks = sis_generic_masks; - agp_bridge->aperture_sizes = (void *) sis_generic_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = sis_configure; - agp_bridge->fetch_size = sis_fetch_size; - agp_bridge->cleanup = sis_cleanup; - agp_bridge->tlb_flush = sis_tlbflush; - agp_bridge->mask_memory = sis_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - - return 0; -} +struct agp_bridge_driver sis_driver = { + .owner = THIS_MODULE, + .masks = sis_generic_masks, + .aperture_sizes = sis_generic_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = sis_configure, + .fetch_size = sis_fetch_size, + .cleanup = sis_cleanup, + .tlb_flush = sis_tlbflush, + .mask_memory = sis_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; struct agp_device_ids sis_agp_device_ids[] __initdata = { { .device_id = PCI_DEVICE_ID_SI_740, - .chipset = SIS_GENERIC, .chipset_name = "740", }, { .device_id = PCI_DEVICE_ID_SI_650, - .chipset = SIS_GENERIC, .chipset_name = "650", }, { .device_id = PCI_DEVICE_ID_SI_651, - .chipset = SIS_GENERIC, .chipset_name = "651", }, { .device_id = PCI_DEVICE_ID_SI_645, - .chipset = SIS_GENERIC, .chipset_name = "645", }, { .device_id = PCI_DEVICE_ID_SI_646, - .chipset = SIS_GENERIC, .chipset_name = "646", }, { .device_id = PCI_DEVICE_ID_SI_735, - .chipset = SIS_GENERIC, .chipset_name = "735", }, { .device_id = PCI_DEVICE_ID_SI_745, - .chipset = SIS_GENERIC, .chipset_name = "745", }, { .device_id = PCI_DEVICE_ID_SI_730, - .chipset = SIS_GENERIC, .chipset_name = "730", }, { .device_id = PCI_DEVICE_ID_SI_630, - .chipset = SIS_GENERIC, .chipset_name = "630", }, { .device_id = PCI_DEVICE_ID_SI_540, - .chipset = SIS_GENERIC, .chipset_name = "540", }, { .device_id = PCI_DEVICE_ID_SI_620, - .chipset = SIS_GENERIC, .chipset_name = "620", }, { .device_id = PCI_DEVICE_ID_SI_530, - .chipset = SIS_GENERIC, .chipset_name = "530", }, { .device_id = PCI_DEVICE_ID_SI_550, - .chipset = SIS_GENERIC, .chipset_name = "550", }, { }, /* dummy final entry, always present */ }; -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +static int __init agp_sis_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int j=0; - struct agp_device_ids *devs; - - devs = sis_agp_device_ids; + struct agp_device_ids *devs = sis_agp_device_ids; + struct agp_bridge_data *bridge; + u8 cap_ptr; + int j; - while (devs[j].chipset_name != NULL) { + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; + + /* probe for known chipsets */ + for (j = 0; devs[j].chipset_name; j++) { if (pdev->device == devs[j].device_id) { - printk (KERN_INFO PFX "Detected SiS %s chipset\n", - devs[j].chipset_name); - agp_bridge->type = devs[j].chipset; - - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return sis_generic_setup(pdev); + printk(KERN_INFO PFX "Detected SiS %s chipset\n", + devs[j].chipset_name); + goto found; } - j++; } - /* try init anyway, if user requests it */ - if (agp_try_unsupported) { - printk(KERN_WARNING PFX "Trying generic SiS routines" - " for device id: %04x\n", pdev->device); - agp_bridge->type = SIS_GENERIC; - return sis_generic_setup(pdev); + if (!agp_try_unsupported) { + printk(KERN_ERR PFX + "Unsupported SiS chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; } - printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)," - " you might want to try agp_try_unsupported=1.\n", pdev->device); - return -ENODEV; -} + printk(KERN_WARNING PFX "Trying generic SiS routines" + " for device id: %04x\n", pdev->device); -static struct agp_driver sis_agp_driver = { - .owner = THIS_MODULE, -}; +found: + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; -static int __init agp_sis_probe (struct pci_dev *dev, const struct pci_device_id *ent) -{ - u8 cap_ptr = 0; + bridge->driver = &sis_driver; + bridge->dev = pdev; + bridge->capndx = cap_ptr; - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, + &bridge->mode); - /* probe for known chipsets */ - if (agp_lookup_host_bridge(dev) != -ENODEV) { - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - sis_agp_driver.dev = dev; - agp_register_driver(&sis_agp_driver); - return 0; - } - return -ENODEV; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); +} + +static void __devexit agp_sis_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_sis_pci_table[] __initdata = { @@ -264,22 +244,16 @@ .name = "agpgart-sis", .id_table = agp_sis_pci_table, .probe = agp_sis_probe, + .remove = agp_sis_remove, }; static int __init agp_sis_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_sis_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_sis_pci_driver); } static void __exit agp_sis_cleanup(void) { - agp_unregister_driver(&sis_agp_driver); pci_unregister_driver(&agp_sis_pci_driver); } diff -Nru a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c --- a/drivers/char/agp/sworks-agp.c Mon May 12 20:55:46 2003 +++ b/drivers/char/agp/sworks-agp.c Mon May 12 20:55:46 2003 @@ -35,7 +35,7 @@ return -ENOMEM; } SetPageReserved(virt_to_page(page_map->real)); - CACHE_FLUSH(); + global_cache_flush(); page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { @@ -44,7 +44,7 @@ page_map->real = NULL; return -ENOMEM; } - CACHE_FLUSH(); + global_cache_flush(); for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { page_map->remapped[i] = agp_bridge->scratch_page; @@ -203,7 +203,7 @@ u32 temp2; struct aper_size_info_lvl2 *values; - values = A_SIZE_LVL2(agp_bridge->aperture_sizes); + values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes); pci_read_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp); pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs, SVWRKS_SIZE_MASK); @@ -211,7 +211,7 @@ pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,temp); temp2 &= SVWRKS_SIZE_MASK; - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp2 == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -224,6 +224,37 @@ return 0; } +/* + * This routine could be implemented by taking the addresses + * written to the GATT, and flushing them individually. However + * currently it just flushes the whole table. Which is probably + * more efficent, since agp_memory blocks can be a large number of + * entries. + */ +static void serverworks_tlbflush(agp_memory * temp) +{ + unsigned long end; + + OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); + end = jiffies + 3*HZ; + while(INREG8(serverworks_private.registers, + SVWRKS_POSTFLUSH) == 0x01) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "Posted write buffer flush took more" + "then 3 seconds\n"); + } + } + OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); + end = jiffies + 3*HZ; + while(INREG32(serverworks_private.registers, + SVWRKS_DIRFLUSH) == 0x00000001) { + if((signed)(end - jiffies) <= 0) { + printk(KERN_ERR "TLB flush took more" + "then 3 seconds\n"); + } + } +} + static int serverworks_configure(void) { struct aper_size_info_lvl2 *current_size; @@ -253,7 +284,7 @@ enable_reg |= 0x1; /* Agp Enable bit */ pci_write_config_byte(serverworks_private.svrwrks_dev, SVWRKS_AGP_ENABLE, enable_reg); - agp_bridge->tlb_flush(NULL); + serverworks_tlbflush(NULL); agp_bridge->capndx = pci_find_capability(serverworks_private.svrwrks_dev, PCI_CAP_ID_AGP); @@ -277,43 +308,11 @@ iounmap((void *) serverworks_private.registers); } -/* - * This routine could be implemented by taking the addresses - * written to the GATT, and flushing them individually. However - * currently it just flushes the whole table. Which is probably - * more efficent, since agp_memory blocks can be a large number of - * entries. - */ - -static void serverworks_tlbflush(agp_memory * temp) -{ - unsigned long end; - - OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01); - end = jiffies + 3*HZ; - while(INREG8(serverworks_private.registers, - SVWRKS_POSTFLUSH) == 0x01) { - if((signed)(end - jiffies) <= 0) { - printk(KERN_ERR "Posted write buffer flush took more" - "then 3 seconds\n"); - } - } - OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001); - end = jiffies + 3*HZ; - while(INREG32(serverworks_private.registers, - SVWRKS_DIRFLUSH) == 0x00000001) { - if((signed)(end - jiffies) <= 0) { - printk(KERN_ERR "TLB flush took more" - "then 3 seconds\n"); - } - } -} - static unsigned long serverworks_mask_memory(unsigned long addr, int type) { /* Only type 0 is supported by the serverworks chipsets */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } static int serverworks_insert_memory(agp_memory * mem, @@ -336,14 +335,14 @@ while (j < (pg_start + mem->page_count)) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) { return -EBUSY; } j++; } if (mem->is_flushed == FALSE) { - CACHE_FLUSH(); + global_cache_flush(); mem->is_flushed = TRUE; } @@ -351,9 +350,9 @@ addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); cur_gatt[GET_GATT_OFF(addr)] = - agp_bridge->mask_memory(mem->memory[i], mem->type); + agp_bridge->driver->mask_memory(mem->memory[i], mem->type); } - agp_bridge->tlb_flush(mem); + serverworks_tlbflush(mem); return 0; } @@ -368,8 +367,8 @@ return -EINVAL; } - CACHE_FLUSH(); - agp_bridge->tlb_flush(mem); + global_cache_flush(); + serverworks_tlbflush(mem); for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; @@ -378,7 +377,7 @@ (unsigned long) agp_bridge->scratch_page; } - agp_bridge->tlb_flush(mem); + serverworks_tlbflush(mem); return 0; } @@ -420,123 +419,103 @@ agp_device_command(command, 0); } -static int __init serverworks_setup (struct pci_dev *pdev) +struct agp_bridge_driver sworks_driver = { + .owner = THIS_MODULE, + .masks = serverworks_masks, + .aperture_sizes = serverworks_sizes, + .size_type = LVL2_APER_SIZE, + .num_aperture_sizes = 7, + .configure = serverworks_configure, + .fetch_size = serverworks_fetch_size, + .cleanup = serverworks_cleanup, + .tlb_flush = serverworks_tlbflush, + .mask_memory = serverworks_mask_memory, + .agp_enable = serverworks_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = serverworks_create_gatt_table, + .free_gatt_table = serverworks_free_gatt_table, + .insert_memory = serverworks_insert_memory, + .remove_memory = serverworks_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; + +static int __init agp_serverworks_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - u32 temp; - u32 temp2; + struct agp_bridge_data *bridge; + struct pci_dev *bridge_dev; + u32 temp, temp2; - serverworks_private.svrwrks_dev = pdev; + /* Everything is on func 1 here so we are hardcoding function one */ + bridge_dev = pci_find_slot((unsigned int)pdev->bus->number, + PCI_DEVFN(0, 1)); + if (!bridge_dev) { + printk(KERN_INFO PFX "agpgart: Detected a Serverworks " + "Chipset, but could not find the secondary " + "device.\n"); + return -ENODEV; + } - agp_bridge->masks = serverworks_masks; - agp_bridge->aperture_sizes = (void *) serverworks_sizes; - agp_bridge->size_type = LVL2_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = (void *) &serverworks_private; - agp_bridge->needs_scratch_page = TRUE; - agp_bridge->configure = serverworks_configure; - agp_bridge->fetch_size = serverworks_fetch_size; - agp_bridge->cleanup = serverworks_cleanup; - agp_bridge->tlb_flush = serverworks_tlbflush; - agp_bridge->mask_memory = serverworks_mask_memory; - agp_bridge->agp_enable = serverworks_agp_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = serverworks_create_gatt_table; - agp_bridge->free_gatt_table = serverworks_free_gatt_table; - agp_bridge->insert_memory = serverworks_insert_memory; - agp_bridge->remove_memory = serverworks_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - - pci_read_config_dword(agp_bridge->dev, - SVWRKS_APSIZE, - &temp); + switch (pdev->device) { + case PCI_DEVICE_ID_SERVERWORKS_HE: + case PCI_DEVICE_ID_SERVERWORKS_LE: + case 0x0007: + break; + default: + if (!agp_try_unsupported) + return -ENODEV; + break; + } + serverworks_private.svrwrks_dev = bridge_dev; serverworks_private.gart_addr_ofs = 0x10; - - if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(agp_bridge->dev, - SVWRKS_APSIZE + 4, - &temp2); - if(temp2 != 0) { + + pci_read_config_dword(pdev, SVWRKS_APSIZE, &temp); + if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(pdev, SVWRKS_APSIZE + 4, &temp2); + if (temp2 != 0) { printk("Detected 64 bit aperture address, but top " "bits are not zero. Disabling agp\n"); return -ENODEV; } serverworks_private.mm_addr_ofs = 0x18; - } else { + } else serverworks_private.mm_addr_ofs = 0x14; - } - pci_read_config_dword(agp_bridge->dev, - serverworks_private.mm_addr_ofs, - &temp); - if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(agp_bridge->dev, - serverworks_private.mm_addr_ofs + 4, - &temp2); - if(temp2 != 0) { + pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs, &temp); + if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_read_config_dword(pdev, + serverworks_private.mm_addr_ofs + 4, &temp2); + if (temp2 != 0) { printk("Detected 64 bit MMIO address, but top " "bits are not zero. Disabling agp\n"); return -ENODEV; } } - return 0; -} - - -static int __init agp_find_supported_device(struct pci_dev *dev) -{ - struct pci_dev *bridge_dev; - - /* Everything is on func 1 here so we are hardcoding function one */ - bridge_dev = pci_find_slot ((unsigned int)dev->bus->number, PCI_DEVFN(0, 1)); - if(bridge_dev == NULL) { - printk(KERN_INFO PFX "agpgart: Detected a Serverworks " - "Chipset, but could not find the secondary " - "device.\n"); - return -ENODEV; - } - - agp_bridge->dev = dev; - - switch (dev->device) { - case PCI_DEVICE_ID_SERVERWORKS_HE: - agp_bridge->type = SVWRKS_HE; - return serverworks_setup(bridge_dev); + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; - case PCI_DEVICE_ID_SERVERWORKS_LE: - case 0x0007: - agp_bridge->type = SVWRKS_LE; - return serverworks_setup(bridge_dev); + bridge->driver = &sworks_driver; + bridge->dev_private_data = &serverworks_private, + bridge->dev = pdev; - default: - if(agp_try_unsupported) { - agp_bridge->type = SVWRKS_GENERIC; - return serverworks_setup(bridge_dev); - } - break; - } - return -ENODEV; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); } -static struct agp_driver serverworks_agp_driver = { - .owner = THIS_MODULE, -}; - -static int __init agp_serverworks_probe (struct pci_dev *dev, const struct pci_device_id *ent) +static void __devexit agp_serverworks_remove(struct pci_dev *pdev) { - if (agp_find_supported_device(dev) == 0) { - serverworks_agp_driver.dev = dev; - agp_register_driver(&serverworks_agp_driver); - return 0; - } - return -ENODEV; + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); } static struct pci_device_id agp_serverworks_pci_table[] __initdata = { @@ -557,22 +536,16 @@ .name = "agpgart-serverworks", .id_table = agp_serverworks_pci_table, .probe = agp_serverworks_probe, + .remove = agp_serverworks_remove, }; static int __init agp_serverworks_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_serverworks_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_serverworks_pci_driver); } static void __exit agp_serverworks_cleanup(void) { - agp_unregister_driver(&serverworks_agp_driver); pci_unregister_driver(&agp_serverworks_pci_driver); } diff -Nru a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c --- a/drivers/char/agp/via-agp.c Mon May 12 20:55:48 2003 +++ b/drivers/char/agp/via-agp.c Mon May 12 20:55:48 2003 @@ -18,9 +18,9 @@ u8 temp; struct aper_size_info_8 *values; - values = A_SIZE_8(agp_bridge->aperture_sizes); + values = A_SIZE_8(agp_bridge->driver->aperture_sizes); pci_read_config_byte(agp_bridge->dev, VIA_APSIZE, &temp); - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -79,7 +79,7 @@ { /* Memory type is ignored */ - return addr | agp_bridge->masks[0].mask; + return addr | agp_bridge->driver->masks[0].mask; } @@ -107,11 +107,11 @@ u16 temp; struct aper_size_info_16 *values; - values = A_SIZE_16(agp_bridge->aperture_sizes); + values = A_SIZE_16(agp_bridge->driver->aperture_sizes); pci_read_config_word(agp_bridge->dev, VIA_AGP3_APSIZE, &temp); temp &= 0xfff; - for (i = 0; i < agp_bridge->num_aperture_sizes; i++) { + for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); @@ -174,99 +174,55 @@ { 2048, 524288, 9, 1<<11} /* 2GB <- Max supported */ }; +struct agp_bridge_driver via_agp3_driver = { + .owner = THIS_MODULE, + .masks = via_generic_masks, + .aperture_sizes = via_generic_agp3_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 10, + .configure = via_configure_agp3, + .fetch_size = via_fetch_size_agp3, + .cleanup = via_cleanup_agp3, + .tlb_flush = via_tlbflush_agp3, + .mask_memory = via_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; -static int __init via_generic_agp3_setup (struct pci_dev *pdev) -{ - agp_bridge->dev = pdev; - agp_bridge->type = VIA_GENERIC; - agp_bridge->masks = via_generic_masks; - agp_bridge->aperture_sizes = (void *) via_generic_agp3_sizes; - agp_bridge->size_type = U16_APER_SIZE; - agp_bridge->num_aperture_sizes = 10; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->configure = via_configure_agp3; - agp_bridge->fetch_size = via_fetch_size_agp3; - agp_bridge->cleanup = via_cleanup_agp3; - agp_bridge->tlb_flush = via_tlbflush_agp3; - agp_bridge->mask_memory = via_mask_memory; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} - - -static int __init via_generic_setup (struct pci_dev *pdev) -{ - /* Garg, there are KT400s with KT266 IDs. */ - if (pdev->device == PCI_DEVICE_ID_VIA_8367_0) { - - /* Is there a KT400 subsystem ? */ - if (pdev->subsystem_device==PCI_DEVICE_ID_VIA_8377_0) { - u8 reg; - - printk (KERN_INFO PFX "Found KT400 in disguise as a KT266.\n"); - - /* Check AGP compatibility mode. */ - pci_read_config_byte(pdev, VIA_AGPSEL, ®); - if ((reg & (1<<1))==0) - return via_generic_agp3_setup(pdev); - - /* Its in 2.0 mode, drop through. */ - } - } - - agp_bridge->masks = via_generic_masks; - agp_bridge->aperture_sizes = (void *) via_generic_sizes; - agp_bridge->size_type = U8_APER_SIZE; - agp_bridge->num_aperture_sizes = 7; - agp_bridge->dev_private_data = NULL; - agp_bridge->needs_scratch_page = FALSE; - agp_bridge->configure = via_configure; - agp_bridge->fetch_size = via_fetch_size; - agp_bridge->cleanup = via_cleanup; - agp_bridge->tlb_flush = via_tlbflush; - agp_bridge->mask_memory = via_mask_memory; - agp_bridge->agp_enable = agp_generic_enable; - agp_bridge->cache_flush = global_cache_flush; - agp_bridge->create_gatt_table = agp_generic_create_gatt_table; - agp_bridge->free_gatt_table = agp_generic_free_gatt_table; - agp_bridge->insert_memory = agp_generic_insert_memory; - agp_bridge->remove_memory = agp_generic_remove_memory; - agp_bridge->alloc_by_type = agp_generic_alloc_by_type; - agp_bridge->free_by_type = agp_generic_free_by_type; - agp_bridge->agp_alloc_page = agp_generic_alloc_page; - agp_bridge->agp_destroy_page = agp_generic_destroy_page; - agp_bridge->suspend = agp_generic_suspend; - agp_bridge->resume = agp_generic_resume; - agp_bridge->cant_use_aperture = 0; - return 0; -} - - -/* The KT400 does magick to put the AGP bridge compliant with the same - * standards version as the graphics card. */ -static int __init via_kt400_setup(struct pci_dev *pdev) -{ - u8 reg; - pci_read_config_byte(pdev, VIA_AGPSEL, ®); - /* Check AGP 2.0 compatibility mode. */ - if ((reg & (1<<1))==0) - return via_generic_agp3_setup(pdev); - return via_generic_setup(pdev); -} - +struct agp_bridge_driver via_driver = { + .owner = THIS_MODULE, + .masks = via_generic_masks, + .aperture_sizes = via_generic_sizes, + .size_type = U8_APER_SIZE, + .num_aperture_sizes = 7, + .configure = via_configure, + .fetch_size = via_fetch_size, + .cleanup = via_cleanup, + .tlb_flush = via_tlbflush, + .mask_memory = via_mask_memory, + .agp_enable = agp_generic_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = agp_generic_create_gatt_table, + .free_gatt_table = agp_generic_free_gatt_table, + .insert_memory = agp_generic_insert_memory, + .remove_memory = agp_generic_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .suspend = agp_generic_suspend, + .resume = agp_generic_resume, +}; static struct agp_device_ids via_agp_device_ids[] __initdata = { @@ -310,7 +266,7 @@ /* VT8361 */ { - .device_id = PCI_DEVICE_ID_VIA_8361, // 0x3112 + .device_id = PCI_DEVICE_ID_VIA_8361, .chipset_name = "Apollo KLE133", }, @@ -353,7 +309,6 @@ { .device_id = PCI_DEVICE_ID_VIA_8377_0, .chipset_name = "Apollo Pro KT400", - .chipset_setup = via_kt400_setup, }, /* VT8604 / VT8605 / VT8603 / TwisterT @@ -402,74 +357,99 @@ /* P4M400 */ { .device_id = PCI_DEVICE_ID_VIA_P4M400, - .chipset_name = "PM400", + .chipset_name = "P4M400", }, { }, /* dummy final entry, always present */ }; - -/* scan table above for supported devices */ -static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +static int __init agp_via_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int j=0; - struct agp_device_ids *devs; - - devs = via_agp_device_ids; + struct agp_device_ids *devs = via_agp_device_ids; + struct agp_bridge_data *bridge; + int j = 0; + u8 cap_ptr, reg; - while (devs[j].chipset_name != NULL) { - if (pdev->device == devs[j].device_id) { - printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name); - agp_bridge->type = VIA_GENERIC; + cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); + if (!cap_ptr) + return -ENODEV; - if (devs[j].chipset_setup != NULL) - return devs[j].chipset_setup(pdev); - else - return via_generic_setup(pdev); + /* probe for known chipsets */ + for (j = 0; devs[j].chipset_name; j++) { + if (pdev->device == devs[j].device_id) { + printk (KERN_INFO PFX "Detected VIA %s chipset\n", + devs[j].chipset_name); + goto found; } - j++; } - /* try init anyway, if user requests it */ if (agp_try_unsupported) { - printk(KERN_WARNING PFX "Trying generic VIA routines" - " for device id: %04x\n", pdev->device); - agp_bridge->type = VIA_GENERIC; - return via_generic_setup(pdev); + printk(KERN_ERR PFX + "Unsupported VIA chipset (device id: %04x)," + " you might want to try agp_try_unsupported=1.\n", + pdev->device); + return -ENODEV; } - printk(KERN_ERR PFX "Unsupported VIA chipset (device id: %04x)," - " you might want to try agp_try_unsupported=1.\n", pdev->device); - return -ENODEV; -} + printk(KERN_WARNING PFX "Trying generic VIA routines" + " for device id: %04x\n", pdev->device); - -static struct agp_driver via_agp_driver = { - .owner = THIS_MODULE, -}; +found: + bridge = agp_alloc_bridge(); + if (!bridge) + return -ENOMEM; + + bridge->dev = pdev; + bridge->capndx = cap_ptr; + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_8367_0: + /* + * Garg, there are KT400s with KT266 IDs. + */ + /* Is there a KT400 subsystem ? */ + if (pdev->subsystem_device != PCI_DEVICE_ID_VIA_8377_0) + break; + + printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n"); + /*FALLTHROUGH*/ + case PCI_DEVICE_ID_VIA_8377_0: + /* + * The KT400 does magick to put the AGP bridge compliant + * with the same standards version as the graphics card. + */ + pci_read_config_byte(pdev, VIA_AGPSEL, ®); + /* Check AGP 2.0 compatibility mode. */ + if ((reg & (1<<1))==0) { + bridge->driver = &via_agp3_driver; + break; + } + /*FALLTHROUGH*/ + default: + bridge->driver = &via_driver; + break; + } -static int __init agp_via_probe (struct pci_dev *dev, const struct pci_device_id *ent) -{ - u8 cap_ptr = 0; + bridge->dev = pdev; + bridge->capndx = cap_ptr; - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - if (cap_ptr == 0) - return -ENODEV; + /* Fill in the mode register */ + pci_read_config_dword(pdev, + bridge->capndx+PCI_AGP_STATUS, &bridge->mode); - /* probe for known chipsets */ - if (agp_lookup_host_bridge (dev) != -ENODEV) { - agp_bridge->dev = dev; - agp_bridge->capndx = cap_ptr; - /* Fill in the mode register */ - pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode); - via_agp_driver.dev = dev; - agp_register_driver(&via_agp_driver); - return 0; - } - return -ENODEV; + pci_set_drvdata(pdev, bridge); + return agp_add_bridge(bridge); } +static void __devexit agp_via_remove(struct pci_dev *pdev) +{ + struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + + agp_remove_bridge(bridge); + agp_put_bridge(bridge); +} static struct pci_device_id agp_via_pci_table[] __initdata = { { @@ -490,27 +470,19 @@ .name = "agpgart-via", .id_table = agp_via_pci_table, .probe = agp_via_probe, + .remove = agp_via_remove, }; static int __init agp_via_init(void) { - int ret_val; - - ret_val = pci_module_init(&agp_via_pci_driver); - if (ret_val) - agp_bridge->type = NOT_SUPPORTED; - - return ret_val; + return pci_module_init(&agp_via_pci_driver); } - static void __exit agp_via_cleanup(void) { - agp_unregister_driver(&via_agp_driver); pci_unregister_driver(&agp_via_pci_driver); } - module_init(agp_via_init); module_exit(agp_via_cleanup); diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c --- a/drivers/char/amiserial.c Mon May 12 20:55:49 2003 +++ b/drivers/char/amiserial.c Mon May 12 20:55:49 2003 @@ -1528,7 +1528,6 @@ if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); - MOD_DEC_USE_COUNT; local_irq_restore(flags); return; } @@ -1555,7 +1554,6 @@ } if (state->count) { DBG_CNT("before DEC-2"); - MOD_DEC_USE_COUNT; local_irq_restore(flags); return; } @@ -1615,7 +1613,6 @@ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; local_irq_restore(flags); } @@ -1894,15 +1891,12 @@ int retval, line; unsigned long page; - MOD_INC_USE_COUNT; line = tty->index; if ((line < 0) || (line >= NR_PORTS)) { - MOD_DEC_USE_COUNT; return -ENODEV; } retval = get_async_struct(line, &info); if (retval) { - MOD_DEC_USE_COUNT; return retval; } tty->driver_data = info; @@ -2116,6 +2110,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.owner = THIS_MODULE; serial_driver.driver_name = "amiserial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c --- a/drivers/char/cyclades.c Mon May 12 20:55:45 2003 +++ b/drivers/char/cyclades.c Mon May 12 20:55:45 2003 @@ -2579,15 +2579,12 @@ int retval, line; unsigned long page; - MOD_INC_USE_COUNT; line = tty->index; if ((line < 0) || (NR_PORTS <= line)){ - MOD_DEC_USE_COUNT; return -ENODEV; } info = &cy_port[line]; if (info->line < 0){ - MOD_DEC_USE_COUNT; return -ENODEV; } @@ -2607,7 +2604,6 @@ } else { printk("cyc:Cyclades-Z firmware not yet loaded\n"); } - MOD_DEC_USE_COUNT; return -ENODEV; } #ifdef CONFIG_CYZ_INTR @@ -2803,7 +2799,6 @@ CY_LOCK(info, flags); /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; CY_UNLOCK(info, flags); return; } @@ -2834,7 +2829,6 @@ info->count = 0; } if (info->count) { - MOD_DEC_USE_COUNT; CY_UNLOCK(info, flags); return; } @@ -2931,7 +2925,6 @@ printk(" cyc:cy_close done\n"); #endif - MOD_DEC_USE_COUNT; CY_UNLOCK(info, flags); return; } /* cy_close */ @@ -5494,6 +5487,7 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; + cy_serial_driver.owner = THIS_MODULE; cy_serial_driver.driver_name = "cyclades"; cy_serial_driver.name = "ttyC"; cy_serial_driver.major = CYCLADES_MAJOR; diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h --- a/drivers/char/drm/drm_drv.h Mon May 12 20:55:48 2003 +++ b/drivers/char/drm/drm_drv.h Mon May 12 20:55:48 2003 @@ -334,7 +334,6 @@ dev->last_context = 0; dev->last_switch = 0; dev->last_checked = 0; - init_timer( &dev->timer ); init_waitqueue_head( &dev->context_wait ); dev->ctx_start = 0; @@ -590,6 +589,7 @@ dev = &(DRM(device)[i]); memset( (void *)dev, 0, sizeof(*dev) ); dev->count_lock = SPIN_LOCK_UNLOCKED; + init_timer( &dev->timer ); sema_init( &dev->struct_sem, 1 ); if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c --- a/drivers/char/drm/radeon_cp.c Mon May 12 20:55:45 2003 +++ b/drivers/char/drm/radeon_cp.c Mon May 12 20:55:45 2003 @@ -903,8 +903,8 @@ RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]); - DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", - entry->busaddr[page_ofs], + DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", + (unsigned long) entry->busaddr[page_ofs], entry->handle + tmp_ofs ); } diff -Nru a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c --- a/drivers/char/dsp56k.c Mon May 12 20:55:46 2003 +++ b/drivers/char/dsp56k.c Mon May 12 20:55:46 2003 @@ -512,10 +512,9 @@ printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT, - DSP56K_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &dsp56k_fops, NULL); + + devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), + S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); printk(banner); return 0; diff -Nru a/drivers/char/dtlk.c b/drivers/char/dtlk.c --- a/drivers/char/dtlk.c Mon May 12 20:55:46 2003 +++ b/drivers/char/dtlk.c Mon May 12 20:55:46 2003 @@ -345,10 +345,9 @@ } if (dtlk_dev_probe() == 0) printk(", MAJOR %d\n", dtlk_major); - devfs_register(NULL, "dtlk", DEVFS_FL_DEFAULT, - dtlk_major, DTLK_MINOR, - S_IFCHR | S_IRUSR | S_IWUSR, - &dtlk_fops, NULL); + + devfs_mk_cdev(MKDEV(dtlk_major, DTLK_MINOR), + S_IFCHR | S_IRUSR | S_IWUSR, "dtlk"); init_timer(&dtlk_timer); dtlk_timer.function = dtlk_timer_tick; diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c --- a/drivers/char/dz.c Mon May 12 20:55:44 2003 +++ b/drivers/char/dz.c Mon May 12 20:55:44 2003 @@ -1332,6 +1332,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.owner = THIS_MODULE; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "ttyS"; #else @@ -1425,8 +1426,8 @@ printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, SERIAL); - tty_register_device(&serial_driver, info->line); - tty_register_device(&callout_driver, info->line); + tty_register_device(&serial_driver, info->line, NULL); + tty_register_device(&callout_driver, info->line, NULL); } /* Reset the chip */ diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c --- a/drivers/char/esp.c Mon May 12 20:55:44 2003 +++ b/drivers/char/esp.c Mon May 12 20:55:44 2003 @@ -643,9 +643,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - MOD_INC_USE_COUNT; - if (schedule_task(&info->tqueue_hangup) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&info->tqueue_hangup); } } } @@ -811,7 +809,6 @@ tty = info->tty; if (tty) tty_hangup(tty); - MOD_DEC_USE_COUNT; } /* @@ -2132,7 +2129,7 @@ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); -out: MOD_DEC_USE_COUNT; +out: restore_flags(flags); } @@ -2375,7 +2372,6 @@ #ifdef SERIAL_DEBUG_OPEN printk("esp_open %s, count = %d\n", tty->name, info->count); #endif - MOD_INC_USE_COUNT; info->count++; tty->driver_data = info; info->tty = tty; @@ -2551,6 +2547,7 @@ memset(&esp_driver, 0, sizeof(struct tty_driver)); esp_driver.magic = TTY_DRIVER_MAGIC; + esp_driver.owner = THIS_MODULE; esp_driver.name = "ttyP"; esp_driver.major = ESP_IN_MAJOR; esp_driver.minor_start = 0; diff -Nru a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c --- a/drivers/char/ftape/zftape/zftape-init.c Mon May 12 20:55:46 2003 +++ b/drivers/char/ftape/zftape/zftape-init.c Mon May 12 20:55:46 2003 @@ -342,38 +342,24 @@ TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); for (i = 0; i < 4; i++) { - char devname[9]; - - sprintf (devname, "qft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i, - S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); - sprintf (devname, "nqft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i + 4, - S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); - sprintf (devname, "zqft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i + 16, - S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); - sprintf (devname, "nzqft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i + 20, - S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); - sprintf (devname, "rawqft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i + 32, - S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); - sprintf (devname, "nrawqft%i", i); - devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - QIC117_TAPE_MAJOR, i + 36, + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, - &zft_cdev, NULL); + "qft%i", i); + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), + S_IFCHR | S_IRUSR | S_IWUSR, + "nqft%i", i); + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), + S_IFCHR | S_IRUSR | S_IWUSR, + "zqft%i", i); + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), + S_IFCHR | S_IRUSR | S_IWUSR, + "nzqft%i", i); + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), + S_IFCHR | S_IRUSR | S_IWUSR, + "rawqft%i", i); + devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), + S_IFCHR | S_IRUSR | S_IWUSR, + "nrawqft%i", i); } #ifdef CONFIG_ZFT_COMPRESSOR diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c --- a/drivers/char/hvc_console.c Mon May 12 20:55:48 2003 +++ b/drivers/char/hvc_console.c Mon May 12 20:55:48 2003 @@ -227,7 +227,12 @@ spin_unlock_irqrestore(&hp->lock, flags); } +#if defined (CONFIG_XMON) extern unsigned long cpus_in_xmon; +#else +unsigned long cpus_in_xmon=0; +#endif + int khvcd(void *unused) { @@ -252,6 +257,7 @@ memset(&hvc_driver, 0, sizeof(struct tty_driver)); hvc_driver.magic = TTY_DRIVER_MAGIC; + hvc_driver.owner = THIS_MODULE; hvc_driver.driver_name = "hvc"; hvc_driver.name = "hvc/"; hvc_driver.major = HVC_MAJOR; @@ -277,7 +283,7 @@ for (i = 0; i < hvc_driver.num; i++) { hvc_struct[i].lock = SPIN_LOCK_UNLOCKED; hvc_struct[i].index = i; - tty_register_device(&hvc_driver, i); + tty_register_device(&hvc_driver, i, NULL); } if (tty_register_driver(&hvc_driver)) diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c --- a/drivers/char/ip2main.c Mon May 12 20:55:49 2003 +++ b/drivers/char/ip2main.c Mon May 12 20:55:49 2003 @@ -793,6 +793,7 @@ /* Initialise the relevant fields. */ ip2_tty_driver.magic = TTY_DRIVER_MAGIC; + ip2_tty_driver.owner = THIS_MODULE; ip2_tty_driver.name = pcTty; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) ip2_tty_driver.driver_name = pcDriver_name; @@ -869,29 +870,19 @@ */ for( i = 0; i < IP2_MAX_BOARDS; ++i ) { -#ifdef CONFIG_DEVFS_FS - char name[16]; -#endif - if ( 0 == ip2config.addr[i] ) { continue; } #ifdef CONFIG_DEVFS_FS if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - sprintf( name, "ip2/ipl%d", i ); - devfs_register(NULL, name, - DEVFS_FL_DEFAULT, - IP2_IPL_MAJOR, 4 * i, + devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - &ip2_ipl, NULL); + "ip2/ipl%d", i); - sprintf( name, "ip2/stat%d", i ); - devfs_register(NULL, name, - DEVFS_FL_DEFAULT, - IP2_IPL_MAJOR, 4 * i + 1, + devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - &ip2_ipl, NULL); + "ip2/stat%d", i); for ( box = 0; box < ABS_MAX_BOXES; ++box ) { @@ -901,10 +892,10 @@ { tty_register_device(&ip2_tty_driver, j + ABS_BIGGEST_BOX * - (box+i*ABS_MAX_BOXES)); + (box+i*ABS_MAX_BOXES), NULL); tty_register_device(&ip2_callout_driver, j + ABS_BIGGEST_BOX * - (box+i*ABS_MAX_BOXES)); + (box+i*ABS_MAX_BOXES), NULL); } } } @@ -1577,7 +1568,6 @@ /* Setup pointer links in device and tty structures */ pCh->pTTY = tty; tty->driver_data = pCh; - MOD_INC_USE_COUNT; #ifdef IP2DEBUG_OPEN printk(KERN_DEBUG \ @@ -1777,14 +1767,12 @@ #endif if ( tty_hung_up_p ( pFile ) ) { - MOD_DEC_USE_COUNT; ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 ); return; } if ( tty->count > 1 ) { /* not the last close */ - MOD_DEC_USE_COUNT; ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 ); @@ -1852,7 +1840,6 @@ DBG_CNT("ip2_close: after wakeups--"); #endif - MOD_DEC_USE_COUNT; ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 ); diff -Nru a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c --- a/drivers/char/ipmi/ipmi_devintf.c Mon May 12 20:55:48 2003 +++ b/drivers/char/ipmi/ipmi_devintf.c Mon May 12 20:55:48 2003 @@ -441,24 +441,17 @@ static void ipmi_new_smi(int if_num) { - char name[10]; - - if (if_num > MAX_DEVICES) - return; - - snprintf(name, sizeof(name), "ipmidev/%d", if_num); - - devfs_register(NULL, name, 0, ipmi_major, if_num, - S_IFCHR | S_IRUSR | S_IWUSR, - &ipmi_fops, NULL); + if (if_num <= MAX_DEVICES) { + devfs_mk_cdev(MKDEV(ipmi_major, if_num), + S_IFCHR | S_IRUSR | S_IWUSR, + "ipmidev/%d", if_num); + } } static void ipmi_smi_gone(int if_num) { - if (if_num > MAX_DEVICES) - return; - - devfs_remove("ipmidev/%d", if_num); + if (if_num <= MAX_DEVICES) + devfs_remove("ipmidev/%d", if_num); } static struct ipmi_smi_watcher smi_watcher = diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c --- a/drivers/char/isicom.c Mon May 12 20:55:44 2003 +++ b/drivers/char/isicom.c Mon May 12 20:55:44 2003 @@ -590,9 +590,7 @@ port->status &= ~ISI_DCD; if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && (port->flags & ASYNC_CALLOUT_NOHUP))) { - MOD_INC_USE_COUNT; - if (schedule_task(&port->hangup_tq) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&port->hangup_tq); } } } @@ -846,7 +844,6 @@ #endif bp->status |= BOARD_ACTIVE; - MOD_INC_USE_COUNT; return; } @@ -1104,7 +1101,6 @@ for(channel = 0; channel < bp->port_count; channel++, port++) { drop_dtr_rts(port); } - MOD_DEC_USE_COUNT; } static void isicom_shutdown_port(struct isi_port * port) @@ -1644,7 +1640,6 @@ tty = port->tty; if (tty) tty_hangup(tty); /* FIXME: module removal race here - AKPM */ - MOD_DEC_USE_COUNT; } static void isicom_hangup(struct tty_struct * tty) @@ -1715,6 +1710,7 @@ /* tty driver structure initialization */ memset(&isicom_normal, 0, sizeof(struct tty_driver)); isicom_normal.magic = TTY_DRIVER_MAGIC; + isicom_normal.owner = THIS_MODULE; isicom_normal.name = "ttyM"; isicom_normal.major = ISICOM_NMAJOR; isicom_normal.minor_start = 0; diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c --- a/drivers/char/istallion.c Mon May 12 20:55:47 2003 +++ b/drivers/char/istallion.c Mon May 12 20:55:47 2003 @@ -1054,7 +1054,6 @@ if (portp->devnr < 1) return(-ENODEV); - MOD_INC_USE_COUNT; /* * Check if this port is in the middle of closing. If so then wait @@ -1170,14 +1169,12 @@ save_flags(flags); cli(); if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; restore_flags(flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { - MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -1232,7 +1229,6 @@ portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); - MOD_DEC_USE_COUNT; restore_flags(flags); } @@ -2369,7 +2365,6 @@ tty_hangup(portp->tty); } } - MOD_DEC_USE_COUNT; } /*****************************************************************************/ @@ -3004,9 +2999,7 @@ if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && (portp->flags & ASYNC_CALLOUT_NOHUP))) { if (tty != (struct tty_struct *) NULL) { - MOD_INC_USE_COUNT; - if (schedule_task(&portp->tqhangup) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&portp->tqhangup); } } } @@ -5336,12 +5329,9 @@ devfs_mk_dir("staliomem"); for (i = 0; i < 4; i++) { - char name[16]; - sprintf(name, "staliomem/%d", i); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - STL_SIOMEMMAJOR, i, + devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, - &stli_fsiomem, NULL); + "staliomem/%d", i); } /* @@ -5350,6 +5340,7 @@ */ memset(&stli_serial, 0, sizeof(struct tty_driver)); stli_serial.magic = TTY_DRIVER_MAGIC; + stli_serial.owner = THIS_MODULE; stli_serial.driver_name = stli_drvname; stli_serial.name = stli_serialname; stli_serial.major = STL_SERIALMAJOR; diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c --- a/drivers/char/keyboard.c Mon May 12 20:55:46 2003 +++ b/drivers/char/keyboard.c Mon May 12 20:55:46 2003 @@ -1047,8 +1047,8 @@ printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (keycode == KEY_SYSRQ && !rep) { - sysrq_down = sysrq_alt && down; + if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { + sysrq_down = down; return; } if (sysrq_down && down && !rep) { diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c --- a/drivers/char/lp.c Mon May 12 20:55:44 2003 +++ b/drivers/char/lp.c Mon May 12 20:55:44 2003 @@ -784,8 +784,6 @@ static int lp_register(int nr, struct parport *port) { - char name[16]; - lp_table[nr].dev = parport_register_device(port, "lp", lp_preempt, NULL, NULL, 0, (void *) &lp_table[nr]); @@ -796,11 +794,8 @@ if (reset) lp_reset(nr); - sprintf (name, "printers/%d", nr); - devfs_register (NULL, name, - DEVFS_FL_DEFAULT, LP_MAJOR, nr, - S_IFCHR | S_IRUGO | S_IWUGO, - &lp_fops, NULL); + devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, + "printers/%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c --- a/drivers/char/mem.c Mon May 12 20:55:46 2003 +++ b/drivers/char/mem.c Mon May 12 20:55:46 2003 @@ -660,15 +660,16 @@ return 0; } -void __init memory_devfs_register (void) -{ - /* These are never unregistered */ - static const struct { - unsigned short minor; - char *name; - umode_t mode; - struct file_operations *fops; - } list[] = { /* list of minor devices */ +static struct file_operations memory_fops = { + .open = memory_open, /* just a selector for the real open */ +}; + +static const struct { + unsigned int minor; + char *name; + umode_t mode; + struct file_operations *fops; +} devlist[] = { /* list of minor devices */ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, @@ -680,25 +681,20 @@ {8, "random", S_IRUGO | S_IWUSR, &random_fops}, {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, - }; - int i; - - for (i=0; i<(sizeof(list)/sizeof(*list)); i++) - devfs_register (NULL, list[i].name, DEVFS_FL_NONE, - MEM_MAJOR, list[i].minor, - list[i].mode | S_IFCHR, - list[i].fops, NULL); -} - -static struct file_operations memory_fops = { - .open = memory_open, /* just a selector for the real open */ }; -int __init chr_dev_init(void) +static int __init chr_dev_init(void) { + int i; + if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); - memory_devfs_register(); + + for (i = 0; i < ARRAY_SIZE(devlist); i++) { + devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), + S_IFCHR | devlist[i].mode, devlist[i].name); + } + rand_initialize(); #if defined (CONFIG_FB) fbmem_init(); diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c --- a/drivers/char/misc.c Mon May 12 20:55:48 2003 +++ b/drivers/char/misc.c Mon May 12 20:55:48 2003 @@ -200,8 +200,8 @@ "misc/%s", misc->name); } - devfs_register(NULL, misc->devfs_name, 0, MISC_MAJOR, misc->minor, - S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->fops, NULL); + devfs_mk_cdev(MKDEV(MISC_MAJOR, misc->minor), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); /* * Add it to the front, so that later devices can "override" diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c --- a/drivers/char/moxa.c Mon May 12 20:55:48 2003 +++ b/drivers/char/moxa.c Mon May 12 20:55:48 2003 @@ -341,6 +341,7 @@ memset(&moxaDriver, 0, sizeof(struct tty_driver)); memset(&moxaCallout, 0, sizeof(struct tty_driver)); moxaDriver.magic = TTY_DRIVER_MAGIC; + moxaDriver.owner = THIS_MODULE; moxaDriver.name = "ttya"; moxaDriver.major = ttymajor; moxaDriver.minor_start = 0; @@ -544,7 +545,6 @@ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); } } - MOD_DEC_USE_COUNT; } static int moxa_open(struct tty_struct *tty, struct file *filp) @@ -556,7 +556,6 @@ port = PORTNO(tty); if (port == MAX_PORTS) { - MOD_INC_USE_COUNT; return (0); } if (!MoxaPortIsValid(port)) { @@ -579,7 +578,6 @@ } up(&moxaBuffSem); - MOD_INC_USE_COUNT; ch = &moxaChannels[port]; ch->count++; tty->driver_data = ch; @@ -619,7 +617,6 @@ port = PORTNO(tty); if (port == MAX_PORTS) { - MOD_DEC_USE_COUNT; return; } if (!MoxaPortIsValid(port)) { @@ -633,7 +630,6 @@ return; } if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; return; } ch = (struct moxa_str *) tty->driver_data; @@ -649,7 +645,6 @@ ch->count = 0; } if (ch->count) { - MOD_DEC_USE_COUNT; return; } ch->asyncflags |= ASYNC_CLOSING; @@ -688,7 +683,6 @@ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); - MOD_DEC_USE_COUNT; } static int moxa_write(struct tty_struct *tty, int from_user, @@ -1024,9 +1018,7 @@ wake_up_interruptible(&ch->open_wait); else { set_bit(MOXA_EVENT_HANGUP, &ch->event); - MOD_DEC_USE_COUNT; - if (schedule_work(&ch->tqueue) == 0) - MOD_INC_USE_COUNT; + schedule_work(&ch->tqueue); } } } diff -Nru a/drivers/char/mwave/mwavedd.h b/drivers/char/mwave/mwavedd.h --- a/drivers/char/mwave/mwavedd.h Mon May 12 20:55:47 2003 +++ b/drivers/char/mwave/mwavedd.h Mon May 12 20:55:47 2003 @@ -50,9 +50,11 @@ #define _LINUX_MWAVEDD_H #include "3780i.h" #include "tp3780i.h" +#include "smapi.h" #include "mwavepub.h" #include #include +#include extern int mwave_debug; extern int mwave_3780i_irq; diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c --- a/drivers/char/mxser.c Mon May 12 20:55:47 2003 +++ b/drivers/char/mxser.c Mon May 12 20:55:47 2003 @@ -501,6 +501,7 @@ memset(&mxvar_sdriver, 0, sizeof(struct tty_driver)); mxvar_sdriver.magic = TTY_DRIVER_MAGIC; + mxvar_sdriver.owner = THIS_MODULE; mxvar_sdriver.name = "ttyM"; mxvar_sdriver.major = ttymajor; mxvar_sdriver.minor_start = 0; @@ -708,7 +709,6 @@ tty_hangup(tty); /* FIXME: module removal race here - AKPM */ } } - MOD_DEC_USE_COUNT; } /* @@ -767,8 +767,6 @@ info->session = current->session; info->pgrp = current->pgrp; - MOD_INC_USE_COUNT; - return (0); } @@ -795,7 +793,6 @@ if (tty_hung_up_p(filp)) { restore_flags(flags); - MOD_DEC_USE_COUNT; return; } if ((tty->count == 1) && (info->count != 1)) { @@ -817,7 +814,6 @@ } if (info->count) { restore_flags(flags); - MOD_DEC_USE_COUNT; return; } info->flags |= ASYNC_CLOSING; @@ -881,7 +877,6 @@ wake_up_interruptible(&info->close_wait); restore_flags(flags); - MOD_DEC_USE_COUNT; } static int mxser_write(struct tty_struct *tty, int from_user, @@ -1492,9 +1487,7 @@ if (info->xmit_cnt < WAKEUP_CHARS) { set_bit(MXSER_EVENT_TXLOW, &info->event); - MOD_INC_USE_COUNT; - if (schedule_work(&info->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_work(&info->tqueue); } if (info->xmit_cnt <= 0) { info->IER &= ~UART_IER_THRI; @@ -1523,9 +1516,7 @@ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) set_bit(MXSER_EVENT_HANGUP, &info->event); - MOD_INC_USE_COUNT; - if (schedule_work(&info->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_work(&info->tqueue); } if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { @@ -1535,9 +1526,7 @@ outb(info->IER, info->base + UART_IER); set_bit(MXSER_EVENT_TXLOW, &info->event); - MOD_INC_USE_COUNT; - if (schedule_work(&info->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_work(&info->tqueue); } } else { if (!(status & UART_MSR_CTS)) { diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c --- a/drivers/char/n_hdlc.c Mon May 12 20:55:45 2003 +++ b/drivers/char/n_hdlc.c Mon May 12 20:55:45 2003 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * $Id: n_hdlc.c,v 4.6 2003/04/21 19:14:07 paulkf Exp $ + * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "$Revision: 4.6 $" +#define HDLC_VERSION "$Revision: 4.8 $" #include #include @@ -215,6 +215,21 @@ /* Define this string only once for all macro invocations */ static char szVersion[] = HDLC_VERSION; +static struct tty_ldisc n_hdlc_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "hdlc", + .open = n_hdlc_tty_open, + .close = n_hdlc_tty_close, + .read = n_hdlc_tty_read, + .write = n_hdlc_tty_write, + .ioctl = n_hdlc_tty_ioctl, + .poll = n_hdlc_tty_poll, + .receive_buf = n_hdlc_tty_receive, + .receive_room = n_hdlc_tty_room, + .write_wakeup = n_hdlc_tty_wakeup, +}; + /* n_hdlc_release() * * release an n_hdlc per device line discipline info structure @@ -968,25 +983,6 @@ static int __init n_hdlc_init(void) { - static struct tty_ldisc n_hdlc_ldisc = { - TTY_LDISC_MAGIC, /* magic */ - "hdlc", /* name */ - 0, /* num */ - 0, /* flags */ - n_hdlc_tty_open, /* open */ - n_hdlc_tty_close, /* close */ - 0, /* flush_buffer */ - 0, /* chars_in_buffer */ - n_hdlc_tty_read, /* read */ - n_hdlc_tty_write, /* write */ - n_hdlc_tty_ioctl, /* ioctl */ - 0, /* set_termios */ - n_hdlc_tty_poll, /* poll */ - n_hdlc_tty_receive, /* receive_buf */ - n_hdlc_tty_room, /* receive_room */ - n_hdlc_tty_wakeup, /* write_wakeup */ - THIS_MODULE /* owner */ - }; int status; /* range check maxframe arg */ diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c --- a/drivers/char/pcxx.c Mon May 12 20:55:47 2003 +++ b/drivers/char/pcxx.c Mon May 12 20:55:47 2003 @@ -431,8 +431,6 @@ return(-ENODEV); } - /* flag the kernel that there is somebody using this guy */ - MOD_INC_USE_COUNT; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. @@ -576,7 +574,6 @@ if(tty_hung_up_p(filp)) { /* flag that somebody is done with this module */ - MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -594,7 +591,6 @@ } if (info->count-- > 1) { restore_flags(flags); - MOD_DEC_USE_COUNT; return; } if (info->count < 0) { @@ -651,7 +647,6 @@ info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE| ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; restore_flags(flags); } } @@ -1228,6 +1223,7 @@ memset(&pcxe_driver, 0, sizeof(struct tty_driver)); pcxe_driver.magic = TTY_DRIVER_MAGIC; + pcxe_driver.owner = THIS_MODULE; pcxe_driver.name = "ttyD"; pcxe_driver.major = DIGI_MAJOR; pcxe_driver.minor_start = 0; diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c --- a/drivers/char/ppdev.c Mon May 12 20:55:49 2003 +++ b/drivers/char/ppdev.c Mon May 12 20:55:49 2003 @@ -760,10 +760,8 @@ } devfs_mk_dir("parports"); for (i = 0; i < PARPORT_MAX; i++) { - char name[16]; - sprintf(name, "parports/%d", i); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, PP_MAJOR, i, - S_IFCHR | S_IRUGO | S_IWUGO, &pp_fops, NULL); + devfs_mk_cdev(MKDEV(PP_MAJOR, i), + S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i); } printk (KERN_INFO PP_VERSION "\n"); diff -Nru a/drivers/char/random.c b/drivers/char/random.c --- a/drivers/char/random.c Mon May 12 20:55:44 2003 +++ b/drivers/char/random.c Mon May 12 20:55:44 2003 @@ -1527,7 +1527,7 @@ * If we gave the user some bytes, update the access time. */ if (count != 0) { - UPDATE_ATIME(file->f_dentry->d_inode); + update_atime(file->f_dentry->d_inode); } return (count ? count : retval); diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c --- a/drivers/char/raw.c Mon May 12 20:55:47 2003 +++ b/drivers/char/raw.c Mon May 12 20:55:47 2003 @@ -181,7 +181,7 @@ } if (rawdev->binding) { bdput(rawdev->binding); - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); } if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ @@ -191,7 +191,7 @@ if (rawdev->binding == NULL) err = -ENOMEM; else - try_module_get(THIS_MODULE); + __module_get(THIS_MODULE); } up(&raw_mutex); } else { diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c --- a/drivers/char/rio/rio_linux.c Mon May 12 20:55:47 2003 +++ b/drivers/char/rio/rio_linux.c Mon May 12 20:55:47 2003 @@ -389,29 +389,6 @@ udelay (usecs); } - -void rio_inc_mod_count (void) -{ -#ifdef MODULE - func_enter (); - rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_inc_mod_count\n"); - MOD_INC_USE_COUNT; - func_exit (); -#endif -} - - -void rio_dec_mod_count (void) -{ -#ifdef MODULE - func_enter (); - rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_dec_mod_count\n"); - MOD_DEC_USE_COUNT; - func_exit (); -#endif -} - - static int rio_set_real_termios (void *ptr) { int rv, modem; @@ -660,7 +637,6 @@ PortP = (struct Port *)ptr; PortP->gs.tty = NULL; - rio_dec_mod_count (); func_exit (); } @@ -686,7 +662,6 @@ } PortP->gs.tty = NULL; - rio_dec_mod_count (); func_exit (); } @@ -908,6 +883,7 @@ memset(&rio_driver, 0, sizeof(rio_driver)); rio_driver.magic = TTY_DRIVER_MAGIC; + rio_driver.owner = THIS_MODULE; rio_driver.driver_name = "specialix_rio"; rio_driver.name = "ttySR"; rio_driver.major = RIO_NORMAL_MAJOR0; diff -Nru a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h --- a/drivers/char/rio/rio_linux.h Mon May 12 20:55:47 2003 +++ b/drivers/char/rio/rio_linux.h Mon May 12 20:55:47 2003 @@ -87,9 +87,6 @@ #endif -void rio_dec_mod_count (void); -void rio_inc_mod_count (void); - /* Allow us to debug "in the field" without requiring clients to recompile.... */ #if 1 diff -Nru a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c --- a/drivers/char/rio/riotty.c Mon May 12 20:55:46 2003 +++ b/drivers/char/rio/riotty.c Mon May 12 20:55:46 2003 @@ -139,7 +139,6 @@ extern struct rio_info *p; -extern void rio_inc_mod_count (void); int @@ -205,8 +204,6 @@ tty->driver_data = PortP; PortP->gs.tty = tty; - if (!PortP->gs.count) - rio_inc_mod_count (); PortP->gs.count++; rio_dprintk (RIO_DEBUG_TTY, "%d bytes in tx buffer\n", @@ -215,8 +212,6 @@ retval = gs_init_port (&PortP->gs); if (retval) { PortP->gs.count--; - if (PortP->gs.count) - rio_dec_mod_count (); return -ENXIO; } /* diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c --- a/drivers/char/riscom8.c Mon May 12 20:55:46 2003 +++ b/drivers/char/riscom8.c Mon May 12 20:55:46 2003 @@ -552,9 +552,7 @@ wake_up_interruptible(&port->open_wait); else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && (port->flags & ASYNC_CALLOUT_NOHUP))) { - MOD_INC_USE_COUNT; - if (schedule_task(&port->tqueue_hangup) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&port->tqueue_hangup); } } @@ -676,7 +674,6 @@ IRQ_to_board[bp->irq] = bp; bp->flags |= RC_BOARD_ACTIVE; - MOD_INC_USE_COUNT; return 0; } @@ -694,7 +691,6 @@ bp->DTR = ~0; rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */ - MOD_DEC_USE_COUNT; } /* @@ -1678,7 +1674,6 @@ tty = port->tty; if (tty) tty_hangup(tty); /* FIXME: module removal race still here */ - MOD_DEC_USE_COUNT; } static void rc_hangup(struct tty_struct * tty) @@ -1757,6 +1752,7 @@ memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); memset(&riscom_driver, 0, sizeof(riscom_driver)); riscom_driver.magic = TTY_DRIVER_MAGIC; + riscom_driver.owner = THIS_MODULE; riscom_driver.name = "ttyL"; riscom_driver.major = RISCOM8_NORMAL_MAJOR; riscom_driver.num = RC_NBOARD * RC_NPORT; diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c --- a/drivers/char/rocket.c Mon May 12 20:55:47 2003 +++ b/drivers/char/rocket.c Mon May 12 20:55:47 2003 @@ -874,9 +874,6 @@ } if (info->count++ == 0) { -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif rp_num_ports_open++; #ifdef ROCKET_DEBUG_OPEN printk("rocket mod++ = %d...", rp_num_ports_open); @@ -1071,9 +1068,6 @@ tty->closing = 0; wake_up_interruptible(&info->close_wait); -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif rp_num_ports_open--; #ifdef ROCKET_DEBUG_OPEN printk("rocket mod-- = %d...", rp_num_ports_open); @@ -1504,9 +1498,6 @@ return; } if (info->count) { -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif rp_num_ports_open--; } @@ -2012,6 +2003,7 @@ */ memset(&rocket_driver, 0, sizeof(struct tty_driver)); rocket_driver.magic = TTY_DRIVER_MAGIC; + rocket_driver.owner = THIS_MODULE; #ifdef CONFIG_DEVFS_FS rocket_driver.name = "tts/R"; #else diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c --- a/drivers/char/ser_a2232.c Mon May 12 20:55:45 2003 +++ b/drivers/char/ser_a2232.c Mon May 12 20:55:45 2003 @@ -272,7 +272,6 @@ not in "a2232_close()". See the comment in "sx.c", too. If you run into problems, compile this driver into the kernel instead of compiling it as a module. */ - MOD_DEC_USE_COUNT; } static int a2232_set_real_termios(void *ptr) @@ -414,7 +413,6 @@ a2232_disable_tx_interrupts(ptr); a2232_disable_rx_interrupts(ptr); /* see the comment in a2232_shutdown_port above. */ - /* MOD_DEC_USE_COUNT; */ } static void a2232_hungup(void *ptr) @@ -468,13 +466,9 @@ return retval; } port->gs.flags |= GS_ACTIVE; - if (port->gs.count == 1) { - MOD_INC_USE_COUNT; - } retval = gs_block_til_ready(port, filp); if (retval) { - MOD_DEC_USE_COUNT; port->gs.count--; return retval; } @@ -711,6 +705,7 @@ memset(&a2232_driver, 0, sizeof(a2232_driver)); a2232_driver.magic = TTY_DRIVER_MAGIC; + a2232_driver.owner = THIS_MODULE; a2232_driver.driver_name = "commodore_a2232"; a2232_driver.name = "ttyY"; a2232_driver.major = A2232_NORMAL_MAJOR; diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c --- a/drivers/char/serial167.c Mon May 12 20:55:46 2003 +++ b/drivers/char/serial167.c Mon May 12 20:55:46 2003 @@ -2395,6 +2395,7 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; + cy_serial_driver.owner = THIS_MODULE; #ifdef CONFIG_DEVFS_FS cy_serial_driver.name = "tts/"; #else diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c --- a/drivers/char/serial_tx3912.c Mon May 12 20:55:47 2003 +++ b/drivers/char/serial_tx3912.c Mon May 12 20:55:47 2003 @@ -41,8 +41,6 @@ static void rs_shutdown_port (void * ptr); static int rs_set_real_termios (void *ptr); static int rs_chars_in_buffer (void * ptr); -static void rs_hungup (void *ptr); -static void rs_close (void *ptr); /* * Used by generic serial driver to access hardware @@ -56,8 +54,6 @@ .shutdown_port = rs_shutdown_port, .set_real_termios = rs_set_real_termios, .chars_in_buffer = rs_chars_in_buffer, - .close = rs_close, - .hungup = rs_hungup, }; /* @@ -579,9 +575,6 @@ rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", port->gs.count); - if (port->gs.count == 1) { - MOD_INC_USE_COUNT; - } rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n"); /* Jim: Initialize port hardware here */ @@ -595,7 +588,6 @@ retval, port->gs.count); if (retval) { - MOD_DEC_USE_COUNT; port->gs.count--; return retval; } @@ -621,32 +613,6 @@ } - -static void rs_close (void *ptr) -{ - func_enter (); - - /* Anything to do here? */ - - MOD_DEC_USE_COUNT; - func_exit (); -} - - -/* I haven't the foggiest why the decrement use count has to happen - here. The whole linux serial drivers stuff needs to be redesigned. - My guess is that this is a hack to minimize the impact of a bug - elsewhere. Thinking about it some more. (try it sometime) Try - running minicom on a serial port that is driven by a modularized - driver. Have the modem hangup. Then remove the driver module. Then - exit minicom. I expect an "oops". -- REW */ -static void rs_hungup (void *ptr) -{ - func_enter (); - MOD_DEC_USE_COUNT; - func_exit (); -} - static int rs_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -839,6 +805,7 @@ memset(&rs_driver, 0, sizeof(rs_driver)); rs_driver.magic = TTY_DRIVER_MAGIC; + rs_driver.owner = THIS_MODULE; rs_driver.driver_name = "serial"; rs_driver.name = "ttyS"; rs_driver.major = TTY_MAJOR; diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c --- a/drivers/char/sh-sci.c Mon May 12 20:55:49 2003 +++ b/drivers/char/sh-sci.c Mon May 12 20:55:49 2003 @@ -71,8 +71,6 @@ static int sci_get_CD(void *ptr); static void sci_shutdown_port(void *ptr); static int sci_set_real_termios(void *ptr); -static void sci_hungup(void *ptr); -static void sci_close(void *ptr); static int sci_chars_in_buffer(void *ptr); static int sci_request_irq(struct sci_port *port); static void sci_free_irq(struct sci_port *port); @@ -216,8 +214,6 @@ sci_shutdown_port, sci_set_real_termios, sci_chars_in_buffer, - sci_close, - sci_hungup, NULL }; @@ -838,12 +834,7 @@ sci_setsignals(port, 1,1); if (port->gs.count == 1) { - MOD_INC_USE_COUNT; - retval = sci_request_irq(port); - if (retval) { - goto failed_2; - } } retval = gs_block_til_ready(port, filp); @@ -878,23 +869,11 @@ failed_3: sci_free_irq(port); -failed_2: - MOD_DEC_USE_COUNT; failed_1: port->gs.count--; return retval; } -static void sci_hungup(void *ptr) -{ - MOD_DEC_USE_COUNT; -} - -static void sci_close(void *ptr) -{ - MOD_DEC_USE_COUNT; -} - static int sci_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -1019,6 +998,7 @@ memset(&sci_driver, 0, sizeof(sci_driver)); sci_driver.magic = TTY_DRIVER_MAGIC; + sci_driver.owner = THIS_MODULE; sci_driver.driver_name = "sci"; #ifdef CONFIG_DEVFS_FS sci_driver.name = "ttsc/"; diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c --- a/drivers/char/specialix.c Mon May 12 20:55:48 2003 +++ b/drivers/char/specialix.c Mon May 12 20:55:48 2003 @@ -833,9 +833,7 @@ #ifdef SPECIALIX_DEBUG printk ( "Sending HUP.\n"); #endif - MOD_INC_USE_COUNT; - if (schedule_task(&port->tqueue_hangup) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&port->tqueue_hangup); } else { #ifdef SPECIALIX_DEBUG printk ( "Don't need to send HUP.\n"); @@ -980,7 +978,6 @@ turn_ints_on (bp); bp->flags |= SX_BOARD_ACTIVE; - MOD_INC_USE_COUNT; return 0; } @@ -1000,7 +997,6 @@ turn_ints_off (bp); - MOD_DEC_USE_COUNT; } @@ -2150,7 +2146,6 @@ tty = port->tty; if (tty) tty_hangup(tty); /* FIXME: module removal race here */ - MOD_DEC_USE_COUNT; } @@ -2233,6 +2228,7 @@ init_bh(SPECIALIX_BH, do_specialix_bh); memset(&specialix_driver, 0, sizeof(specialix_driver)); specialix_driver.magic = TTY_DRIVER_MAGIC; + specialix_driver.owner = THIS_MODULE; specialix_driver.name = "ttyW"; specialix_driver.major = SPECIALIX_NORMAL_MAJOR; specialix_driver.num = SX_NBOARD * SX_NPORT; diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c --- a/drivers/char/stallion.c Mon May 12 20:55:48 2003 +++ b/drivers/char/stallion.c Mon May 12 20:55:48 2003 @@ -1044,8 +1044,6 @@ if (portp == (stlport_t *) NULL) return(-ENODEV); - MOD_INC_USE_COUNT; - /* * On the first open of the device setup the port hardware, and * initialize the per port data structure. @@ -1207,14 +1205,12 @@ save_flags(flags); cli(); if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; restore_flags(flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { - MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -1267,7 +1263,6 @@ portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); - MOD_DEC_USE_COUNT; restore_flags(flags); } @@ -2241,11 +2236,11 @@ #endif if (portp == (stlport_t *) NULL) - goto out; + return; tty = portp->tty; if (tty == (struct tty_struct *) NULL) - goto out; + return; lock_kernel(); if (test_bit(ASYI_TXLOW, &portp->istate)) { @@ -2270,8 +2265,6 @@ } } unlock_kernel(); -out: - MOD_DEC_USE_COUNT; } /*****************************************************************************/ @@ -3216,13 +3209,11 @@ if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) printk("STALLION: failed to register serial board device\n"); devfs_mk_dir("staliomem"); + for (i = 0; i < 4; i++) { - char name[16]; - sprintf(name, "staliomem/%d", i); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - STL_SIOMEMMAJOR, i, - S_IFCHR | S_IRUSR | S_IWUSR, - &stl_fsiomem, NULL); + devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), + S_IFCHR|S_IRUSR|S_IWUSR, + &stl_fsiomem, NULL, "staliomem/%d", i); } /* @@ -3231,6 +3222,7 @@ */ memset(&stl_serial, 0, sizeof(struct tty_driver)); stl_serial.magic = TTY_DRIVER_MAGIC; + stl_serial.owner = THIS_MODULE; stl_serial.driver_name = stl_drvname; stl_serial.name = stl_serialname; stl_serial.major = STL_SERIALMAJOR; @@ -4136,9 +4128,7 @@ if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - MOD_INC_USE_COUNT; - if (schedule_work(&portp->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_work(&portp->tqueue); } if (len == 0) { @@ -4318,9 +4308,7 @@ misr = inb(ioaddr + EREG_DATA); if (misr & MISR_DCD) { set_bit(ASYI_DCDCHANGE, &portp->istate); - MOD_INC_USE_COUNT; - if (schedule_task(&portp->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&portp->tqueue); portp->stats.modem++; } @@ -5117,9 +5105,7 @@ if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - MOD_INC_USE_COUNT; - if (schedule_task(&portp->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&portp->tqueue); } if (len == 0) { @@ -5336,9 +5322,7 @@ ipr = stl_sc26198getreg(portp, IPR); if (ipr & IPR_DCDCHANGE) { set_bit(ASYI_DCDCHANGE, &portp->istate); - MOD_INC_USE_COUNT; - if (schedule_task(&portp->tqueue) == 0) - MOD_DEC_USE_COUNT; + schedule_task(&portp->tqueue); portp->stats.modem++; } break; diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Mon May 12 20:55:46 2003 +++ b/drivers/char/synclink.c Mon May 12 20:55:46 2003 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.6 2003/04/21 17:46:54 paulkf Exp $ + * $Id: synclink.c,v 4.9 2003/05/06 21:18:51 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -193,6 +193,7 @@ int flags; int count; /* count of opens */ int line; + int hw_version; unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ @@ -917,7 +918,7 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.6 $"; +static char *driver_version = "$Revision: 4.9 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -925,6 +926,7 @@ static struct pci_device_id synclink_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, synclink_pci_tbl); @@ -4216,9 +4218,7 @@ info->get_tx_holding_index=0; /* restart transmit timer */ - del_timer(&info->tx_timer); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); - add_timer(&info->tx_timer); + mod_timer(&info->tx_timer, jiffies + jiffies_from_ms(5000)); ret = 1; } @@ -4436,12 +4436,12 @@ info->max_frame_size = 65535; if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { - printk( "SyncLink device %s added:PCI bus IO=%04X IRQ=%d Mem=%08X LCR=%08X MaxFrameSize=%u\n", - info->device_name, info->io_base, info->irq_level, + printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n", + info->hw_version + 1, info->device_name, info->io_base, info->irq_level, info->phys_memory_base, info->phys_lcr_base, info->max_frame_size ); } else { - printk( "SyncLink device %s added:ISA bus IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n", + printk( "SyncLink ISA %s: IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n", info->device_name, info->io_base, info->irq_level, info->dma_level, info->max_frame_size ); } @@ -5296,10 +5296,11 @@ info->mbre_bit = BIT8; outw( BIT8, info->io_base ); /* set Master Bus Enable (DCAR) */ - /* Enable DMAEN (Port 7, Bit 14) */ - /* This connects the DMA request signal to the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14) ); + if (info->bus_type == MGSL_BUS_TYPE_ISA) { + /* Enable DMAEN (Port 7, Bit 14) */ + /* This connects the DMA request signal to the ISA bus */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14)); + } /* DMA Control Register (DCR) * @@ -6276,10 +6277,11 @@ usc_EnableMasterIrqBit( info ); - /* Enable INTEN (Port 6, Bit12) */ - /* This connects the IRQ request signal to the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12) ); + if (info->bus_type == MGSL_BUS_TYPE_ISA) { + /* Enable INTEN (Port 6, Bit12) */ + /* This connects the IRQ request signal to the ISA bus */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); + } } /* end of usc_set_async_mode() */ @@ -6370,10 +6372,11 @@ usc_loopback_frame( info ); usc_set_sdlc_mode( info ); - /* Enable INTEN (Port 6, Bit12) */ - /* This connects the IRQ request signal to the ISA bus */ - /* on the ISA adapter. This has no effect for the PCI adapter */ - usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); + if (info->bus_type == MGSL_BUS_TYPE_ISA) { + /* Enable INTEN (Port 6, Bit12) */ + /* This connects the IRQ request signal to the ISA bus */ + usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); + } usc_enable_aux_clock(info, info->params.clock_speed); @@ -8115,17 +8118,20 @@ info->bus_type = MGSL_BUS_TYPE_PCI; info->io_addr_size = 8; info->irq_flags = SA_SHIRQ; - - /* Store the PCI9050 misc control register value because a flaw - * in the PCI9050 prevents LCR registers from being read if - * BIOS assigns an LCR base address with bit 7 set. - * - * Only the misc control register is accessed for which only - * write access is needed, so set an initial value and change - * bits to the device instance data as we write the value - * to the actual misc control register. - */ - info->misc_ctrl_value = 0x087e4546; + + if (dev->device == 0x0210) { + /* Version 1 PCI9030 based universal PCI adapter */ + info->misc_ctrl_value = 0x007c4080; + info->hw_version = 1; + } else { + /* Version 0 PCI9050 based 5V PCI adapter + * A PCI9050 bug prevents reading LCR registers if + * LCR base address bit 7 is set. Maintain shadow + * value so we can write to LCR misc control reg. + */ + info->misc_ctrl_value = 0x087e4546; + info->hw_version = 0; + } mgsl_add_device(info); diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c --- a/drivers/char/sysrq.c Mon May 12 20:55:48 2003 +++ b/drivers/char/sysrq.c Mon May 12 20:55:48 2003 @@ -101,131 +101,19 @@ { machine_restart(NULL); } + static struct sysrq_key_op sysrq_reboot_op = { .handler = sysrq_handle_reboot, .help_msg = "reBoot", .action_msg = "Resetting", }; - - -/* SYNC SYSRQ HANDLERS BLOCK */ - -/* do_emergency_sync helper function */ -/* Guesses if the device is a local hard drive */ -static int is_local_disk(struct block_device *bdev) -{ - switch (MAJOR(bdev->bd_dev)) { - case IDE0_MAJOR: - case IDE1_MAJOR: - case IDE2_MAJOR: - case IDE3_MAJOR: - case IDE4_MAJOR: - case IDE5_MAJOR: - case IDE6_MAJOR: - case IDE7_MAJOR: - case IDE8_MAJOR: - case IDE9_MAJOR: - case SCSI_DISK0_MAJOR: - case SCSI_DISK1_MAJOR: - case SCSI_DISK2_MAJOR: - case SCSI_DISK3_MAJOR: - case SCSI_DISK4_MAJOR: - case SCSI_DISK5_MAJOR: - case SCSI_DISK6_MAJOR: - case SCSI_DISK7_MAJOR: - case XT_DISK_MAJOR: - return 1; - default: - return 0; - } -} - -/* do_emergency_sync helper function */ -static void go_sync(struct super_block *sb, int remount_flag) -{ - int orig_loglevel; - orig_loglevel = console_loglevel; - console_loglevel = 7; - printk(KERN_INFO "%sing device %s ... ", - remount_flag ? "Remount" : "Sync", - sb->s_id); - - if (remount_flag) { /* Remount R/O */ - int ret, flags; - struct file *file; - - if (sb->s_flags & MS_RDONLY) { - printk("R/O\n"); - return; - } - - file_list_lock(); - list_for_each_entry(file, &sb->s_files, f_list) { - if (file->f_dentry && file_count(file) - && S_ISREG(file->f_dentry->d_inode->i_mode)) - file->f_mode &= ~2; - } - file_list_unlock(); - DQUOT_OFF(sb); - fsync_bdev(sb->s_bdev); - flags = MS_RDONLY; - if (sb->s_op && sb->s_op->remount_fs) { - ret = sb->s_op->remount_fs(sb, &flags, NULL); - if (ret) - printk("error %d\n", ret); - else { - sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); - printk("OK\n"); - } - } else - printk("nothing to do\n"); - } else { /* Sync only */ - fsync_bdev(sb->s_bdev); - printk("OK\n"); - } - console_loglevel = orig_loglevel; -} -/* - * Emergency Sync or Unmount. We cannot do it directly, so we set a special - * flag and wake up the bdflush kernel thread which immediately calls this function. - * We process all mounted hard drives first to recover from crashed experimental - * block devices and malfunctional network filesystems. - */ - -int emergency_sync_scheduled; - -void do_emergency_sync(void) { - struct super_block *sb; - int remount_flag; - int orig_loglevel; - - lock_kernel(); - remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); - emergency_sync_scheduled = 0; - - list_for_each_entry(sb, &super_blocks, s_list) - if (sb->s_bdev && is_local_disk(sb->s_bdev)) - go_sync(sb, remount_flag); - - list_for_each_entry(sb, &super_blocks, s_list) - if (sb->s_bdev && !is_local_disk(sb->s_bdev)) - go_sync(sb, remount_flag); - - unlock_kernel(); - - orig_loglevel = console_loglevel; - console_loglevel = 7; - printk(KERN_INFO "Done.\n"); - console_loglevel = orig_loglevel; -} - static void sysrq_handle_sync(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { - emergency_sync_scheduled = EMERG_SYNC; - wakeup_bdflush(0); + emergency_sync(); } + static struct sysrq_key_op sysrq_sync_op = { .handler = sysrq_handle_sync, .help_msg = "Sync", @@ -235,9 +123,9 @@ static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { - emergency_sync_scheduled = EMERG_REMOUNT; - wakeup_bdflush(0); + emergency_remount(); } + static struct sysrq_key_op sysrq_mountro_op = { .handler = sysrq_handle_mountro, .help_msg = "Unmount", diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c --- a/drivers/char/tipar.c Mon May 12 20:55:48 2003 +++ b/drivers/char/tipar.c Mon May 12 20:55:48 2003 @@ -421,8 +421,6 @@ static int tipar_register(int nr, struct parport *port) { - char name[32]; - /* Register our module into parport */ table[nr].dev = parport_register_device(port, "tipar", NULL, NULL, NULL, 0, @@ -432,13 +430,9 @@ return 1; /* Use devfs, tree: /dev/ticables/par/[0..2] */ - sprintf(name, "ticables/par/%d", nr); - printk - ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n", - TISER_MAJOR, (TIPAR_MINOR + nr), name); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR, - TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO, - &tipar_fops, NULL); + devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), + S_IFCHR | S_IRUGO | S_IWUGO, + "ticables/par/%d", nr); /* Display informations */ printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name, diff -Nru a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c --- a/drivers/char/tpqic02.c Mon May 12 20:55:46 2003 +++ b/drivers/char/tpqic02.c Mon May 12 20:55:46 2003 @@ -2694,38 +2694,27 @@ #endif return -ENODEV; } - devfs_register(NULL, "ntpqic11", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 2, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "tpqic11", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 3, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "ntpqic24", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 4, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "tpqic24", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 5, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "ntpqic120", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 6, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "tpqic120", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 7, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "ntpqic150", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 8, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); - devfs_register(NULL, "tpqic150", DEVFS_FL_DEFAULT, - QIC02_TAPE_MAJOR, 9, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, - &qic02_tape_fops, NULL); + + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 2), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic11"); + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 3), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic11"); + + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 4), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic24"); + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 5), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic24"); + + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 6), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic120"); + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 7), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic120"); + + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 8), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic150"); + devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 9), + S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic150"); + init_waitqueue_head(&qic02_tape_transfer); /* prepare timer */ TIMEROFF; diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Mon May 12 20:55:47 2003 +++ b/drivers/char/tty_io.c Mon May 12 20:55:47 2003 @@ -2088,22 +2088,6 @@ } #ifdef CONFIG_DEVFS_FS -static void tty_register_devfs(struct tty_driver *driver, unsigned index) -{ - dev_t dev = MKDEV(driver->major, driver->minor_start) + index; - char buf[32]; - - if (index >= driver->num) { - printk(KERN_ERR "Attempt to register invalid tty line number " - "with devfs (%d).\n", index); - return; - } - - tty_line_name(driver, index, buf); - devfs_register(NULL, buf, 0, MAJOR(dev), MINOR(dev), - S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL); -} - static void tty_unregister_devfs(struct tty_driver *driver, int index) { char path[64]; @@ -2111,21 +2095,137 @@ devfs_remove(path); } #else -# define tty_register_devfs(driver, index) do { } while (0) # define tty_unregister_devfs(driver, index) do { } while (0) #endif /* CONFIG_DEVFS_FS */ -/* - * Register a tty device described by , with minor number . +static struct class tty_class = { + .name = "tty", +}; + +struct tty_dev { + struct list_head node; + dev_t dev; + struct class_device class_dev; +}; +#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) + +static LIST_HEAD(tty_dev_list); +static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; + +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct tty_dev *tty_dev = to_tty_dev(class_dev); + return sprintf(buf, "%04x\n", tty_dev->dev); +} +static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); + +static void tty_add_class_device(char *name, dev_t dev, struct device *device) +{ + struct tty_dev *tty_dev = NULL; + char *temp; + int retval; + + tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL); + if (!tty_dev) + return; + memset(tty_dev, 0x00, sizeof(*tty_dev)); + + /* stupid '/' in tty name strings... */ + temp = strrchr(name, '/'); + if (temp && (temp[1] != 0x00)) + ++temp; + else + temp = name; + + tty_dev->class_dev.dev = device; + tty_dev->class_dev.class = &tty_class; + snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", temp); + retval = class_device_register(&tty_dev->class_dev); + if (retval) + goto error; + class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev); + tty_dev->dev = dev; + spin_lock(&tty_dev_list_lock); + list_add(&tty_dev->node, &tty_dev_list); + spin_unlock(&tty_dev_list_lock); + return; +error: + kfree(tty_dev); +} + +void tty_remove_class_device(dev_t dev) +{ + struct tty_dev *tty_dev = NULL; + struct list_head *tmp; + int found = 0; + + spin_lock(&tty_dev_list_lock); + list_for_each (tmp, &tty_dev_list) { + tty_dev = list_entry(tmp, struct tty_dev, node); + if ((MAJOR(tty_dev->dev) == MAJOR(dev)) && + (MINOR(tty_dev->dev) == MINOR(dev))) { + found = 1; + break; + } + } + if (found) { + list_del(&tty_dev->node); + spin_unlock(&tty_dev_list_lock); + class_device_unregister(&tty_dev->class_dev); + kfree(tty_dev); + } else { + spin_unlock(&tty_dev_list_lock); + } +} + +/** + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device for this + * tty device it can be set to NULL safely. + * + * This call is required to be made to register an individual tty device if + * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that + * bit is not set, this function should not be called. */ -void tty_register_device(struct tty_driver *driver, unsigned index) +void tty_register_device(struct tty_driver *driver, unsigned index, + struct device *device) { - tty_register_devfs(driver, index); + dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + char name[64]; + + if (index >= driver->num) { + printk(KERN_ERR "Attempt to register invalid tty line number " + " (%d).\n", index); + return; + } + + tty_line_name(driver, index, name); + devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, name); + + /* stupid console driver devfs names... change vc/X into ttyX */ + if (driver->type == TTY_DRIVER_TYPE_CONSOLE) + sprintf(name, "tty%d", MINOR(dev)); + + /* we don't care about the ptys */ + if (driver->type != TTY_DRIVER_TYPE_PTY) + tty_add_class_device (name, dev, device); } +/** + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * + * If a tty device is registered with a call to tty_register_device() then + * this function must be made when the tty device is gone. + */ void tty_unregister_device(struct tty_driver *driver, unsigned index) { tty_unregister_devfs(driver, index); + tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2207,7 +2307,7 @@ if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { for(i = 0; i < driver->num; i++) - tty_register_device(driver, i); + tty_register_device(driver, i, NULL); } proc_tty_register_driver(driver); return error; @@ -2288,10 +2388,6 @@ extern int vty_init(void); #endif -static struct class tty_class = { - .name = "tty", -}; - static int __init tty_class_init(void) { return class_register(&tty_class); @@ -2308,33 +2404,29 @@ if (register_chrdev_region(TTYAUX_MAJOR, 0, 1, "/dev/tty", &tty_fops) < 0) panic("Couldn't register /dev/tty driver\n"); - - devfs_register (NULL, "tty", 0, TTYAUX_MAJOR, 0, - S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); + tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); if (register_chrdev_region(TTYAUX_MAJOR, 1, 1, "/dev/console", &tty_fops) < 0) panic("Couldn't register /dev/console driver\n"); - - devfs_register (NULL, "console", 0, TTYAUX_MAJOR, 1, - S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); + tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL); #ifdef CONFIG_UNIX98_PTYS if (register_chrdev_region(TTYAUX_MAJOR, 2, 1, "/dev/ptmx", &tty_fops) < 0) panic("Couldn't register /dev/ptmx driver\n"); - - devfs_register (NULL, "ptmx", 0, TTYAUX_MAJOR, 2, - S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); + tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL); #endif #ifdef CONFIG_VT if (register_chrdev_region(TTY_MAJOR, 0, 1, "/dev/vc/0", &tty_fops) < 0) panic("Couldn't register /dev/tty0 driver\n"); - - devfs_register (NULL, "vc/0", 0, TTY_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL); + devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); + tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL); vty_init(); #endif diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c --- a/drivers/char/vc_screen.c Mon May 12 20:55:45 2003 +++ b/drivers/char/vc_screen.c Mon May 12 20:55:45 2003 @@ -469,40 +469,27 @@ .open = vcs_open, }; -void vcs_make_devfs (unsigned int index, int unregister) +void vcs_make_devfs(struct tty_struct *tty) { -#ifdef CONFIG_DEVFS_FS - - if (unregister) { - devfs_remove("vcc/%u", index + 1); - devfs_remove("vcc/a%u", index + 1); - } else { - char name[16]; - sprintf(name, "vcc/%u", index + 1); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - VCS_MAJOR, index + 1, - S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); - sprintf(name, "vcc/a%u", index + 1); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - VCS_MAJOR, index + 129, - S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); - } -#endif /* CONFIG_DEVFS_FS */ + devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1), + S_IFCHR|S_IRUSR|S_IWUSR, + "vcc/%u", tty->index + 1); + devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), + S_IFCHR|S_IRUSR|S_IWUSR, + "vcc/a%u", tty->index + 1); +} +void vcs_remove_devfs(struct tty_struct *tty) +{ + devfs_remove("vcc/%u", tty->index + 1); + devfs_remove("vcc/a%u", tty->index + 1); } int __init vcs_init(void) { - int error; - - error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops); - - if (error) - printk("unable to get major %d for vcs device", VCS_MAJOR); - - devfs_register(NULL, "vcc/0", DEVFS_FL_DEFAULT, VCS_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); - devfs_register(NULL, "vcc/a", DEVFS_FL_DEFAULT, VCS_MAJOR, 128, - S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL); + if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) + panic("unable to get major %d for vcs device", VCS_MAJOR); - return error; + devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); + devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); + return 0; } diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c --- a/drivers/char/vme_scc.c Mon May 12 20:55:44 2003 +++ b/drivers/char/vme_scc.c Mon May 12 20:55:44 2003 @@ -129,6 +129,7 @@ memset(&scc_driver, 0, sizeof(scc_driver)); scc_driver.magic = TTY_DRIVER_MAGIC; + scc_driver.owner = THIS_MODULE; scc_driver.driver_name = "scc"; #ifdef CONFIG_DEVFS_FS scc_driver.name = "tts/"; @@ -795,7 +796,6 @@ { scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr); - MOD_DEC_USE_COUNT; } @@ -803,7 +803,6 @@ { scc_disable_tx_interrupts(ptr); scc_disable_rx_interrupts(ptr); - MOD_DEC_USE_COUNT; } @@ -938,13 +937,9 @@ return retval; } port->gs.flags |= GS_ACTIVE; - if (port->gs.count == 1) { - MOD_INC_USE_COUNT; - } retval = gs_block_til_ready(port, filp); if (retval) { - MOD_DEC_USE_COUNT; port->gs.count--; return retval; } diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c Mon May 12 20:55:48 2003 +++ b/drivers/char/vt.c Mon May 12 20:55:48 2003 @@ -124,7 +124,9 @@ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) -extern void vcs_make_devfs (unsigned int index, int unregister); +extern void vcs_make_devfs(struct tty_struct *tty); +extern void vcs_remove_devfs(struct tty_struct *tty); + extern void console_map_init(void); #ifdef CONFIG_PROM_CONSOLE extern void prom_con_init(void); @@ -158,7 +160,6 @@ static void hide_cursor(int currcons); static void unblank_screen_t(unsigned long dummy); static void console_callback(void *ignored); -static void __init con_init_devfs (void); static int printable; /* Is console ready for printing? */ @@ -2410,7 +2411,7 @@ tty->winsize.ws_col = video_num_columns; } if (tty->count == 1) - vcs_make_devfs (currcons, 0); + vcs_make_devfs(tty); return 0; } @@ -2418,10 +2419,10 @@ { struct vt_struct *vt; - if (!tty) + if (!tty || tty->count != 1) return; - if (tty->count != 1) return; - vcs_make_devfs (tty->index, 1); + + vcs_remove_devfs(tty); vt = (struct vt_struct*)tty->driver_data; if (vt) vc_cons[vt->vc_num].d->vc_tty = NULL; @@ -2525,11 +2526,6 @@ console_driver.type = TTY_DRIVER_TYPE_CONSOLE; console_driver.init_termios = tty_std_termios; console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - /* Tell tty_register_driver() to skip consoles because they are - * registered before kmalloc() is ready. We'll patch them in later. - * See comments at console_init(); see also con_init_devfs(). - */ - console_driver.flags |= TTY_DRIVER_NO_DEVFS; console_driver.refcount = &console_refcount; console_driver.table = console_table; console_driver.termios = console_termios; @@ -2562,7 +2558,6 @@ #ifdef CONFIG_FRAMEBUFFER_CONSOLE fb_console_init(); #endif - con_init_devfs(); vcs_init(); return 0; } @@ -2655,18 +2650,6 @@ unsigned int mode; get_user(mode, argp); vesa_blank_mode = (mode < 4) ? mode : 0; -} - -/* We can't register the console with devfs during con_init(), because it - * is called before kmalloc() works. This function is called later to - * do the registration. - */ -static void __init con_init_devfs (void) -{ - int i; - - for (i = 0; i < console_driver.num; i++) - tty_register_device (&console_driver, i); } /* diff -Nru a/drivers/hotplug/Kconfig b/drivers/hotplug/Kconfig --- a/drivers/hotplug/Kconfig Mon May 12 20:55:46 2003 +++ b/drivers/hotplug/Kconfig Mon May 12 20:55:46 2003 @@ -61,7 +61,7 @@ config HOTPLUG_PCI_ACPI tristate "ACPI PCI Hotplug driver" - depends on ACPI && HOTPLUG_PCI + depends on ACPI_BUS && HOTPLUG_PCI help Say Y here if you have a system that supports PCI Hotplug using ACPI. diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c --- a/drivers/hotplug/acpiphp_glue.c Mon May 12 20:55:45 2003 +++ b/drivers/hotplug/acpiphp_glue.c Mon May 12 20:55:45 2003 @@ -806,6 +806,7 @@ struct list_head *l; struct acpiphp_func *func; int retval = 0; + int num; if (slot->flags & SLOT_ENABLED) goto err_exit; @@ -825,7 +826,10 @@ goto err_exit; /* returned `dev' is the *first function* only! */ - dev = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); + num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); + if (num) + pci_bus_add_devices(slot->bridge->pci_bus); + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); if (!dev) { err("No new device found\n"); diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h --- a/drivers/hotplug/cpqphp.h Mon May 12 20:55:48 2003 +++ b/drivers/hotplug/cpqphp.h Mon May 12 20:55:48 2003 @@ -31,7 +31,7 @@ #include "pci_hotplug.h" #include #include /* for read? and write? functions */ - +#include /* for delays */ #if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) #define MY_NAME "cpqphp.o" @@ -146,6 +146,10 @@ u8 reserved11; /* 0x2b */ u8 slot_SERR; /* 0x2c */ u8 slot_power; /* 0x2d */ + u8 reserved12; /* 0x2e */ + u8 reserved13; /* 0x2f */ + u8 next_curr_freq; /* 0x30 */ + u8 reset_freq_mode; /* 0x31 */ } __attribute__ ((packed)); /* offsets to the controller registers based on the above structure layout */ @@ -173,6 +177,8 @@ CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), SLOT_POWER = offsetof(struct ctrl_reg, slot_power), + NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), + RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), }; struct hrt { @@ -294,12 +300,11 @@ struct pci_resource *bus_head; struct pci_dev *pci_dev; struct pci_bus *pci_bus; - struct proc_dir_entry* proc_entry; - struct proc_dir_entry* proc_entry2; struct event_info event_queue[10]; struct slot *slot; u8 next_event; u8 interrupt; + u8 cfgspc_irq; u8 bus; /* bus number for the pci hotplug controller */ u8 rev; u8 slot_device_offset; @@ -316,8 +321,6 @@ u8 pcix_speed_capability; /* PCI-X */ u8 pcix_support; /* PCI-X */ u16 vendor_id; - char proc_name[20]; - char proc_name2[20]; struct work_struct int_task_event; wait_queue_head_t queue; /* sleep & wake process */ }; @@ -344,6 +347,7 @@ #define PCI_SUB_HPC_ID2 0xA2F8 #define PCI_SUB_HPC_ID3 0xA2F9 #define PCI_SUB_HPC_ID_INTC 0xA2FA +#define PCI_SUB_HPC_ID4 0xA2FD #define INT_BUTTON_IGNORE 0 #define INT_PRESENCE_ON 1 @@ -436,7 +440,7 @@ extern void cpqhp_destroy_resource_list (struct resource_lists * resources); extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); extern int cpqhp_unconfigure_device (struct pci_func* func); - +extern struct slot *cpqhp_find_slot (struct controller *ctrl, u8 device); /* Global variables */ extern int cpqhp_debug; @@ -564,6 +568,7 @@ u32 led_control; led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); led_control |= (0x0001L << slot); writel(led_control, ctrl->hpc_reg + LED_CONTROL); } @@ -605,14 +610,63 @@ } +/* + * get_controller_speed - find the current frequency/mode of controller. + * + * @ctrl: controller to get frequency/mode for. + * + * Returns controller speed. + * + */ static inline u8 get_controller_speed (struct controller *ctrl) { - u16 misc; - - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + u8 curr_freq; + u16 misc; + + if (ctrl->pcix_support) { + curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); + if ((curr_freq & 0xB0) == 0xB0) + return PCI_SPEED_133MHz_PCIX; + if ((curr_freq & 0xA0) == 0xA0) + return PCI_SPEED_100MHz_PCIX; + if ((curr_freq & 0x90) == 0x90) + return PCI_SPEED_66MHz_PCIX; + if (curr_freq & 0x10) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; + } + + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; } + + +/* + * get_adapter_speed - find the max supported frequency/mode of adapter. + * + * @ctrl: hotplug controller. + * @hp_slot: hotplug slot where adapter is installed. + * + * Returns adapter speed. + * + */ +static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot) +{ + u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); + dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); + if (ctrl->pcix_support) { + if (temp_dword & (0x10000 << hp_slot)) + return PCI_SPEED_133MHz_PCIX; + if (temp_dword & (0x100 << hp_slot)) + return PCI_SPEED_66MHz_PCIX; + } + if (temp_dword & (0x01 << hp_slot)) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; +} static inline void enable_slot_power (struct controller *ctrl, u8 slot) { @@ -719,6 +773,139 @@ dbg("%s - end\n", __FUNCTION__); return retval; +} + + +/** + * set_controller_speed - set the frequency and/or mode of a specific + * controller segment. + * + * @ctrl: controller to change frequency/mode for. + * @adapter_speed: the speed of the adapter we want to match. + * @hp_slot: the slot number where the adapter is installed. + * + * Returns 0 if we successfully change frequency and/or mode to match the + * adapter speed. + * + */ +static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) +{ + struct slot *slot; + u8 reg; + u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + u16 reg16; + u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); + + if (ctrl->speed == adapter_speed) + return 0; + + /* We don't allow freq/mode changes if we find another adapter running + * in another slot on this controller */ + for(slot = ctrl->slot; slot; slot = slot->next) { + if (slot->device == (hp_slot + ctrl->slot_device_offset)) + continue; + if (!slot->hotplug_slot && !slot->hotplug_slot->info) + continue; + if (slot->hotplug_slot->info->adapter_status == 0) + continue; + /* If another adapter is running on the same segment but at a + * lower speed/mode, we allow the new adapter to function at + * this rate if supported */ + if (ctrl->speed < adapter_speed) + return 0; + + return 1; + } + + /* If the controller doesn't support freq/mode changes and the + * controller is running at a higher mode, we bail */ + if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) + return 1; + + /* But we allow the adapter to run at a lower rate if possible */ + if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) + return 0; + + /* We try to set the max speed supported by both the adapter and + * controller */ + if (ctrl->speed_capability < adapter_speed) { + if (ctrl->speed == ctrl->speed_capability) + return 0; + adapter_speed = ctrl->speed_capability; + } + + writel(0x0L, ctrl->hpc_reg + LED_CONTROL); + writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + if (adapter_speed != PCI_SPEED_133MHz_PCIX) + reg = 0xF5; + else + reg = 0xF4; + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); + reg16 &= ~0x000F; + switch(adapter_speed) { + case(PCI_SPEED_133MHz_PCIX): + reg = 0x75; + reg16 |= 0xB; + break; + case(PCI_SPEED_100MHz_PCIX): + reg = 0x74; + reg16 |= 0xA; + break; + case(PCI_SPEED_66MHz_PCIX): + reg = 0x73; + reg16 |= 0x9; + break; + case(PCI_SPEED_66MHz): + reg = 0x73; + reg16 |= 0x1; + break; + default: /* 33MHz PCI 2.2 */ + reg = 0x71; + break; + + } + reg16 |= 0xB << 12; + writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); + + mdelay(5); + + /* Reenable interrupts */ + writel(0, ctrl->hpc_reg + INT_MASK); + + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + /* Restart state machine */ + reg = ~0xF; + pci_read_config_byte(ctrl->pci_dev, 0x43, ®); + pci_write_config_byte(ctrl->pci_dev, 0x43, reg); + + /* Only if mode change...*/ + if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || + ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) + set_SOGO(ctrl); + + wait_for_ctrl_irq(ctrl); + mdelay(1100); + + /* Restore LED/Slot state */ + writel(leds, ctrl->hpc_reg + LED_CONTROL); + writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + ctrl->speed = adapter_speed; + slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + info("Successfully changed frequency/mode for adapter in slot %d\n", + slot->number); + return 0; } #endif diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c --- a/drivers/hotplug/cpqphp_core.c Mon May 12 20:55:44 2003 +++ b/drivers/hotplug/cpqphp_core.c Mon May 12 20:55:44 2003 @@ -24,6 +24,9 @@ * * Send feedback to * + * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, + * Torben Mathiasen + * */ #include @@ -57,7 +60,7 @@ static u8 power_mode; static int debug; -#define DRIVER_VERSION "0.9.6" +#define DRIVER_VERSION "0.9.7" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " #define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" @@ -835,6 +838,7 @@ u8 hp_slot = 0; u8 device; u8 rev; + u8 bus_cap; u16 temp_word; u16 vendor_id; u16 subsystem_vid; @@ -896,6 +900,39 @@ switch (subsystem_vid) { case PCI_VENDOR_ID_COMPAQ: + if (rev >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 20) { + dbg("bus max supports 66MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; + break; + } + if (bus_cap & 10) { + dbg("bus max supports 66MHz PCI\n"); + ctrl->speed_capability = PCI_SPEED_66MHz; + break; + } + + break; + } + switch (subsystem_deviceid) { case PCI_SUB_HPC_ID: /* Original 6500/7000 implementation */ @@ -939,8 +976,18 @@ ctrl->pcix_support = 0; // PCI-X not supported ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 0; + break; default: - // TODO: Add SSIDs for CPQ systems that support PCI-X err(msg_HPC_not_supported); rc = -ENODEV; goto err_free_ctrl; @@ -1029,7 +1076,7 @@ info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); dbg ("Hotplug controller capabilities:\n"); - dbg (" speed_capability %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz"); + dbg (" speed_capability %d\n", ctrl->speed_capability); dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); @@ -1082,7 +1129,6 @@ } // Check for 66Mhz operation - // TODO: Add PCI-X support ctrl->speed = get_controller_speed(ctrl); @@ -1118,6 +1164,9 @@ */ // The next line is required for cpqhp_find_available_resources ctrl->interrupt = pdev->irq; + + ctrl->cfgspc_irq = 0; + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq); rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); ctrl->add_support = !rc; diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c --- a/drivers/hotplug/cpqphp_ctrl.c Mon May 12 20:55:45 2003 +++ b/drivers/hotplug/cpqphp_ctrl.c Mon May 12 20:55:45 2003 @@ -136,9 +136,9 @@ /* - * find_slot + * cpqhp_find_slot */ -static inline struct slot *find_slot (struct controller * ctrl, u8 device) +struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device) { struct slot *slot; @@ -187,7 +187,7 @@ rc++; - p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); + p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); if (!p_slot) return 0; @@ -920,6 +920,7 @@ { struct controller *ctrl = data; u8 schedule_flag = 0; + u8 reset; u16 misc; u32 Diff; u32 temp_dword; @@ -971,6 +972,15 @@ schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); } + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + if (reset & 0x40) { + /* Bus reset has completed */ + reset &= 0xCF; + writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE); + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + wake_up_interruptible(&ctrl->queue); + } + if (schedule_flag) { up(&event_semaphore); dbg("Signal event_semaphore\n"); @@ -1172,6 +1182,7 @@ { u8 hp_slot; u8 temp_byte; + u8 adapter_speed; u32 index; u32 rc = 0; u32 src = 8; @@ -1189,46 +1200,46 @@ //********************************* rc = CARD_FUNCTIONING; } else { - if (ctrl->speed == PCI_SPEED_66MHz) { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); - set_SOGO(ctrl); + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + set_SOGO(ctrl); - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); - set_SOGO(ctrl); + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + set_SOGO(ctrl); - if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; - } - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); - set_SOGO(ctrl); + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + set_SOGO(ctrl); - // Done with exclusive hardware access - up(&ctrl->crit_sect); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); - if (rc) - return(rc); - } + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); // Wait for exclusive access to hardware down(&ctrl->crit_sect); @@ -1376,6 +1387,7 @@ { u8 hp_slot; u8 temp_byte; + u8 adapter_speed; int index; u32 temp_register = 0xFFFFFFFF; u32 rc = 0; @@ -1387,47 +1399,48 @@ dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); - if (ctrl->speed == PCI_SPEED_66MHz) { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); - set_SOGO(ctrl); + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + set_SOGO(ctrl); - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); - set_SOGO(ctrl); + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + set_SOGO(ctrl); - if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) { + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) rc = WRONG_BUS_FREQUENCY; - } - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); + + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); - set_SOGO(ctrl); + set_SOGO(ctrl); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); - // Done with exclusive hardware access - up(&ctrl->crit_sect); + // Done with exclusive hardware access + up(&ctrl->crit_sect); - if (rc) - return(rc); - } - p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + if (rc) + return(rc); + + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); // turn on board and blink green LED @@ -1800,7 +1813,7 @@ if (!func) return; - p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); if (!p_slot) return; @@ -1860,11 +1873,12 @@ } // Wait for exclusive access to hardware down(&ctrl->crit_sect); - + dbg("blink green LED and turn off amber\n"); + amber_LED_off (ctrl, hp_slot); green_LED_blink (ctrl, hp_slot); - + set_SOGO(ctrl); // Wait for SOBS to be unset @@ -1992,7 +2006,7 @@ device = func->device; hp_slot = device - ctrl->slot_device_offset; - p_slot = find_slot(ctrl, device); + p_slot = cpqhp_find_slot(ctrl, device); if (p_slot) { physical_slot = p_slot->number; } @@ -2091,7 +2105,7 @@ device = func->device; func = cpqhp_slot_find(ctrl->bus, device, index++); - p_slot = find_slot(ctrl, device); + p_slot = cpqhp_find_slot(ctrl, device); if (p_slot) { physical_slot = p_slot->number; } diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c --- a/drivers/hotplug/cpqphp_pci.c Mon May 12 20:55:49 2003 +++ b/drivers/hotplug/cpqphp_pci.c Mon May 12 20:55:49 2003 @@ -85,18 +85,20 @@ { unsigned char bus; struct pci_bus *child; - int rc = 0; + int num; if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7)); + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - //Still NULL ? Well then scan for it ! + /* No pci device, we need to create it then */ if (func->pci_dev == NULL) { dbg("INFO: pci_dev still null\n"); - //this will generate pci_dev structures for all functions, but we will only call this case when lookup fails - func->pci_dev = pci_scan_slot(ctrl->pci_dev->bus, - (func->device << 3) + (func->function & 0x7)); + num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(ctrl->pci_dev->bus); + + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); if (func->pci_dev == NULL) { dbg("ERROR: pci_dev still null\n"); return 0; @@ -107,10 +109,9 @@ pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); pci_do_scan_bus(child); - } - return rc; + return 0; } @@ -1209,11 +1210,11 @@ temp = 0; if (!cpqhp_nic_irq) { - cpqhp_nic_irq = ctrl->interrupt; + cpqhp_nic_irq = ctrl->cfgspc_irq; } if (!cpqhp_disk_irq) { - cpqhp_disk_irq = ctrl->interrupt; + cpqhp_disk_irq = ctrl->cfgspc_irq; } dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c --- a/drivers/hotplug/ibmphp_core.c Mon May 12 20:55:49 2003 +++ b/drivers/hotplug/ibmphp_core.c Mon May 12 20:55:49 2003 @@ -846,22 +846,24 @@ { unsigned char bus; struct pci_bus *child; - int rc = 0; + int num; int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ if (!(bus_structure_fixup (func->busno))) flag = 1; if (func->dev == NULL) - func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7)); + func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { struct pci_bus *bus = ibmphp_find_bus (func->busno); if (!bus) return 0; - func->dev = pci_scan_slot(bus, - (func->device << 3) + (func->function & 0x7)); + num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(bus); + func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function)); if (func->dev == NULL) { err ("ERROR... : pci_dev still NULL \n"); return 0; @@ -873,7 +875,7 @@ pci_do_scan_bus (child); } - return rc; + return 0; } /******************************************************* @@ -1415,7 +1417,7 @@ /* lock ourselves into memory with a module * count of -1 so that no one can unload us. */ - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); exit: return rc; diff -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c --- a/drivers/i2c/busses/i2c-ali15x3.c Mon May 12 20:55:46 2003 +++ b/drivers/i2c/busses/i2c-ali15x3.c Mon May 12 20:55:46 2003 @@ -475,6 +475,7 @@ static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &smbus_algorithm, .dev = { .name = "unset", diff -Nru a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c --- a/drivers/i2c/busses/i2c-amd756.c Mon May 12 20:55:48 2003 +++ b/drivers/i2c/busses/i2c-amd756.c Mon May 12 20:55:48 2003 @@ -313,6 +313,7 @@ static struct i2c_adapter amd756_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &smbus_algorithm, .dev = { .name = "unset", diff -Nru a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c --- a/drivers/i2c/busses/i2c-amd8111.c Mon May 12 20:55:48 2003 +++ b/drivers/i2c/busses/i2c-amd8111.c Mon May 12 20:55:48 2003 @@ -360,6 +360,7 @@ snprintf(smbus->adapter.dev.name, DEVICE_NAME_SIZE, "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; + smbus->adapter.class = I2C_ADAP_CLASS_SMBUS; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c --- a/drivers/i2c/busses/i2c-i801.c Mon May 12 20:55:46 2003 +++ b/drivers/i2c/busses/i2c-i801.c Mon May 12 20:55:46 2003 @@ -547,6 +547,7 @@ static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &smbus_algorithm, .dev = { .name = "unset", diff -Nru a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c --- a/drivers/i2c/busses/i2c-isa.c Mon May 12 20:55:47 2003 +++ b/drivers/i2c/busses/i2c-isa.c Mon May 12 20:55:47 2003 @@ -40,6 +40,7 @@ static struct i2c_adapter isa_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_ISA | I2C_HW_ISA, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &isa_algorithm, .dev = { .name = "ISA main adapter", diff -Nru a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c --- a/drivers/i2c/busses/i2c-piix4.c Mon May 12 20:55:45 2003 +++ b/drivers/i2c/busses/i2c-piix4.c Mon May 12 20:55:45 2003 @@ -395,6 +395,7 @@ static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &smbus_algorithm, .dev = { .name = "unset", diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c --- a/drivers/i2c/busses/i2c-viapro.c Mon May 12 20:55:48 2003 +++ b/drivers/i2c/busses/i2c-viapro.c Mon May 12 20:55:48 2003 @@ -295,6 +295,7 @@ static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2, + .class = I2C_ADAP_CLASS_SMBUS, .algo = &smbus_algorithm, .dev = { .name = "unset", diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c Mon May 12 20:55:44 2003 +++ b/drivers/i2c/chips/adm1021.c Mon May 12 20:55:44 2003 @@ -203,6 +203,8 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; return i2c_detect(adapter, &addr_data, adm1021_detect); } diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c --- a/drivers/i2c/chips/it87.c Mon May 12 20:55:48 2003 +++ b/drivers/i2c/chips/it87.c Mon May 12 20:55:48 2003 @@ -3,7 +3,7 @@ monitoring. Supports: IT8705F Super I/O chip w/LPC interface - IT8712F Super I/O chup w/LPC interface & SMbus + IT8712F Super I/O chip w/LPC interface & SMbus Sis950 A clone of the IT8705F Copyright (c) 2001 Chris Gauthron @@ -80,17 +80,17 @@ /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ -#define IT87_REG_FAN(nr) (0x0c + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x0f + (nr)) +#define IT87_REG_FAN(nr) (0x0d + (nr)) +#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) #define IT87_REG_FAN_CTRL 0x13 #define IT87_REG_VIN(nr) (0x20 + (nr)) -#define IT87_REG_TEMP(nr) (0x28 + (nr)) +#define IT87_REG_TEMP(nr) (0x29 + (nr)) #define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) #define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) -#define IT87_REG_TEMP_HIGH(nr) (0x3e + (nr) * 2) -#define IT87_REG_TEMP_LOW(nr) (0x3f + (nr) * 2) +#define IT87_REG_TEMP_HIGH(nr) (0x40 + ((nr) * 2)) +#define IT87_REG_TEMP_LOW(nr) (0x41 + ((nr) * 2)) #define IT87_REG_I2C_ADDR 0x48 @@ -99,46 +99,8 @@ #define IT87_REG_CHIPID 0x58 -static inline u8 IN_TO_REG(long val, int inNum) -{ - /* to avoid floating point, we multiply everything by 100. - val is guaranteed to be positive, so we can achieve the effect of - rounding by (...*10+5)/10. Note that the *10 is hidden in the - /250 (which should really be /2500). - At the end, we need to /100 because we *100 everything and we need - to /10 because of the rounding thing, so we /1000. */ - if (inNum <= 1) - return (u8) - SENSORS_LIMIT(((val * 210240 - 13300) / 250 + 5) / 1000, - 0, 255); - else if (inNum == 2) - return (u8) - SENSORS_LIMIT(((val * 157370 - 13300) / 250 + 5) / 1000, - 0, 255); - else if (inNum == 3) - return (u8) - SENSORS_LIMIT(((val * 101080 - 13300) / 250 + 5) / 1000, - 0, 255); - else - return (u8) SENSORS_LIMIT(((val * 41714 - 13300) / 250 + 5) - / 1000, 0, 255); -} - -static inline long IN_FROM_REG(u8 val, int inNum) -{ - /* to avoid floating point, we multiply everything by 100. - val is guaranteed to be positive, so we can achieve the effect of - rounding by adding 0.5. Or, to avoid fp math, we do (...*10+5)/10. - We need to scale with *100 anyway, so no need to /100 at the end. */ - if (inNum <= 1) - return (long) (((250000 * val + 13300) / 210240 * 10 + 5) /10); - else if (inNum == 2) - return (long) (((250000 * val + 13300) / 157370 * 10 + 5) /10); - else if (inNum == 3) - return (long) (((250000 * val + 13300) / 101080 * 10 + 5) /10); - else - return (long) (((250000 * val + 13300) / 41714 * 10 + 5) /10); -} +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) +#define IN_FROM_REG(val) (((val) * 16) / 10) static inline u8 FAN_TO_REG(long rpm, int div) { @@ -159,7 +121,14 @@ 205-(val)*5) #define ALARMS_FROM_REG(val) (val) -#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) +static int log2(int val) +{ + int answer = 0; + while ((val >>= 1)) + answer++; + return answer; +} +#define DIV_TO_REG(val) log2(val) #define DIV_FROM_REG(val) (1 << (val)) /* Initial limits. Use the config file to set better limits. */ @@ -238,6 +207,7 @@ u8 temp[3]; /* Register value */ u8 temp_high[3]; /* Register value */ u8 temp_low[3]; /* Register value */ + u8 sensor; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u32 alarms; /* Register encoding, combined */ @@ -252,7 +222,7 @@ static int it87_write_value(struct i2c_client *client, u8 register, u8 value); static void it87_update_client(struct i2c_client *client); -static void it87_init_client(struct i2c_client *client); +static void it87_init_client(struct i2c_client *client, struct it87_data *data); static struct i2c_driver it87_driver = { @@ -271,7 +241,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 ); } static ssize_t show_in_min(struct device *dev, char *buf, int nr) @@ -279,7 +249,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 ); } static ssize_t show_in_max(struct device *dev, char *buf, int nr) @@ -287,7 +257,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)*10 ); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 ); } static ssize_t set_in_min(struct device *dev, const char *buf, @@ -296,7 +266,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10)/10; - data->in_min[nr] = IN_TO_REG(val,nr); + data->in_min[nr] = IN_TO_REG(val); it87_write_value(client, IT87_REG_VIN_MIN(nr), data->in_min[nr]); return count; @@ -307,7 +277,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10)/10; - data->in_max[nr] = IN_TO_REG(val,nr); + data->in_max[nr] = IN_TO_REG(val); it87_write_value(client, IT87_REG_VIN_MAX(nr), data->in_max[nr]); return count; @@ -319,6 +289,9 @@ { \ return show_in(dev, buf, 0x##offset); \ } \ +static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL) + +#define limit_in_offset(offset) \ static ssize_t \ show_in##offset##_min (struct device *dev, char *buf) \ { \ @@ -339,17 +312,28 @@ { \ return set_in_max(dev, buf, count, 0x##offset); \ } \ -static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL) \ static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \ show_in##offset##_min, set_in##offset##_min) \ static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \ show_in##offset##_max, set_in##offset##_max) show_in_offset(0); +limit_in_offset(0); show_in_offset(1); +limit_in_offset(1); show_in_offset(2); +limit_in_offset(2); show_in_offset(3); +limit_in_offset(3); show_in_offset(4); +limit_in_offset(4); +show_in_offset(5); +limit_in_offset(5); +show_in_offset(6); +limit_in_offset(6); +show_in_offset(7); +limit_in_offset(7); +show_in_offset(8); /* 3 temperatures */ static ssize_t show_temp(struct device *dev, char *buf, int nr) @@ -357,7 +341,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*10 ); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 ); } /* more like overshoot temperature */ static ssize_t show_temp_max(struct device *dev, char *buf, int nr) @@ -365,7 +349,7 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*10); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100); } /* more like hysteresis temperature */ static ssize_t show_temp_min(struct device *dev, char *buf, int nr) @@ -373,14 +357,14 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); it87_update_client(client); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*10); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100); } static ssize_t set_temp_max(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10)/10; + int val = simple_strtol(buf, NULL, 10)/100; data->temp_high[nr] = TEMP_TO_REG(val); it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); return count; @@ -390,7 +374,7 @@ { struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10)/10; + int val = simple_strtol(buf, NULL, 10)/100; data->temp_low[nr] = TEMP_TO_REG(val); it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); return count; @@ -430,7 +414,52 @@ show_temp_offset(2); show_temp_offset(3); -/* 2 Fans */ +/* more like overshoot temperature */ +static ssize_t show_sensor(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + it87_update_client(client); + if (data->sensor & (1 << nr)) + return sprintf(buf, "1\n"); + if (data->sensor & (8 << nr)) + return sprintf(buf, "2\n"); + return sprintf(buf, "0\n"); +} +static ssize_t set_sensor(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + data->sensor &= ~(1 << nr); + data->sensor &= ~(8 << nr); + if (val == 1) + data->sensor |= 1 << nr; + else if (val == 2) + data->sensor |= 8 << nr; + it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); + return count; +} +#define show_sensor_offset(offset) \ +static ssize_t show_sensor_##offset (struct device *dev, char *buf) \ +{ \ + return show_sensor(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_sensor_##offset (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_sensor(dev, buf, count, 0x##offset - 1); \ +} \ +static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR, \ + show_sensor_##offset, set_sensor_##offset) + +show_sensor_offset(1); +show_sensor_offset(2); +show_sensor_offset(3); + +/* 3 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) { struct i2c_client *client = to_i2c_client(dev); @@ -461,7 +490,7 @@ struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(client, IT87_REG_FAN_MIN(nr+1), data->fan_min[nr]); + it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); return count; } static ssize_t set_fan_div(struct device *dev, const char *buf, @@ -470,10 +499,34 @@ struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); - int old = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[nr] = DIV_TO_REG(val); - old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); - it87_write_value(client, IT87_REG_FAN_DIV, old); + int i, min[3]; + u8 old = it87_read_value(client, IT87_REG_FAN_DIV); + + for (i = 0; i < 3; i++) + min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); + + switch (nr) { + case 0: + case 1: + data->fan_div[nr] = DIV_TO_REG(val); + break; + case 2: + if (val < 8) + data->fan_div[nr] = 1; + else + data->fan_div[nr] = 3; + } + val = old & 0x100; + val |= (data->fan_div[0] & 0x07); + val |= (data->fan_div[1] & 0x07) << 3; + if (data->fan_div[2] == 3) + val |= 0x1 << 6; + it87_write_value(client, IT87_REG_FAN_DIV, val); + + for (i = 0; i < 3; i++) { + data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); + it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); + } return count; } @@ -508,6 +561,7 @@ show_fan_offset(1); show_fan_offset(2); +show_fan_offset(3); /* Alarm */ static ssize_t show_alarm(struct device *dev, char *buf) @@ -525,6 +579,8 @@ * when a new adapter is inserted (and it87_driver is still present) */ static int it87_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; return i2c_detect(adapter, &addr_data, it87_detect); } @@ -574,6 +630,7 @@ } } } + memset (new_client, 0x00, sizeof(struct i2c_client) + sizeof(struct it87_data)); /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. @@ -585,6 +642,8 @@ err = -ENOMEM; goto ERROR1; } + memset(new_client, 0x00, sizeof(struct i2c_client) + + sizeof(struct it87_data)); data = (struct it87_data *) (new_client + 1); if (is_isa) @@ -652,16 +711,26 @@ device_create_file(&new_client->dev, &dev_attr_in_input2); device_create_file(&new_client->dev, &dev_attr_in_input3); device_create_file(&new_client->dev, &dev_attr_in_input4); + device_create_file(&new_client->dev, &dev_attr_in_input5); + device_create_file(&new_client->dev, &dev_attr_in_input6); + device_create_file(&new_client->dev, &dev_attr_in_input7); + device_create_file(&new_client->dev, &dev_attr_in_input8); device_create_file(&new_client->dev, &dev_attr_in_min0); device_create_file(&new_client->dev, &dev_attr_in_min1); device_create_file(&new_client->dev, &dev_attr_in_min2); device_create_file(&new_client->dev, &dev_attr_in_min3); device_create_file(&new_client->dev, &dev_attr_in_min4); + device_create_file(&new_client->dev, &dev_attr_in_min5); + device_create_file(&new_client->dev, &dev_attr_in_min6); + device_create_file(&new_client->dev, &dev_attr_in_min7); device_create_file(&new_client->dev, &dev_attr_in_max0); device_create_file(&new_client->dev, &dev_attr_in_max1); device_create_file(&new_client->dev, &dev_attr_in_max2); device_create_file(&new_client->dev, &dev_attr_in_max3); device_create_file(&new_client->dev, &dev_attr_in_max4); + device_create_file(&new_client->dev, &dev_attr_in_max5); + device_create_file(&new_client->dev, &dev_attr_in_max6); + device_create_file(&new_client->dev, &dev_attr_in_max7); device_create_file(&new_client->dev, &dev_attr_temp_input1); device_create_file(&new_client->dev, &dev_attr_temp_input2); device_create_file(&new_client->dev, &dev_attr_temp_input3); @@ -671,16 +740,22 @@ device_create_file(&new_client->dev, &dev_attr_temp_min1); device_create_file(&new_client->dev, &dev_attr_temp_min2); device_create_file(&new_client->dev, &dev_attr_temp_min3); + device_create_file(&new_client->dev, &dev_attr_sensor1); + device_create_file(&new_client->dev, &dev_attr_sensor2); + device_create_file(&new_client->dev, &dev_attr_sensor3); device_create_file(&new_client->dev, &dev_attr_fan_input1); device_create_file(&new_client->dev, &dev_attr_fan_input2); + device_create_file(&new_client->dev, &dev_attr_fan_input3); device_create_file(&new_client->dev, &dev_attr_fan_min1); device_create_file(&new_client->dev, &dev_attr_fan_min2); + device_create_file(&new_client->dev, &dev_attr_fan_min3); device_create_file(&new_client->dev, &dev_attr_fan_div1); device_create_file(&new_client->dev, &dev_attr_fan_div2); + device_create_file(&new_client->dev, &dev_attr_fan_div3); device_create_file(&new_client->dev, &dev_attr_alarm); /* Initialize the IT87 chip */ - it87_init_client(new_client); + it87_init_client(new_client, data); return 0; ERROR1: @@ -753,70 +828,70 @@ } /* Called when we have found a new IT87. It should set limits, etc. */ -static void it87_init_client(struct i2c_client *client) +static void it87_init_client(struct i2c_client *client, struct it87_data *data) { /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ it87_write_value(client, IT87_REG_CONFIG, 0x80); it87_write_value(client, IT87_REG_VIN_MIN(0), - IN_TO_REG(IT87_INIT_IN_MIN_0, 0)); + IN_TO_REG(IT87_INIT_IN_MIN_0)); it87_write_value(client, IT87_REG_VIN_MAX(0), - IN_TO_REG(IT87_INIT_IN_MAX_0, 0)); + IN_TO_REG(IT87_INIT_IN_MAX_0)); it87_write_value(client, IT87_REG_VIN_MIN(1), - IN_TO_REG(IT87_INIT_IN_MIN_1, 1)); + IN_TO_REG(IT87_INIT_IN_MIN_1)); it87_write_value(client, IT87_REG_VIN_MAX(1), - IN_TO_REG(IT87_INIT_IN_MAX_1, 1)); + IN_TO_REG(IT87_INIT_IN_MAX_1)); it87_write_value(client, IT87_REG_VIN_MIN(2), - IN_TO_REG(IT87_INIT_IN_MIN_2, 2)); + IN_TO_REG(IT87_INIT_IN_MIN_2)); it87_write_value(client, IT87_REG_VIN_MAX(2), - IN_TO_REG(IT87_INIT_IN_MAX_2, 2)); + IN_TO_REG(IT87_INIT_IN_MAX_2)); it87_write_value(client, IT87_REG_VIN_MIN(3), - IN_TO_REG(IT87_INIT_IN_MIN_3, 3)); + IN_TO_REG(IT87_INIT_IN_MIN_3)); it87_write_value(client, IT87_REG_VIN_MAX(3), - IN_TO_REG(IT87_INIT_IN_MAX_3, 3)); + IN_TO_REG(IT87_INIT_IN_MAX_3)); it87_write_value(client, IT87_REG_VIN_MIN(4), - IN_TO_REG(IT87_INIT_IN_MIN_4, 4)); + IN_TO_REG(IT87_INIT_IN_MIN_4)); it87_write_value(client, IT87_REG_VIN_MAX(4), - IN_TO_REG(IT87_INIT_IN_MAX_4, 4)); + IN_TO_REG(IT87_INIT_IN_MAX_4)); it87_write_value(client, IT87_REG_VIN_MIN(5), - IN_TO_REG(IT87_INIT_IN_MIN_5, 5)); + IN_TO_REG(IT87_INIT_IN_MIN_5)); it87_write_value(client, IT87_REG_VIN_MAX(5), - IN_TO_REG(IT87_INIT_IN_MAX_5, 5)); + IN_TO_REG(IT87_INIT_IN_MAX_5)); it87_write_value(client, IT87_REG_VIN_MIN(6), - IN_TO_REG(IT87_INIT_IN_MIN_6, 6)); + IN_TO_REG(IT87_INIT_IN_MIN_6)); it87_write_value(client, IT87_REG_VIN_MAX(6), - IN_TO_REG(IT87_INIT_IN_MAX_6, 6)); + IN_TO_REG(IT87_INIT_IN_MAX_6)); it87_write_value(client, IT87_REG_VIN_MIN(7), - IN_TO_REG(IT87_INIT_IN_MIN_7, 7)); + IN_TO_REG(IT87_INIT_IN_MIN_7)); it87_write_value(client, IT87_REG_VIN_MAX(7), - IN_TO_REG(IT87_INIT_IN_MAX_7, 7)); + IN_TO_REG(IT87_INIT_IN_MAX_7)); /* Note: Battery voltage does not have limit registers */ - it87_write_value(client, IT87_REG_FAN_MIN(1), + it87_write_value(client, IT87_REG_FAN_MIN(0), FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2)); - it87_write_value(client, IT87_REG_FAN_MIN(2), + it87_write_value(client, IT87_REG_FAN_MIN(1), FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2)); - it87_write_value(client, IT87_REG_FAN_MIN(3), + it87_write_value(client, IT87_REG_FAN_MIN(2), FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2)); - it87_write_value(client, IT87_REG_TEMP_HIGH(1), + it87_write_value(client, IT87_REG_TEMP_HIGH(0), TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1)); - it87_write_value(client, IT87_REG_TEMP_LOW(1), + it87_write_value(client, IT87_REG_TEMP_LOW(0), TEMP_TO_REG(IT87_INIT_TEMP_LOW_1)); - it87_write_value(client, IT87_REG_TEMP_HIGH(2), + it87_write_value(client, IT87_REG_TEMP_HIGH(1), TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2)); - it87_write_value(client, IT87_REG_TEMP_LOW(2), + it87_write_value(client, IT87_REG_TEMP_LOW(1), TEMP_TO_REG(IT87_INIT_TEMP_LOW_2)); - it87_write_value(client, IT87_REG_TEMP_HIGH(3), + it87_write_value(client, IT87_REG_TEMP_HIGH(2), TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3)); - it87_write_value(client, IT87_REG_TEMP_LOW(3), + it87_write_value(client, IT87_REG_TEMP_LOW(2), TEMP_TO_REG(IT87_INIT_TEMP_LOW_3)); /* Enable voltage monitors */ it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff); /* Enable Temp1-Temp3 */ - it87_write_value(client, IT87_REG_TEMP_ENABLE, - (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0) - | (temp_type & 0x3f)); + data->sensor = (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0); + data->sensor |= temp_type & 0x3f; + it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor); /* Enable fans */ it87_write_value(client, IT87_REG_FAN_CTRL, @@ -860,18 +935,18 @@ data->in_min[8] = 0; data->in_max[8] = 255; - for (i = 1; i <= 3; i++) { - data->fan[i - 1] = + for (i = 0; i < 3; i++) { + data->fan[i] = it87_read_value(client, IT87_REG_FAN(i)); - data->fan_min[i - 1] = + data->fan_min[i] = it87_read_value(client, IT87_REG_FAN_MIN(i)); } - for (i = 1; i <= 3; i++) { - data->temp[i - 1] = + for (i = 0; i < 3; i++) { + data->temp[i] = it87_read_value(client, IT87_REG_TEMP(i)); - data->temp_high[i - 1] = + data->temp_high[i] = it87_read_value(client, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i - 1] = + data->temp_low[i] = it87_read_value(client, IT87_REG_TEMP_LOW(i)); } @@ -887,7 +962,7 @@ i = it87_read_value(client, IT87_REG_FAN_DIV); data->fan_div[0] = i & 0x07; data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = 1; + data->fan_div[2] = (i & 0x40) ? 3 : 1; data->alarms = it87_read_value(client, IT87_REG_ALARM1) | diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c --- a/drivers/i2c/chips/lm75.c Mon May 12 20:55:44 2003 +++ b/drivers/i2c/chips/lm75.c Mon May 12 20:55:44 2003 @@ -121,6 +121,8 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; return i2c_detect(adapter, &addr_data, lm75_detect); } diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- a/drivers/i2c/chips/via686a.c Mon May 12 20:55:44 2003 +++ b/drivers/i2c/chips/via686a.c Mon May 12 20:55:44 2003 @@ -661,6 +661,8 @@ /* This is called when the module is loaded */ static int via686a_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; return i2c_detect(adapter, &addr_data, via686a_detect); } diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c Mon May 12 20:55:44 2003 +++ b/drivers/i2c/chips/w83781d.c Mon May 12 20:55:44 2003 @@ -1026,6 +1026,8 @@ static int w83781d_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; return i2c_detect(adapter, &addr_data, w83781d_detect); } diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c --- a/drivers/i2c/i2c-core.c Mon May 12 20:55:44 2003 +++ b/drivers/i2c/i2c-core.c Mon May 12 20:55:44 2003 @@ -38,8 +38,8 @@ #define DEB(x) if (i2c_debug>=1) x; #define DEB2(x) if (i2c_debug>=2) x; -static struct i2c_adapter *adapters[I2C_ADAP_MAX]; -static struct i2c_driver *drivers[I2C_DRIVER_MAX]; +static LIST_HEAD(adapters); +static LIST_HEAD(drivers); static DECLARE_MUTEX(core_lists); /**** debug level */ @@ -55,13 +55,17 @@ return 0; } -static struct device_driver i2c_generic_driver = { - .name = "i2c", +static struct device_driver i2c_adapter_driver = { + .name = "i2c_adapter", .bus = &i2c_bus_type, .probe = i2c_device_probe, .remove = i2c_device_remove, }; +static struct class i2c_adapter_class = { + .name = "i2c-adapter" +}; + /* --------------------------------------------------- * registering functions @@ -75,23 +79,17 @@ */ int i2c_add_adapter(struct i2c_adapter *adap) { - int res = 0, i, j; + static int nr = 0; + struct list_head *item; + struct i2c_driver *driver; down(&core_lists); - for (i = 0; i < I2C_ADAP_MAX; i++) - if (NULL == adapters[i]) - break; - if (I2C_ADAP_MAX == i) { - dev_warn(&adap->dev, - "register_adapter - enlarge I2C_ADAP_MAX.\n"); - res = -ENOMEM; - goto out_unlock; - } - - adapters[i] = adap; - init_MUTEX(&adap->bus); - init_MUTEX(&adap->list); + adap->nr = nr++; + init_MUTEX(&adap->bus_lock); + init_MUTEX(&adap->clist_lock); + list_add_tail(&adap->list,&adapters); + INIT_LIST_HEAD(&adap->clients); /* Add the adapter to the driver core. * If the parent pointer is not set up, @@ -99,77 +97,73 @@ */ if (adap->dev.parent == NULL) adap->dev.parent = &legacy_bus; - sprintf(adap->dev.bus_id, "i2c-%d", i); - adap->dev.driver = &i2c_generic_driver; + sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); + adap->dev.driver = &i2c_adapter_driver; device_register(&adap->dev); + /* Add this adapter to the i2c_adapter class */ + memset(&adap->class_dev, 0x00, sizeof(struct class_device)); + adap->class_dev.dev = &adap->dev; + adap->class_dev.class = &i2c_adapter_class; + strncpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE); + class_device_register(&adap->class_dev); + /* inform drivers of new adapters */ - for (j=0;jflags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) + list_for_each(item,&drivers) { + driver = list_entry(item, struct i2c_driver, list); + if (driver->flags & I2C_DF_NOTIFY) /* We ignore the return code; if it fails, too bad */ - drivers[j]->attach_adapter(adap); + driver->attach_adapter(adap); + } up(&core_lists); - - DEB(dev_dbg(&adap->dev, "registered as adapter %d.\n", i)); - out_unlock: - up(&core_lists); - return res;; + DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr)); + return 0; } int i2c_del_adapter(struct i2c_adapter *adap) { - int res = 0, i, j; + struct list_head *item; + struct i2c_driver *driver; + struct i2c_client *client; + int res = 0; down(&core_lists); - for (i = 0; i < I2C_ADAP_MAX; i++) - if (adap == adapters[i]) - break; - if (I2C_ADAP_MAX == i) { - dev_warn(&adap->dev, "unregister_adapter adap not found.\n"); - res = -ENODEV; - goto out_unlock; - } - /* DUMMY drivers do not register their clients, so we have to - * use a trick here: we call driver->attach_adapter to - * *detach* it! Of course, each dummy driver should know about - * this or hell will break loose... - */ - for (j = 0; j < I2C_DRIVER_MAX; j++) - if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) - if ((res = drivers[j]->attach_adapter(adap))) { + list_for_each(item,&drivers) { + driver = list_entry(item, struct i2c_driver, list); + if (driver->detach_adapter) + if ((res = driver->detach_adapter(adap))) { dev_warn(&adap->dev, "can't detach adapter" - "while detaching driver %s: driver not " - "detached!", drivers[j]->name); + "while detaching driver %s: driver not " + "detached!", driver->name); goto out_unlock; } + } /* detach any active clients. This must be done first, because * it can fail; in which case we give upp. */ - for (j=0;jclients[j]; - if (client!=NULL) { - /* detaching devices is unconditional of the set notify - * flag, as _all_ clients that reside on the adapter - * must be deleted, as this would cause invalid states. - */ - if ((res=client->driver->detach_client(client))) { - dev_err(&adap->dev, "adapter not " - "unregistered, because client at " - "address %02x can't be detached. ", - client->addr); - goto out_unlock; - } + list_for_each(item,&adap->clients) { + client = list_entry(item, struct i2c_client, list); + + /* detaching devices is unconditional of the set notify + * flag, as _all_ clients that reside on the adapter + * must be deleted, as this would cause invalid states. + */ + if ((res=client->driver->detach_client(client))) { + dev_err(&adap->dev, "adapter not " + "unregistered, because client at " + "address %02x can't be detached. ", + client->addr); + goto out_unlock; } } /* clean up the sysfs representation */ + class_device_unregister(&adap->class_dev); device_unregister(&adap->dev); - - adapters[i] = NULL; + list_del(&adap->list); DEB(dev_dbg(&adap->dev, "adapter unregistered\n")); @@ -187,24 +181,11 @@ int i2c_add_driver(struct i2c_driver *driver) { - int res = 0, i; + struct list_head *item; + struct i2c_adapter *adapter; + int res = 0; down(&core_lists); - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (NULL == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) { - printk(KERN_WARNING - " i2c-core.o: register_driver(%s) " - "- enlarge I2C_DRIVER_MAX.\n", - driver->name); - res = -ENOMEM; - goto out_unlock; - } - - drivers[i] = driver; - - DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); /* add the driver to the list of i2c drivers in the driver core */ driver->driver.name = driver->name; @@ -216,13 +197,14 @@ if (res) goto out_unlock; - /* now look for instances of driver on our adapters - */ - if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) { - for (i=0;iattach_adapter(adapters[i]); + list_add_tail(&driver->list,&drivers); + DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); + + /* now look for instances of driver on our adapters */ + if (driver->flags & I2C_DF_NOTIFY) { + list_for_each(item,&adapters) { + adapter = list_entry(item, struct i2c_adapter, list); + driver->attach_adapter(adapter); } } @@ -233,44 +215,29 @@ int i2c_del_driver(struct i2c_driver *driver) { - int res = 0, i, j, k; + struct list_head *item1; + struct list_head *item2; + struct i2c_client *client; + struct i2c_adapter *adap; + + int res = 0; down(&core_lists); - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (driver == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) { - printk(KERN_WARNING " i2c-core.o: unregister_driver: " - "[%s] not found\n", - driver->name); - res = -ENODEV; - goto out_unlock; - } - - driver_unregister(&driver->driver); /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver * afterwards. */ DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); - /* removing clients does not depend on the notify flag, else * invalid operation might (will!) result, when using stale client * pointers. */ - for (k=0;kdev, "examining adapter\n")); - if (driver->flags & I2C_DF_DUMMY) { - /* DUMMY drivers do not register their clients, so we have to - * use a trick here: we call driver->attach_adapter to - * *detach* it! Of course, each dummy driver should know about - * this or hell will break loose... - */ - if ((res = driver->attach_adapter(adap))) { + if (driver->detach_adapter) { + if ((res = driver->detach_adapter(adap))) { dev_warn(&adap->dev, "while unregistering " "dummy driver %s, adapter could " "not be detached properly; driver " @@ -278,31 +245,31 @@ goto out_unlock; } } else { - for (j=0;jclients[j]; - if (client != NULL && - client->driver == driver) { - DEB2(printk(KERN_DEBUG "i2c-core.o: " - "detaching client %s:\n", - client->dev.name)); - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "while " - "unregistering driver " - "`%s', the client at " - "address %02x of " - "adapter could not " - "be detached; driver " - "not unloaded!", - driver->name, - client->addr); - goto out_unlock; - } + list_for_each(item2,&adap->clients) { + client = list_entry(item2, struct i2c_client, list); + if (client->driver != driver) + continue; + DEB2(printk(KERN_DEBUG "i2c-core.o: " + "detaching client %s:\n", + client->dev.name)); + if ((res = driver->detach_client(client))) { + dev_err(&adap->dev, "while " + "unregistering driver " + "`%s', the client at " + "address %02x of " + "adapter could not " + "be detached; driver " + "not unloaded!", + driver->name, + client->addr); + goto out_unlock; } } } } - drivers[i] = NULL; - + + driver_unregister(&driver->driver); + list_del(&driver->list); DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); out_unlock: @@ -310,14 +277,16 @@ return 0; } -static int __i2c_check_addr(struct i2c_adapter *adapter, int addr) +static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - int i; + struct list_head *item; + struct i2c_client *client; - for (i = 0; i < I2C_CLIENT_MAX ; i++) - if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) + list_for_each(item,&adapter->clients) { + client = list_entry(item, struct i2c_client, list); + if (client->addr == addr) return -EBUSY; - + } return 0; } @@ -325,9 +294,9 @@ { int rval; - down(&adapter->list); + down(&adapter->clist_lock); rval = __i2c_check_addr(adapter, addr); - up(&adapter->list); + up(&adapter->clist_lock); return rval; } @@ -335,28 +304,14 @@ int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - int i; - - down(&adapter->list); - if (__i2c_check_addr(client->adapter, client->addr)) - goto out_unlock_list; - for (i = 0; i < I2C_CLIENT_MAX; i++) { - if (!adapter->clients[i]) - goto free_slot; + down(&adapter->clist_lock); + if (__i2c_check_addr(client->adapter, client->addr)) { + up(&adapter->clist_lock); + return -EBUSY; } - - printk(KERN_WARNING - " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", - client->dev.name); - - out_unlock_list: - up(&adapter->list); - return -EBUSY; - - free_slot: - adapter->clients[i] = client; - up(&adapter->list); + list_add_tail(&client->list,&adapter->clients); + up(&adapter->clist_lock); if (adapter->client_register) { if (adapter->client_register(client)) { @@ -366,8 +321,8 @@ } } - DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter " - "(pos. %d).\n", client->dev.name, i)); + DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter\n", + client->dev.name)); if (client->flags & I2C_CLIENT_ALLOW_USE) client->usage_count = 0; @@ -388,7 +343,7 @@ int i2c_detach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - int res = 0, i; + int res = 0; if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0)) return -EBUSY; @@ -403,22 +358,11 @@ } } - down(&adapter->list); - for (i = 0; i < I2C_CLIENT_MAX; i++) { - if (client == adapter->clients[i]) { - adapter->clients[i] = NULL; - goto out_unlock; - } - } - - printk(KERN_WARNING - " i2c-core.o: unregister_client [%s] not found\n", - client->dev.name); - res = -ENODEV; - - out_unlock: + down(&adapter->clist_lock); + list_del(&client->list); device_unregister(&client->dev); - up(&adapter->list); + up(&adapter->clist_lock); + out: return res; } @@ -479,6 +423,27 @@ return 0; } +void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) +{ + struct list_head *item; + struct i2c_client *client; + + down(&adap->clist_lock); + list_for_each(item,&adap->clients) { + client = list_entry(item, struct i2c_client, list); + if (!try_module_get(client->driver->owner)) + continue; + if (NULL != client->driver->command) { + up(&adap->clist_lock); + client->driver->command(client,cmd,arg); + down(&adap->clist_lock); + } + module_put(client->driver->owner); + } + up(&adap->clist_lock); +} + + /* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { @@ -490,14 +455,23 @@ .match = i2c_device_match, }; - static int __init i2c_init(void) { - return bus_register(&i2c_bus_type); + int retval; + + retval = bus_register(&i2c_bus_type); + if (retval) + return retval; + retval = driver_register(&i2c_adapter_driver); + if (retval) + return retval; + return class_register(&i2c_adapter_class); } static void __exit i2c_exit(void) { + class_unregister(&i2c_adapter_class); + driver_unregister(&i2c_adapter_driver); bus_unregister(&i2c_bus_type); } @@ -516,13 +490,13 @@ if (adap->algo->master_xfer) { DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num)); - down(&adap->bus); + down(&adap->bus_lock); ret = adap->algo->master_xfer(adap,msgs,num); - up(&adap->bus); + up(&adap->bus_lock); return ret; } else { - dev_err(&adap->dev, "I2C level transfers not supported\n"); + DEB2(dev_dbg(&adap->dev, "I2C level transfers not supported\n")); return -ENOSYS; } } @@ -542,9 +516,9 @@ DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", count)); - down(&adap->bus); + down(&adap->bus_lock); ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus); + up(&adap->bus_lock); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. @@ -572,9 +546,9 @@ DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", count)); - down(&adap->bus); + down(&adap->bus_lock); ret = adap->algo->master_xfer(adap,&msg,1); - up(&adap->bus); + up(&adap->bus_lock); DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); @@ -743,11 +717,30 @@ */ int i2c_adapter_id(struct i2c_adapter *adap) { - int i; - for (i = 0; i < I2C_ADAP_MAX; i++) - if (adap == adapters[i]) - return i; - return -1; + return adap->nr; +} + +struct i2c_adapter* i2c_get_adapter(int id) +{ + struct list_head *item; + struct i2c_adapter *adapter; + + down(&core_lists); + list_for_each(item,&adapters) { + adapter = list_entry(item, struct i2c_adapter, list); + if (id == adapter->nr && + try_module_get(adapter->owner)) { + up(&core_lists); + return adapter; + } + } + up(&core_lists); + return NULL; +} + +void i2c_put_adapter(struct i2c_adapter *adap) +{ + module_put(adap->owner); } /* The SMBus parts */ @@ -1189,10 +1182,10 @@ } if (adapter->algo->smbus_xfer) { - down(&adapter->bus); + down(&adapter->bus_lock); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, command,size,data); - up(&adapter->bus); + up(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); @@ -1232,6 +1225,7 @@ EXPORT_SYMBOL(i2c_detach_client); EXPORT_SYMBOL(i2c_use_client); EXPORT_SYMBOL(i2c_release_client); +EXPORT_SYMBOL(i2c_clients_command); EXPORT_SYMBOL(i2c_check_addr); EXPORT_SYMBOL(i2c_master_send); @@ -1239,6 +1233,8 @@ EXPORT_SYMBOL(i2c_control); EXPORT_SYMBOL(i2c_transfer); EXPORT_SYMBOL(i2c_adapter_id); +EXPORT_SYMBOL(i2c_get_adapter); +EXPORT_SYMBOL(i2c_put_adapter); EXPORT_SYMBOL(i2c_probe); EXPORT_SYMBOL(i2c_smbus_xfer); diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c --- a/drivers/i2c/i2c-dev.c Mon May 12 20:55:48 2003 +++ b/drivers/i2c/i2c-dev.c Mon May 12 20:55:48 2003 @@ -58,6 +58,7 @@ static int i2cdev_release (struct inode *inode, struct file *file); static int i2cdev_attach_adapter(struct i2c_adapter *adap); +static int i2cdev_detach_adapter(struct i2c_adapter *adap); static int i2cdev_detach_client(struct i2c_client *client); static int i2cdev_command(struct i2c_client *client, unsigned int cmd, void *arg); @@ -72,15 +73,13 @@ .release = i2cdev_release, }; -#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX -static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX]; - static struct i2c_driver i2cdev_driver = { .owner = THIS_MODULE, .name = "dev driver", .id = I2C_DRIVERID_I2CDEV, - .flags = I2C_DF_DUMMY, + .flags = I2C_DF_NOTIFY, .attach_adapter = i2cdev_attach_adapter, + .detach_adapter = i2cdev_detach_adapter, .detach_client = i2cdev_detach_client, .command = i2cdev_command, }; @@ -340,35 +339,31 @@ { unsigned int minor = minor(inode->i_rdev); struct i2c_client *client; + struct i2c_adapter *adap; - if ((minor >= I2CDEV_ADAPS_MAX) || !(i2cdev_adaps[minor])) + adap = i2c_get_adapter(minor); + if (NULL == adap) return -ENODEV; client = kmalloc(sizeof(*client), GFP_KERNEL); - if (!client) + if (!client) { + i2c_put_adapter(adap); return -ENOMEM; + } memcpy(client, &i2cdev_client_template, sizeof(*client)); /* registered with adapter, passed as client to user */ - client->adapter = i2cdev_adaps[minor]; + client->adapter = adap; file->private_data = client; - /* use adapter module, i2c-dev handled with fops */ - if (!try_module_get(client->adapter->owner)) - goto out_kfree; - return 0; - -out_kfree: - kfree(client); - return -ENODEV; } static int i2cdev_release(struct inode *inode, struct file *file) { struct i2c_client *client = file->private_data; - module_put(client->adapter->owner); + i2c_put_adapter(client->adapter); kfree(client); file->private_data = NULL; @@ -378,32 +373,22 @@ int i2cdev_attach_adapter(struct i2c_adapter *adap) { int i; - char name[12]; - if ((i = i2c_adapter_id(adap)) < 0) { - dev_dbg(&adap->dev, "Unknown adapter ?!?\n"); - return -ENODEV; - } - if (i >= I2CDEV_ADAPS_MAX) { - dev_dbg(&adap->dev, "Adapter number too large?!? (%d)\n",i); - return -ENODEV; - } + i = i2c_adapter_id(adap); + devfs_mk_cdev(MKDEV(I2C_MAJOR, i), + S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i); + dev_dbg(&adap->dev, "Registered as minor %d\n", i); + return 0; +} - sprintf (name, "i2c/%d", i); - if (! i2cdev_adaps[i]) { - i2cdev_adaps[i] = adap; - devfs_register (NULL, name, - DEVFS_FL_DEFAULT, I2C_MAJOR, i, - S_IFCHR | S_IRUSR | S_IWUSR, - &i2cdev_fops, NULL); - dev_dbg(&adap->dev, "Registered as minor %d\n", i); - } else { - /* This is actually a detach_adapter call! */ - devfs_remove("i2c/%d", i); - i2cdev_adaps[i] = NULL; - dev_dbg(&adap->dev, "Adapter unregistered\n"); - } +int i2cdev_detach_adapter(struct i2c_adapter *adap) +{ + int i; + + i = i2c_adapter_id(adap); + devfs_remove("i2c/%d", i); + dev_dbg(&adap->dev, "Adapter unregistered\n"); return 0; } diff -Nru a/drivers/i2c/i2c-keywest.c b/drivers/i2c/i2c-keywest.c --- a/drivers/i2c/i2c-keywest.c Mon May 12 20:55:47 2003 +++ b/drivers/i2c/i2c-keywest.c Mon May 12 20:55:47 2003 @@ -212,7 +212,7 @@ #ifndef POLLED_MODE /* Interrupt handler */ -static void +static irqreturn_t keywest_irq(int irq, void *dev_id, struct pt_regs *regs) { struct keywest_iface *iface = (struct keywest_iface *)dev_id; @@ -225,6 +225,7 @@ add_timer(&iface->timeout_timer); } spin_unlock(&iface->lock); + return IRQ_HANDLED; } static void diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Mon May 12 20:55:46 2003 +++ b/drivers/ide/ide-cd.c Mon May 12 20:55:46 2003 @@ -2871,6 +2871,11 @@ struct atapi_capabilities_page cap; int nslots = 1; + if (drive->media == ide_optical) { + printk("%s: ATAPI magneto-optical drive\n", drive->name); + return nslots; + } + if (CDROM_CONFIG_FLAGS(drive)->nec260) { CDROM_CONFIG_FLAGS(drive)->no_eject = 0; CDROM_CONFIG_FLAGS(drive)->audio_play = 1; @@ -3337,7 +3342,7 @@ goto failed; if (!drive->present) goto failed; - if (drive->media != ide_cdrom) + if (drive->media != ide_cdrom && drive->media != ide_optical) goto failed; /* skip drives that we were told to ignore */ if (ignore != NULL) { diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c --- a/drivers/ide/ide-io.c Mon May 12 20:55:48 2003 +++ b/drivers/ide/ide-io.c Mon May 12 20:55:48 2003 @@ -850,14 +850,14 @@ * happens anyway when any interrupt comes in, IDE or otherwise * -- the kernel masks the IRQ while it is being handled. */ - if (hwif->irq != masked_irq) + if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) disable_irq_nosync(hwif->irq); spin_unlock(&ide_lock); local_irq_enable(); /* allow other IRQs while we start this request */ startstop = start_request(drive, rq); spin_lock_irq(&ide_lock); - if (hwif->irq != masked_irq) + if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) enable_irq(hwif->irq); if (startstop == ide_released) goto queue_next; diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Mon May 12 20:55:47 2003 +++ b/drivers/ide/ide-probe.c Mon May 12 20:55:47 2003 @@ -803,7 +803,7 @@ return; if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) && -#if CONFIG_BLK_DEV_PDC4030 +#ifdef CONFIG_BLK_DEV_PDC4030 (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ (hwif_check_regions(hwif))) { @@ -1235,7 +1235,7 @@ (void) request_module("ide-disk"); if (drive->scsi) (void) request_module("ide-scsi"); - if (drive->media == ide_cdrom) + if (drive->media == ide_cdrom || drive->media == ide_optical) (void) request_module("ide-cd"); if (drive->media == ide_tape) (void) request_module("ide-tape"); diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Mon May 12 20:55:45 2003 +++ b/drivers/ide/ide-tape.c Mon May 12 20:55:45 2003 @@ -6292,11 +6292,9 @@ devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor) S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL, "%s/mt", drive->devfs_name); devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128), S_IFCHR | S_IRUGO | S_IWUGO, - &idetape_fops, NULL, "%s/mtn", drive->devfs_name); drive->disk->number = devfs_register_tape(drive->devfs_name); diff -Nru a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c --- a/drivers/ieee1394/amdtp.c Mon May 12 20:55:47 2003 +++ b/drivers/ieee1394/amdtp.c Mon May 12 20:55:47 2003 @@ -1205,7 +1205,6 @@ { struct amdtp_host *ah; int minor; - char name[16]; if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0) return; @@ -1223,13 +1222,11 @@ minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id; - sprintf(name, "amdtp/%d", ah->ohci->id); - INIT_LIST_HEAD(&ah->stream_list); spin_lock_init(&ah->stream_list_lock); - devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor, - S_IFCHR | S_IRUSR | S_IWUSR, &amdtp_fops, NULL); + devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), + S_IFCHR|S_IRUSR|S_IWUSR, "amdtp/%d", ah->ohci->id); } static void amdtp_remove_host(struct hpsb_host *host) diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Mon May 12 20:55:48 2003 +++ b/drivers/ieee1394/dv1394.c Mon May 12 20:55:48 2003 @@ -2420,24 +2420,6 @@ }; -#ifdef CONFIG_DEVFS_FS -static int dv1394_devfs_add_entry(struct video_card *video) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "ieee1394/dv/host%d/%s/%s", - (video->id>>2), - (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), - (video->mode == MODE_RECEIVE ? "in" : "out")); - - devfs_register(NULL, buf, 0, IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_DV1394*16 + video->id, - S_IFCHR | S_IRUGO | S_IWUGO, &dv1394_fops, video); - return 0; -} -#endif /* CONFIG_DEVFS_FS */ - - /*** HOTPLUG STUFF **********************************************************/ /* * Export information about protocols/devices supported by this driver. @@ -2536,10 +2518,14 @@ list_add_tail(&video->list, &dv1394_cards); spin_unlock_irqrestore(&dv1394_cards_lock, flags); -#ifdef CONFIG_DEVFS_FS - if (dv1394_devfs_add_entry(video) < 0) + if (devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_DV1394*16 + video->id), + S_IFCHR|S_IRUGO|S_IWUGO, + "ieee1394/dv/host%d/%s/%s", + (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), + (video->mode == MODE_RECEIVE ? "in" : "out")) < 0) goto err_free; -#endif debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id); @@ -2562,9 +2548,7 @@ (video->mode == MODE_RECEIVE ? "in" : "out") ); -#ifdef CONFIG_DEVFS_FS devfs_remove("ieee1394/%s", buf); -#endif #ifdef CONFIG_PROC_FS dv1394_procfs_del(buf); #endif @@ -2602,11 +2586,9 @@ n = (video->id >> 2); -#ifdef CONFIG_DEVFS_FS devfs_remove("ieee1394/dv/host%d/NTSC", n); devfs_remove("ieee1394/dv/host%d/PAL", n); devfs_remove("ieee1394/dv/host%d", n); -#endif #ifdef CONFIG_PROC_FS snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); @@ -2642,11 +2624,9 @@ } #endif -#ifdef CONFIG_DEVFS_FS devfs_mk_dir("ieee1394/dv/host%d", ohci->id); devfs_mk_dir("ieee1394/dv/host%d/NTSC", ohci->id); devfs_mk_dir("ieee1394/dv/host%d/PAL", ohci->id); -#endif dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT); @@ -2901,9 +2881,7 @@ hpsb_unregister_highlevel(&dv1394_highlevel); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); -#ifdef CONFIG_DEVFS_FS devfs_remove("ieee1394/dv"); -#endif #ifdef CONFIG_PROC_FS dv1394_procfs_del("dv"); #endif @@ -2920,18 +2898,14 @@ return -EIO; } -#ifdef CONFIG_DEVFS_FS devfs_mk_dir("ieee1394/dv"); -#endif #ifdef CONFIG_PROC_FS ret = dv1394_procfs_add_dir("dv",NULL,NULL); if (ret < 0) { printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); -#ifdef CONFIG_DEVFS_FS devfs_remove("ieee1394/dv"); -#endif return -ENOMEM; } #endif diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c --- a/drivers/ieee1394/raw1394.c Mon May 12 20:55:44 2003 +++ b/drivers/ieee1394/raw1394.c Mon May 12 20:55:44 2003 @@ -2531,9 +2531,8 @@ { hpsb_register_highlevel(&raw1394_highlevel); - devfs_register(NULL, RAW1394_DEVICE_NAME, 0, - IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16, - S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL); + devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), + S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME); if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394, THIS_MODULE, &file_ops)) { diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c --- a/drivers/ieee1394/video1394.c Mon May 12 20:55:45 2003 +++ b/drivers/ieee1394/video1394.c Mon May 12 20:55:45 2003 @@ -1257,7 +1257,6 @@ static void video1394_add_host (struct hpsb_host *host) { struct ti_ohci *ohci; - char name[16]; int minor; /* We only work with the OHCI-1394 driver */ @@ -1274,12 +1273,10 @@ hpsb_set_hostinfo(&video1394_highlevel, host, ohci); hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->id); - sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id); - minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id; - devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor, - S_IFCHR | S_IRUSR | S_IWUSR, &video1394_fops, NULL); - - return; + minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id; + devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor), + S_IFCHR | S_IRUSR | S_IWUSR, + "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id); } diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c --- a/drivers/input/evdev.c Mon May 12 20:55:48 2003 +++ b/drivers/input/evdev.c Mon May 12 20:55:48 2003 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -400,7 +401,9 @@ sprintf(evdev->name, "event%d", minor); evdev_table[minor] = evdev; - input_register_minor("input/event%d", minor, EVDEV_MINOR_BASE); + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor), + S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor); return &evdev->handle; } diff -Nru a/drivers/input/input.c b/drivers/input/input.c --- a/drivers/input/input.c Mon May 12 20:55:47 2003 +++ b/drivers/input/input.c Mon May 12 20:55:47 2003 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,6 @@ EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_register_handler); EXPORT_SYMBOL(input_unregister_handler); -EXPORT_SYMBOL(input_register_minor); EXPORT_SYMBOL(input_open_device); EXPORT_SYMBOL(input_close_device); EXPORT_SYMBOL(input_accept_process); @@ -40,7 +40,6 @@ EXPORT_SYMBOL(input_event); EXPORT_SYMBOL(input_class); -#define INPUT_MAJOR 13 #define INPUT_DEVICES 256 static LIST_HEAD(input_dev_list); @@ -540,15 +539,6 @@ .owner = THIS_MODULE, .open = input_open_file, }; - -void input_register_minor(char *name, int minor, int minor_base) -{ - char devfs_name[16]; - - sprintf(devfs_name, name, minor); - devfs_register(NULL, devfs_name, 0, INPUT_MAJOR, minor_base + minor, - S_IFCHR|S_IRUGO|S_IWUSR, &input_fops, NULL); -} #ifdef CONFIG_PROC_FS diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c --- a/drivers/input/joydev.c Mon May 12 20:55:46 2003 +++ b/drivers/input/joydev.c Mon May 12 20:55:46 2003 @@ -445,7 +445,9 @@ } joydev_table[minor] = joydev; - input_register_minor("js%d", minor, JOYDEV_MINOR_BASE); + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + S_IFCHR|S_IRUGO|S_IWUSR, "js%d", minor); return &joydev->handle; } diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c --- a/drivers/input/mousedev.c Mon May 12 20:55:48 2003 +++ b/drivers/input/mousedev.c Mon May 12 20:55:48 2003 @@ -432,7 +432,9 @@ input_open_device(&mousedev->handle); mousedev_table[minor] = mousedev; - input_register_minor("input/mouse%d", minor, MOUSEDEV_MINOR_BASE); + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor); return &mousedev->handle; } @@ -502,7 +504,10 @@ mousedev_table[MOUSEDEV_MIX] = &mousedev_mix; mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - input_register_minor("input/mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), + S_IFCHR|S_IRUGO|S_IWUSR, "input/mice"); + #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX if (!(mousedev_mix.misc = !misc_register(&psaux_mouse))) diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c Mon May 12 20:55:44 2003 +++ b/drivers/input/serio/i8042.c Mon May 12 20:55:44 2003 @@ -62,6 +62,12 @@ static unsigned char i8042_mux_open; struct timer_list i8042_timer; +/* + * Shared IRQ's require a device pointer, but this driver doesn't support + * multiple devices + */ +#define i8042_request_irq_cookie (&i8042_timer) + static unsigned long i8042_unxlate_seen[256 / BITS_PER_LONG]; static unsigned char i8042_unxlate_table[128] = { 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, @@ -235,7 +241,8 @@ if (i8042_mux_open++) return 0; - if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) { + if (request_irq(values->irq, i8042_interrupt, + SA_SHIRQ, "i8042", i8042_request_irq_cookie)) { printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name); values->exists = 0; serio_unregister_port(port); @@ -275,7 +282,7 @@ return; } - free_irq(values->irq, NULL); + free_irq(values->irq, i8042_request_irq_cookie); i8042_flush(); } @@ -572,9 +579,10 @@ * Check if AUX irq is available. */ - if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) + if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ, + "i8042", i8042_request_irq_cookie)) return -1; - free_irq(values->irq, NULL); + free_irq(values->irq, i8042_request_irq_cookie); /* * Get rid of bytes in the queue. @@ -643,9 +651,10 @@ * in trying to detect AUX presence. */ - if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) + if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ, + "i8042", i8042_request_irq_cookie)) return -1; - free_irq(values->irq, NULL); + free_irq(values->irq, i8042_request_irq_cookie); /* * Get rid of bytes in the queue. diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c --- a/drivers/input/tsdev.c Mon May 12 20:55:49 2003 +++ b/drivers/input/tsdev.c Mon May 12 20:55:49 2003 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -329,8 +330,9 @@ tsdev->handle.private = tsdev; tsdev_table[minor] = tsdev; - input_register_minor("input/ts%d", minor, TSDEV_MINOR_BASE); - + + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), + S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); return &tsdev->handle; } diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c --- a/drivers/isdn/capi/capi.c Mon May 12 20:55:49 2003 +++ b/drivers/isdn/capi/capi.c Mon May 12 20:55:49 2003 @@ -200,10 +200,8 @@ unsigned int minor = 0; unsigned long flags; - MOD_INC_USE_COUNT; mp = kmalloc(sizeof(*mp), GFP_ATOMIC); if (!mp) { - MOD_DEC_USE_COUNT; printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; } @@ -249,7 +247,6 @@ skb_queue_purge(&mp->outqueue); capiminor_del_all_ack(mp); kfree(mp); - MOD_DEC_USE_COUNT; } struct capiminor *capiminor_find(unsigned int minor) @@ -1280,6 +1277,7 @@ memset(drv, 0, sizeof(struct tty_driver)); drv->magic = TTY_DRIVER_MAGIC; + drv->owner = THIS_MODULE; drv->driver_name = "capi_nc"; drv->name = "capi/"; drv->major = capi_ttymajor; @@ -1460,7 +1458,6 @@ char *p; char *compileinfo; - MOD_INC_USE_COUNT; if ((p = strchr(revision, ':')) != 0 && p[1]) { strncpy(rev, p + 2, sizeof(rev)); @@ -1472,19 +1469,17 @@ if (register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); - MOD_DEC_USE_COUNT; return -EIO; } - devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT, - capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, - &capi_fops, NULL); + devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, + "isdn/capi20"); + printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { unregister_chrdev(capi_major, "capi20"); - MOD_DEC_USE_COUNT; return -ENOMEM; } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -1503,7 +1498,6 @@ printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n", rev, capi_major, compileinfo); - MOD_DEC_USE_COUNT; return 0; } diff -Nru a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c --- a/drivers/isdn/eicon/eicon_mod.c Mon May 12 20:55:44 2003 +++ b/drivers/isdn/eicon/eicon_mod.c Mon May 12 20:55:44 2003 @@ -245,7 +245,7 @@ card->hwif.isa.shmem = (eicon_isa_shmem *)a; return 0; case EICON_BUS_MCA: -#if CONFIG_MCA +#ifdef CONFIG_MCA if (eicon_mca_find_card( 0, a, card->hwif.isa.irq, @@ -853,7 +853,7 @@ card->type = Type; switch (Type) { #ifdef CONFIG_ISDN_DRV_EICON_ISA -#if CONFIG_MCA /* only needed for MCA */ +#ifdef CONFIG_MCA /* only needed for MCA */ case EICON_CTYPE_S: case EICON_CTYPE_SX: case EICON_CTYPE_SCOM: @@ -1342,7 +1342,7 @@ static void __exit eicon_exit(void) { -#if CONFIG_PCI +#ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI card_t *pCard; word wCardIndex; @@ -1374,7 +1374,7 @@ eicon_freecard(last); } -#if CONFIG_PCI +#ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI pCard = DivasCards; for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++) diff -Nru a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c --- a/drivers/isdn/eicon/eicon_pci.c Mon May 12 20:55:48 2003 +++ b/drivers/isdn/eicon/eicon_pci.c Mon May 12 20:55:48 2003 @@ -26,7 +26,7 @@ char *eicon_pci_revision = "$Revision: 1.1.4.1.2.3 $"; -#if CONFIG_PCI /* intire stuff is only for PCI */ +#ifdef CONFIG_PCI /* entire stuff is only for PCI */ #ifdef CONFIG_ISDN_DRV_EICON_PCI int eicon_pci_find_card(char *ID) diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c --- a/drivers/isdn/hardware/eicon/divamnt.c Mon May 12 20:55:46 2003 +++ b/drivers/isdn/hardware/eicon/divamnt.c Mon May 12 20:55:46 2003 @@ -420,10 +420,8 @@ DRIVERLNAME); return (0); } - devfs_register(NULL, "DivasMAINT", DEVFS_FL_DEFAULT, major, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &divas_maint_fops, - NULL); + devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DivasMAINT); return (1); } diff -Nru a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c --- a/drivers/isdn/hardware/eicon/divasi.c Mon May 12 20:55:46 2003 +++ b/drivers/isdn/hardware/eicon/divasi.c Mon May 12 20:55:46 2003 @@ -179,10 +179,8 @@ DRIVERLNAME); return (0); } - devfs_register(NULL, "DivasIDI", DEVFS_FL_DEFAULT, major, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &divas_idi_fops, - NULL); + devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "DivasIDI"); return (1); } diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c --- a/drivers/isdn/hardware/eicon/divasmain.c Mon May 12 20:55:44 2003 +++ b/drivers/isdn/hardware/eicon/divasmain.c Mon May 12 20:55:44 2003 @@ -788,9 +788,8 @@ DRIVERLNAME); return (0); } - devfs_register(NULL, "Divas", DEVFS_FL_DEFAULT, major, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &divas_fops, NULL); + devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "Divas"); return (1); } diff -Nru a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c --- a/drivers/isdn/hisax/avm_pci.c Mon May 12 20:55:45 2003 +++ b/drivers/isdn/hisax/avm_pci.c Mon May 12 20:55:45 2003 @@ -730,7 +730,7 @@ } } #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, dev_avm))) { if (avm_pci_probe(card->cs, dev_avm)) diff -Nru a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c --- a/drivers/isdn/hisax/diva.c Mon May 12 20:55:49 2003 +++ b/drivers/isdn/hisax/diva.c Mon May 12 20:55:49 2003 @@ -772,7 +772,7 @@ } } #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c --- a/drivers/isdn/hisax/elsa.c Mon May 12 20:55:45 2003 +++ b/drivers/isdn/hisax/elsa.c Mon May 12 20:55:45 2003 @@ -1098,7 +1098,7 @@ return 0; return 1; } else if (card->typ == ISDN_CTYPE_ELSA_PCI) { -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { if (elsa_qs_pci_probe(card->cs, dev_qs1000, diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c --- a/drivers/isdn/hisax/niccy.c Mon May 12 20:55:46 2003 +++ b/drivers/isdn/hisax/niccy.c Mon May 12 20:55:46 2003 @@ -319,7 +319,7 @@ return 0; return 1; } else { -#if CONFIG_PCI +#ifdef CONFIG_PCI if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) { if (niccy_pci_probe(card->cs, niccy_dev) < 0) diff -Nru a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c --- a/drivers/isdn/hisax/sedlbauer.c Mon May 12 20:55:49 2003 +++ b/drivers/isdn/hisax/sedlbauer.c Mon May 12 20:55:49 2003 @@ -789,7 +789,7 @@ } #endif /* Probe for Sedlbauer speed pci */ -#if CONFIG_PCI +#ifdef CONFIG_PCI dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100, dev_sedl); if (dev_sedl) { diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c --- a/drivers/isdn/i4l/isdn_common.c Mon May 12 20:55:45 2003 +++ b/drivers/isdn/i4l/isdn_common.c Mon May 12 20:55:45 2003 @@ -37,9 +37,6 @@ static void isdn_lock_driver(struct isdn_driver *drv); static void isdn_unlock_driver(struct isdn_driver *drv); -static void isdn_register_devfs(int); -static void isdn_unregister_devfs(int); - /* ====================================================================== */ /* Description of hardware-level-driver */ @@ -2157,85 +2154,37 @@ return max; } -/* - ***************************************************************************** - * And now the modules code. - ***************************************************************************** - */ - -#ifdef CONFIG_DEVFS_FS - -static void isdn_register_devfs(int k) -{ - char buf[16]; - - sprintf (buf, "isdn/isdnctrl%d", k); - devfs_register(NULL, buf, DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR, - &isdn_fops, NULL); -} - -static void isdn_unregister_devfs(int k) +static void isdn_init_devfs(void) { - devfs_remove("isdn/isdnctrl%d", k); -} + devfs_mk_dir("isdn"); -static void isdn_init_devfs(void) +#ifdef CONFIG_ISDN_PPP { -# ifdef CONFIG_ISDN_PPP int i; -# endif - devfs_mk_dir("isdn"); -# ifdef CONFIG_ISDN_PPP - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - char buf[16]; + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_PPP + i), + 0600 | S_IFCHR, "isdn/ippp%d", i); +} +#endif - sprintf (buf, "isdn/ippp%d", i); - devfs_register(NULL, buf, DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_PPP + i, - 0600 | S_IFCHR, &isdn_fops, NULL); - } -# endif - - devfs_register(NULL, "isdn/isdninfo", DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR, - &isdn_fops, NULL); - devfs_register(NULL, "isdn/isdnctrl", DEVFS_FL_DEFAULT, - ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, - &isdn_fops, NULL); + devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_STATUS), + 0600 | S_IFCHR, "isdn/isdninfo"); + devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_CTRL), + 0600 | S_IFCHR, "isdn/isdnctrl"); } static void isdn_cleanup_devfs(void) { -# ifdef CONFIG_ISDN_PPP +#ifdef CONFIG_ISDN_PPP int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) devfs_remove("isdn/ippp%d", i); -# endif +#endif devfs_remove("isdn/isdninfo"); devfs_remove("isdn/isdnctrl"); devfs_remove("isdn"); } - -#else /* CONFIG_DEVFS_FS */ -static void isdn_register_devfs(int dummy) -{ -} - -static void isdn_unregister_devfs(int dummy) -{ -} - -static void isdn_init_devfs(void) -{ -} - -static void isdn_cleanup_devfs(void) -{ -} - -#endif /* CONFIG_DEVFS_FS */ /* * Allocate and initialize all data, register modem-devices diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c --- a/drivers/macintosh/adb.c Mon May 12 20:55:49 2003 +++ b/drivers/macintosh/adb.c Mon May 12 20:55:49 2003 @@ -896,8 +896,6 @@ if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); else - devfs_register (NULL, "adb", DEVFS_FL_DEFAULT, - ADB_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &adb_fops, NULL); + devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), + S_IFCHR | S_IRUSR | S_IWUSR, "adb"); } diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c --- a/drivers/macintosh/macserial.c Mon May 12 20:55:49 2003 +++ b/drivers/macintosh/macserial.c Mon May 12 20:55:49 2003 @@ -1932,7 +1932,6 @@ spin_lock_irqsave(&info->lock, flags); if (tty_hung_up_p(filp)) { - MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&info->lock, flags); return; } @@ -1956,7 +1955,6 @@ info->count = 0; } if (info->count) { - MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&info->lock, flags); return; } @@ -2026,7 +2024,6 @@ info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; } /* @@ -2233,17 +2230,14 @@ int retval, line; unsigned long page; - MOD_INC_USE_COUNT; line = tty->index; if ((line < 0) || (line >= zs_channels_found)) { - MOD_DEC_USE_COUNT; return -ENODEV; } info = zs_soft + line; #ifdef CONFIG_KGDB if (info->kgdb_channel) { - MOD_DEC_USE_COUNT; return -ENODEV; } #endif @@ -2610,6 +2604,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.owner = THIS_MODULE; serial_driver.driver_name = "macserial"; #ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/"; diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Mon May 12 20:55:45 2003 +++ b/drivers/md/md.c Mon May 12 20:55:45 2003 @@ -1111,8 +1111,10 @@ static void print_desc(mdp_disk_t *desc) { + char b[BDEVNAME_SIZE]; + printk(" DISK\n", desc->number, - partition_name(MKDEV(desc->major,desc->minor)), + __bdevname(MKDEV(desc->major, desc->minor), b), desc->major,desc->minor,desc->raid_disk,desc->state); } @@ -1294,6 +1296,7 @@ */ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_minor) { + char b[BDEVNAME_SIZE]; int err; mdk_rdev_t *rdev; sector_t size; @@ -1301,7 +1304,7 @@ rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { printk(KERN_ERR "md: could not alloc mem for %s!\n", - partition_name(newdev)); + __bdevname(newdev, b)); return ERR_PTR(-ENOMEM); } memset(rdev, 0, sizeof(*rdev)); @@ -1312,7 +1315,7 @@ err = lock_rdev(rdev, newdev); if (err) { printk(KERN_ERR "md: could not lock %s.\n", - partition_name(newdev)); + __bdevname(newdev, b)); goto abort_free; } rdev->desc_nr = -1; @@ -1840,6 +1843,7 @@ static int autostart_array(dev_t startdev) { + char b[BDEVNAME_SIZE]; int err = -EINVAL, i; mdp_super_t *sb = NULL; mdk_rdev_t *start_rdev = NULL, *rdev; @@ -1847,7 +1851,7 @@ start_rdev = md_import_device(startdev, 0, 0); if (IS_ERR(start_rdev)) { printk(KERN_WARNING "md: could not import %s!\n", - partition_name(startdev)); + __bdevname(startdev, b)); return err; } @@ -1884,7 +1888,7 @@ if (IS_ERR(rdev)) { printk(KERN_WARNING "md: could not import %s," " trying to run array nevertheless.\n", - partition_name(dev)); + __bdevname(dev, b)); continue; } list_add(&rdev->same_set, &pending_raid_disks); @@ -2116,6 +2120,7 @@ static int hot_generate_error(mddev_t * mddev, dev_t dev) { + char b[BDEVNAME_SIZE]; struct request_queue *q; mdk_rdev_t *rdev; @@ -2123,7 +2128,7 @@ return -ENODEV; printk(KERN_INFO "md: trying to generate %s error in md%d ... \n", - partition_name(dev), mdidx(mddev)); + __bdevname(dev, b), mdidx(mddev)); rdev = find_rdev(mddev, dev); if (!rdev) { @@ -2151,13 +2156,14 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev) { + char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; if (!mddev->pers) return -ENODEV; printk(KERN_INFO "md: trying to remove %s from md%d ... \n", - partition_name(dev), mdidx(mddev)); + __bdevname(dev, b), mdidx(mddev)); rdev = find_rdev(mddev, dev); if (!rdev) @@ -2178,6 +2184,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) { + char b[BDEVNAME_SIZE]; int err; unsigned int size; mdk_rdev_t *rdev; @@ -2186,7 +2193,7 @@ return -ENODEV; printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n", - partition_name(dev), mdidx(mddev)); + __bdevname(dev, b), mdidx(mddev)); if (mddev->major_version != 0) { printk(KERN_WARNING "md%d: HOT_ADD may only be used with" @@ -2344,6 +2351,7 @@ static int md_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + char b[BDEVNAME_SIZE]; unsigned int minor; int err = 0; struct hd_geometry *loc = (struct hd_geometry *) arg; @@ -2403,7 +2411,7 @@ err = autostart_array(arg); if (err) { printk(KERN_WARNING "md: autostart %s failed!\n", - partition_name(arg)); + __bdevname(arg, b)); goto abort; } goto done; @@ -3516,6 +3524,7 @@ static void autostart_arrays(void) { + char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; int i; @@ -3527,7 +3536,7 @@ rdev = md_import_device(dev,0, 0); if (IS_ERR(rdev)) { printk(KERN_ALERT "md: could not import %s!\n", - partition_name(dev)); + __bdevname(dev, b)); continue; } if (rdev->faulty) { diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c --- a/drivers/media/dvb/dvb-core/dvbdev.c Mon May 12 20:55:45 2003 +++ b/drivers/media/dvb/dvb-core/dvbdev.c Mon May 12 20:55:45 2003 @@ -189,7 +189,6 @@ const struct dvb_device *template, void *priv, int type) { u32 id; - char name [20]; struct dvb_device *dvbdev; if (down_interruptible (&dvbdev_register_lock)) @@ -219,12 +218,12 @@ list_add_tail (&dvbdev->list_head, &adap->device_list); - sprintf(name, "dvb/adapter%d%s%d", adap->num, dnames[type], id); - devfs_register(NULL, name, 0, DVB_MAJOR, nums2minor(adap->num, type, id), - S_IFCHR | S_IRUSR | S_IWUSR, dvbdev->fops, dvbdev); + devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + S_IFCHR | S_IRUSR | S_IWUSR, + "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - dprintk("DVB: register adapter%d/%s @ minor: %i (0x%02x)\n", - adap->num, name, nums2minor(adap->num, type, id), + dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", + adap->num, dnames[type], id, nums2minor(adap->num, type, id), nums2minor(adap->num, type, id)); return 0; @@ -234,7 +233,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev) { if (dvbdev) { - devfs_remove("dvb/adapter%d%s%d", dvbdev->adapter->num, + devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); list_del(&dvbdev->list_head); kfree(dvbdev); @@ -322,12 +321,12 @@ int __init init_dvbdev(void) { devfs_mk_dir("dvb"); -#ifndef CONFIG_DVB_DEVFS_ONLY + if(register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops)) { printk("video_dev: unable to get major %d\n", DVB_MAJOR); return -EIO; } -#endif + return 0; } @@ -335,9 +334,7 @@ static void __exit exit_dvbdev(void) { -#ifndef CONFIG_DVB_DEVFS_ONLY unregister_chrdev(DVB_MAJOR, "DVB"); -#endif devfs_remove("dvb"); } diff -Nru a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c --- a/drivers/media/video/bt832.c Mon May 12 20:55:48 2003 +++ b/drivers/media/video/bt832.c Mon May 12 20:55:48 2003 @@ -198,25 +198,9 @@ static int bt832_probe(struct i2c_adapter *adap) { - int rc; - - printk("bt832_probe\n"); - - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: - printk("bt832: probing %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); - rc = i2c_probe(adap, &addr_data, bt832_attach); - break; - default: - printk("bt832: ignoring %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); - rc = 0; - /* nothing */ - } - return rc; + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, bt832_attach); + return 0; } static int bt832_detach(struct i2c_client *client) diff -Nru a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c --- a/drivers/media/video/bttv-if.c Mon May 12 20:55:44 2003 +++ b/drivers/media/video/bttv-if.c Mon May 12 20:55:44 2003 @@ -7,7 +7,7 @@ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999,2000 Gerd Knorr + (c) 1999-2003 Gerd Knorr 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 @@ -195,51 +195,21 @@ static int attach_inform(struct i2c_client *client) { struct bttv *btv = i2c_get_adapdata(client->adapter); - int i; - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] == NULL) { - btv->i2c_clients[i] = client; - break; - } - } - if (btv->tuner_type != -1) + if (btv->tuner_type != UNSET) bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - if (bttv_verbose) - printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr, - client->dev.name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - struct bttv *btv = i2c_get_adapdata(client->adapter); - int i; - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] == client) { - btv->i2c_clients[i] = NULL; - break; - } - } - if (bttv_verbose) - printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr, - client->dev.name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + if (bttv_debug) + printk("bttv%d: i2c attach [client=%s]\n", + btv->nr, i2c_clientname(client)); return 0; } void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) { - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (NULL == btv->i2c_clients[i]) - continue; - if (NULL == btv->i2c_clients[i]->driver->command) - continue; - btv->i2c_clients[i]->driver->command( - btv->i2c_clients[i],cmd,arg); - } + if (0 != btv->i2c_rc) + return; + i2c_clients_command(&btv->i2c_adap, cmd, arg); } void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) @@ -260,20 +230,16 @@ }; static struct i2c_adapter bttv_i2c_adap_template = { - .owner = THIS_MODULE, + .owner = THIS_MODULE, + I2C_DEVNAME("bt848"), .id = I2C_HW_B_BT848, + .class = I2C_ADAP_CLASS_TV_ANALOG, .client_register = attach_inform, - .client_unregister = detach_inform, - .dev = { - .name = "bt848", - }, }; static struct i2c_client bttv_i2c_client_template = { - .id = -1, - .dev = { - .name = "bttv internal", - }, + I2C_DEVNAME("bttv internal"), + .id = -1, }; @@ -347,8 +313,8 @@ memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client)); - sprintf(btv->i2c_adap.dev.name+strlen(btv->i2c_adap.dev.name), - " #%d", btv->nr); + sprintf(btv->i2c_adap.dev.name, "bt848 #%d", btv->nr); + btv->i2c_algo.data = btv; i2c_set_adapdata(&btv->i2c_adap, btv); btv->i2c_adap.algo_data = &btv->i2c_algo; diff -Nru a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h --- a/drivers/media/video/bttv.h Mon May 12 20:55:44 2003 +++ b/drivers/media/video/bttv.h Mon May 12 20:55:44 2003 @@ -243,7 +243,6 @@ /* i2c */ -#define I2C_CLIENTS_MAX 16 extern void bttv_bit_setscl(void *data, int state); extern void bttv_bit_setsda(void *data, int state); extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h --- a/drivers/media/video/bttvp.h Mon May 12 20:55:46 2003 +++ b/drivers/media/video/bttvp.h Mon May 12 20:55:46 2003 @@ -62,6 +62,8 @@ #define RAW_LINES 640 #define RAW_BPL 1024 +#define UNSET (-1U) + /* ---------------------------------------------------------- */ struct bttv_tvnorm @@ -276,7 +278,6 @@ struct i2c_algo_bit_data i2c_algo; struct i2c_client i2c_client; int i2c_state, i2c_rc; - struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; /* video4linux (1) */ struct video_device video_dev; diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c --- a/drivers/media/video/cpia.c Mon May 12 20:55:47 2003 +++ b/drivers/media/video/cpia.c Mon May 12 20:55:47 2003 @@ -1409,12 +1409,10 @@ LOG("Unable to initialise /proc/cpia\n"); } -#ifdef MODULE -static void proc_cpia_destroy(void) +static void __exit proc_cpia_destroy(void) { remove_proc_entry("cpia", 0); } -#endif /*MODULE*/ #endif /* CONFIG_PROC_FS */ /* ----------------------- debug functions ---------------------- */ diff -Nru a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c --- a/drivers/media/video/dpc7146.c Mon May 12 20:55:46 2003 +++ b/drivers/media/video/dpc7146.c Mon May 12 20:55:46 2003 @@ -96,7 +96,8 @@ static int dpc_probe(struct saa7146_dev* dev) { struct dpc* dpc = 0; - int i = 0; + struct i2c_client *client; + struct list_head *item; dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL); if( NULL == dpc ) { @@ -117,12 +118,10 @@ } /* loop through all i2c-devices on the bus and look who is there */ - for(i = 0; i < I2C_CLIENT_MAX; i++) { - if( NULL == dpc->i2c_adapter.clients[i] ) { - continue; - } - if( I2C_SAA7111A == dpc->i2c_adapter.clients[i]->addr ) - dpc->saa7111a = dpc->i2c_adapter.clients[i]; + list_for_each(item,&dpc->i2c_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + if( I2C_SAA7111A == client->addr ) + dpc->saa7111a = client; } /* check if all devices are present */ diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c --- a/drivers/media/video/msp3400.c Mon May 12 20:55:47 2003 +++ b/drivers/media/video/msp3400.c Mon May 12 20:55:47 2003 @@ -1372,7 +1372,7 @@ static int msp_probe(struct i2c_adapter *adap) { - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, msp_attach); return 0; } diff -Nru a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c --- a/drivers/media/video/mxb.c Mon May 12 20:55:44 2003 +++ b/drivers/media/video/mxb.c Mon May 12 20:55:44 2003 @@ -208,7 +208,8 @@ static int mxb_probe(struct saa7146_dev* dev) { struct mxb* mxb = 0; - int i = 0; + struct i2c_client *client; + struct list_head *item; request_module("tuner"); request_module("tea6420"); @@ -235,22 +236,20 @@ } /* loop through all i2c-devices on the bus and look who is there */ - for(i = 0; i < I2C_CLIENT_MAX; i++) { - if( NULL == mxb->i2c_adapter.clients[i] ) { - continue; - } - if( I2C_TEA6420_1 == mxb->i2c_adapter.clients[i]->addr ) - mxb->tea6420_1 = mxb->i2c_adapter.clients[i]; - if( I2C_TEA6420_2 == mxb->i2c_adapter.clients[i]->addr ) - mxb->tea6420_2 = mxb->i2c_adapter.clients[i]; - if( I2C_TEA6415C_2 == mxb->i2c_adapter.clients[i]->addr ) - mxb->tea6415c = mxb->i2c_adapter.clients[i]; - if( I2C_TDA9840 == mxb->i2c_adapter.clients[i]->addr ) - mxb->tda9840 = mxb->i2c_adapter.clients[i]; - if( I2C_SAA7111A == mxb->i2c_adapter.clients[i]->addr ) - mxb->saa7111a = mxb->i2c_adapter.clients[i]; - if( 0x60 == mxb->i2c_adapter.clients[i]->addr ) - mxb->tuner = mxb->i2c_adapter.clients[i]; + list_for_each(item,&mxb->i2c_adapter.clients) { + client = list_entry(item, struct i2c_client, list); + if( I2C_TEA6420_1 == client->addr ) + mxb->tea6420_1 = client; + if( I2C_TEA6420_2 == client->addr ) + mxb->tea6420_2 = client; + if( I2C_TEA6415C_2 == client->addr ) + mxb->tea6415c = client; + if( I2C_TDA9840 == client->addr ) + mxb->tda9840 = client; + if( I2C_SAA7111A == client->addr ) + mxb->saa7111a = client; + if( 0x60 == client->addr ) + mxb->tuner = client; } /* check if all devices are present */ diff -Nru a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c --- a/drivers/media/video/saa5249.c Mon May 12 20:55:48 2003 +++ b/drivers/media/video/saa5249.c Mon May 12 20:55:48 2003 @@ -224,12 +224,8 @@ static int saa5249_probe(struct i2c_adapter *adap) { - /* Only attach these chips to the BT848 bus for now */ - - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - { + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, saa5249_attach); - } return 0; } diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c --- a/drivers/media/video/saa7134/saa7134-i2c.c Mon May 12 20:55:45 2003 +++ b/drivers/media/video/saa7134/saa7134-i2c.c Mon May 12 20:55:45 2003 @@ -334,19 +334,16 @@ static struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, + I2C_DEVNAME("saa7134"), .id = I2C_ALGO_SAA7134, + .class = I2C_ADAP_CLASS_TV_ANALOG, .algo = &saa7134_algo, .client_register = attach_inform, - .dev = { - .name = "saa7134", - }, }; static struct i2c_client saa7134_client_template = { - .id = -1, - .dev = { - .name = "saa7134 internal", - }, + I2C_DEVNAME("saa7134 internal"), + .id = -1, }; /* ----------------------------------------------------------- */ @@ -399,22 +396,13 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, unsigned int cmd, void *arg) { - int i; - - for (i = 0; i < I2C_CLIENT_MAX; i++) { - if (NULL == dev->i2c_adap.clients[i]) - continue; - if (NULL == dev->i2c_adap.clients[i]->driver->command) - continue; - dev->i2c_adap.clients[i]->driver->command - (dev->i2c_adap.clients[i],cmd,arg); - } + i2c_clients_command(&dev->i2c_adap, cmd, arg); } int saa7134_i2c_register(struct saa7134_dev *dev) { dev->i2c_adap = saa7134_adap_template; - strncpy(dev->i2c_adap.dev.name, dev->name, DEVICE_NAME_SIZE); + strcpy(dev->i2c_adap.dev.name,dev->name); dev->i2c_adap.algo_data = dev; i2c_add_adapter(&dev->i2c_adap); diff -Nru a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c --- a/drivers/media/video/tda7432.c Mon May 12 20:55:48 2003 +++ b/drivers/media/video/tda7432.c Mon May 12 20:55:48 2003 @@ -340,7 +340,7 @@ static int tda7432_probe(struct i2c_adapter *adap) { - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda7432_attach); return 0; } diff -Nru a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c --- a/drivers/media/video/tda9875.c Mon May 12 20:55:46 2003 +++ b/drivers/media/video/tda9875.c Mon May 12 20:55:46 2003 @@ -273,7 +273,7 @@ static int tda9875_probe(struct i2c_adapter *adap) { - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tda9875_attach); return 0; } diff -Nru a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c --- a/drivers/media/video/tda9887.c Mon May 12 20:55:44 2003 +++ b/drivers/media/video/tda9887.c Mon May 12 20:55:44 2003 @@ -368,23 +368,9 @@ static int tda9887_probe(struct i2c_adapter *adap) { - int rc; - - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: - printk("tda9887: probing %s i2c adapter [id=0x%x]\n", - adap->dev.name,adap->id); - rc = i2c_probe(adap, &addr_data, tda9887_attach); - break; - default: - printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n", - adap->dev.name,adap->id); - rc = 0; - /* nothing */ - } - return rc; + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, tda9887_attach); + return 0; } static int tda9887_detach(struct i2c_client *client) diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c --- a/drivers/media/video/tuner.c Mon May 12 20:55:48 2003 +++ b/drivers/media/video/tuner.c Mon May 12 20:55:48 2003 @@ -817,29 +817,15 @@ static int tuner_probe(struct i2c_adapter *adap) { - int rc; - if (0 != addr) { normal_i2c_range[0] = addr; normal_i2c_range[1] = addr; } this_adap = 0; - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - case I2C_ALGO_SAA7134: - case I2C_ALGO_SAA7146: - printk("tuner: probing %s i2c adapter [id=0x%x]\n", - adap->dev.name,adap->id); - rc = i2c_probe(adap, &addr_data, tuner_attach); - break; - default: - printk("tuner: ignoring %s i2c adapter [id=0x%x]\n", - adap->dev.name,adap->id); - rc = 0; - /* nothing */ - } - return rc; + + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; } static int tuner_detach(struct i2c_client *client) diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c --- a/drivers/media/video/tvaudio.c Mon May 12 20:55:45 2003 +++ b/drivers/media/video/tvaudio.c Mon May 12 20:55:45 2003 @@ -1408,14 +1408,9 @@ static int chip_probe(struct i2c_adapter *adap) { - switch (adap->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: + if (adap->class & I2C_ADAP_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, chip_attach); - default: - /* ignore this i2c bus */ - return 0; - } + return 0; } static int chip_detach(struct i2c_client *client) diff -Nru a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c --- a/drivers/media/video/tvmixer.c Mon May 12 20:55:48 2003 +++ b/drivers/media/video/tvmixer.c Mon May 12 20:55:48 2003 @@ -217,8 +217,9 @@ .owner = THIS_MODULE, .name = "tv card mixer driver", .id = I2C_DRIVERID_TVMIXER, - .flags = I2C_DF_DUMMY, + .flags = I2C_DF_NOTIFY, .attach_adapter = tvmixer_adapters, + .detach_adapter = tvmixer_adapters, .detach_client = tvmixer_clients, }; @@ -234,14 +235,15 @@ static int tvmixer_adapters(struct i2c_adapter *adap) { - int i; + struct list_head *item; + struct i2c_client *client; if (debug) printk("tvmixer: adapter %s\n",adap->dev.name); - for (i=0; iclients[i]) - continue; - tvmixer_clients(adap->clients[i]); + + list_for_each(item,&adap->clients) { + client = list_entry(item, struct i2c_client, list); + tvmixer_clients(client); } return 0; } @@ -252,19 +254,15 @@ int i,minor; /* TV card ??? */ - switch (client->adapter->id) { - case I2C_ALGO_BIT | I2C_HW_B_BT848: - case I2C_ALGO_BIT | I2C_HW_B_RIVA: - /* ok, have a look ... */ - break; - default: + if (!(client->adapter->class & I2C_ADAP_CLASS_TV_ANALOG)) { /* ignore that one */ if (debug) printk("tvmixer: %s is not a tv card\n", client->adapter->dev.name); return -1; } - printk("tvmixer: debug: %s\n",client->dev.name); + if (debug) + printk("tvmixer: debug: %s\n",client->dev.name); /* unregister ?? */ for (i = 0; i < DEV_MAX; i++) { diff -Nru a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c --- a/drivers/media/video/videodev.c Mon May 12 20:55:44 2003 +++ b/drivers/media/video/videodev.c Mon May 12 20:55:44 2003 @@ -427,8 +427,8 @@ up(&videodev_lock); sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base); - devfs_register(NULL, vfd->devfs_name, 0, VIDEO_MAJOR, vfd->minor, - S_IFCHR | S_IRUSR | S_IWUSR, &video_fops, NULL); + devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor), + S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name); init_MUTEX(&vfd->lock); #ifdef CONFIG_VIDEO_PROC_FS diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c --- a/drivers/mtd/maps/sa1100-flash.c Mon May 12 20:55:45 2003 +++ b/drivers/mtd/maps/sa1100-flash.c Mon May 12 20:55:45 2003 @@ -337,7 +337,7 @@ #ifdef CONFIG_SA1100_FREEBIRD static struct mtd_partition freebird_partitions[] = { -#if CONFIG_SA1100_FREEBIRD_NEW +#ifdef CONFIG_SA1100_FREEBIRD_NEW { .name = "firmware", .size = 0x00040000, diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c --- a/drivers/mtd/mtdchar.c Mon May 12 20:55:47 2003 +++ b/drivers/mtd/mtdchar.c Mon May 12 20:55:47 2003 @@ -461,22 +461,12 @@ static void mtd_notify_add(struct mtd_info* mtd) { - char name[16]; - if (!mtd) return; - - sprintf(name, "mtd/%d", mtd->index); - devfs_register(NULL, name, - DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2, - S_IFCHR | S_IRUGO | S_IWUGO, - &mtd_fops, NULL); - - sprintf(name, "mtd/%dro", mtd->index); - devfs_register(NULL, name, - DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1, - S_IFCHR | S_IRUGO | S_IWUGO, - &mtd_fops, NULL); + devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2), + S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index); + devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), + S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%dro", mtd->index); } static void mtd_notify_remove(struct mtd_info* mtd) diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Mon May 12 20:55:48 2003 +++ b/drivers/net/Kconfig Mon May 12 20:55:48 2003 @@ -158,7 +158,7 @@ config NET_SB1000 tristate "General Instruments Surfboard 1000" - depends on NETDEVICES && ISAPNP + depends on NETDEVICES && PNP ---help--- This is a driver for the General Instrument (also known as NextLevel) SURFboard 1000 internal diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c --- a/drivers/net/acenic.c Mon May 12 20:55:46 2003 +++ b/drivers/net/acenic.c Mon May 12 20:55:46 2003 @@ -1871,7 +1871,9 @@ } else { printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n", dev->name); +#if 0 netif_wake_queue(dev); +#endif } } diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c --- a/drivers/net/bmac.c Mon May 12 20:55:44 2003 +++ b/drivers/net/bmac.c Mon May 12 20:55:44 2003 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ int opened; unsigned short hash_use_count[64]; unsigned short hash_table_mask[4]; + spinlock_t lock; struct net_device *next_bmac; }; @@ -159,9 +161,9 @@ static void bmac_init_registers(struct net_device *dev); static void bmac_enable_and_reset_chip(struct net_device *dev); static int bmac_set_address(struct net_device *dev, void *addr); -static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs); -static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); -static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void bmac_set_timeout(struct net_device *dev); static void bmac_tx_timeout(unsigned long data); static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length); @@ -485,7 +487,7 @@ case PBOOK_SLEEP_NOW: netif_device_detach(dev); /* prolly should wait for dma to finish & turn off the chip */ - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); if (bp->timeout_active) { del_timer(&bp->tx_timeout); bp->timeout_active = 0; @@ -494,7 +496,7 @@ disable_irq(bp->tx_dma_intr); disable_irq(bp->rx_dma_intr); bp->sleeping = 1; - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); if (bp->opened) { volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; @@ -539,13 +541,14 @@ static int bmac_set_address(struct net_device *dev, void *addr) { + struct bmac_data *bp = (struct bmac_data *) dev->priv; unsigned char *p = addr; unsigned short *pWord16; unsigned long flags; int i; XXDEBUG(("bmac: enter set_address\n")); - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); for (i = 0; i < 6; ++i) { dev->dev_addr[i] = p[i]; @@ -556,7 +559,7 @@ bmwrite(dev, MADD1, *pWord16++); bmwrite(dev, MADD2, *pWord16); - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); XXDEBUG(("bmac: exit set_address\n")); return 0; } @@ -566,8 +569,7 @@ struct bmac_data *bp = (struct bmac_data *) dev->priv; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&bp->lock, flags); if (bp->timeout_active) del_timer(&bp->tx_timeout); bp->tx_timeout.expires = jiffies + TX_TIMEOUT; @@ -575,7 +577,7 @@ bp->tx_timeout.data = (unsigned long) dev; add_timer(&bp->tx_timeout); bp->timeout_active = 1; - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); } static void @@ -703,7 +705,7 @@ static int rxintcount; -static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *) dev->priv; @@ -715,7 +717,7 @@ int last; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); if (++rxintcount < 10) { XXDEBUG(("bmac_rxdma_intr\n")); @@ -769,18 +771,18 @@ bp->rx_empty = i; } - restore_flags(flags); - dbdma_continue(rd); + spin_unlock_irqrestore(&bp->lock, flags); if (rxintcount < 10) { XXDEBUG(("bmac_rxdma_intr done\n")); } + return IRQ_HANDLED; } static int txintcount; -static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *) dev->priv; @@ -788,7 +790,7 @@ int stat; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); if (txintcount++ < 10) { XXDEBUG(("bmac_txdma_intr\n")); @@ -824,13 +826,14 @@ break; } - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); if (txintcount < 10) { XXDEBUG(("bmac_txdma_intr done->bmac_start\n")); } bmac_start(dev); + return IRQ_HANDLED; } static struct net_device_stats *bmac_stats(struct net_device *dev) @@ -1096,7 +1099,7 @@ static int miscintcount; -static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct bmac_data *bp = (struct bmac_data *)dev->priv; @@ -1117,6 +1120,7 @@ if (status & TxErrorMask) bp->stats.tx_errors++; if (status & TxUnderrun) bp->stats.tx_fifo_errors++; if (status & TxNormalCollExp) bp->stats.collisions++; + return IRQ_HANDLED; } /* @@ -1249,7 +1253,7 @@ struct sk_buff *skb; unsigned char *data; - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); bmac_enable_and_reset_chip(dev); bmac_init_tx_ring(bp); bmac_init_rx_ring(bp); @@ -1270,7 +1274,7 @@ memcpy(data+6, dev->dev_addr, 6); bmac_transmit_packet(skb, dev); } - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); } static int __init bmac_probe(void) @@ -1336,6 +1340,7 @@ bp = (struct bmac_data *) dev->priv; SET_MODULE_OWNER(dev); bp->node = bmac; + spin_lock_init(&bp->lock); if (!request_OF_resource(bmac, 0, " (bmac)")) { printk(KERN_ERR "BMAC: can't request IO resource !\n"); @@ -1522,7 +1527,7 @@ if (bp->sleeping) return; - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); while (1) { i = bp->tx_fill + 1; if (i >= N_TX_RING) @@ -1534,7 +1539,7 @@ break; bmac_transmit_packet(skb, dev); } - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); } static int @@ -1558,7 +1563,7 @@ int i; XXDEBUG(("bmac: tx_timeout called\n")); - save_flags(flags); cli(); + spin_lock_irqsave(&bp->lock, flags); bp->timeout_active = 0; /* update various counters */ @@ -1614,7 +1619,7 @@ oldConfig = bmread(dev, TXCFG); bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); - restore_flags(flags); + spin_unlock_irqrestore(&bp->lock, flags); } #if 0 diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c --- a/drivers/net/depca.c Mon May 12 20:55:46 2003 +++ b/drivers/net/depca.c Mon May 12 20:55:46 2003 @@ -230,6 +230,7 @@ by acme@conectiva.com.br 0.54 08-Nov-01 use library crc32 functions by Matt_Domsch@dell.com + 0.55 01-Mar-03 Use EISA/sysfs framework ========================================================================= */ @@ -263,6 +264,11 @@ #include #endif +#ifdef CONFIG_EISA +#include +#include +#endif + #include "depca.h" static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n"; @@ -328,6 +334,25 @@ DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown } adapter; +#ifdef CONFIG_EISA +struct eisa_device_id depca_eisa_ids[] = { + { "DEC4220" }, + { "" } +}; + +static int depca_eisa_probe (struct device *device); +static int depca_eisa_remove (struct device *device); + +struct eisa_driver depca_eisa_driver = { + .id_table = depca_eisa_ids, + .driver = { + .name = "depca", + .probe = depca_eisa_probe, + .remove = __devexit_p (depca_eisa_remove) + } +}; +#endif + /* ** Miscellaneous info... */ @@ -388,6 +413,8 @@ void *rx_buff[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */ void *tx_buff[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */ void *sh_mem; /* CPU mapped virt address of device RAM */ + u_long mem_start; /* Bus address of device RAM (before remap) */ + u_long mem_len; /* device memory size */ /* Device address space fields */ u_long device_ram_start; /* Start of RAM in device addr space */ /* Offsets used in both address spaces */ @@ -450,10 +477,8 @@ static void DepcaSignature(char *name, u_long paddr); static int DevicePresent(u_long ioaddr); static int get_hw_addr(struct net_device *dev); -static int EISA_signature(char *name, s32 eisa_id); static void SetMulticastFilter(struct net_device *dev); static void isa_probe(struct net_device *dev, u_long iobase); -static void eisa_probe(struct net_device *dev, u_long iobase); #ifdef CONFIG_MCA static void mca_probe(struct net_device *dev, u_long iobase); #endif @@ -503,7 +528,9 @@ mca_probe(dev, iobase); #endif isa_probe(dev, iobase); - eisa_probe(dev, iobase); +#ifdef CONFIG_EISA + eisa_driver_register (&depca_eisa_driver); +#endif if ((tmp == num_depcas) && (iobase != 0) && loading_module) { printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, iobase); @@ -530,6 +557,7 @@ int i, j, offset, netRAM, mem_len, status = 0; s16 nicsr; u_long mem_start = 0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES; + int is_eisa = ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS); STOP_DEPCA; @@ -555,7 +583,7 @@ if (mca_slot != -1) { printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, ioaddr, mca_slot); - } else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */ + } else if (is_eisa) { /* EISA slot address */ printk("%s: %s at 0x%04lx (EISA slot %d)", dev->name, name, ioaddr, (int) ((ioaddr >> 12) & 0x0f)); } else { /* ISA port address */ printk("%s: %s at 0x%04lx", dev->name, name, ioaddr); @@ -600,9 +628,11 @@ } /* Define the device private memory */ - dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; + if (!is_eisa) { + dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + } lp = (struct depca_private *) dev->priv; memset((char *) dev->priv, 0, sizeof(struct depca_private)); lp->adapter = adapter; @@ -610,18 +640,23 @@ lp->lock = SPIN_LOCK_UNLOCKED; sprintf(lp->adapter_name, "%s (%s)", name, dev->name); status = -EBUSY; - if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) { - printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n", DEPCA_TOTAL_SIZE, ioaddr); - goto out_priv; - } /* Initialisation Block */ - lp->sh_mem = ioremap(mem_start, mem_len); + if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) { + printk(KERN_ERR "depca: cannot request ISA memory, aborting\n"); + goto out_priv; + } + status = -EIO; + lp->sh_mem = ioremap(mem_start, mem_len); if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - goto out_region; + release_mem_region (mem_start, mem_len); + goto out_priv; } + + lp->mem_start = mem_start; + lp->mem_len = mem_len; lp->device_ram_start = mem_start & LA_MASK; offset = 0; @@ -703,7 +738,7 @@ status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - goto out_region; + goto out_priv; } else { for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { @@ -714,7 +749,7 @@ status = -ENXIO; if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - goto out_region; + goto out_priv; } } #endif /* MODULE */ @@ -739,13 +774,16 @@ dev->mem_start = 0; /* Fill in the generic field of the device structure. */ - ether_setup(dev); + if (!is_eisa) + ether_setup(dev); return 0; - out_region: - release_region(ioaddr, DEPCA_TOTAL_SIZE); out_priv: - kfree(dev->priv); - dev->priv = NULL; + if (!is_eisa) { + kfree(dev->priv); + dev->priv = NULL; + } else { + unregister_netdev (dev); + } return status; } @@ -1351,31 +1389,35 @@ ** Get everything allocated and initialized... (almost just ** like the ISA and EISA probes) */ + if (!request_region (iobase, DEPCA_TOTAL_SIZE, "depca")) { + if (autoprobed) + printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase); + goto next; + } if (DevicePresent(iobase) != 0) { /* ** If the MCA configuration says the card should be here, ** it really should be here. */ printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase); + goto release_next; } - if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - dev->irq = irq; - if (depca_hw_init(dev, iobase, slot) == 0) { - /* - ** Adapter initialized correctly: Name it in - ** /proc/mca. - */ - mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter"); - mca_mark_as_used(slot); - num_depcas++; - } - num_eth++; - } - } else if (autoprobed) { - printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase); - } + if (!(dev = alloc_device(dev, iobase))) + goto release_next; + + num_eth++; + dev->irq = irq; + if (depca_hw_init(dev, iobase, slot)) + goto release_next; + + /* + ** Adapter initialized correctly: Name it in + ** /proc/mca. + */ + mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter"); + mca_mark_as_used(slot); + num_depcas++; /* ** If this is a probe by a module, return after setting up the @@ -1385,9 +1427,15 @@ return; /* - ** Set up to check the next slot and loop. + ** Set up to check the next slot and loop. */ slot++; + continue; + + release_next: + release_region (iobase, DEPCA_TOTAL_SIZE); + next: + slot++; } } @@ -1418,69 +1466,100 @@ } for (; (i < maxSlots) && (dev != NULL) && ports[i]; i++) { - if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) { - if (DevicePresent(ports[i]) == 0) { - if ((dev = alloc_device(dev, ports[i])) != NULL) { - if (depca_hw_init(dev, ports[i], -1) == 0) { - num_depcas++; - } - num_eth++; - } - } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]); + if (!request_region (ports[i], DEPCA_TOTAL_SIZE, "depca")) { + if (autoprobed) + printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]); + continue; } + + if (DevicePresent(ports[i])) { + release_region (ports[i], DEPCA_TOTAL_SIZE); + continue; + } + + if (!(dev = alloc_device(dev, ports[i]))) { + release_region (ports[i], DEPCA_TOTAL_SIZE); + continue; + } + + num_eth++; + + if (depca_hw_init(dev, ports[i], -1)) { + release_region (ports[i], DEPCA_TOTAL_SIZE); + continue; + } + + num_depcas++; } return; } /* -** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually -** the motherboard. Upto 15 EISA devices are supported. +** EISA callbacks from sysfs. */ -static void __init eisa_probe(struct net_device *dev, u_long ioaddr) + +#ifdef CONFIG_EISA +static int __init depca_eisa_probe (struct device *device) { - int i, maxSlots; + struct eisa_device *edev; + struct net_device *dev; u_long iobase; - char name[DEPCA_STRLEN]; + int status = 0; - if (!ioaddr && autoprobed) - return; /* Been here before ! */ - if ((ioaddr < 0x400) && (ioaddr > 0)) - return; /* ISA Address */ + edev = to_eisa_device (device); + iobase = edev->base_addr + DEPCA_EISA_IO_PORTS; - if (ioaddr == 0) { /* Autoprobing */ - iobase = EISA_SLOT_INC; /* Get the first slot address */ - i = 1; - maxSlots = MAX_EISA_SLOTS; - } else { /* Probe a specific location */ - iobase = ioaddr; - i = (ioaddr >> 12); - maxSlots = i + 1; + if (!request_region (iobase, DEPCA_TOTAL_SIZE, "depca")) { + status = -EBUSY; + goto out; + } + + if (DevicePresent(iobase)) { + status = -ENODEV; + goto out_release; } - if ((iobase & 0x0fff) == 0) - iobase += DEPCA_EISA_IO_PORTS; - for (; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) { - if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) { - if (EISA_signature(name, EISA_ID)) { - if (DevicePresent(iobase) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if (depca_hw_init(dev, iobase, -1) == 0) { - num_depcas++; - } - num_eth++; - } - } - } - } else if (autoprobed) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase); - } + if (!(dev = init_etherdev (NULL, sizeof (struct depca_private)))) { + status = -ENOMEM; + goto out_release; } + + eisa_set_drvdata (edev, dev); - return; + if ((status = depca_hw_init(dev, iobase, -1))) + goto out_free; + + num_depcas++; + return 0; + + out_free: + kfree (dev); + out_release: + release_region (iobase, DEPCA_TOTAL_SIZE); + out: + return status; +} + +static int __devexit depca_eisa_remove (struct device *device) +{ + struct net_device *dev; + struct eisa_device *edev; + struct depca_private *lp; + + edev = to_eisa_device (device); + dev = eisa_get_drvdata (edev); + lp = dev->priv; + + unregister_netdev (dev); + iounmap (lp->sh_mem); + release_mem_region (lp->mem_start, lp->mem_len); + release_region (dev->base_addr, DEPCA_TOTAL_SIZE); + kfree (dev); + + return 0; } +#endif /* ** Search the entire 'eth' device list for a fixed probe. If a match isn't @@ -1781,40 +1860,6 @@ return status; } -/* -** Look for a particular board name in the EISA configuration space -*/ -static int __init EISA_signature(char *name, s32 eisa_id) -{ - u_int i; - const char *signatures[] = DEPCA_SIGNATURE; - char ManCode[DEPCA_STRLEN]; - union { - s32 ID; - char Id[4]; - } Eisa; - int status = 0; - - *name = '\0'; - Eisa.ID = inl(eisa_id); - - ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40); - ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); - ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); - ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); - ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); - ManCode[5] = '\0'; - - for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) { - if (strstr(ManCode, signatures[i]) != NULL) { - strcpy(name, ManCode); - status = 1; - } - } - - return status; -} - static void depca_dbg_open(struct net_device *dev) { struct depca_private *lp = (struct depca_private *) dev->priv; @@ -2067,6 +2112,7 @@ unregister_netdev(&thisDepca); if (lp) { iounmap(lp->sh_mem); + release_mem_region (lp->mem_start, lp->mem_len); #ifdef CONFIG_MCA if (lp->mca_slot != -1) mca_mark_as_unused(lp->mca_slot); diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Mon May 12 20:55:45 2003 +++ b/drivers/net/mace.c Mon May 12 20:55:45 2003 @@ -86,9 +86,9 @@ static void mace_set_multicast(struct net_device *dev); static void mace_reset(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); -static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); -static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void mace_set_timeout(struct net_device *dev); static void mace_tx_timeout(unsigned long data); static inline void dbdma_reset(volatile struct dbdma_regs *dma); @@ -622,7 +622,7 @@ printk(KERN_DEBUG "mace: jabbering transceiver\n"); } -static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; @@ -765,6 +765,7 @@ mace_set_timeout(dev); } spin_unlock_irqrestore(&mp->lock, flags); + return IRQ_HANDLED; } static void mace_tx_timeout(unsigned long data) @@ -833,11 +834,12 @@ spin_unlock_irqrestore(&mp->lock, flags); } -static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) { + return IRQ_HANDLED; } -static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; struct mace_data *mp = (struct mace_data *) dev->priv; @@ -947,6 +949,7 @@ mp->rx_fill = i; } spin_unlock_irqrestore(&mp->lock, flags); + return IRQ_HANDLED; } MODULE_AUTHOR("Paul Mackerras"); diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c --- a/drivers/net/pcmcia/3c589_cs.c Mon May 12 20:55:49 2003 +++ b/drivers/net/pcmcia/3c589_cs.c Mon May 12 20:55:49 2003 @@ -159,7 +159,7 @@ static int el3_config(struct net_device *dev, struct ifmap *map); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev); @@ -816,15 +816,16 @@ } /* The EL3 interrupt handler. */ -static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct el3_private *lp = dev_id; struct net_device *dev = &lp->dev; ioaddr_t ioaddr, status; - int i = 0; + int i = 0, handled = 1; if (!netif_device_present(dev)) - return; + return IRQ_NONE; + ioaddr = dev->base_addr; DEBUG(3, "%s: interrupt, status %4.4x.\n", @@ -833,9 +834,9 @@ spin_lock(&lp->lock); while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if (!netif_device_present(dev) || - ((status & 0xe000) != 0x2000)) { + if ((status & 0xe000) != 0x2000) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); + handled = 0; break; } @@ -897,7 +898,7 @@ spin_unlock(&lp->lock); DEBUG(3, "%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); - return; + return IRQ_RETVAL(handled); } static void media_check(unsigned long arg) diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Mon May 12 20:55:47 2003 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Mon May 12 20:55:47 2003 @@ -107,7 +107,7 @@ static int fjn_open(struct net_device *dev); static int fjn_close(struct net_device *dev); static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void fjn_rx(struct net_device *dev); static void fjn_reset(struct net_device *dev); static struct net_device_stats *fjn_get_stats(struct net_device *dev); @@ -845,7 +845,7 @@ /*====================================================================*/ -static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { local_info_t *lp = dev_id; struct net_device *dev = &lp->dev; @@ -855,7 +855,7 @@ if (lp == NULL) { printk(KERN_NOTICE "fjn_interrupt(): irq %d for " "unknown device.\n", irq); - return; + return IRQ_NONE; } ioaddr = dev->base_addr; @@ -899,6 +899,7 @@ outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); + return IRQ_HANDLED; } /* fjn_interrupt */ diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Mon May 12 20:55:47 2003 +++ b/drivers/net/pcmcia/ibmtr_cs.c Mon May 12 20:55:47 2003 @@ -127,7 +127,7 @@ extern int ibmtr_probe(struct net_device *dev); extern int trdev_init(struct net_device *dev); -extern void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c --- a/drivers/net/pcmcia/nmclan_cs.c Mon May 12 20:55:44 2003 +++ b/drivers/net/pcmcia/nmclan_cs.c Mon May 12 20:55:44 2003 @@ -431,7 +431,7 @@ static int mace_close(struct net_device *dev); static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev); static void mace_tx_timeout(struct net_device *dev); -static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs); static struct net_device_stats *mace_get_stats(struct net_device *dev); static int mace_rx(struct net_device *dev, unsigned char RxCnt); static void restore_multicast_list(struct net_device *dev); @@ -1143,7 +1143,7 @@ mace_interrupt The interrupt handler. ---------------------------------------------------------------------------- */ -static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs) { mace_private *lp = (mace_private *)dev_id; struct net_device *dev = &lp->dev; @@ -1154,7 +1154,7 @@ if (dev == NULL) { DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n", irq); - return; + return IRQ_NONE; } if (lp->tx_irq_disabled) { @@ -1169,12 +1169,12 @@ inb(ioaddr + AM2150_MACE_BASE + MACE_IMR) ); /* WARNING: MACE_IR has been read! */ - return; + return IRQ_NONE; } if (!netif_device_present(dev)) { DEBUG(2, "%s: interrupt from dead card\n", dev->name); - goto exception; + return IRQ_NONE; } do { @@ -1279,8 +1279,7 @@ } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); -exception: - return; + return IRQ_HANDLED; } /* mace_interrupt */ /* ---------------------------------------------------------------------------- diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c --- a/drivers/net/pcmcia/smc91c92_cs.c Mon May 12 20:55:47 2003 +++ b/drivers/net/pcmcia/smc91c92_cs.c Mon May 12 20:55:47 2003 @@ -293,7 +293,7 @@ static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void smc_tx_timeout(struct net_device *dev); static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void smc_rx(struct net_device *dev); static struct net_device_stats *smc_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); @@ -1574,16 +1574,18 @@ /*====================================================================*/ -static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct smc_private *smc = dev_id; struct net_device *dev = &smc->dev; ioaddr_t ioaddr; u_short saved_bank, saved_pointer, mask, status; + unsigned int handled = 1; char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ if (!netif_device_present(dev)) - return; + return IRQ_NONE; + ioaddr = dev->base_addr; DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name, @@ -1596,6 +1598,7 @@ maybe it has been ejected. */ DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent" "/ejected device.\n", dev->name, irq); + handled = 0; goto irq_done; } @@ -1609,9 +1612,11 @@ status = inw(ioaddr + INTERRUPT) & 0xff; DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name, status, mask); - if ((status & mask) == 0) + if ((status & mask) == 0) { + if (bogus_cnt == INTR_WORK) + handled = 0; break; - + } if (status & IM_RCV_INT) { /* Got a packet(s). */ smc_rx(dev); @@ -1683,6 +1688,7 @@ readb(smc->base+MEGAHERTZ_ISR); } #endif + return IRQ_RETVAL(handled); } /*====================================================================*/ diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Mon May 12 20:55:46 2003 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Mon May 12 20:55:46 2003 @@ -317,7 +317,7 @@ * less on other parts of the kernel. */ -static void xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* * The dev_info variable is the "key" that is used to match up this @@ -1296,7 +1296,7 @@ /**************** * This is the Interrupt service route. */ -static void +static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; @@ -1305,14 +1305,14 @@ u_char saved_page; unsigned bytes_rcvd; unsigned int_status, eth_status, rx_status, tx_status; - unsigned rsr, pktlen; + unsigned rsr, pktlen, handled = 1; ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days * is this something to worry about? * -- on a laptop? */ if (!netif_device_present(dev)) - return; + return IRQ_NONE; ioaddr = dev->base_addr; if (lp->mohawk) { /* must disable the interrupt */ @@ -1330,6 +1330,7 @@ loop_entry: if (int_status == 0xff) { /* card may be ejected */ DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq); + handled = 0; goto leave; } eth_status = GetByte(XIRCREG_ESR); @@ -1514,6 +1515,7 @@ * force an interrupt with this command: * PutByte(XIRCREG_CR, EnableIntr|ForceIntr); */ + return IRQ_RETVAL(handled); } /* xirc2ps_interrupt */ /*====================================================================*/ diff -Nru a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c --- a/drivers/net/ppp_deflate.c Mon May 12 20:55:48 2003 +++ b/drivers/net/ppp_deflate.c Mon May 12 20:55:48 2003 @@ -88,7 +88,6 @@ if (state->strm.workspace) vfree(state->strm.workspace); kfree(state); - MOD_DEC_USE_COUNT; } } @@ -118,7 +117,6 @@ if (state == NULL) return NULL; - MOD_INC_USE_COUNT; memset (state, 0, sizeof (struct ppp_deflate_state)); state->strm.next_in = NULL; state->w_size = w_size; @@ -274,7 +272,6 @@ if (state->strm.workspace) kfree(state->strm.workspace); kfree(state); - MOD_DEC_USE_COUNT; } } @@ -303,7 +300,6 @@ if (state == NULL) return NULL; - MOD_INC_USE_COUNT; memset (state, 0, sizeof (struct ppp_deflate_state)); state->w_size = w_size; state->strm.next_out = NULL; diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c Mon May 12 20:55:49 2003 +++ b/drivers/net/ppp_generic.c Mon May 12 20:55:49 2003 @@ -57,7 +57,9 @@ #define NP_IPV6 1 /* Internet Protocol V6 */ #define NP_IPX 2 /* IPX protocol */ #define NP_AT 3 /* Appletalk protocol */ -#define NUM_NP 4 /* Number of NPs. */ +#define NP_MPLS_UC 4 /* MPLS unicast */ +#define NP_MPLS_MC 5 /* MPLS multicast */ +#define NUM_NP 6 /* Number of NPs. */ #define MPHDRLEN 6 /* multilink protocol header length */ #define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */ @@ -281,6 +283,10 @@ return NP_IPX; case PPP_AT: return NP_AT; + case PPP_MPLS_UC: + return NP_MPLS_UC; + case PPP_MPLS_MC: + return NP_MPLS_MC; } return -EINVAL; } @@ -291,6 +297,8 @@ PPP_IPV6, PPP_IPX, PPP_AT, + PPP_MPLS_UC, + PPP_MPLS_MC, }; /* Translates an ethertype into an NP index */ @@ -306,6 +314,10 @@ case ETH_P_PPPTALK: case ETH_P_ATALK: return NP_AT; + case ETH_P_MPLS_UC: + return NP_MPLS_UC; + case ETH_P_MPLS_MC: + return NP_MPLS_MC; } return -1; } @@ -316,6 +328,8 @@ ETH_P_IPV6, ETH_P_IPX, ETH_P_PPPTALK, + ETH_P_MPLS_UC, + ETH_P_MPLS_MC, }; /* @@ -784,11 +798,14 @@ printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops); - if (err) + if (!err) { + err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), + S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); + } + + if (!err) printk(KERN_ERR "failed to register PPP device (%d)\n", err); - devfs_register(NULL, "ppp", DEVFS_FL_DEFAULT, PPP_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, &ppp_device_fops, NULL); - return 0; + return err; } /* diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c --- a/drivers/net/sb1000.c Mon May 12 20:55:44 2003 +++ b/drivers/net/sb1000.c Mon May 12 20:55:44 2003 @@ -49,7 +49,7 @@ #include #include /* for udelay() */ #include -#include +#include #include #include @@ -131,146 +131,122 @@ static inline int sb1000_rx(struct net_device *dev); static inline void sb1000_error_dpc(struct net_device *dev); -static struct isapnp_device_id id_table[] = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('G','I','C'), ISAPNP_FUNCTION(0x1000), 0 }, - {0} +static const struct pnp_device_id sb1000_pnp_ids[] = { + { "GIC1000", 0 }, + { "", 0 } }; +MODULE_DEVICE_TABLE(pnp, sb1000_pnp_ids); -MODULE_DEVICE_TABLE(isapnp, id_table); - -/* probe for SB1000 using Plug-n-Play mechanism */ -int -sb1000_probe(struct net_device *dev) +static void +sb1000_setup(struct net_device *dev) { + dev->type = ARPHRD_ETHER; + dev->mtu = 1500; + dev->addr_len = ETH_ALEN; + + /* New-style flags. */ + dev->flags = IFF_POINTOPOINT|IFF_NOARP; +} +static int +sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) +{ + struct net_device *dev; unsigned short ioaddr[2], irq; - struct pnp_dev *idev=NULL; unsigned int serial_number; + int error = -ENODEV; - while(1) - { - /* - * Find the card - */ - - idev=pnp_find_dev(NULL, ISAPNP_VENDOR('G','I','C'), - ISAPNP_FUNCTION(0x1000), idev); - - /* - * No card - */ - - if(idev==NULL || idev->card == NULL) - return -ENODEV; - - /* - * Bring it online - */ - - if (pnp_device_attach(idev) < 0) - continue; - if (pnp_activate_dev(idev) < 0) { - __again: - pnp_device_detach(idev); - continue; - } - - /* - * Ports free ? - */ - - if(!pnp_port_valid(idev, 0) || !pnp_port_valid(idev, 1) || !pnp_irq_valid(idev, 0)) - goto __again; + if (pnp_device_attach(pdev) < 0) + return -ENODEV; + if (pnp_activate_dev(pdev) < 0) + goto out_detach; + + if (!pnp_port_valid(pdev, 0) || !pnp_port_valid(pdev, 1)) + goto out_disable; + if (!pnp_irq_valid(pdev, 0)) + goto out_disable; - serial_number = idev->card->serial; + serial_number = pdev->card->serial; - ioaddr[0]=pnp_port_start(idev, 0); - ioaddr[1]=pnp_port_start(idev, 0); + ioaddr[0] = pnp_port_start(pdev, 0); + ioaddr[1] = pnp_port_start(pdev, 0); - irq = pnp_irq(idev, 0); + irq = pnp_irq(pdev, 0); - /* check I/O base and IRQ */ - if (dev->base_addr != 0 && dev->base_addr != ioaddr[0]) - goto __again; - if (dev->mem_start != 0 && dev->mem_start != ioaddr[1]) - goto __again; - if (dev->irq != 0 && dev->irq != irq) - goto __again; - - /* - * Ok set it up. - */ - if (!request_region(ioaddr[0], 16, dev->name)) - goto __again; - if (!request_region(ioaddr[1], 16, dev->name)) { - release_region(ioaddr[0], 16); - goto __again; - } + if (!request_region(ioaddr[0], 16, dev->name)) + goto out_disable; + if (!request_region(ioaddr[1], 16, dev->name)) + goto out_release_region0; - dev->base_addr = ioaddr[0]; - /* mem_start holds the second I/O address */ - dev->mem_start = ioaddr[1]; - dev->irq = irq; - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), " - "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, - dev->mem_start, serial_number, dev->irq); - - dev = init_etherdev(dev, 0); - if (!dev) { - pnp_device_detach(idev); - release_region(ioaddr[1], 16); - release_region(ioaddr[0], 16); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - - /* Make up a SB1000-specific-data structure. */ - dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct sb1000_private)); - - if (sb1000_debug > 0) - printk(KERN_NOTICE "%s", version); - - /* The SB1000-specific entries in the device structure. */ - dev->open = sb1000_open; - dev->do_ioctl = sb1000_dev_ioctl; - dev->hard_start_xmit = sb1000_start_xmit; - dev->stop = sb1000_close; - dev->get_stats = sb1000_stats; - - /* Fill in the generic fields of the device structure. */ - dev->change_mtu = NULL; - dev->hard_header = NULL; - dev->rebuild_header = NULL; - dev->set_mac_address = NULL; - dev->header_cache_update= NULL; - - dev->type = ARPHRD_ETHER; - dev->hard_header_len = 0; - dev->mtu = 1500; - dev->addr_len = ETH_ALEN; - /* hardware address is 0:0:serial_number */ - dev->dev_addr[0] = 0; - dev->dev_addr[1] = 0; - dev->dev_addr[2] = serial_number >> 24 & 0xff; - dev->dev_addr[3] = serial_number >> 16 & 0xff; - dev->dev_addr[4] = serial_number >> 8 & 0xff; - dev->dev_addr[5] = serial_number >> 0 & 0xff; - dev->tx_queue_len = 0; - - /* New-style flags. */ - dev->flags = IFF_POINTOPOINT|IFF_NOARP; + dev->base_addr = ioaddr[0]; + /* mem_start holds the second I/O address */ + dev->mem_start = ioaddr[1]; + dev->irq = irq; - /* Lock resources */ + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), " + "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, + dev->mem_start, serial_number, dev->irq); + + dev = alloc_netdev(sizeof(struct sb1000_private), "cm%d", sb1000_setup); + if (!dev) { + error = -ENOMEM; + goto out_release_regions; + } + SET_MODULE_OWNER(dev); + + if (sb1000_debug > 0) + printk(KERN_NOTICE "%s", version); + + /* The SB1000-specific entries in the device structure. */ + dev->open = sb1000_open; + dev->do_ioctl = sb1000_dev_ioctl; + dev->hard_start_xmit = sb1000_start_xmit; + dev->stop = sb1000_close; + dev->get_stats = sb1000_stats; + + /* hardware address is 0:0:serial_number */ + dev->dev_addr[2] = serial_number >> 24 & 0xff; + dev->dev_addr[3] = serial_number >> 16 & 0xff; + dev->dev_addr[4] = serial_number >> 8 & 0xff; + dev->dev_addr[5] = serial_number >> 0 & 0xff; + + pnp_set_drvdata(pdev, dev); + + error = register_netdev(dev); + if (error) + goto out_unregister; + return 0; - return 0; - } -} + out_unregister: + unregister_netdev(dev); + out_release_regions: + release_region(ioaddr[1], 16); + out_release_region0: + release_region(ioaddr[0], 16); + out_disable: + pnp_disable_dev(pdev); + out_detach: + pnp_device_detach(pdev); + return error; +} + +static void +sb1000_remove_one(struct pnp_dev *pdev) +{ + struct net_device *dev = pnp_get_drvdata(pdev); + + unregister_netdev(dev); + release_region(dev->base_addr, 16); + release_region(dev->mem_start, 16); +} + +static struct pnp_driver sb1000_driver = { + .name = "sb1000", + .id_table = sb1000_pnp_ids, + .probe = sb1000_probe_one, + .remove = sb1000_remove_one, +}; /* @@ -1207,60 +1183,21 @@ return 0; } -#ifdef MODULE MODULE_AUTHOR("Franco Venturi "); MODULE_DESCRIPTION("General Instruments SB1000 driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(io, "1-2i"); -MODULE_PARM(irq, "i"); -MODULE_PARM_DESC(io, "SB1000 I/O base addresses"); -MODULE_PARM_DESC(irq, "SB1000 IRQ number"); - -static struct net_device dev_sb1000; -static int io[2]; -static int irq; - -int -init_module(void) +static int __init +sb1000_init(void) { - int i; - for (i = 0; i < 100; i++) { - sprintf(dev_sb1000.name, "cm%d", i); - if (dev_get(dev_sb1000.name) == 0) break; - } - if (i == 100) { - printk(KERN_ERR "sb1000: can't register any device cm\n"); - return -ENFILE; - } - dev_sb1000.init = sb1000_probe; - dev_sb1000.base_addr = io[0]; - /* mem_start holds the second I/O address */ - dev_sb1000.mem_start = io[1]; - dev_sb1000.irq = irq; - if (register_netdev(&dev_sb1000) != 0) { - printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x " - "irq: %d)\n", io[0], io[1], irq); - return -EIO; - } - return 0; + return pnp_register_driver(&sb1000_driver); } -void cleanup_module(void) +static void __exit +sb1000_exit(void) { - unregister_netdev(&dev_sb1000); - release_region(dev_sb1000.base_addr, 16); - release_region(dev_sb1000.mem_start, 16); - kfree(dev_sb1000.priv); - dev_sb1000.priv = NULL; + pnp_unregister_driver(&sb1000_driver); } -#endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O -m486 -c sb1000.c" - * version-control: t - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ + +module_init(sb1000_init); +module_exit(sb1000_exit); diff -Nru a/drivers/net/setup.c b/drivers/net/setup.c --- a/drivers/net/setup.c Mon May 12 20:55:48 2003 +++ b/drivers/net/setup.c Mon May 12 20:55:48 2003 @@ -9,15 +9,11 @@ #include #include -extern int slip_init_ctrl_dev(void); -extern int x25_asy_init_ctrl_dev(void); - extern int dmascc_init(void); extern int arcnet_init(void); extern int scc_enet_init(void); extern int fec_enet_init(void); -extern int dlci_setup(void); extern int sdla_setup(void); extern int sdla_c_setup(void); extern int comx_init(void); @@ -25,14 +21,6 @@ extern int madgemc_probe(void); -/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ -#define __PAD6 "\0\0\0\0\0\0\0\0\0" -#define __PAD5 __PAD6 "\0" -#define __PAD4 __PAD5 "\0" -#define __PAD3 __PAD4 "\0" -#define __PAD2 __PAD3 "\0" - - /* * Devices in this list must do new style probing. That is they must * allocate their own device objects and do their own bus scans. @@ -52,9 +40,6 @@ #if defined(CONFIG_DMASCC) {dmascc_init, 0}, #endif -#if defined(CONFIG_DLCI) - {dlci_setup, 0}, -#endif #if defined(CONFIG_SDLA) {sdla_c_setup, 0}, #endif @@ -91,7 +76,7 @@ * into them. */ -static void __init network_probe(void) +void __init net_device_init(void) { struct net_probe *p = pci_probes; @@ -100,48 +85,4 @@ p->status = p->probe(); p++; } -} - - -/* - * Initialise the line discipline drivers - */ - -static void __init network_ldisc_init(void) -{ -#if defined(CONFIG_SLIP) - slip_init_ctrl_dev(); -#endif -#if defined(CONFIG_X25_ASY) - x25_asy_init_ctrl_dev(); -#endif -} - - -static void __init special_device_init(void) -{ -#ifdef CONFIG_NET_SB1000 - extern int sb1000_probe(struct net_device *dev); - - static struct net_device sb1000_dev = { - .name = "cm0" __PAD3, - .init = sb1000_probe, - }; - register_netdev(&sb1000_dev); -#endif -} - -/* - * Initialise network devices - */ - -void __init net_device_init(void) -{ - /* Devices supporting the new probing API */ - network_probe(); - /* Line disciplines */ - network_ldisc_init(); - /* Special devices */ - special_device_init(); - /* That kicks off the legacy init functions */ } diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c Mon May 12 20:55:45 2003 +++ b/drivers/net/sk98lin/skge.c Mon May 12 20:55:45 2003 @@ -348,12 +348,12 @@ static int SkGeIocMib(DEV_NET*, unsigned int, int); -/*Extern */ +static const char SK_Root_Dir_entry[] = "sk98lin"; +static struct proc_dir_entry *pSkRootDir; -extern struct proc_dir_entry *pSkRootDir; //extern struct proc_dir_entry Our_Proc_Dir; -extern int proc_read(char *buffer, char **buffer_location, +extern int sk_proc_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data); @@ -376,17 +376,6 @@ static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480}; - -void proc_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - - /***************************************************************************** * * skge_probe - find all SK-98xx adapters @@ -481,20 +470,20 @@ dev->change_mtu = &SkGeChangeMtu; if(!proc_root_initialized) { - pSkRootDir = create_proc_entry("sk98lin", + pSkRootDir = create_proc_entry(SK_Root_Dir_entry, S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net); pSkRootDir->owner = THIS_MODULE; - proc_root_initialized = 1; } pProcFile = create_proc_entry(dev->name, S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = proc_read; + pProcFile->read_proc = sk_proc_read; pProcFile->write_proc = NULL; pProcFile->nlink = 1; pProcFile->size = sizeof(dev->name+1); pProcFile->data = (void*)pProcFile; + pProcFile->owner = THIS_MODULE; /* * Dummy value. @@ -571,11 +560,12 @@ pProcFile = create_proc_entry(dev->name, S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = proc_read; + pProcFile->read_proc = sk_proc_read; pProcFile->write_proc = NULL; pProcFile->nlink = 1; pProcFile->size = sizeof(dev->name+1); pProcFile->data = (void*)pProcFile; + pProcFile->owner = THIS_MODULE; memcpy((caddr_t) &dev->dev_addr, (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); diff -Nru a/drivers/net/sk98lin/skproc.c b/drivers/net/sk98lin/skproc.c --- a/drivers/net/sk98lin/skproc.c Mon May 12 20:55:44 2003 +++ b/drivers/net/sk98lin/skproc.c Mon May 12 20:55:44 2003 @@ -54,7 +54,6 @@ //#define SPECIAL 32 /* 0x */ #define LARGE 64 -extern void proc_fill_inode(struct inode *inode, int fill); extern char * SkNumber(char * str, long long num, int base, int size, int precision ,int type); int proc_read(char *buffer, @@ -64,19 +63,8 @@ int *eof, void *data); -static const char SK_Root_Dir_entry[] = "sk98lin"; -extern struct net_device *sk98lin_root_dev; - - -struct proc_dir_entry pSkRootDir = { - 0, - sizeof(SK_Root_Dir_entry)-1, - (const char*)SK_Root_Dir_entry, - S_IFDIR | S_IRUGO, - 2, 0, 0, 0, NULL, - NULL -}; +extern struct net_device *sk98lin_root_dev; /***************************************************************************** * @@ -90,7 +78,7 @@ * Returns: buffer with statistic data * */ -int proc_read(char *buffer, +int sk_proc_read(char *buffer, char **buffer_location, off_t offset, int buffer_length, diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c --- a/drivers/net/skfp/skfddi.c Mon May 12 20:55:44 2003 +++ b/drivers/net/skfp/skfddi.c Mon May 12 20:55:44 2003 @@ -539,6 +539,8 @@ dev->header_cache_update = NULL; /* not supported */ dev->change_mtu = NULL; /* set in fddi_setup() */ + SET_MODULE_OWNER(dev); + /* Initialize remaining device structure information */ fddi_setup(dev); } // init_device @@ -791,8 +793,6 @@ smt_online(smc, 1); STI_FBI(); - MOD_INC_USE_COUNT; - /* Clear local multicast address tables */ mac_clear_multicast(smc); @@ -853,8 +853,6 @@ bp->QueueSkb++; dev_kfree_skb(skb); } - - MOD_DEC_USE_COUNT; return (0); } // skfp_close diff -Nru a/drivers/net/slip.c b/drivers/net/slip.c --- a/drivers/net/slip.c Mon May 12 20:55:49 2003 +++ b/drivers/net/slip.c Mon May 12 20:55:49 2003 @@ -81,11 +81,7 @@ #include #endif -#ifdef MODULE -#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY-MODULAR" -#else -#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" -#endif +#define SLIP_VERSION "0.8.4-NET3.019-NEWTTY" typedef struct slip_ctrl { @@ -98,8 +94,6 @@ MODULE_PARM(slip_maxdev, "i"); MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices"); -static struct tty_ldisc sl_ldisc; - static int slip_esc(unsigned char *p, unsigned char *d, int len); static void slip_unesc(struct slip *sl, unsigned char c); #ifdef CONFIG_SLIP_MODE_SLIP6 @@ -1309,13 +1303,24 @@ #endif /* VSV changes end */ -/* Initialize SLIP control device -- register SLIP line discipline */ +static struct tty_ldisc sl_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "slip", + .open = slip_open, + .close = slip_close, + .ioctl = slip_ioctl, + .receive_buf = slip_receive_buf, + .receive_room = slip_receive_room, + .write_wakeup = slip_write_wakeup, +}; -int __init slip_init_ctrl_dev(void) +static int __init slip_init(void) { int status; - if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */ + if (slip_maxdev < 4) + slip_maxdev = 4; /* Sanity */ printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)" #ifdef CONFIG_SLIP_MODE_SLIP6 @@ -1323,16 +1328,15 @@ #endif ".\n", SLIP_VERSION, slip_maxdev ); -#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE) +#if defined(SL_INCLUDE_CSLIP) printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); #endif #ifdef CONFIG_SLIP_SMART printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); - if (slip_ctrls == NULL) - { + slip_ctrls = kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); + if (!slip_ctrls) { printk(KERN_ERR "SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } @@ -1347,28 +1351,7 @@ return status; } -static struct tty_ldisc sl_ldisc = -{ - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "slip", - .open = slip_open, - .close = slip_close, - .ioctl = slip_ioctl, - .receive_buf = slip_receive_buf, - .receive_room = slip_receive_room, - .write_wakeup = slip_write_wakeup, -}; - -#ifdef MODULE - -int init_module(void) -{ - return slip_init_ctrl_dev(); -} - -void -cleanup_module(void) +static void __exit slip_exit(void) { int i; @@ -1425,7 +1408,9 @@ printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); } } -#endif /* MODULE */ + +module_init(slip_init); +module_exit(slip_exit); #ifdef CONFIG_SLIP_SMART /* diff -Nru a/drivers/net/slip.h b/drivers/net/slip.h --- a/drivers/net/slip.h Mon May 12 20:55:47 2003 +++ b/drivers/net/slip.h Mon May 12 20:55:47 2003 @@ -116,10 +116,6 @@ #endif }; - - #define SLIP_MAGIC 0x5302 - -extern int slip_init(struct net_device *dev); #endif /* _LINUX_SLIP.H */ diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Mon May 12 20:55:47 2003 +++ b/drivers/net/tulip/tulip_core.c Mon May 12 20:55:47 2003 @@ -223,6 +223,7 @@ { 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, /* ALi 1563 integrated ethernet */ { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, tulip_pci_tbl); @@ -1325,12 +1326,14 @@ csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */ /* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */ - if (pdev->vendor == 0x1282 && pdev->device == 0x9102) + if ((pdev->vendor == 0x1282 && pdev->device == 0x9102) + || (pdev->vendor == 0x10b9 && pdev->device == 0x5261)) csr0 &= ~0x01f100ff; #if defined(__sparc__) /* DM9102A needs 32-dword alignment/burst length on sparc - chip bug? */ - if (pdev->vendor == 0x1282 && pdev->device == 0x9102) + if ((pdev->vendor == 0x1282 && pdev->device == 0x9102) + || (pdev->vendor == 0x10b9 && pdev->device == 0x5261)) csr0 = (csr0 & ~0xff00) | 0xe000; #endif diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c --- a/drivers/net/wan/cosa.c Mon May 12 20:55:44 2003 +++ b/drivers/net/wan/cosa.c Mon May 12 20:55:44 2003 @@ -392,12 +392,9 @@ } devfs_mk_dir("cosa"); for (i=0; i #include #include +#include #include #include #include @@ -577,9 +578,10 @@ return(0); } -int __init dlci_setup(void) +int __init init_dlci(void) { int i; + dlci_ioctl_set(dlci_ioctl); printk("%s.\n", version); @@ -589,25 +591,16 @@ for(i=0;idev))) return err; - MOD_INC_USE_COUNT; - /* Done. We have linked the TTY line to a channel. */ return sl->dev->base_addr; } @@ -664,7 +660,6 @@ sl->tty = NULL; x25_asy_free(sl); unregister_netdev(sl->dev); - MOD_DEC_USE_COUNT; } @@ -769,32 +764,29 @@ /* Perform I/O control on an active X.25 channel. */ -static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { struct x25_asy *sl = (struct x25_asy *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC) { + if (!sl || sl->magic != X25_ASY_MAGIC) return -EINVAL; - } - switch(cmd) - { - case SIOCGIFNAME: - if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1)) - return -EFAULT; - return 0; - - case SIOCSIFHWADDR: - return -EINVAL; - - /* Allow stty to read, but not set, the serial port */ - case TCGETS: - case TCGETA: - return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg); - - default: - return -ENOIOCTLCMD; + switch(cmd) { + case SIOCGIFNAME: + if (copy_to_user((void *)arg, sl->dev->name, + strlen(sl->dev->name) + 1)) + return -EFAULT; + return 0; + case SIOCSIFHWADDR: + return -EINVAL; + /* Allow stty to read, but not set, the serial port */ + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, file, cmd, arg); + default: + return -ENOIOCTLCMD; } } @@ -806,51 +798,7 @@ return 0; } -/* Initialize X.25 control device -- register X.25 line discipline */ - -int __init x25_asy_init_ctrl_dev(void) -{ - int status; - - if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */ - - printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n", - x25_asy_maxdev ); - x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL); - if (x25_asy_ctrls == NULL) - { - printk("X25 async: Can't allocate x25_asy_ctrls[] array! Uaargh! (-> No X.25 available)\n"); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */ - - /* Fill in our line protocol discipline, and register it */ - memset(&x25_ldisc, 0, sizeof(x25_ldisc)); - x25_ldisc.magic = TTY_LDISC_MAGIC; - x25_ldisc.name = "X.25"; - x25_ldisc.flags = 0; - x25_ldisc.open = x25_asy_open_tty; - x25_ldisc.close = x25_asy_close_tty; - x25_ldisc.read = NULL; - x25_ldisc.write = NULL; - x25_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long)) x25_asy_ioctl; - x25_ldisc.poll = NULL; - x25_ldisc.receive_buf = x25_asy_receive_buf; - x25_ldisc.receive_room = x25_asy_receive_room; - x25_ldisc.write_wakeup = x25_asy_write_wakeup; - if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0) { - printk("X.25 async: can't register line discipline (err = %d)\n", status); - } - - return status; -} - - /* Initialise the X.25 driver. Called by the device init code */ - int x25_asy_init(struct net_device *dev) { struct x25_asy *sl = (struct x25_asy*)(dev->priv); @@ -885,43 +833,58 @@ return 0; } -#ifdef MODULE -int -init_module(void) -{ - return x25_asy_init_ctrl_dev(); +static struct tty_ldisc x25_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "X.25", + .open = x25_asy_open_tty, + .close = x25_asy_close_tty, + .ioctl = x25_asy_ioctl, + .receive_buf = x25_asy_receive_buf, + .receive_room = x25_asy_receive_room, + .write_wakeup = x25_asy_write_wakeup, +}; + +static int __init init_x25_asy(void) +{ + if (x25_asy_maxdev < 4) + x25_asy_maxdev = 4; /* Sanity */ + + printk(KERN_INFO "X.25 async: version 0.00 ALPHA " + "(dynamic channels, max=%d).\n", x25_asy_maxdev ); + x25_asy_ctrls = kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL); + if (!x25_asy_ctrls) { + printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] " + "array! Uaargh! (-> No X.25 available)\n"); + return -ENOMEM; + } + memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */ + + return tty_register_ldisc(N_X25, &x25_ldisc); } -void -cleanup_module(void) + +static void __exit exit_x25_asy(void) { int i; - if (x25_asy_ctrls != NULL) - { - for (i = 0; i < x25_asy_maxdev; i++) - { - if (x25_asy_ctrls[i]) - { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (netif_running(&(x25_asy_ctrls[i]->dev))) - unregister_netdev(&(x25_asy_ctrls[i]->dev)); + for (i = 0; i < x25_asy_maxdev; i++) { + if (x25_asy_ctrls[i]) { + /* + * VSV = if dev->start==0, then device + * unregistered while close proc. + */ + if (netif_running(&(x25_asy_ctrls[i]->dev))) + unregister_netdev(&(x25_asy_ctrls[i]->dev)); - kfree(x25_asy_ctrls[i]); - x25_asy_ctrls[i] = NULL; - } + kfree(x25_asy_ctrls[i]); } - kfree(x25_asy_ctrls); - x25_asy_ctrls = NULL; - } - if ((i = tty_register_ldisc(N_X25, NULL))) - { - printk("X.25 async: can't unregister line discipline (err = %d)\n", i); } + + kfree(x25_asy_ctrls); + tty_register_ldisc(N_X25, NULL); } -#endif /* MODULE */ +module_init(init_x25_asy); +module_exit(exit_x25_asy); diff -Nru a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c --- a/drivers/net/wireless/netwave_cs.c Mon May 12 20:55:49 2003 +++ b/drivers/net/wireless/netwave_cs.c Mon May 12 20:55:49 2003 @@ -227,7 +227,7 @@ static int netwave_rx( struct net_device *dev); /* Interrupt routines */ -static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void netwave_watchdog(struct net_device *); /* Statistics */ @@ -1456,7 +1456,7 @@ * ready to transmit another packet. * 3. A command has completed execution. */ -static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) { +static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) { ioaddr_t iobase; u_char *ramBase; struct net_device *dev = (struct net_device *)dev_id; @@ -1465,7 +1465,7 @@ int i; if (!netif_device_present(dev)) - return; + return IRQ_NONE; iobase = dev->base_addr; ramBase = priv->ramBase; @@ -1476,7 +1476,7 @@ wait_WOC(iobase); if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02)) - break; /* None of the interrupt sources asserted */ + break; /* None of the interrupt sources asserted (normal exit) */ status = inb(iobase + NETWAVE_REG_ASR); @@ -1569,6 +1569,8 @@ } */ } + /* Handled if we looped at least one time - Jean II */ + return IRQ_RETVAL(i); } /* netwave_interrupt */ /* diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c --- a/drivers/net/wireless/wavelan.c Mon May 12 20:55:48 2003 +++ b/drivers/net/wireless/wavelan.c Mon May 12 20:55:48 2003 @@ -1717,31 +1717,28 @@ return (i); } -#ifdef WIRELESS_SPY +#ifdef IW_WIRELESS_SPY /*------------------------------------------------------------------*/ /* * Gather wireless spy statistics: for each packet, compare the source * address with our list, and if they match, get the statistics. * Sorry, but this function really needs the wireless extensions. */ -static inline void wl_spy_gather(device * dev, u8 * mac, /* MAC address */ - u8 * stats) -{ /* Statistics to gather */ - net_local *lp = (net_local *) dev->priv; - int i; +static inline void wl_spy_gather(device * dev, + u8 * mac, /* MAC address */ + u8 * stats) /* Statistics to gather */ +{ + struct iw_quality wstats; - /* Check all addresses. */ - for (i = 0; i < lp->spy_number; i++) - /* If match */ - if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) { - /* Update statistics */ - lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; - lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; - lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; - lp->spy_stat[i].updated = 0x7; - } + wstats.qual = stats[2] & MMR_SGNL_QUAL; + wstats.level = stats[0] & MMR_SIGNAL_LVL; + wstats.noise = stats[1] & MMR_SILENCE_LVL; + wstats.updated = 0x7; + + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); } -#endif /* WIRELESS_SPY */ +#endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM /*------------------------------------------------------------------*/ @@ -1767,7 +1764,7 @@ /* Increment interval counter. */ (lp->his_sum[i])++; } -#endif /* HISTOGRAM */ +#endif /* HISTOGRAM */ /*------------------------------------------------------------------*/ /* @@ -2203,93 +2200,6 @@ return ret; } -#ifdef WIRELESS_SPY -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set spy list - */ -static int wavelan_set_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; - int ret = 0; - - /* Disable spy while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->spy_number = 0; - - /* Are there are addresses to copy? */ - if (wrqu->data.length > 0) { - /* Copy addresses to the lp structure. */ - for (i = 0; i < wrqu->data.length; i++) { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); - } - - /* Reset structure. */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG - "SetSpy: set of new addresses is: \n"); - for (i = 0; i < wrqu->data.length; i++) - printk(KERN_DEBUG - "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } - - /* Now we can set the number of addresses */ - lp->spy_number = wrqu->data.length; - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get spy list - */ -static int wavelan_get_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; - - /* Set the number of addresses */ - wrqu->data.length = lp->spy_number; - - /* Copy addresses from the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(address[i].sa_data, - lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } - /* Copy stats to the user buffer (just after). */ - if(lp->spy_number > 0) - memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number); - - /* Reset updated flags. */ - for (i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - - return(0); -} -#endif /* WIRELESS_SPY */ - /*------------------------------------------------------------------*/ /* * Wireless Private Handler : set quality threshold @@ -2439,15 +2349,10 @@ NULL, /* SIOCGIWPRIV */ NULL, /* SIOCSIWSTATS */ NULL, /* SIOCGIWSTATS */ -#ifdef WIRELESS_SPY - wavelan_set_spy, /* SIOCSIWSPY */ - wavelan_get_spy, /* SIOCGIWSPY */ -#else /* WIRELESS_SPY */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ -#endif /* WIRELESS_SPY */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ NULL, /* SIOCSIWAP */ NULL, /* SIOCGIWAP */ NULL, /* -- hole -- */ @@ -2501,6 +2406,8 @@ .standard = (iw_handler *) wavelan_handler, .private = (iw_handler *) wavelan_private_handler, .private_args = (struct iw_priv_args *) wavelan_private_args, + .spy_offset = ((void *) (&((net_local *) NULL)->spy_data) - + (void *) NULL), }; /*------------------------------------------------------------------*/ @@ -2618,22 +2525,23 @@ #endif /* DEBUG_RX_INFO */ /* Statistics-gathering and associated stuff. - * It seem a bit messy with all the define, but it's really simple... */ -#if defined(WIRELESS_SPY) || defined(HISTOGRAM) + * It seem a bit messy with all the define, but it's really + * simple... */ if ( -#ifdef WIRELESS_SPY - (lp->spy_number > 0) || -#endif /* WIRELESS_SPY */ +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + (lp->spy_data.spy_number > 0) || +#endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM (lp->his_number > 0) || -#endif /* HISTOGRAM */ +#endif /* HISTOGRAM */ 0) { u8 stats[3]; /* signal level, noise level, signal quality */ - /* Read signal level, silence level and signal quality bytes. */ - /* Note: in the PCMCIA hardware, these are part of the frame. It seems - * that for the ISA hardware, it's nowhere to be found in the frame, - * so I'm obliged to do this (it has a side effect on /proc/net/wireless). + /* Read signal level, silence level and signal quality bytes */ + /* Note: in the PCMCIA hardware, these are part of the frame. + * It seems that for the ISA hardware, it's nowhere to be + * found in the frame, so I'm obliged to do this (it has a + * side effect on /proc/net/wireless). * Any ideas? */ mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); @@ -2648,15 +2556,14 @@ #endif /* Spying stuff */ -#ifdef WIRELESS_SPY +#ifdef IW_WIRELESS_SPY wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); -#endif /* WIRELESS_SPY */ +#endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM wl_his_gather(dev, stats); -#endif /* HISTOGRAM */ +#endif /* HISTOGRAM */ } -#endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */ /* * Hand the packet to the network module. @@ -2884,10 +2791,6 @@ length); #endif - /* Do we need some padding? */ - if (clen < ETH_ZLEN) - clen = ETH_ZLEN; - spin_lock_irqsave(&lp->spinlock, flags); /* Check nothing bad has happened */ @@ -3008,12 +2911,6 @@ (unsigned) skb); #endif - if (skb->len < ETH_ZLEN) { - skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; - } - /* * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. @@ -3035,6 +2932,17 @@ if (skb->next) printk(KERN_INFO "skb has next\n"); #endif + + /* Do we need some padding? */ + /* Note : on wireless the propagation time is in the order of 1us, + * and we don't have the Ethernet specific requirement of beeing + * able to detect collisions, therefore in theory we don't really + * need to pad. Jean II */ + if (skb->len < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) + return 0; + } /* Write packet on the card */ if(wv_packet_write(dev, skb->data, skb->len)) diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h --- a/drivers/net/wireless/wavelan.p.h Mon May 12 20:55:48 2003 +++ b/drivers/net/wireless/wavelan.p.h Mon May 12 20:55:48 2003 @@ -509,13 +509,9 @@ #ifdef WIRELESS_EXT iw_stats wstats; /* Wireless-specific statistics */ -#endif -#ifdef WIRELESS_SPY - int spy_number; /* number of addresses to spy */ - mac_addr spy_address[IW_MAX_SPY]; /* the addresses to spy */ - iw_qual spy_stat[IW_MAX_SPY]; /* statistics gathered */ -#endif /* WIRELESS_SPY */ + struct iw_spy_data spy_data; +#endif #ifdef HISTOGRAM int his_number; /* number of intervals */ diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c --- a/drivers/net/wireless/wavelan_cs.c Mon May 12 20:55:47 2003 +++ b/drivers/net/wireless/wavelan_cs.c Mon May 12 20:55:47 2003 @@ -1757,10 +1757,8 @@ u_short table[10]; /* Authorized frequency table */ long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ int i; /* index in the table */ -#if WIRELESS_EXT > 7 const int BAND_NUM = 10; /* Number of bands */ int c = 0; /* Channel number */ -#endif /* WIRELESS_EXT */ /* Read the frequency table */ fee_read(base, 0x71 /* frequency table */, @@ -1772,13 +1770,11 @@ /* Look in the table if the frequency is allowed */ if(table[9 - (freq / 16)] & (1 << (freq % 16))) { -#if WIRELESS_EXT > 7 /* Compute approximate channel number */ while((((channel_bands[c] >> 1) - 24) < freq) && (c < BAND_NUM)) c++; list[i].i = c; /* Set the list index */ -#endif /* WIRELESS_EXT */ /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; @@ -1792,7 +1788,7 @@ return(i); } -#ifdef WIRELESS_SPY +#ifdef IW_WIRELESS_SPY /*------------------------------------------------------------------*/ /* * Gather wireless spy statistics : for each packet, compare the source @@ -1804,22 +1800,17 @@ u_char * mac, /* MAC address */ u_char * stats) /* Statistics to gather */ { - net_local * lp = (net_local *) dev->priv; - int i; + struct iw_quality wstats; - /* Look all addresses */ - for(i = 0; i < lp->spy_number; i++) - /* If match */ - if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) - { - /* Update statistics */ - lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; - lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; - lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; - lp->spy_stat[i].updated = 0x7; - } + wstats.qual = stats[2] & MMR_SGNL_QUAL; + wstats.level = stats[0] & MMR_SIGNAL_LVL; + wstats.noise = stats[1] & MMR_SILENCE_LVL; + wstats.updated = 0x7; + + /* Update spy records */ + wireless_spy_update(dev, mac, &wstats); } -#endif /* WIRELESS_SPY */ +#endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM /*------------------------------------------------------------------*/ @@ -1904,17 +1895,10 @@ spin_lock_irqsave(&lp->spinlock, flags); /* Set NWID in WaveLAN. */ -#if WIRELESS_EXT > 8 if (!wrqu->nwid.disabled) { /* Set NWID in psa */ psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8; psa.psa_nwid[1] = wrqu->nwid.value & 0xFF; -#else /* WIRELESS_EXT > 8 */ - if(wrq->u.nwid.on) { - /* Set NWID in psa */ - psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; -#endif /* WIRELESS_EXT > 8 */ psa.psa_nwid_select = 0x01; psa_write(dev, (char *) psa.psa_nwid - (char *) &psa, @@ -1971,14 +1955,9 @@ psa_read(dev, (char *) psa.psa_nwid - (char *) &psa, (unsigned char *) psa.psa_nwid, 3); -#if WIRELESS_EXT > 8 wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrqu->nwid.disabled = !(psa.psa_nwid_select); wrqu->nwid.fixed = 1; /* Superfluous */ -#else /* WIRELESS_EXT > 8 */ - wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.on = psa.psa_nwid_select; -#endif /* WIRELESS_EXT > 8 */ /* Enable interrupts and restore flags. */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -2081,13 +2060,9 @@ spin_lock_irqsave(&lp->spinlock, flags); /* Set the level threshold. */ -#if WIRELESS_EXT > 7 /* We should complain loudly if wrqu->sens.fixed = 0, because we * can't set auto mode... */ psa.psa_thr_pre_set = wrqu->sens.value & 0x3F; -#else /* WIRELESS_EXT > 7 */ - psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; -#endif /* WIRELESS_EXT > 7 */ psa_write(dev, (char *) &psa.psa_thr_pre_set - (char *) &psa, (unsigned char *) &psa.psa_thr_pre_set, 1); @@ -2123,12 +2098,8 @@ psa_read(dev, (char *) &psa.psa_thr_pre_set - (char *) &psa, (unsigned char *) &psa.psa_thr_pre_set, 1); -#if WIRELESS_EXT > 7 wrqu->sens.value = psa.psa_thr_pre_set & 0x3F; wrqu->sens.fixed = 1; -#else /* WIRELESS_EXT > 7 */ - wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; -#endif /* WIRELESS_EXT > 7 */ /* Enable interrupts and restore flags. */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -2136,7 +2107,6 @@ return ret; } -#if WIRELESS_EXT > 8 /*------------------------------------------------------------------*/ /* * Wireless Handler : set encryption key @@ -2253,10 +2223,8 @@ return ret; } -#endif /* WIRELESS_EXT > 8 */ #ifdef WAVELAN_ROAMING_EXT -#if WIRELESS_EXT > 5 /*------------------------------------------------------------------*/ /* * Wireless Handler : set ESSID (domain) @@ -2367,10 +2335,8 @@ return -EOPNOTSUPP; } -#endif /* WIRELESS_EXT > 5 */ #endif /* WAVELAN_ROAMING_EXT */ -#if WIRELESS_EXT > 8 #ifdef WAVELAN_ROAMING /*------------------------------------------------------------------*/ /* @@ -2429,7 +2395,6 @@ return 0; } #endif /* WAVELAN_ROAMING */ -#endif /* WIRELESS_EXT > 8 */ /*------------------------------------------------------------------*/ /* @@ -2452,11 +2417,9 @@ /* Set all the info we don't care or don't know about to zero */ memset(range, 0, sizeof(struct iw_range)); -#if WIRELESS_EXT > 10 /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 9; -#endif /* WIRELESS_EXT > 10 */ /* Set information in the range struct. */ range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ @@ -2467,17 +2430,13 @@ range->max_qual.qual = MMR_SGNL_QUAL; range->max_qual.level = MMR_SIGNAL_LVL; range->max_qual.noise = MMR_SILENCE_LVL; -#if WIRELESS_EXT > 11 range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ /* Need to get better values for those two */ range->avg_qual.level = 30; range->avg_qual.noise = 8; -#endif /* WIRELESS_EXT > 11 */ -#if WIRELESS_EXT > 7 range->num_bitrates = 1; range->bitrate[0] = 2000000; /* 2 Mb/s */ -#endif /* WIRELESS_EXT > 7 */ /* Disable interrupts and save flags. */ spin_lock_irqsave(&lp->spinlock, flags); @@ -2491,7 +2450,6 @@ } else range->num_channels = range->num_frequency = 0; -#if WIRELESS_EXT > 8 /* Encryption supported ? */ if (mmc_encr(base)) { range->encoding_size[0] = 8; /* DES = 64 bits key */ @@ -2501,7 +2459,6 @@ range->num_encoding_sizes = 0; range->max_encoding_tokens = 0; } -#endif /* WIRELESS_EXT > 8 */ /* Enable interrupts and restore flags. */ spin_unlock_irqrestore(&lp->spinlock, flags); @@ -2509,93 +2466,6 @@ return ret; } -#ifdef WIRELESS_SPY -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : set spy list - */ -static int wavelan_set_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; - int ret = 0; - - /* Disable spy while we copy the addresses. - * As we don't disable interrupts, we need to do this */ - lp->spy_number = 0; - - /* Are there are addresses to copy? */ - if (wrqu->data.length > 0) { - /* Copy addresses to the lp structure. */ - for (i = 0; i < wrqu->data.length; i++) { - memcpy(lp->spy_address[i], address[i].sa_data, - WAVELAN_ADDR_SIZE); - } - - /* Reset structure. */ - memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); - -#ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG - "SetSpy: set of new addresses is: \n"); - for (i = 0; i < wrqu->data.length; i++) - printk(KERN_DEBUG - "%02X:%02X:%02X:%02X:%02X:%02X \n", - lp->spy_address[i][0], - lp->spy_address[i][1], - lp->spy_address[i][2], - lp->spy_address[i][3], - lp->spy_address[i][4], - lp->spy_address[i][5]); -#endif /* DEBUG_IOCTL_INFO */ - } - - /* Now we can set the number of addresses */ - lp->spy_number = wrqu->data.length; - - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * Wireless Handler : get spy list - */ -static int wavelan_get_spy(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ - struct sockaddr *address = (struct sockaddr *) extra; - int i; - - /* Set the number of addresses */ - wrqu->data.length = lp->spy_number; - - /* Copy addresses from the lp structure. */ - for (i = 0; i < lp->spy_number; i++) { - memcpy(address[i].sa_data, - lp->spy_address[i], - WAVELAN_ADDR_SIZE); - address[i].sa_family = AF_UNIX; - } - /* Copy stats to the user buffer (just after). */ - if(lp->spy_number > 0) - memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number), - lp->spy_stat, sizeof(iw_qual) * lp->spy_number); - - /* Reset updated flags. */ - for (i = 0; i < lp->spy_number; i++) - lp->spy_stat[i].updated = 0x0; - - return(0); -} -#endif /* WIRELESS_SPY */ - /*------------------------------------------------------------------*/ /* * Wireless Private Handler : set quality threshold @@ -2781,8 +2651,6 @@ { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, }; -#if WIRELESS_EXT > 12 - static const iw_handler wavelan_handler[] = { NULL, /* SIOCSIWNAME */ @@ -2806,15 +2674,10 @@ NULL, /* SIOCGIWPRIV */ NULL, /* SIOCSIWSTATS */ NULL, /* SIOCGIWSTATS */ -#ifdef WIRELESS_SPY - wavelan_set_spy, /* SIOCSIWSPY */ - wavelan_get_spy, /* SIOCGIWSPY */ -#else /* WIRELESS_SPY */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ -#endif /* WIRELESS_SPY */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ #ifdef WAVELAN_ROAMING_EXT wavelan_set_wap, /* SIOCSIWAP */ wavelan_get_wap, /* SIOCGIWAP */ @@ -2834,7 +2697,6 @@ NULL, /* SIOCSIWESSID */ NULL, /* SIOCGIWESSID */ #endif /* WAVELAN_ROAMING_EXT */ -#if WIRELESS_EXT > 8 NULL, /* SIOCSIWNICKN */ NULL, /* SIOCGIWNICKN */ NULL, /* -- hole -- */ @@ -2851,7 +2713,6 @@ NULL, /* SIOCGIWRETRY */ wavelan_set_encode, /* SIOCSIWENCODE */ wavelan_get_encode, /* SIOCGIWENCODE */ -#endif /* WIRELESS_EXT > 8 */ }; static const iw_handler wavelan_private_handler[] = @@ -2879,8 +2740,9 @@ .standard = (iw_handler *) wavelan_handler, .private = (iw_handler *) wavelan_private_handler, .private_args = (struct iw_priv_args *) wavelan_private_args, + .spy_offset = ((void *) (&((net_local *) NULL)->spy_data) - + (void *) NULL), }; -#endif /* WIRELESS_EXT > 12 */ /*------------------------------------------------------------------*/ /* @@ -2892,9 +2754,6 @@ struct ifreq * rq, /* Data passed */ int cmd) /* Ioctl number */ { -#if WIRELESS_EXT <= 12 - struct iwreq * wrq = (struct iwreq *) rq; -#endif int ret = 0; #ifdef DEBUG_IOCTL_TRACE @@ -2908,284 +2767,6 @@ ret = wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); break; -#if WIRELESS_EXT <= 12 - /* --------------- WIRELESS EXTENSIONS --------------- */ - /* Now done as iw_handler - Jean II */ - case SIOCGIWNAME: - wavelan_get_name(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCSIWNWID: - ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIWNWID: - ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCSIWFREQ: - ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIWFREQ: - ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCSIWSENS: - ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIWSENS: - ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL); - break; - -#if WIRELESS_EXT > 8 - case SIOCSIWENCODE: - { - char keybuf[8]; - if (wrq->u.encoding.pointer) { - /* We actually have a key to set */ - if (wrq->u.encoding.length != 8) { - ret = -EINVAL; - break; - } - if (copy_from_user(keybuf, - wrq->u.encoding.pointer, - wrq->u.encoding.length)) { - ret = -EFAULT; - break; - } - } else if (wrq->u.encoding.length != 0) { - ret = -EINVAL; - break; - } - ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf); - } - break; - - case SIOCGIWENCODE: - if (! capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - { - char keybuf[8]; - ret = wavelan_get_encode(dev, NULL, - &(wrq->u), - keybuf); - if (wrq->u.encoding.pointer) { - if (copy_to_user(wrq->u.encoding.pointer, - keybuf, - wrq->u.encoding.length)) - ret = -EFAULT; - } - } - break; -#endif /* WIRELESS_EXT > 8 */ - -#ifdef WAVELAN_ROAMING_EXT -#if WIRELESS_EXT > 5 - case SIOCSIWESSID: - { - char essidbuf[IW_ESSID_MAX_SIZE+1]; - if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) { - ret = -E2BIG; - break; - } - if (copy_from_user(essidbuf, wrq->u.essid.pointer, - wrq->u.essid.length)) { - ret = -EFAULT; - break; - } - ret = wavelan_set_essid(dev, NULL, - &(wrq->u), - essidbuf); - } - break; - - case SIOCGIWESSID: - { - char essidbuf[IW_ESSID_MAX_SIZE+1]; - ret = wavelan_get_essid(dev, NULL, - &(wrq->u), - essidbuf); - if (wrq->u.essid.pointer) - if ( copy_to_user(wrq->u.essid.pointer, - essidbuf, - wrq->u.essid.length) ) - ret = -EFAULT; - } - break; - - case SIOCSIWAP: - ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIWAP: - ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL); - break; -#endif /* WIRELESS_EXT > 5 */ -#endif /* WAVELAN_ROAMING_EXT */ - -#if WIRELESS_EXT > 8 -#ifdef WAVELAN_ROAMING - case SIOCSIWMODE: - ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIWMODE: - ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL); - break; -#endif /* WAVELAN_ROAMING */ -#endif /* WIRELESS_EXT > 8 */ - - case SIOCGIWRANGE: - { - struct iw_range range; - ret = wavelan_get_range(dev, NULL, - &(wrq->u), - (char *) &range); - if (copy_to_user(wrq->u.data.pointer, &range, - sizeof(struct iw_range))) - ret = -EFAULT; - } - break; - - case SIOCGIWPRIV: - /* Basic checking... */ - if(wrq->u.data.pointer != (caddr_t) 0) - { - /* Set the number of ioctl available */ - wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]); - - /* Copy structure to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args, - sizeof(wavelan_private_args))) - ret = -EFAULT; - } - break; - -#ifdef WIRELESS_SPY - case SIOCSIWSPY: - { - struct sockaddr address[IW_MAX_SPY]; - /* Check the number of addresses */ - if (wrq->u.data.length > IW_MAX_SPY) { - ret = -E2BIG; - break; - } - /* Get the data in the driver */ - if (wrq->u.data.pointer) { - if (copy_from_user((char *) address, - wrq->u.data.pointer, - sizeof(struct sockaddr) * - wrq->u.data.length)) { - ret = -EFAULT; - break; - } - } else if (wrq->u.data.length != 0) { - ret = -EINVAL; - break; - } - ret = wavelan_set_spy(dev, NULL, &(wrq->u), - (char *) address); - } - break; - - case SIOCGIWSPY: - { - char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) + - sizeof(struct iw_quality))]; - ret = wavelan_get_spy(dev, NULL, &(wrq->u), - buffer); - if (wrq->u.data.pointer) { - if (copy_to_user(wrq->u.data.pointer, - buffer, - (wrq->u.data.length * - (sizeof(struct sockaddr) + - sizeof(struct iw_quality))) - )) - ret = -EFAULT; - } - } - break; -#endif /* WIRELESS_SPY */ - - /* ------------------ PRIVATE IOCTL ------------------ */ - - case SIOCSIPQTHR: - if(!capable(CAP_NET_ADMIN)) - { - ret = -EPERM; - break; - } - ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIPQTHR: - ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL); - break; - -#ifdef WAVELAN_ROAMING - case SIOCSIPROAM: - /* Note : should check if user == root */ - ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL); - break; - - case SIOCGIPROAM: - ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL); - break; -#endif /* WAVELAN_ROAMING */ - -#ifdef HISTOGRAM - case SIOCSIPHISTO: - /* Verif if the user is root */ - if(!capable(CAP_NET_ADMIN)) - { - ret = -EPERM; - } - { - char buffer[16]; - /* Check the number of intervals */ - if(wrq->u.data.length > 16) - { - ret = -E2BIG; - break; - } - /* Get the data in the driver */ - if (wrq->u.data.pointer) { - if (copy_from_user(buffer, - wrq->u.data.pointer, - sizeof(struct sockaddr) * - wrq->u.data.length)) { - ret = -EFAULT; - break; - } - } else if (wrq->u.data.length != 0) { - ret = -EINVAL; - break; - } - ret = wavelan_set_histo(dev, NULL, &(wrq->u), - buffer); - } - break; - - case SIOCGIPHISTO: - { - long buffer[16]; - ret = wavelan_get_histo(dev, NULL, &(wrq->u), - (char *) buffer); - if (wrq->u.data.pointer) { - if (copy_to_user(wrq->u.data.pointer, - buffer, - (wrq->u.data.length * sizeof(long)))) - ret = -EFAULT; - } - } - break; -#endif /* HISTOGRAM */ -#endif /* WIRELESS_EXT <= 12 */ - /* ------------------- OTHER IOCTL ------------------- */ default: @@ -3368,9 +2949,9 @@ /* Statistics gathering & stuff associated. * It seem a bit messy with all the define, but it's really simple... */ if( -#ifdef WIRELESS_SPY - (lp->spy_number > 0) || -#endif /* WIRELESS_SPY */ +#ifdef IW_WIRELESS_SPY + (lp->spy_data.spy_number > 0) || +#endif /* IW_WIRELESS_SPY */ #ifdef HISTOGRAM (lp->his_number > 0) || #endif /* HISTOGRAM */ @@ -3581,10 +3162,6 @@ spin_lock_irqsave(&lp->spinlock, flags); - /* Check if we need some padding */ - if(clen < ETH_ZLEN) - clen = ETH_ZLEN; - /* Write the length of data buffer followed by the buffer */ outb(xmtdata_base & 0xff, PIORL(base)); outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base)); @@ -3664,6 +3241,17 @@ printk(KERN_INFO "skb has next\n"); #endif + /* Check if we need some padding */ + /* Note : on wireless the propagation time is in the order of 1us, + * and we don't have the Ethernet specific requirement of beeing + * able to detect collisions, therefore in theory we don't really + * need to pad. Jean II */ + if (skb->len < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) + return 0; + } + wv_packet_write(dev, skb->data, skb->len); dev_kfree_skb(skb); @@ -4644,7 +4232,7 @@ * ready to transmit another packet. * 3. A command has completed execution. */ -static void +static irqreturn_t wavelan_interrupt(int irq, void * dev_id, struct pt_regs * regs) @@ -4661,7 +4249,7 @@ printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", irq); #endif - return; + return IRQ_NONE; } #ifdef DEBUG_INTERRUPT_TRACE @@ -4883,6 +4471,24 @@ #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); #endif + + /* We always return IRQ_HANDLED, because we will receive empty + * interrupts under normal operations. Anyway, it doesn't matter + * as we are dealing with an ISA interrupt that can't be shared. + * + * Explanation : under heavy receive, the following happens : + * ->wavelan_interrupt() + * (status0 & SR0_INTERRUPT) != 0 + * ->wv_packet_rcv() + * (status0 & SR0_INTERRUPT) != 0 + * ->wv_packet_rcv() + * (status0 & SR0_INTERRUPT) == 0 // i.e. no more event + * <-wavelan_interrupt() + * ->wavelan_interrupt() + * (status0 & SR0_INTERRUPT) == 0 // i.e. empty interrupt + * <-wavelan_interrupt() + * Jean II */ + return IRQ_HANDLED; } /* wv_interrupt */ /*------------------------------------------------------------------*/ @@ -5189,9 +4795,7 @@ dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ -#if WIRELESS_EXT > 12 dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; -#endif /* WIRELESS_EXT > 12 */ dev->do_ioctl = wavelan_ioctl; /* old wireless extensions */ dev->get_wireless_stats = wavelan_get_wireless_stats; #endif diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h --- a/drivers/net/wireless/wavelan_cs.p.h Mon May 12 20:55:48 2003 +++ b/drivers/net/wireless/wavelan_cs.p.h Mon May 12 20:55:48 2003 @@ -443,9 +443,7 @@ #ifdef CONFIG_NET_RADIO #include /* Wireless extensions */ -#if WIRELESS_EXT > 12 -#include -#endif /* WIRELESS_EXT > 12 */ +#include /* New driver API */ #endif /* Pcmcia headers that we need */ @@ -527,13 +525,6 @@ /* ------------------------ PRIVATE IOCTL ------------------------ */ -/* Wireless Extension Backward compatibility - Jean II - * If the new wireless device private ioctl range is not defined, - * default to standard device private ioctl range */ -#ifndef SIOCIWFIRSTPRIV -#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE -#endif /* SIOCIWFIRSTPRIV */ - #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ @@ -605,16 +596,6 @@ typedef struct net_local net_local; typedef struct timer_list timer_list; -#if WIRELESS_EXT <= 12 -/* Wireless extensions backward compatibility */ -/* Part of iw_handler prototype we need */ -struct iw_request_info -{ - __u16 cmd; /* Wireless Extension command */ - __u16 flags; /* More to come ;-) */ -}; -#endif /* WIRELESS_EXT <= 12 */ - /* Basic types */ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ @@ -647,13 +628,10 @@ #ifdef WIRELESS_EXT iw_stats wstats; /* Wireless specific stats */ + + struct iw_spy_data spy_data; #endif -#ifdef WIRELESS_SPY - int spy_number; /* Number of addresses to spy */ - mac_addr spy_address[IW_MAX_SPY]; /* The addresses to spy */ - iw_qual spy_stat[IW_MAX_SPY]; /* Statistics gathered */ -#endif /* WIRELESS_SPY */ #ifdef HISTOGRAM int his_number; /* Number of intervals */ u_char his_range[16]; /* Boundaries of interval ]n-1; n] */ @@ -686,11 +664,6 @@ void wv_roam_cleanup(struct net_device *dev); #endif /* WAVELAN_ROAMING */ -/* ----------------------- MISC SUBROUTINES ------------------------ */ -static void - cs_error(client_handle_t, /* Report error to cardmgr */ - int, - int); /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */ static inline u_char /* data */ hasr_read(u_long); /* Read the host interface : base address */ @@ -791,7 +764,7 @@ wv_pcmcia_release(u_long), /* Remove a device */ wv_flush_stale_links(void); /* "detach" all possible devices */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ -static void +static irqreturn_t wavelan_interrupt(int, /* Interrupt handler */ void *, struct pt_regs *); diff -Nru a/drivers/s390/char/tuball.c b/drivers/s390/char/tuball.c --- a/drivers/s390/char/tuball.c Mon May 12 20:55:48 2003 +++ b/drivers/s390/char/tuball.c Mon May 12 20:55:48 2003 @@ -468,9 +468,8 @@ } #endif /* CONFIG_TN3270_CONSOLE */ -#ifdef CONFIG_DEVFS_FS - fs3270_devfs_register(tubp); -#endif + devfs_mk_cdev(MKDEV(IBM_FS3270_MAJOR, tubp->minor), + S_IFCHR|S_IRUSR|S_IWUSR, "3270/tub%.4x"); TUBUNLOCK(tubp->irq, flags); return minor; @@ -492,9 +491,7 @@ for (i = 0; i < TUBMAXMINS; i++) { tubpp = &(*tubminors)[i]; if ((tubp = *tubpp)) { -#ifdef CONFIG_DEVFS_FS - fs3270_devfs_unregister(tubp); -#endif + devfs_remove("3270/tub%.4x", tubp->devno); tubdelbyirq(tubp, tubp->irq); tty3270_rcl_fini(tubp); kfree(tubp->tty_bcb.bc_buf); diff -Nru a/drivers/s390/char/tubfs.c b/drivers/s390/char/tubfs.c --- a/drivers/s390/char/tubfs.c Mon May 12 20:55:47 2003 +++ b/drivers/s390/char/tubfs.c Mon May 12 20:55:47 2003 @@ -23,9 +23,7 @@ extern void tty3270_refresh(tub_t *); static struct file_operations fs3270_fops = { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) .owner = THIS_MODULE, /* owner */ -#endif .read = fs3270_read, /* read */ .write = fs3270_write, /* write */ .ioctl = fs3270_ioctl, /* ioctl */ @@ -33,27 +31,6 @@ .release = fs3270_close, /* release */ }; -#ifdef CONFIG_DEVFS_FS -void fs3270_devfs_register(tub_t *tubp) -{ - char name[16]; - - sprintf(name, "3270/tub%.4x", tubp->devno); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - IBM_FS3270_MAJOR, tubp->minor, - S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL); - sprintf(name, "tty%.4x", tubp->devno); - tty_register_devfs_name(&tty3270_driver, 0, tubp->minor, - NULL, name); -} - -void fs3270_devfs_unregister(tub_t *tubp) -{ - devfs_remove("3270/tub%.4x", tubp->devno); - devfs_remove("3270/tty%.4x", tubp->devno); -} -#endif - /* * fs3270_init() -- Initialize fullscreen tubes */ @@ -69,10 +46,8 @@ return -1; } devfs_mk_dir("3270"); - devfs_register(NULL, "3270/tub", 0, - IBM_FS3270_MAJOR, 0, - S_IFCHR | S_IRUGO | S_IWUGO, - &fs3270_fops, NULL); + devfs_mk_cdev(MKDEV(IBM_FS3270_MAJOR, 0), + S_IFCHR|S_IRUGO|S_IWUGO, "3270/tub"); fs3270_major = IBM_FS3270_MAJOR; return 0; } diff -Nru a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h --- a/drivers/s390/char/tubio.h Mon May 12 20:55:46 2003 +++ b/drivers/s390/char/tubio.h Mon May 12 20:55:46 2003 @@ -337,10 +337,6 @@ extern int tty3270_proc_misc; extern enum tubwhat tty3270_proc_what; extern struct tty_driver tty3270_driver; -#ifdef CONFIG_DEVFS_FS -extern void fs3270_devfs_register(tub_t *); -extern void fs3270_devfs_unregister(tub_t *); -#endif #ifndef spin_trylock_irqsave #define spin_trylock_irqsave(lock, flags) \ diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c --- a/drivers/s390/char/tubtty.c Mon May 12 20:55:48 2003 +++ b/drivers/s390/char/tubtty.c Mon May 12 20:55:48 2003 @@ -90,9 +90,7 @@ td->subtype = SYSTEM_TYPE_TTY; td->init_termios = tty_std_termios; td->flags = TTY_DRIVER_RESET_TERMIOS; -#ifdef CONFIG_DEVFS_FS td->flags |= TTY_DRIVER_NO_DEVFS; -#endif td->refcount = &tty3270_refcount; td->table = tty3270_table; td->termios = tty3270_termios; diff -Nru a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c --- a/drivers/sbus/char/bpp.c Mon May 12 20:55:44 2003 +++ b/drivers/sbus/char/bpp.c Mon May 12 20:55:44 2003 @@ -1051,11 +1051,8 @@ } devfs_mk_dir("bpp"); for (idx = 0; idx < BPP_NO; idx++) { - char name[16]; - sprintf(name, "bpp/%d", idx); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, - BPP_MAJOR, idx, S_IFCHR | S_IRUSR | S_IWUSR, - &bpp_fops, NULL); + devfs_mk_cdev(MKDEV(BPP_MAJOR, idx), + S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx); } return 0; diff -Nru a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c --- a/drivers/sbus/char/vfc_dev.c Mon May 12 20:55:47 2003 +++ b/drivers/sbus/char/vfc_dev.c Mon May 12 20:55:47 2003 @@ -143,8 +143,6 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance) { - char devname[16]; - if(dev == NULL) { printk(KERN_ERR "VFC: Bogus pointer passed\n"); return -ENOMEM; @@ -167,11 +165,9 @@ if (init_vfc_hw(dev)) return -EIO; - sprintf (devname, "vfc/%d", instance); - dev->de = devfs_register (NULL, devname, DEVFS_FL_DEFAULT, - VFC_MAJOR, instance, - S_IFCHR | S_IRUSR | S_IWUSR, - &vfc_fops, NULL); + devfs_mk_cdev(MKDEV(VFC_MAJOR, instance), + S_IFCHR | S_IRUSR | S_IWUSR, + "vfc/%d", instance); return 0; } diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h --- a/drivers/scsi/aic7xxx/aic79xx_osm.h Mon May 12 20:55:47 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h Mon May 12 20:55:47 2003 @@ -246,7 +246,7 @@ typedef struct timer_list ahd_timer_t; /********************************** Includes **********************************/ -#if CONFIG_AIC79XX_REG_PRETTY_PRINT +#ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT #define AIC_DEBUG_REGISTERS 1 #else #define AIC_DEBUG_REGISTERS 0 diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon May 12 20:55:46 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon May 12 20:55:46 2003 @@ -258,7 +258,7 @@ typedef struct timer_list ahc_timer_t; /********************************** Includes **********************************/ -#if CONFIG_AIC7XXX_REG_PRETTY_PRINT +#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT #define AIC_DEBUG_REGISTERS 1 #else #define AIC_DEBUG_REGISTERS 0 @@ -768,7 +768,7 @@ } static __inline void -ahc_list_lockinit() +ahc_list_lockinit(void) { spin_lock_init(&ahc_list_spinlock); } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon May 12 20:55:44 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon May 12 20:55:44 2003 @@ -1958,8 +1958,7 @@ } static uint8_t -read_brdctl(ahc) - struct ahc_softc *ahc; +read_brdctl(struct ahc_softc *ahc) { uint8_t brdctl; uint8_t value; diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c Mon May 12 20:55:49 2003 +++ b/drivers/scsi/esp.c Mon May 12 20:55:49 2003 @@ -4380,10 +4380,7 @@ .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, -/* Sparc32's iommu code cannot handle highmem pages yet. */ -#ifdef CONFIG_SPARC64 .highmem_io = 1, -#endif }; #include "scsi_module.c" diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c --- a/drivers/scsi/osst.c Mon May 12 20:55:46 2003 +++ b/drivers/scsi/osst.c Mon May 12 20:55:46 2003 @@ -5527,11 +5527,10 @@ write_unlock(&os_scsi_tapes_lock); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - char name[8], devfs_name[64]; + char name[8]; /* Rewind entry */ sprintf(name, "ot%s", osst_formats[mode]); - sprintf(devfs_name, "%s/ot%s", SDp->devfs_name, osst_formats[mode]); sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", SDp->sdev_driverfs_dev.bus_id, name); @@ -5545,13 +5544,13 @@ device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_type); device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev); - devfs_register(NULL, devfs_name, 0, - OSST_MAJOR, dev_num + (mode << 5), - S_IFCHR | S_IRUGO | S_IWUGO, - &osst_fops, NULL); + + devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)), + S_IFCHR | S_IRUGO | S_IWUGO, + "%s/ot%s", SDp->devfs_name, osst_formats[mode]); + /* No-rewind entry */ sprintf (name, "ot%sn", osst_formats[mode]); - sprintf(devfs_name, "%s/ot%sn", SDp->devfs_name, osst_formats[mode]); sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", SDp->sdev_driverfs_dev.bus_id, name); @@ -5566,10 +5565,10 @@ &dev_attr_type); device_create_file(&tpnt->driverfs_dev_n[mode], &dev_attr_kdev); - devfs_register(NULL, devfs_name, 0, - OSST_MAJOR, dev_num + (mode << 5) + 128, - S_IFCHR | S_IRUGO | S_IWUGO, - &osst_fops, NULL); + + devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128), + S_IFCHR | S_IRUGO | S_IWUGO, + "%s/ot%sn", SDp->devfs_name, osst_formats[mode]); } drive->number = devfs_register_tape(SDp->devfs_name); diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Mon May 12 20:55:44 2003 +++ b/drivers/scsi/scsi_error.c Mon May 12 20:55:44 2003 @@ -188,7 +188,7 @@ return sdev->online; } -#if CONFIG_SCSI_LOGGING +#ifdef CONFIG_SCSI_LOGGING /** * scsi_eh_prt_fail_stats - Log info on failures. * @shost: scsi host being recovered. diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Mon May 12 20:55:48 2003 +++ b/drivers/scsi/sd.c Mon May 12 20:55:48 2003 @@ -696,7 +696,7 @@ int good_sectors = (result == 0 ? this_count : 0); sector_t block_sectors = 1; sector_t error_sector; -#if CONFIG_SCSI_LOGGING +#ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); if (0 != result) { diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Mon May 12 20:55:46 2003 +++ b/drivers/scsi/sg.c Mon May 12 20:55:46 2003 @@ -1350,7 +1350,6 @@ struct gendisk *disk; Sg_device *sdp = NULL; unsigned long iflags; - char devfs_name[64]; int k, error; disk = alloc_disk(1); @@ -1449,11 +1448,9 @@ device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type); device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev); - sprintf(devfs_name, "%s/generic", scsidp->devfs_name); - devfs_register(NULL, devfs_name, 0, - SCSI_GENERIC_MAJOR, k, + devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &sg_fops, sdp); + "%s/generic", scsidp->devfs_name); switch (scsidp->type) { case TYPE_DISK: diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Mon May 12 20:55:47 2003 +++ b/drivers/scsi/st.c Mon May 12 20:55:47 2003 @@ -3865,11 +3865,10 @@ write_unlock(&st_dev_arr_lock); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - char name[8], devfs_name[64]; + char name[8]; /* Rewind entry */ sprintf(name, "mt%s", st_formats[mode]); - sprintf(devfs_name, "%s/mt%s", SDp->devfs_name, st_formats[mode]); sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", SDp->sdev_driverfs_dev.bus_id, name); @@ -3883,13 +3882,12 @@ device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_type); device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev); - devfs_register(NULL, devfs_name, 0, - SCSI_TAPE_MAJOR, dev_num + (mode << 5), + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), S_IFCHR | S_IRUGO | S_IWUGO, - &st_fops, NULL); + "%s/mt%s", SDp->devfs_name, st_formats[mode]); + /* No-rewind entry */ sprintf (name, "mt%sn", st_formats[mode]); - sprintf(devfs_name, "%s/mt%sn", SDp->devfs_name, st_formats[mode]); sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", SDp->sdev_driverfs_dev.bus_id, name); @@ -3904,10 +3902,9 @@ &dev_attr_type); device_create_file(&tpnt->driverfs_dev_n[mode], &dev_attr_kdev); - devfs_register(NULL, devfs_name, 0, - SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128, + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), S_IFCHR | S_IRUGO | S_IWUGO, - &st_fops, NULL); + "%s/mt%sn", SDp->devfs_name, st_formats[mode]); } disk->number = devfs_register_tape(SDp->devfs_name); diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Mon May 12 20:55:45 2003 +++ b/drivers/serial/core.c Mon May 12 20:55:45 2003 @@ -2242,7 +2242,7 @@ * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_register_device(drv->tty_driver, port->line); + tty_register_device(drv->tty_driver, port->line, NULL); out: up(&port_sem); diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c --- a/drivers/sgi/char/sgiserial.c Mon May 12 20:55:45 2003 +++ b/drivers/sgi/char/sgiserial.c Mon May 12 20:55:45 2003 @@ -1867,6 +1867,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.owner = THIS_MODULE; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; diff -Nru a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c --- a/drivers/sgi/char/shmiq.c Mon May 12 20:55:48 2003 +++ b/drivers/sgi/char/shmiq.c Mon May 12 20:55:48 2003 @@ -470,9 +470,8 @@ printk ("SHMIQ setup\n"); register_chrdev(SHMIQ_MAJOR, "shmiq", &shmiq_fops); for (i = 0; i < 3; i++) { - devfs_register (NULL, names[i], DEVFS_FL_DEFAULT, - SHMIQ_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR, - &shmiq_fops, NULL); + devfs_mk_cdev(MKDEV(SHMIQ_MAJOR, i), + S_IFCHR | S_IRUSR | S_IWUSR, names[i]); } } diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c --- a/drivers/tc/zs.c Mon May 12 20:55:48 2003 +++ b/drivers/tc/zs.c Mon May 12 20:55:48 2003 @@ -1872,6 +1872,7 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.owner = THIS_MODULE; #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/"; #else @@ -1970,8 +1971,8 @@ printk("ttyS%02d at 0x%08x (irq = %d)", info->line, info->port, info->irq); printk(" is a Z85C30 SCC\n"); - tty_register_device(&serial_driver, info->line); - tty_register_device(&callout_driver, info->line); + tty_register_device(&serial_driver, info->line, NULL); + tty_register_device(&callout_driver, info->line, NULL); } diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig --- a/drivers/usb/Kconfig Mon May 12 20:55:45 2003 +++ b/drivers/usb/Kconfig Mon May 12 20:55:45 2003 @@ -91,5 +91,7 @@ source "drivers/usb/misc/Kconfig" +source "drivers/usb/gadget/Kconfig" + endmenu diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile Mon May 12 20:55:49 2003 +++ b/drivers/usb/Makefile Mon May 12 20:55:49 2003 @@ -58,3 +58,4 @@ obj-$(CONFIG_USB_TEST) += misc/ obj-$(CONFIG_USB_TIGL) += misc/ obj-$(CONFIG_USB_USS720) += misc/ + diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Mon May 12 20:55:48 2003 +++ b/drivers/usb/class/bluetty.c Mon May 12 20:55:48 2003 @@ -1198,7 +1198,7 @@ bluetooth, endpoint->bInterval); /* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */ - tty_register_device (&bluetooth_tty_driver, minor); + tty_register_device (&bluetooth_tty_driver, minor, &intf->dev); info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor); bluetooth_table[minor] = bluetooth; diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/class/cdc-acm.c Mon May 12 20:55:47 2003 @@ -653,7 +653,7 @@ usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm); usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm); - tty_register_device(&acm_tty_driver, minor); + tty_register_device(&acm_tty_driver, minor, &intf->dev); acm_table[minor] = acm; usb_set_intfdata (intf, acm); diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c Mon May 12 20:55:45 2003 +++ b/drivers/usb/class/usblp.c Mon May 12 20:55:45 2003 @@ -54,7 +54,6 @@ #include #include #include -#include #undef DEBUG #include @@ -109,11 +108,7 @@ #define USBLP_REQ_RESET 0x02 #define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define USBLP_MINORS 256 -#else #define USBLP_MINORS 16 -#endif #define USBLP_MINOR_BASE 0 #define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */ @@ -324,13 +319,13 @@ struct usb_interface *intf; int retval; - if (minor < 0 || minor >= USBLP_MINORS) + if (minor < 0) return -ENODEV; lock_kernel(); retval = -ENODEV; - intf = usb_find_interface(&usblp_driver, mk_kdev(USB_MAJOR,minor)); + intf = usb_find_interface(&usblp_driver, minor); if (!intf) { goto out; } @@ -380,8 +375,6 @@ static void usblp_cleanup (struct usblp *usblp) { - devfs_remove ("usb/lp%d", usblp->minor); - usb_deregister_dev (1, usblp->minor); info("usblp%d: removed", usblp->minor); usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, @@ -809,6 +802,13 @@ .release = usblp_release, }; +static struct usb_class_driver usblp_class = { + .name = "usb/lp%d", + .fops = &usblp_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = USBLP_MINOR_BASE, +}; + static int usblp_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -816,7 +816,6 @@ struct usblp *usblp = 0; int protocol; int retval; - char name[10]; /* Malloc and start initializing usblp structure so we can use it * directly. */ @@ -830,11 +829,12 @@ init_waitqueue_head(&usblp->wait); usblp->ifnum = intf->altsetting->desc.bInterfaceNumber; - retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor); + retval = usb_register_dev(intf, &usblp_class); if (retval) { err("Not able to get a minor for this device."); goto abort; } + usblp->minor = intf->minor; usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { @@ -904,13 +904,6 @@ usblp_check_status(usblp, 0); #endif - /* If we have devfs, create with perms=660. */ - sprintf(name, "usb/lp%d", usblp->minor); - devfs_register(NULL, name, 0, USB_MAJOR, - usblp->minor, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP, &usblp_fops, NULL); - info("usblp%d: USB %sdirectional printer dev %d " "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X", usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, @@ -921,13 +914,10 @@ usb_set_intfdata (intf, usblp); - /* add device id so the device works when advertised */ - intf->kdev = mk_kdev(USB_MAJOR,usblp->minor); - return 0; abort_minor: - usb_deregister_dev (1, usblp->minor); + usb_deregister_dev(intf, &usblp_class); abort: if (usblp) { if (usblp->writebuf) @@ -1108,8 +1098,7 @@ { struct usblp *usblp = usb_get_intfdata (intf); - /* remove device id to disable open() */ - intf->kdev = NODEV; + usb_deregister_dev(intf, &usblp_class); if (!usblp || !usblp->dev) { err("bogus disconnect"); diff -Nru a/drivers/usb/core/file.c b/drivers/usb/core/file.c --- a/drivers/usb/core/file.c Mon May 12 20:55:49 2003 +++ b/drivers/usb/core/file.c Mon May 12 20:55:49 2003 @@ -11,7 +11,7 @@ more docs, etc) * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002 + * (C) Copyright Greg Kroah-Hartman 2002-2003 * */ @@ -66,6 +66,10 @@ .open = usb_open, }; +static struct class usb_class = { + .name = "usb", +}; + int usb_major_init(void) { if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) { @@ -74,41 +78,53 @@ } devfs_mk_dir("usb"); + class_register(&usb_class); return 0; } void usb_major_cleanup(void) { + class_unregister(&usb_class); devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct usb_interface *intf = class_dev_to_usb_interface(class_dev); + dev_t dev = MKDEV(USB_MAJOR, intf->minor); + return sprintf(buf, "%04x\n", dev); +} +static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); + /** * usb_register_dev - register a USB device, and ask for a minor number - * @fops: the file operations for this USB device - * @minor: the requested starting minor for this device. - * @num_minors: number of minor numbers requested for this device - * @start_minor: place to put the new starting minor number + * @intf: pointer to the usb_interface that is being registered + * @class_driver: pointer to the usb_class_driver for this device * * This should be called by all USB drivers that use the USB major number. * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be * dynamically allocated out of the list of available ones. If it is not * enabled, the minor number will be based on the next available free minor, - * starting at the requested @minor. + * starting at the class_driver->minor_base. + * + * This function also creates the devfs file for the usb device, if devfs + * is enabled, and creates a usb class device in the sysfs tree. * * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. * * Returns -EINVAL if something bad happens with trying to register a - * device, and 0 on success, alone with a value that the driver should - * use in start_minor. + * device, and 0 on success. */ -int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor) +int usb_register_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver) { - int i; - int j; - int good_spot; int retval = -EINVAL; + int minor_base = class_driver->minor_base; + int minor = 0; + char name[DEVICE_ID_SIZE]; + char *temp; #ifdef CONFIG_USB_DYNAMIC_MINORS /* @@ -116,65 +132,93 @@ * at zero to pack the devices into the smallest available space with * no holes in the minor range. */ - minor = 0; + minor_base = 0; #endif + intf->minor = -1; - dbg ("asking for %d minors, starting at %d", num_minors, minor); + dbg ("looking for a minor, starting at %d", minor_base); - if (fops == NULL) + if (class_driver->fops == NULL) goto exit; - *start_minor = 0; spin_lock (&minor_lock); - for (i = minor; i < MAX_USB_MINORS; ++i) { - if (usb_minors[i]) + for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { + if (usb_minors[minor]) continue; - good_spot = 1; - for (j = 1; j <= num_minors-1; ++j) - if (usb_minors[i+j]) { - good_spot = 0; - break; - } - if (good_spot == 0) - continue; - - *start_minor = i; - dbg("found a minor chunk free, starting at %d", i); - for (i = *start_minor; i < (*start_minor + num_minors); ++i) - usb_minors[i] = fops; + usb_minors[minor] = class_driver->fops; retval = 0; - goto exit; + break; } -exit: spin_unlock (&minor_lock); + + if (retval) + goto exit; + + intf->minor = minor; + + /* handle the devfs registration */ + snprintf(name, DEVICE_ID_SIZE, class_driver->name, minor - minor_base); + devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); + + /* create a usb class device for this usb interface */ + memset(&intf->class_dev, 0x00, sizeof(struct class_device)); + intf->class_dev.class = &usb_class; + intf->class_dev.dev = &intf->dev; + + temp = strrchr(name, '/'); + if (temp && (temp[1] != 0x00)) + ++temp; + else + temp = name; + snprintf(intf->class_dev.class_id, BUS_ID_SIZE, "%s", temp); + class_device_register(&intf->class_dev); + class_device_create_file (&intf->class_dev, &class_device_attr_dev); +exit: return retval; } EXPORT_SYMBOL(usb_register_dev); /** * usb_deregister_dev - deregister a USB device's dynamic minor. - * @num_minors: number of minor numbers to put back. - * @start_minor: the starting minor number + * @intf: pointer to the usb_interface that is being deregistered + * @class_driver: pointer to the usb_class_driver for this device * * Used in conjunction with usb_register_dev(). This function is called * when the USB driver is finished with the minor numbers gotten from a * call to usb_register_dev() (usually when the device is disconnected * from the system.) + * + * This function also cleans up the devfs file for the usb device, if devfs + * is enabled, and removes the usb class device from the sysfs tree. * * This should be called by all drivers that use the USB major number. */ -void usb_deregister_dev (int num_minors, int start_minor) +void usb_deregister_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver) { - int i; + int minor_base = class_driver->minor_base; + char name[DEVICE_ID_SIZE]; - dbg ("removing %d minors starting at %d", num_minors, start_minor); +#ifdef CONFIG_USB_DYNAMIC_MINORS + minor_base = 0; +#endif + + if (intf->minor == -1) + return; + + dbg ("removing %d minor", intf->minor); spin_lock (&minor_lock); - for (i = start_minor; i < (start_minor + num_minors); ++i) - usb_minors[i] = NULL; + usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); + + snprintf(name, DEVICE_ID_SIZE, class_driver->name, intf->minor - minor_base); + devfs_remove (name); + + class_device_unregister(&intf->class_dev); + intf->minor = -1; } EXPORT_SYMBOL(usb_deregister_dev); diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/core/usb.c Mon May 12 20:55:46 2003 @@ -457,12 +457,13 @@ /** * usb_find_interface - find usb_interface pointer for driver and device * @drv: the driver whose current configuration is considered - * @kdev: the desired device + * @minor: the minor number of the desired device * * This walks the driver device list and returns a pointer to the interface - * with the matching kdev_t. + * with the matching minor. Note, this only works for devices that share the + * USB major number. */ -struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev) +struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { struct list_head *entry; struct device *dev; @@ -476,9 +477,10 @@ continue; intf = to_usb_interface(dev); - if (kdev_same(intf->kdev,kdev)) { + if (intf->minor == -1) + continue; + if (intf->minor == minor) return intf; - } } /* no device found that matches */ diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/Kconfig Mon May 12 20:55:49 2003 @@ -0,0 +1,153 @@ +# +# USB Gadget support on a system involves +# (a) a peripheral controller, and +# (b) the gadget driver using it. +# +# for 2.5 kbuild, drivers/usb/gadget/Kconfig +# source this at the end of drivers/usb/Kconfig +# +menuconfig USB_GADGET + tristate "Support for USB Gadgets" + depends on EXPERIMENTAL + help + USB is a master/slave protocol, organized with one master + host (such as a PC) controlling up to 127 peripheral devices. + The USB hardware is asymmetric, which makes it easier to set up: + you can't connect two "to-the-host" connectors to each other. + + Linux can run in the host, or in the peripheral. In both cases + you need a low level bus controller driver, and some software + talking to it. Peripheral controllers are often discrete silicon, + or are integrated with the CPU in a microcontroller. The more + familiar host side controllers have names like like "EHCI", "OHCI", + or "UHCI", and are usually integrated into southbridges on PC + motherboards. + + Enable this configuration option if you want to run Linux inside + a USB peripheral device. Configure one hardware driver for your + peripheral/device side bus controller, and a "gadget driver" for + your peripheral protocol. (If you use modular gadget drivers, + you may configure more than one.) + + If in doubt, say "N" and don't enable these drivers; most people + don't have this kind of hardware (except maybe inside Linux PDAs). + +# +# USB Peripheral Controller Support +# +# FIXME convert to tristate choice when "choice" behaves as specified +# +comment "USB Peripheral Controller Support" + depends on USB_GADGET + +config USB_NET2280 + tristate "NetChip 2280 USB Peripheral Controller" + depends on PCI && USB_GADGET + help + NetChip 2280 is a PCI based USB peripheral controller which + supports both full and high speed USB 2.0 data transfers. + + It has six configurable endpoints, as well as endpoint zero + (for control transfers) and several endpoints with dedicated + functions. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "net2280" and force all + gadget drivers to also be dynamically linked. + +# +# USB Gadget Drivers +# +# FIXME only one of these may be statically linked; choice/endchoice. +# +comment "USB Gadget Drivers" + depends on USB_GADGET + +# FIXME want better dependency/config approach for drivers. with only +# two knobs to tweak (driver y/m/n, and a hardware symbol) there's no +# good excuse for Kconfig to cause such trouble here. there are clear +# bugs (coredumps, multiple choices enabled, and more) in its (boolean) +# "choice" logic too ... + +config USB_ZERO + tristate "Gadget Zero (DEVELOPMENT)" + depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100) + help + Gadget Zero is a two-configuration device. It either sinks and + sources bulk data; or it loops back a configurable number of + transfers. It also implements control requests, for "chapter 9" + conformance. The driver needs only two bulk-capable endpoints, so + it can work on top of most device-side usb controllers. It's + useful for testing, and is also a working example showing how + USB "gadget drivers" can be written. + + Make this be the first driver you try using on top of any new + USB peripheral controller driver. Then you can use host-side + test software, like the "usbtest" driver, to put your hardware + and its driver through a basic set of functional tests. + + Gadget Zero also works with the host-side "usb-skeleton" driver, + and with many kinds of host-side test software. You may need + to tweak product and vendor IDs before host software knows about + this device, and arrange to select an appropriate configuration. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_zero". + +config USB_ZERO_NET2280 + bool + # for now, treat the "dummy" hcd as if it were a net2280 + depends on USB_ZERO && (USB_NET2280 || USB_DUMMY_HCD) + default y + +config USB_ZERO_PXA250 + bool + depends on USB_ZERO && USB_PXA250 + default y + +config USB_ZERO_SA1100 + bool + depends on USB_ZERO && USB_SA1100 + default y + + +config USB_ETH + tristate "Ethernet Gadget" + depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100) + help + This driver implements the "Communication Device Class" (CDC) + Ethernet Control Model. That protocol is often avoided with pure + Ethernet adapters, in favor of simpler vendor-specific hardware, + but is widely supported by firmware for smart network devices. + + Within the USB device, this gadget driver exposes a network device + "usbX", where X depends on what other networking devices you have. + Treat it like a two-node Ethernet link: host, and gadget. + + The Linux-USB host-side "usbnet" driver interoperates with this + driver, so that deep I/O queues can be supported. (On 2.4 kernels, + use "CDCEther" instead.) Deep queues are especially important with + high speed devices. It should also interoperate with standard CDC + Ethernet class drivers on other host operating systems. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_ether". + + +config USB_ETH_NET2280 + bool + # for now, treat the "dummy" hcd as if it were a net2280 + depends on USB_ETH && (USB_NET2280 || USB_DUMMY_HCD) + default y + +config USB_ETH_PXA250 + bool + depends on USB_ETH && USB_PXA250 + default y + +config USB_ETH_SA1100 + bool + depends on USB_ETH && USB_SA1100 + default y + +# endmenuconfig diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/Makefile Mon May 12 20:55:49 2003 @@ -0,0 +1,14 @@ +# +# USB peripheral controller drivers +# +obj-$(CONFIG_USB_NET2280) += net2280.o + +# +# USB gadget drivers +# +g_zero-objs := zero.o usbstring.o +g_ether-objs := ether.o usbstring.o + +obj-$(CONFIG_USB_ZERO) += g_zero.o +obj-$(CONFIG_USB_ETH) += g_ether.o + diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/ether.c Mon May 12 20:55:49 2003 @@ -0,0 +1,1640 @@ +/* + * ether.c -- CDC 1.1 Ethernet gadget driver + * + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#define DEBUG 1 +// #define VERBOSE + +#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 + +/*-------------------------------------------------------------------------*/ + +/* + * "Communications Device Class" (CDC) Ethernet class driver + * + * CDC Ethernet is the standard USB solution for sending Ethernet frames + * using USB. Real hardware tends to use the same framing protocol but look + * different for control features. And Microsoft pushes their own approach + * (RNDIS) instead of the standard. + */ + +#define DRIVER_DESC "CDC Ethernet Gadget" +#define DRIVER_VERSION "29 April 2003" + +static const char shortname [] = "ether"; +static const char driver_desc [] = DRIVER_DESC; +static const char control_name [] = "Communications Control"; +static const char data_name [] = "CDC Ethernet Data"; + +#define MIN_PACKET sizeof(struct ethhdr) +#define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */ + +/* FIXME allow high speed jumbograms */ + +/*-------------------------------------------------------------------------*/ + +struct eth_dev { + spinlock_t lock; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + + u8 config; + struct usb_ep *in_ep, *out_ep, *status_ep; + const struct usb_endpoint_descriptor + *in, *out, *status; + + struct semaphore mutex; + struct net_device net; + struct net_device_stats stats; + atomic_t tx_qlen; + + struct work_struct work; + unsigned long todo; +#define WORK_RX_MEMORY 0 +}; + +/*-------------------------------------------------------------------------*/ + +/* This driver keeps a variable number of requests queued, more at + * high speeds. (Numbers are just educated guesses, untuned.) + * Shrink the queue if memory is tight, or make it bigger to + * handle bigger traffic bursts between IRQs. + */ + +static unsigned qmult = 4; + +#define HS_FACTOR 15 + +#define qlen(gadget) \ + (qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1)) + +/* defer IRQs on highspeed TX */ +#define TX_DELAY 8 + + +module_param (qmult, uint, S_IRUGO|S_IWUSR); + + +/*-------------------------------------------------------------------------*/ + +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ +#define DRIVER_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ + +/*-------------------------------------------------------------------------*/ + +/* + * hardware-specific configuration, controlled by which device + * controller driver was configured. + * + * CHIP ... hardware identifier + * DRIVER_VERSION_NUM ... alerts the host side driver to differences + * EP0_MAXPACKET ... controls packetization of control requests + * EP_*_NAME ... which endpoints do we use for which purpose? + * EP_*_NUM ... numbers for them (often limited by hardware) + * HIGHSPEED ... define if ep0 and descriptors need high speed support + * MAX_USB_POWER ... define if we use other than 100 mA bus current + * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER + * WAKEUP ... if hardware supports remote wakeup AND we will issue the + * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP + * + * hw_optimize(gadget) ... for any hardware tweaks we want to kick in + * before we enable our endpoints + * + * add other defines for other portability issues, like hardware that + * for some reason doesn't handle full speed bulk maxpacket of 64. + */ + +/* + * NetChip 2280, PCI based. + * + * use DMA with fat fifos for all data traffic, PIO for the status channel + * where its 64 byte maxpacket ceiling is no issue. + * + * performance note: only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f) + * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help. + */ +#ifdef CONFIG_USB_ETH_NET2280 +#define CHIP "net2280" +#define DRIVER_VERSION_NUM 0x0101 +#define EP0_MAXPACKET 64 +static const char EP_OUT_NAME [] = "ep-a"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME [] = "ep-b"; +#define EP_IN_NUM 2 +static const char EP_STATUS_NAME [] = "ep-f"; +#define EP_STATUS_NUM 3 +#define HIGHSPEED +/* specific hardware configs could be bus-powered */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* supports remote wakeup, but this driver doesn't */ + +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + +static inline void hw_optimize (struct usb_gadget *gadget) +{ + /* we can have bigger ep-a/ep-b fifos (2KB each, 4 USB packets + * for highspeed bulk) because we're not using ep-c/ep-d. + */ + net2280_set_fifo_mode (gadget, 1); +} +#endif + +/* + * PXA-250 UDC: widely used in second gen Linux-capable PDAs. + * + * no limitations except from set_interface: docs say "no" to a third + * interface. and the interrupt-only endpoints don't toggle, so we'll + * just use a bulk-capable one instead. + */ +#ifdef CONFIG_USB_ETH_PXA250 +#define CHIP "pxa250" +#define DRIVER_VERSION_NUM 0x0103 +#define EP0_MAXPACKET 16 +static const char EP_OUT_NAME [] = "ep12out-bulk"; +#define EP_OUT_NUM 12 +static const char EP_IN_NAME [] = "ep11in-bulk"; +#define EP_IN_NUM 11 +static const char EP_STATUS_NAME [] = "ep6in-bulk"; +#define EP_STATUS_NUM 6 +/* doesn't support bus-powered operation */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* supports remote wakeup, but this driver doesn't */ + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0); +#endif + +/* + * SA-1100 UDC: widely used in first gen Linux-capable PDAs. + * + * can't have a notification endpoint, since there are only the two + * bulk-capable ones. the CDC spec allows that. + */ +#ifdef CONFIG_USB_ETH_SA1100 +#define CHIP "sa1100" +#define DRIVER_VERSION_NUM 0x0105 +#define EP0_MAXPACKET 8 +static const char EP_OUT_NAME [] = "ep1out-bulk"; +#define EP_OUT_NUM 1 +static const char EP_IN_NAME [] = "ep2in-bulk"; +#define EP_IN_NUM 2 +// EP_STATUS_NUM is undefined +/* doesn't support bus-powered operation */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* doesn't support remote wakeup? */ + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0); +#endif + +/*-------------------------------------------------------------------------*/ + +#ifndef EP0_MAXPACKET +# error Configure some USB peripheral controller driver! +#endif + +/* power usage is config specific. + * hardware that supports remote wakeup defaults to disabling it. + */ + +#ifndef SELFPOWER +/* default: say we rely on bus power */ +#define SELFPOWER 0 +/* else: + * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER + * - MAX_USB_POWER may be nonzero. + */ +#endif + +#ifndef MAX_USB_POWER +/* any hub supports this steady state bus power consumption */ +#define MAX_USB_POWER 100 /* mA */ +#endif + +#ifndef WAKEUP +/* default: this driver won't do remote wakeup */ +#define WAKEUP 0 +/* else value must be USB_CONFIG_ATT_WAKEUP */ +#endif + +/*-------------------------------------------------------------------------*/ + +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#undef DEBUG +#define DEBUG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDEBUG DEBUG +#else +#define VDEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly + * ep0 implementation: descriptors, config management, setup(). + * also optional class-specific notification interrupt transfer. + */ + +/* + * DESCRIPTORS ... most are static, but strings and (full) configuration + * descriptors are built on demand. Notice how most of the cdc descriptors + * add no value to simple (typical) configurations. + */ + +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_ETHADDR 3 +#define STRING_DATA 4 +#define STRING_CONTROL 5 + +#define USB_BUFSIZ 256 /* holds our biggest descriptor */ + +/* + * This device advertises one configuration. + */ +#define CONFIG_CDC_ETHER 3 + +static const struct usb_device_descriptor +device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_COMM, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = EP0_MAXPACKET, + + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), + .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .bNumConfigurations = 1, +}; + +static const struct usb_config_descriptor +eth_config = { + .bLength = sizeof eth_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 2, + .bConfigurationValue = CONFIG_CDC_ETHER, + .iConfiguration = STRING_PRODUCT, + .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, + .bMaxPower = (MAX_USB_POWER + 1) / 2, +}; + +/* master comm interface optionally has a status notification endpoint */ + +static const struct usb_interface_descriptor +control_intf = { + .bLength = sizeof control_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 0, +#ifdef EP_STATUS_NUM + .bNumEndpoints = 1, +#else + .bNumEndpoints = 0, +#endif + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6, /* ethernet control model */ + .bInterfaceProtocol = 0, + .iInterface = STRING_CONTROL, +}; + +/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ +struct header_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u16 bcdCDC; +} __attribute__ ((packed)); + +static const struct header_desc header_desc = { + .bLength = sizeof header_desc, + .bDescriptorType = 0x24, + .bDescriptorSubType = 0, + + .bcdCDC = __constant_cpu_to_le16 (0x0110), +}; + +/* "Union Functional Descriptor" from CDC spec 5.2.3.X */ +struct union_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 bMasterInterface0; + u8 bSlaveInterface0; + /* ... and there could be other slave interfaces */ +} __attribute__ ((packed)); + +static const struct union_desc union_desc = { + .bLength = sizeof union_desc, + .bDescriptorType = 0x24, + .bDescriptorSubType = 6, + + .bMasterInterface0 = 0, /* index of control interface */ + .bSlaveInterface0 = 1, /* index of DATA interface */ +}; + +/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ +struct ether_desc { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 iMACAddress; + u32 bmEthernetStatistics; + u16 wMaxSegmentSize; + u16 wNumberMCFilters; + u8 bNumberPowerFilters; +} __attribute__ ((packed)); + +static const struct ether_desc ether_desc = { + .bLength = sizeof ether_desc, + .bDescriptorType = 0x24, + .bDescriptorSubType = 0x0f, + + /* this descriptor actually adds value, surprise! */ + .iMACAddress = STRING_ETHADDR, + .bmEthernetStatistics = __constant_cpu_to_le32 (0), /* no statistics */ + .wMaxSegmentSize = __constant_cpu_to_le16 (MAX_PACKET + ETH_HLEN), + .wNumberMCFilters = __constant_cpu_to_le16 (0), + .bNumberPowerFilters = 0, +}; + +#ifdef EP_STATUS_NUM + +/* include the status endpoint if we can, even though it's optional. + * + * some drivers (like current Linux cdc-ether!) "need" it to exist even + * if they ignore the connect/disconnect notifications that real aether + * can provide. more advanced cdc configurations might want to support + * encapsulated commands. + */ + +#define LOG2_STATUS_INTERVAL_MSEC 6 +#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ +static const struct usb_endpoint_descriptor +fs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), + .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, +}; +#endif + +/* the default data interface has no endpoints ... */ + +static const struct usb_interface_descriptor +data_nop_intf = { + .bLength = sizeof data_nop_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = STRING_DATA, +}; + +/* ... but the "real" data interface has two full speed bulk endpoints */ + +static const struct usb_interface_descriptor +data_intf = { + .bLength = sizeof data_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = STRING_DATA, +}; + +static const struct usb_endpoint_descriptor +fs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (64), +}; + +static const struct usb_endpoint_descriptor +fs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (64), +}; + +#ifdef HIGHSPEED + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + */ + +#ifdef EP_STATUS_NUM +static const struct usb_endpoint_descriptor +hs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 3, +}; +#endif + +static const struct usb_endpoint_descriptor +hs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (512), + .bInterval = 1, +}; + +static const struct usb_endpoint_descriptor +hs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (512), + .bInterval = 1, +}; + +static const struct usb_qualifier_descriptor +dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + /* assumes ep0 uses the same value for both speeds ... */ + .bMaxPacketSize0 = EP0_MAXPACKET, + + .bNumConfigurations = 2, +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,hs,fs) fs + +#endif /* !HIGHSPEED */ + +/* address that the host will use ... usually assigned at random */ +static char ethaddr [2 * ETH_ALEN + 1]; + +/* static strings, in iso 8859/1 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE "/" CHIP, }, + { STRING_PRODUCT, driver_desc, }, + { STRING_ETHADDR, ethaddr, }, + { STRING_CONTROL, control_name, }, + { STRING_DATA, data_name, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +/* + * one config, two interfaces: control, data. + * complications: class descriptors, and an altsetting. + */ +static int +config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) +{ + const unsigned config_len = USB_DT_CONFIG_SIZE + + 3 * USB_DT_INTERFACE_SIZE + + sizeof header_desc + + sizeof union_desc + + sizeof ether_desc +#ifdef EP_STATUS_NUM + + USB_DT_ENDPOINT_SIZE +#endif + + 2 * USB_DT_ENDPOINT_SIZE; +#ifdef HIGHSPEED + int hs; +#endif + /* a single configuration must always be index 0 */ + if (index > 0) + return -EINVAL; + if (config_len > USB_BUFSIZ) + return -EDOM; + + /* config (or other speed config) */ + memcpy (buf, ð_config, USB_DT_CONFIG_SIZE); + buf [1] = type; + ((struct usb_config_descriptor *) buf)->wTotalLength + = __constant_cpu_to_le16 (config_len); + buf += USB_DT_CONFIG_SIZE; +#ifdef HIGHSPEED + hs = (speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; +#endif + + /* control interface, class descriptors, optional status endpoint */ + memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; + + memcpy (buf, &header_desc, sizeof header_desc); + buf += sizeof header_desc; + memcpy (buf, &union_desc, sizeof union_desc); + buf += sizeof union_desc; + memcpy (buf, ðer_desc, sizeof ether_desc); + buf += sizeof ether_desc; + +#ifdef EP_STATUS_NUM +#ifdef HIGHSPEED + if (hs) + memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE); + else +#endif /* HIGHSPEED */ + memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; +#endif /* EP_STATUS_NUM */ + + /* default data altsetting has no endpoints */ + memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; + + /* the "real" data interface has two endpoints */ + memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; +#ifdef HIGHSPEED + if (hs) { + memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } else +#endif + { + memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } + + return config_len; +} + +/*-------------------------------------------------------------------------*/ + +static int +set_ether_config (struct eth_dev *dev, int gfp_flags) +{ + int result = 0; + struct usb_ep *ep; + struct usb_gadget *gadget = dev->gadget; + + gadget_for_each_ep (ep, gadget) { + const struct usb_endpoint_descriptor *d; + + /* NOTE: the host isn't allowed to use these two data + * endpoints in the default altsetting for the interface. + * so we don't activate them yet. + */ + + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); + ep->driver_data = dev; + dev->in_ep = ep; + dev->in = d; + continue; + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); + ep->driver_data = dev; + dev->out_ep = ep; + dev->out = d; + continue; + +#ifdef EP_STATUS_NUM + /* optional status/notification endpoint */ + } else if (strcmp (ep->name, EP_STATUS_NAME) == 0) { + d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + dev->status_ep = ep; + dev->status = d; + continue; + } +#endif + + /* ignore any other endpoints */ + } else + continue; + + /* stop on error */ + ERROR (dev, "can't enable %s, result %d\n", ep->name, result); + break; + } + + if (result == 0) + DEBUG (dev, "qlen %d\n", qlen (gadget)); + + /* caller is responsible for cleanup on error */ + return result; +} + +static void eth_reset_config (struct eth_dev *dev) +{ + if (dev->config == 0) + return; + + DEBUG (dev, "%s\n", __FUNCTION__); + + netif_stop_queue (&dev->net); + netif_carrier_off (&dev->net); + + /* just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + if (dev->in_ep) { + usb_ep_disable (dev->in_ep); + dev->in_ep = 0; + } + if (dev->out_ep) { + usb_ep_disable (dev->out_ep); + dev->out_ep = 0; + } +#ifdef EP_STATUS_NUM + if (dev->status_ep) { + usb_ep_disable (dev->status_ep); + dev->status_ep = 0; + } +#endif + dev->config = 0; +} + +/* change our operational config. must agree with the code + * that returns config descriptors, and altsetting code. + */ +static int +eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + if (number == dev->config) + return 0; + +#ifdef CONFIG_USB_ETH_SA1100 + if (dev->config && atomic_read (&dev->tx_qlen) != 0) { + /* tx fifo is full, but we can't clear it...*/ + INFO (dev, "can't change configurations\n"); + return -ESPIPE; + } +#endif + eth_reset_config (dev); + hw_optimize (gadget); + + switch (number) { + case CONFIG_CDC_ETHER: + result = set_ether_config (dev, gfp_flags); + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + return result; + } + + if (!result && (!dev->in_ep || !dev->out_ep)) + result = -ENODEV; + if (result) + eth_reset_config (dev); + else { + char *speed; + + switch (gadget->speed) { + case USB_SPEED_FULL: speed = "full"; break; +#ifdef HIGHSPEED + case USB_SPEED_HIGH: speed = "high"; break; +#endif + default: speed = "?"; break; + } + + dev->config = number; + INFO (dev, "%s speed config #%d: %s\n", speed, number, + driver_desc); + } + return result; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef EP_STATUS_NUM + +/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */ +#define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */ +#define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */ + +struct cdc_notification { + u8 bmRequestType; + u8 bNotificationType; + u16 wValue; + u16 wIndex; + u16 wLength; + + /* SPEED_CHANGE data looks like this */ + u32 data [2]; +}; + +static void eth_status_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct cdc_notification *event = req->buf; + int value = req->status; + struct eth_dev *dev = ep->driver_data; + + /* issue the second notification if host reads the first */ + if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION + && value == 0) { + event->bmRequestType = 0xA1; + event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE; + event->wValue = __constant_cpu_to_le16 (0); + event->wIndex = __constant_cpu_to_le16 (1); + event->wLength = __constant_cpu_to_le16 (8); + + /* SPEED_CHANGE data is up/down speeds in bits/sec */ + event->data [0] = event->data [1] = + (dev->gadget->speed == USB_SPEED_HIGH) + ? (13 * 512 * 8 * 1000 * 8) + : (19 * 64 * 1 * 1000 * 8); + + req->length = 16; + value = usb_ep_queue (ep, req, GFP_ATOMIC); + DEBUG (dev, "send SPEED_CHANGE --> %d\n", value); + if (value == 0) + return; + } else + DEBUG (dev, "event %02x --> %d\n", + event->bNotificationType, value); + + /* free when done */ + usb_ep_free_buffer (ep, req->buf, req->dma, 16); + usb_ep_free_request (ep, req); +} + +static void issue_start_status (struct eth_dev *dev) +{ + struct usb_request *req; + struct cdc_notification *event; + int value; + + DEBUG (dev, "%s, flush old status first\n", __FUNCTION__); + + /* flush old status + * + * FIXME ugly idiom, maybe we'd be better with just + * a "cancel the whole queue" primitive since any + * unlink-one primitive has way too many error modes. + */ + usb_ep_disable (dev->status_ep); + usb_ep_enable (dev->status_ep, dev->status); + + /* FIXME make these allocations static like dev->req */ + req = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC); + if (req == 0) { + DEBUG (dev, "status ENOMEM\n"); + return; + } + req->buf = usb_ep_alloc_buffer (dev->status_ep, 16, + &dev->req->dma, GFP_ATOMIC); + if (req->buf == 0) { + DEBUG (dev, "status buf ENOMEM\n"); +free_req: + usb_ep_free_request (dev->status_ep, req); + return; + } + + /* 3.8.1 says to issue first NETWORK_CONNECTION, then + * a SPEED_CHANGE. could be useful in some configs. + */ + event = req->buf; + event->bmRequestType = 0xA1; + event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION; + event->wValue = __constant_cpu_to_le16 (1); /* connected */ + event->wIndex = __constant_cpu_to_le16 (1); + event->wLength = 0; + + req->length = 8; + req->complete = eth_status_complete; + value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC); + if (value < 0) { + DEBUG (dev, "status buf queue --> %d\n", value); + usb_ep_free_buffer (dev->status_ep, + req->buf, dev->req->dma, 16); + goto free_req; + } +} + +#endif + +/*-------------------------------------------------------------------------*/ + +static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DEBUG ((struct eth_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +/* see section 3.8.2 table 10 of the CDC spec for more ethernet + * requests, mostly for filters (multicast, pm) and statistics + */ +#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ + +static void eth_start (struct eth_dev *dev, int gfp_flags); + +/* + * The setup() callback implements all the ep0 functionality that's not + * handled lower down. CDC has a number of less-common features: + * + * - two interfaces: control, and ethernet data + * - data interface has two altsettings: default, and active + * - class-specific descriptors for the control interface + * - a mandatory class-specific control request + */ +static int +eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct eth_dev *dev = get_gadget_data (gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + + /* descriptors just go into the pre-allocated ep0 buffer, + * while config change events may enable network traffic. + */ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + break; + switch (ctrl->wValue >> 8) { + + case USB_DT_DEVICE: + value = min (ctrl->wLength, (u16) sizeof device_desc); + memcpy (req->buf, &device_desc, value); + break; +#ifdef HIGHSPEED + case USB_DT_DEVICE_QUALIFIER: + value = min (ctrl->wLength, (u16) sizeof dev_qualifier); + memcpy (req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + // FALLTHROUGH +#endif /* HIGHSPEED */ + case USB_DT_CONFIG: + value = config_buf (gadget->speed, req->buf, + ctrl->wValue >> 8, + ctrl->wValue & 0xff); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + + case USB_DT_STRING: + value = usb_gadget_get_string (&stringtab, + ctrl->wValue & 0xff, req->buf); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + } + break; + + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + break; + spin_lock (&dev->lock); + value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + break; + *(u8 *)req->buf = dev->config; + value = min (ctrl->wLength, (u16) 1); + break; + + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE + || !dev->config + || ctrl->wIndex > 1) + break; + spin_lock (&dev->lock); + switch (ctrl->wIndex) { + case 0: /* control/master intf */ + if (ctrl->wValue != 0) + break; +#ifdef EP_STATUS_NUM + if (dev->status_ep) { + usb_ep_disable (dev->status_ep); + usb_ep_enable (dev->status_ep, dev->status); + } +#endif + value = 0; + break; + case 1: /* data intf */ + if (ctrl->wValue > 1) + break; + usb_ep_disable (dev->in_ep); + usb_ep_disable (dev->out_ep); + + /* CDC requires the data transfers not be done from + * the default interface setting ... also, setting + * the non-default interface clears filters etc. + */ + if (ctrl->wValue == 1) { + usb_ep_enable (dev->in_ep, dev->in); + usb_ep_enable (dev->out_ep, dev->out); + netif_carrier_on (&dev->net); +#ifdef EP_STATUS_NUM + issue_start_status (dev); +#endif + if (netif_running (&dev->net)) + eth_start (dev, GFP_ATOMIC); + } else { + netif_stop_queue (&dev->net); + netif_carrier_off (&dev->net); + } + value = 0; + break; + } + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) + || !dev->config + || ctrl->wIndex > 1) + break; + + /* if carrier is on, data interface is active. */ + *(u8 *)req->buf = + ((ctrl->wIndex == 1) && netif_carrier_ok (&dev->net)) + ? 1 + : 0, + value = min (ctrl->wLength, (u16) 1); + break; + + case CDC_SET_ETHERNET_PACKET_FILTER: + /* see 6.2.30: no data, wIndex = interface, + * wValue = packet filter bitmap + */ + if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) + || ctrl->wLength != 0 + || ctrl->wIndex > 1) + DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue); + /* NOTE: table 62 has 5 filter bits to reduce traffic, + * and we "must" support multicast and promiscuous. + * this NOP implements a bad filter... + */ + value = 0; + break; + + default: + VDEBUG (dev, + "unknown control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + } + + /* respond with data transfer before status phase? */ + if (value > 0) { + req->length = value; + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DEBUG (dev, "ep_queue --> %d\n", value); + req->status = 0; + eth_setup_complete (gadget->ep0, req); + } + } + + /* host either stalls (value < 0) or reports success */ + return value; +} + +static void +eth_disconnect (struct usb_gadget *gadget) +{ + struct eth_dev *dev = get_gadget_data (gadget); + unsigned long flags; + + spin_lock_irqsave (&dev->lock, flags); + netif_stop_queue (&dev->net); + netif_carrier_off (&dev->net); + eth_reset_config (dev); + spin_unlock_irqrestore (&dev->lock, flags); + + /* next we may get setup() calls to enumerate new connections; + * or an unbind() during shutdown (including removing module). + */ +} + +/*-------------------------------------------------------------------------*/ + +/* NETWORK DRIVER HOOKUP (to the layer above this driver) */ + +static int eth_change_mtu (struct net_device *net, int new_mtu) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + + if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET) + return -ERANGE; + /* no zero-length packet read wanted after mtu-sized packets */ + if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0) + return -EDOM; + net->mtu = new_mtu; + return 0; +} + +static struct net_device_stats *eth_get_stats (struct net_device *net) +{ + return &((struct eth_dev *) net->priv)->stats; +} + +static int eth_ethtool_ioctl (struct net_device *net, void *useraddr) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + u32 cmd; + + if (get_user (cmd, (u32 *)useraddr)) + return -EFAULT; + switch (cmd) { + + case ETHTOOL_GDRVINFO: { /* get driver info */ + struct ethtool_drvinfo info; + + memset (&info, 0, sizeof info); + info.cmd = ETHTOOL_GDRVINFO; + strncpy (info.driver, shortname, sizeof info.driver); + strncpy (info.version, DRIVER_VERSION, sizeof info.version); + strncpy (info.fw_version, CHIP, sizeof info.fw_version); + strncpy (info.bus_info, dev->gadget->dev.bus_id, + sizeof info.bus_info); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + + case ETHTOOL_GLINK: { /* get link status */ + struct ethtool_value edata = { ETHTOOL_GLINK }; + + edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN); + if (copy_to_user (useraddr, &edata, sizeof (edata))) + return -EFAULT; + return 0; + } + + } + /* Note that the ethtool user space code requires EOPNOTSUPP */ + return -EOPNOTSUPP; +} + +static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +{ + switch (cmd) { + case SIOCETHTOOL: + return eth_ethtool_ioctl (net, (void *)rq->ifr_data); + default: + return -EOPNOTSUPP; + } +} + +static void defer_kevent (struct eth_dev *dev, int flag) +{ + set_bit (flag, &dev->todo); + if (!schedule_work (&dev->work)) + ERROR (dev, "kevent %d may have been dropped\n", flag); + else + DEBUG (dev, "kevent %d scheduled\n", flag); +} + +static void rx_complete (struct usb_ep *ep, struct usb_request *req); + +static int +rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) +{ + struct sk_buff *skb; + int retval = 0; + size_t size; + + size = (sizeof (struct ethhdr) + dev->net.mtu); + + if ((skb = alloc_skb (size, gfp_flags)) == 0) { + DEBUG (dev, "no rx skb\n"); + defer_kevent (dev, WORK_RX_MEMORY); + usb_ep_free_request (dev->out_ep, req); + return -ENOMEM; + } + + req->buf = skb->data; + req->length = size; + req->complete = rx_complete; + req->context = skb; + + if (netif_running (&dev->net)) { + retval = usb_ep_queue (dev->out_ep, req, gfp_flags); + if (retval == -ENOMEM) + defer_kevent (dev, WORK_RX_MEMORY); + if (retval) + DEBUG (dev, "%s %d\n", __FUNCTION__, retval); + } else { + DEBUG (dev, "%s stopped\n", __FUNCTION__); + retval = -ENOLINK; + } + if (retval) { + DEBUG (dev, "rx submit --> %d\n", retval); + dev_kfree_skb_any (skb); + usb_ep_free_request (dev->out_ep, req); + } + return retval; +} + +static void rx_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct sk_buff *skb = req->context; + struct eth_dev *dev = ep->driver_data; + int status = req->status; + + switch (status) { + + /* normal completion */ + case 0: + skb_put (skb, req->actual); + if (MIN_PACKET > skb->len + || skb->len > (MAX_PACKET + ETH_HLEN)) { + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + DEBUG (dev, "rx length %d\n", skb->len); + break; + } + + skb->dev = &dev->net; + skb->protocol = eth_type_trans (skb, &dev->net); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + /* no buffer copies needed, unless hardware can't + * use skb buffers. + */ + status = netif_rx (skb); + skb = 0; + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: // unlink + case -ESHUTDOWN: // disconnect etc + VDEBUG (dev, "rx shutdown, code %d\n", status); + usb_ep_free_request (dev->out_ep, req); + req = 0; + break; + + /* data overrun */ + case -EOVERFLOW: + dev->stats.rx_over_errors++; + // FALLTHROUGH + + default: + dev->stats.rx_errors++; + DEBUG (dev, "rx status %d\n", status); + break; + } + + if (skb) + dev_kfree_skb_any (skb); + + if (req) + rx_submit (dev, req, GFP_ATOMIC); +} + +static void eth_work (void *_dev) +{ + struct eth_dev *dev = _dev; + + if (test_bit (WORK_RX_MEMORY, &dev->todo)) { + struct usb_request *req = 0; + + if (netif_running (&dev->net)) + req = usb_ep_alloc_request (dev->in_ep, GFP_KERNEL); + else + clear_bit (WORK_RX_MEMORY, &dev->todo); + if (req != 0) { + clear_bit (WORK_RX_MEMORY, &dev->todo); + rx_submit (dev, req, GFP_KERNEL); + } + } + + if (dev->todo) + DEBUG (dev, "work done, flags = 0x%lx\n", dev->todo); +} + +static void tx_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct sk_buff *skb = req->context; + struct eth_dev *dev = ep->driver_data; + + if (req->status) + dev->stats.tx_errors++; + else + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + + usb_ep_free_request (ep, req); + dev_kfree_skb_any (skb); + + atomic_inc (&dev->tx_qlen); + if (netif_carrier_ok (&dev->net)) + netif_wake_queue (&dev->net); +} + +static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + int length = skb->len; + int retval; + struct usb_request *req = 0; + + if (!(req = usb_ep_alloc_request (dev->in_ep, GFP_ATOMIC))) { + DEBUG (dev, "no request\n"); + goto drop; + } + + /* no buffer copies needed, unless the network stack did it + * or the hardware can't use skb buffers. + */ + req->buf = skb->data; + req->context = skb; + req->complete = tx_complete; + +#ifdef CONFIG_USB_ETH_SA1100 + /* don't demand zlp (req->zero) support from all hardware */ + if ((length % dev->in_ep->maxpacket) == 0) + length++; +#else + /* use zlp framing on tx for strict CDC-Ether conformance, + * though any robust network rx path ignores extra padding. + */ + req->zero = 1; +#endif + req->length = length; + +#ifdef HIGHSPEED + /* throttle highspeed IRQ rate back slightly */ + req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) + ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) + : 0; +#endif + + retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); + switch (retval) { + default: + DEBUG (dev, "tx queue err %d\n", retval); + break; + case 0: + net->trans_start = jiffies; + if (atomic_dec_and_test (&dev->tx_qlen)) + netif_stop_queue (net); + } + + if (retval) { + DEBUG (dev, "drop, code %d\n", retval); +drop: + dev->stats.tx_dropped++; + dev_kfree_skb_any (skb); + usb_ep_free_request (dev->in_ep, req); + } + return 0; +} + +static void eth_start (struct eth_dev *dev, int gfp_flags) +{ + struct usb_request *req; + int retval = 0; + unsigned i; + int size = qlen (dev->gadget); + + DEBUG (dev, "%s\n", __FUNCTION__); + + /* fill the rx queue */ + for (i = 0; retval == 0 && i < size; i++) { + req = usb_ep_alloc_request (dev->in_ep, gfp_flags); + if (req) + retval = rx_submit (dev, req, gfp_flags); + else if (i > 0) + defer_kevent (dev, WORK_RX_MEMORY); + else + retval = -ENOMEM; + } + + /* and open the tx floodgates */ + atomic_set (&dev->tx_qlen, size); + netif_wake_queue (&dev->net); +} + +static int eth_open (struct net_device *net) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + + DEBUG (dev, "%s\n", __FUNCTION__); + down (&dev->mutex); + if (netif_carrier_ok (&dev->net)) + eth_start (dev, GFP_KERNEL); + up (&dev->mutex); + return 0; +} + +static int eth_stop (struct net_device *net) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + + DEBUG (dev, "%s\n", __FUNCTION__); + down (&dev->mutex); + netif_stop_queue (net); + + DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", + dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_errors, dev->stats.tx_errors + ); + + /* ensure there are no more active requests */ + if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + usb_ep_disable (dev->in_ep); + usb_ep_disable (dev->out_ep); + if (netif_carrier_ok (&dev->net)) { + DEBUG (dev, "host still using in/out endpoints\n"); + usb_ep_enable (dev->in_ep, dev->in); + usb_ep_enable (dev->out_ep, dev->out); + } +#ifdef EP_STATUS_NUM + usb_ep_disable (dev->status_ep); + usb_ep_enable (dev->status_ep, dev->status); +#endif + } + + up (&dev->mutex); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void +eth_unbind (struct usb_gadget *gadget) +{ + struct eth_dev *dev = get_gadget_data (gadget); + + DEBUG (dev, "unbind\n"); + down (&dev->mutex); + + /* we've already been disconnected ... no i/o is active */ + if (dev->req) { + usb_ep_free_buffer (gadget->ep0, + dev->req->buf, dev->req->dma, + USB_BUFSIZ); + usb_ep_free_request (gadget->ep0, dev->req); + } + + unregister_netdev (&dev->net); + up (&dev->mutex); + + /* assuming we used keventd, it must quiesce too */ + flush_scheduled_work (); + + kfree (dev); + set_gadget_data (gadget, 0); +} + +static int +eth_bind (struct usb_gadget *gadget) +{ + struct eth_dev *dev; + struct net_device *net; + u8 node_id [ETH_ALEN]; + + /* just one upstream link at a time */ + if (ethaddr [0] != 0) + return -ENODEV; + + dev = kmalloc (sizeof *dev, SLAB_KERNEL); + if (!dev) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + spin_lock_init (&dev->lock); + init_MUTEX_LOCKED (&dev->mutex); + INIT_WORK (&dev->work, eth_work, dev); + + /* network device setup */ + net = &dev->net; + SET_MODULE_OWNER (net); + net->priv = dev; + strcpy (net->name, "usb%d"); + ether_setup (net); + + /* one random address for the gadget device ... both of these could + * reasonably come from an id prom or a module parameter. + */ + get_random_bytes (net->dev_addr, ETH_ALEN); + net->dev_addr [0] &= 0xfe; // clear multicast bit + net->dev_addr [0] |= 0x02; // set local assignment bit (IEEE802) + + /* ... another address for the host, on the other end of the + * link, gets exported through CDC (see CDC spec table 41) + */ + get_random_bytes (node_id, sizeof node_id); + node_id [0] &= 0xfe; // clear multicast bit + node_id [0] |= 0x02; // set local assignment bit (IEEE802) + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + node_id [0], node_id [1], node_id [2], + node_id [3], node_id [4], node_id [5]); + + net->change_mtu = eth_change_mtu; + net->get_stats = eth_get_stats; + net->hard_start_xmit = eth_start_xmit; + net->open = eth_open; + net->stop = eth_stop; + // watchdog_timeo, tx_timeout ... + // set_multicast_list + net->do_ioctl = eth_ioctl; + + /* preallocate control response and buffer */ + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); + if (!dev->req) + goto enomem; + dev->req->complete = eth_setup_complete; + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) { + usb_ep_free_request (gadget->ep0, dev->req); + goto enomem; + } + + /* finish hookup to lower layer ... */ + dev->gadget = gadget; + set_gadget_data (gadget, dev); + gadget->ep0->driver_data = dev; + + /* two kinds of host-initiated state changes: + * - iff DATA transfer is active, carrier is "on" + * - tx queueing enabled if open *and* carrier is "on" + */ + INFO (dev, "%s, host enet %s, version: " DRIVER_VERSION "\n", + driver_desc, ethaddr); + register_netdev (&dev->net); + netif_stop_queue (&dev->net); + netif_carrier_off (&dev->net); + + up (&dev->mutex); + return 0; + +enomem: + eth_unbind (gadget); + return -ENOMEM; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver eth_driver = { +#ifdef HIGHSPEED + .speed = USB_SPEED_HIGH, +#else + .speed = USB_SPEED_FULL, +#endif + .function = (char *) driver_desc, + .bind = eth_bind, + .unbind = eth_unbind, + + .setup = eth_setup, + .disconnect = eth_disconnect, + + .driver = { + .name = (char *) shortname, + // .shutdown = ... + // .suspend = ... + // .resume = ... + }, +}; + +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("GPL"); + + +static int __init init (void) +{ + return usb_gadget_register_driver (ð_driver); +} +module_init (init); + +static void __exit cleanup (void) +{ + usb_gadget_unregister_driver (ð_driver); +} +module_exit (cleanup); + diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/net2280.c Mon May 12 20:55:49 2003 @@ -0,0 +1,2660 @@ +/* + * Driver for the NetChip 2280 USB device controller. + * Specs and errata are available from . + * + * NetChip Technology Inc. supported the development of this driver. + * + * + * CODE STATUS HIGHLIGHTS + * + * Used with a gadget driver like "zero.c" this enumerates fine to Windows + * or Linux hosts; handles disconnect, reconnect, and reset, for full or + * high speed operation; and passes USB-IF "chapter 9" tests. + * + * Handles standard stress loads from the Linux "usbtest" driver, with + * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}. Testing + * with "ttcp" (and the "ether.c" driver) behaves nicely too. + * + * DMA is enabled by default. Drivers using transfer queues might use + * DMA chaining to remove IRQ latencies between transfers. (Except when + * short OUT transfers happen.) Drivers can use the req->no_interrupt + * hint to completely eliminate some IRQs, if a later IRQ is guaranteed + * and DMA chaining is enabled. + */ + +// #define NET2280_DMA_OUT_WORKAROUND +// #define USE_DMA_CHAINING + + +/* + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define DEBUG 1 +// #define VERBOSE /* extra debug messages (success too) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define DRIVER_DESC "NetChip 2280 USB Peripheral Controller" +#define DRIVER_VERSION "May Day 2003" + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) +#define EP_DONTUSE 13 /* nonzero */ + +#define USE_RDK_LEDS /* GPIO pins control three LEDs */ +#define USE_SYSFS_DEBUG_FILES + + +static const char driver_name [] = "net2280"; +static const char driver_desc [] = DRIVER_DESC; + +static const char ep0name [] = "ep0"; +static const char *ep_name [] = { + ep0name, + "ep-a", "ep-b", "ep-c", "ep-d", + "ep-e", "ep-f", +}; + +static int use_dma = 1; + +/* "modprobe net2280 use_dma=n" etc */ +module_param (use_dma, bool, S_IRUGO|S_IWUSR); + +#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") + +#if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG) +static char *type_string (u8 bmAttributes) +{ + switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: return "bulk"; + case USB_ENDPOINT_XFER_ISOC: return "iso"; + case USB_ENDPOINT_XFER_INT: return "intr"; + }; + return "control"; +} +#endif + +#include "net2280.h" + +#define valid_bit __constant_cpu_to_le32 (1 << VALID_BIT) +#define dma_done_ie __constant_cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE) + +/*-------------------------------------------------------------------------*/ + +static int +net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct net2280 *dev; + struct net2280_ep *ep; + u32 max, tmp; + unsigned long flags; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + /* erratum 0119 workaround ties up an endpoint number */ + if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) + return -EDOM; + + /* sanity check ep-e/ep-f since their fifos are small */ + max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff; + if (ep->num > 4 && max > 64) + return -ERANGE; + + spin_lock_irqsave (&dev->lock, flags); + _ep->maxpacket = max & 0x7ff; + ep->desc = desc; + + /* ep_reset() has already been called */ + ep->stopped = 0; + + /* set speed-dependent max packet; may kick in high bandwidth */ + set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max); + + /* FIFO lines can't go to different packets. PIO is ok, so + * use it instead of troublesome (non-bulk) multi-packet DMA. + */ + if (ep->is_in && ep->dma && (max % 4) != 0) { + DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n", + ep->ep.name, ep->ep.maxpacket); + ep->dma = 0; + } + + /* set type, direction, address; reset fifo counters */ + writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); + tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + if (tmp == USB_ENDPOINT_XFER_INT) { + /* not just because of erratum 0105; avoid ever + * kicking in the "toggle-irrelevant" mode. + */ + tmp = USB_ENDPOINT_XFER_BULK; + } + ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; + tmp <<= ENDPOINT_TYPE; + tmp |= desc->bEndpointAddress; + tmp |= (4 << ENDPOINT_BYTE_COUNT); /* default full fifo lines */ + tmp |= 1 << ENDPOINT_ENABLE; + wmb (); + + /* for OUT transfers, block the rx fifo until a read is posted */ + ep->is_in = (tmp & USB_DIR_IN) != 0; + if (!ep->is_in) + writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + + writel (tmp, &ep->regs->ep_cfg); + +#ifdef NET2280_DMA_OUT_WORKAROUND + if (!ep->is_in) + ep->dma = 0; +#endif + + /* enable irqs */ + if (!ep->dma) { /* pio, per-packet */ + tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); + writel (tmp, &dev->regs->pciirqenb0); + + tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) + | readl (&ep->regs->ep_irqenb); + writel (tmp, &ep->regs->ep_irqenb); + } else { /* dma, per-request */ + tmp = (1 << (8 + ep->num)); /* completion */ + tmp |= readl (&dev->regs->pciirqenb1); + writel (tmp, &dev->regs->pciirqenb1); + + /* for short OUT transfers, dma completions can't + * advance the queue; do it pio-style, by hand. + * NOTE erratum 0112 workaround #2 + */ + if ((desc->bEndpointAddress & USB_DIR_IN) == 0) { + tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); + writel (tmp, &ep->regs->ep_irqenb); + + tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); + writel (tmp, &dev->regs->pciirqenb0); + } + } + + tmp = desc->bEndpointAddress; + DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n", + _ep->name, tmp & 0x0f, DIR_STRING (tmp), + type_string (desc->bmAttributes), + ep->dma ? "dma" : "pio", max); + + /* pci writes may still be posted */ + spin_unlock_irqrestore (&dev->lock, flags); + return 0; +} + +static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = readl (ptr); + if (result == ~(u32)0) /* "device unplugged" */ + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay (1); + usec--; + } while (usec > 0); +#ifdef DEBUG + if (done == 0) dump_stack (); /* ignore out_flush timeout */ +#endif + return -ETIMEDOUT; +} + +static struct usb_ep_ops net2280_ep_ops; + +static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep) +{ + u32 tmp; + + ep->desc = 0; + INIT_LIST_HEAD (&ep->queue); + + ep->ep.maxpacket = ~0; + ep->ep.ops = &net2280_ep_ops; + + /* disable the dma, irqs, endpoint... */ + if (ep->dma) { + writel (0, &ep->dma->dmactl); + writel ( (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) + | (1 << DMA_TRANSACTION_DONE_INTERRUPT) + | (1 << DMA_ABORT) + , &ep->dma->dmastat); + + tmp = readl (®s->pciirqenb0); + tmp &= ~(1 << ep->num); + writel (tmp, ®s->pciirqenb0); + } else { + tmp = readl (®s->pciirqenb1); + tmp &= ~(1 << (8 + ep->num)); /* completion */ + writel (tmp, ®s->pciirqenb1); + } + writel (0, &ep->regs->ep_irqenb); + + /* init to our chosen defaults, notably so that we NAK OUT + * packets until the driver queues a read (+note erratum 0112) + */ + writel ( (1 << SET_NAK_OUT_PACKETS_MODE) + | (1 << SET_NAK_OUT_PACKETS) + | (1 << CLEAR_EP_HIDE_STATUS_PHASE) + | (1 << CLEAR_INTERRUPT_MODE) + | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + | (1 << CLEAR_ENDPOINT_TOGGLE) + | (1 << CLEAR_ENDPOINT_HALT) + , &ep->regs->ep_rsp); + + /* scrub most status bits, and flush any fifo state */ + writel ( (1 << TIMEOUT) + | (1 << USB_STALL_SENT) + | (1 << USB_IN_NAK_SENT) + | (1 << USB_IN_ACK_RCVD) + | (1 << USB_OUT_PING_NAK_SENT) + | (1 << USB_OUT_ACK_SENT) + | (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW) + | (1 << FIFO_FLUSH) + | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) + | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) + | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + | (1 << DATA_IN_TOKEN_INTERRUPT) + , &ep->regs->ep_stat); + + /* fifo size is handled separately */ +} + +static void nuke (struct net2280_ep *); + +static int net2280_disable (struct usb_ep *_ep) +{ + struct net2280_ep *ep; + unsigned long flags; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || !ep->desc || _ep->name == ep0name) + return -EINVAL; + + spin_lock_irqsave (&ep->dev->lock, flags); + nuke (ep); + ep_reset (ep->dev->regs, ep); + + VDEBUG (ep->dev, "disabled %s %s\n", + ep->dma ? "dma" : "pio", _ep->name); + + /* synch memory views with the device */ + (void) readl (&ep->regs->ep_cfg); + + if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4) + ep->dma = &ep->dev->dma [ep->num - 1]; + + spin_unlock_irqrestore (&ep->dev->lock, flags); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +net2280_alloc_request (struct usb_ep *_ep, int gfp_flags) +{ + struct net2280_ep *ep; + struct net2280_request *req; + + if (!_ep) + return 0; + ep = container_of (_ep, struct net2280_ep, ep); + + req = kmalloc (sizeof *req, gfp_flags); + if (!req) + return 0; + + memset (req, 0, sizeof *req); + req->req.dma = DMA_ADDR_INVALID; + INIT_LIST_HEAD (&req->queue); + + /* this dma descriptor may be swapped with the previous dummy */ + if (ep->dma) { + struct net2280_dma *td; + + td = pci_pool_alloc (ep->dev->requests, gfp_flags, + &req->td_dma); + if (!td) { + kfree (req); + return 0; + } + td->dmacount = 0; /* not VALID */ + td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID); + req->td = td; + } + return &req->req; +} + +static void +net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) +{ + struct net2280_ep *ep; + struct net2280_request *req; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!ep || !_req || (!ep->desc && ep->num != 0)) + return; + + req = container_of (_req, struct net2280_request, req); + WARN_ON (!list_empty (&req->queue)); + if (req->td) + pci_pool_free (ep->dev->requests, req->td, req->td_dma); + kfree (req); +} + +/*-------------------------------------------------------------------------*/ + +#undef USE_KMALLOC + +/* many common platforms have dma-coherent caches, which means that it's + * safe to use kmalloc() memory for all i/o buffers without using any + * cache flushing calls. (unless you're trying to share cache lines + * between dma and non-dma activities, which is a slow idea in any case.) + * + * other platforms need more care, with 2.5 having a moderately general + * solution (which falls down for allocations smaller than one page) + * that improves significantly on the 2.4 PCI allocators by removing + * the restriction that memory never be freed in_interrupt(). + */ +#if defined(CONFIG_X86) +#define USE_KMALLOC + +#elif define(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) +#define USE_KMALLOC + +/* FIXME there are other cases, including an x86-64 one ... */ +#endif + +/* allocating buffers this way eliminates dma mapping overhead, which + * on some platforms will mean eliminating a per-io buffer copy. with + * some kinds of system caches, further tweaks may still be needed. + */ +static void * +net2280_alloc_buffer ( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + int gfp_flags +) +{ + void *retval; + struct net2280_ep *ep; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!ep || (!ep->desc && ep->num != 0)) + return 0; + + *dma = DMA_ADDR_INVALID; + if (ep->dma) { +#if defined(USE_KMALLOC) + retval = kmalloc (bytes, gfp_flags); + if (retval) + *dma = virt_to_phys (retval); + +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,5,58) +#warning Using dma_alloc_consistent even with sub-page allocations + /* the main problem with this call is that it wastes memory + * on typical 1/N page allocations: it allocates 1-N pages. + */ + retval = dma_alloc_coherent (&ep->dev->pdev->dev, + bytes, dma, gfp_flags); +#else +#error No dma-coherent memory allocator is available + /* pci_alloc_consistent works, but pci_free_consistent() + * isn't safe in_interrupt(). plus, in addition to the + * 1/Nth page weakness, it doesn't understand gfp_flags. + */ +#endif + } else + retval = kmalloc (bytes, gfp_flags); + + return retval; +} + +static void +net2280_free_buffer ( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) { + /* free memory into the right allocator */ +#ifndef USE_KMALLOC + if (dma != DMA_ADDR_INVALID) + dma_free_coherent (ep->dev->pdev, bytes, dma); + else +#endif + kfree (buf); +} + +/*-------------------------------------------------------------------------*/ + +/* load a packet into the fifo we use for usb IN transfers. + * works for all endpoints. + * + * NOTE: pio with ep-a..ep-d could stuff multiple packets into the fifo + * at a time, but this code is simpler because it knows it only writes + * one packet. ep-a..ep-d should use dma instead. + */ +static void +write_fifo (struct net2280_ep *ep, struct usb_request *req) +{ + struct net2280_ep_regs *regs = ep->regs; + u8 *buf; + unsigned count, total; + + /* INVARIANT: fifo is currently empty. (testable) */ + + if (req) { + total = req->length - req->actual; + buf = req->buf + req->actual; + } else { + total = 0; + buf = 0; + } + + /* write just one packet at a time */ + count = min (ep->ep.maxpacket, total); + VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", + ep->ep.name, count, + (count != ep->ep.maxpacket) ? " (short)" : "", + req); + while (count >= 4) { + /* NOTE be careful if you try to align these. fifo lines + * should normally be full (4 bytes) and successive partial + * lines are ok only in certain cases. + */ + writel (get_unaligned ((u32 *)buf), ®s->ep_data); + buf += 4; + count -= 4; + } + + /* last fifo entry is "short" unless we wrote a full packet */ + if (total < ep->ep.maxpacket) { + u32 tmp = count ? get_unaligned ((u32 *)buf) : count; + set_fifo_bytecount (ep, count & 0x03); + writel (tmp, ®s->ep_data); + } + + /* pci writes may still be posted */ +} + +/* work around erratum 0106: PCI and USB race over the OUT fifo. + * caller guarantees chiprev 0100, out endpoint is NAKing, and + * there's no real data in the fifo. + */ +static void out_flush (struct net2280_ep *ep) +{ + u32 *statp, tmp; + + ASSERT_OUT_NAKING (ep); + + statp = &ep->regs->ep_stat; + writel ( (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + , statp); + writel ((1 << FIFO_FLUSH), statp); + mb (); + tmp = readl (statp); + if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) { + unsigned usec; + + if (ep->dev->gadget.speed == USB_SPEED_HIGH) { + if (ep->ep.maxpacket <= 512) + usec = 10; /* 512 byte bulk */ + else + usec = 21; /* 1024 byte interrupt */ + } else + usec = 50; /* 64 byte bulk/interrupt */ + handshake (statp, (1 << USB_OUT_PING_NAK_SENT), + (1 << USB_OUT_PING_NAK_SENT), usec); + /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */ + } +} + +/* unload packet(s) from the fifo we use for usb OUT transfers. + * returns true iff the request completed, because of short packet + * or the request buffer having filled with full packets. + * + * for ep-a..ep-d this will read multiple packets out when they + * have been accepted. + */ +static int +read_fifo (struct net2280_ep *ep, struct net2280_request *req) +{ + struct net2280_ep_regs *regs = ep->regs; + u8 *buf = req->req.buf + req->req.actual; + unsigned count, tmp, is_short; + unsigned cleanup = 0, prevent = 0; + + /* erratum 0106 ... packets coming in during fifo reads might + * be incompletely rejected. not all cases have workarounds. + */ + if (ep->dev->chiprev == 0x0100) { + tmp = readl (&ep->regs->ep_stat); + if ((tmp & (1 << NAK_OUT_PACKETS))) + /* cleanup = 1 */; + else if ((tmp & (1 << FIFO_FULL)) + /* don't break hs PING protocol ... */ + || ep->dev->gadget.speed == USB_SPEED_FULL) { + start_out_naking (ep); + prevent = 1; + } + /* else: hope we don't see the problem */ + } + + /* never overflow the rx buffer. the fifo reads packets until + * it sees a short one; we might not be ready for them all. + */ + count = readl (®s->ep_avail); + tmp = req->req.length - req->req.actual; + if (count > tmp) { + unsigned over = tmp % ep->ep.maxpacket; + + /* FIXME handle this consistently between PIO and DMA */ + if (over) { + ERROR (ep->dev, + "%s out fifo %d bytes, over %d extra %d\n", + ep->ep.name, count, over, count - tmp); + req->req.status = -EOVERFLOW; + tmp -= over; + } + count = tmp; + } + req->req.actual += count; + + is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0); + + VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", + ep->ep.name, count, is_short ? " (short)" : "", + cleanup ? " flush" : "", prevent ? " nak" : "", + req, req->req.actual, req->req.length); + + while (count >= 4) { + put_unaligned (readl (®s->ep_data), (u32 *)buf); + buf += 4; + count -= 4; + } + if (count) { + tmp = readl (®s->ep_data); + do { + *buf++ = (u8) tmp; + tmp >>= 8; + } while (--count); + } + if (cleanup) + out_flush (ep); + if (prevent) { + writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + (void) readl (&ep->regs->ep_rsp); + } + + return is_short || ((req->req.actual == req->req.length) + && !req->req.zero); +} + +/* fill out dma descriptor to match a given request */ +static inline void +fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) +{ + struct net2280_dma *td = req->td; + u32 dmacount = req->req.length; + + /* don't let DMA continue after a short OUT packet, + * so overruns can't affect the next transfer. + */ + if (ep->is_in) + dmacount |= (1 << DMA_DIRECTION); + else if ((dmacount % ep->ep.maxpacket) != 0) + dmacount |= (1 << END_OF_CHAIN); + + req->valid = valid; + if (valid) + dmacount |= (1 << VALID_BIT); +#ifdef USE_DMA_CHAINING + if (!req->req.no_interrupt) +#endif + dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE); + + /* td->dmadesc = previously set by caller */ + td->dmaaddr = cpu_to_le32p (&req->req.dma); + + /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */ + wmb (); + td->dmacount = cpu_to_le32p (&dmacount); +} + +static const u32 dmactl_default = + (1 << DMA_CLEAR_COUNT_ENABLE) + /* erratum 0116 workaround part 1 (use POLLING) */ + | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) + | (1 << DMA_VALID_BIT_POLLING_ENABLE) + | (1 << DMA_VALID_BIT_ENABLE) + | (1 << DMA_SCATTER_GATHER_ENABLE) + /* erratum 0116 workaround part 2 (no AUTOSTART) */ + | (1 << DMA_ENABLE); + +static inline void spin_stop_dma (struct net2280_dma_regs *dma) +{ + handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50); +} + +static inline void stop_dma (struct net2280_dma_regs *dma) +{ + writel (dmactl_default & ~(1 << DMA_ENABLE), &dma->dmactl); + spin_stop_dma (dma); +} + +static void start_dma (struct net2280_ep *ep, struct net2280_request *req) +{ + u32 tmp; + int clear_nak = 0; + struct net2280_dma_regs *dma = ep->dma; + + /* FIXME can't use DMA for ZLPs */ + + /* previous OUT packet might have been short */ + if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) + & (1 << NAK_OUT_PACKETS)) != 0) { + writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT), + &ep->regs->ep_stat); + + tmp = readl (&ep->regs->ep_avail); + if (tmp == 0) + clear_nak = 1; + else { + /* transfer all/some fifo data */ + writel (req->req.dma, &dma->dmaaddr); + tmp = min (tmp, req->req.length); + + /* dma irq, faking scatterlist status */ + req->td->dmacount = cpu_to_le32 (req->req.length - tmp); + writel ((1 << DMA_DONE_INTERRUPT_ENABLE) + | tmp, &dma->dmacount); + + writel ((1 << DMA_ENABLE), &dma->dmactl); + writel ((1 << DMA_START), &dma->dmastat); + return; + } + } + + /* on this path we know there's no dma queue (yet) */ + WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE)); + tmp = dmactl_default; + + /* force packet boundaries between dma requests, but prevent the + * controller from automagically writing a last "short" packet + * (zero length) unless the driver explicitly said to do that. + */ + if (ep->is_in) { + if (likely ((req->req.length % ep->ep.maxpacket) != 0 + || req->req.zero)) { + tmp |= (1 << DMA_FIFO_VALIDATE); + ep->in_fifo_validate = 1; + } else + ep->in_fifo_validate = 0; + } + + /* init req->td, pointing to the current dummy */ + req->td->dmadesc = cpu_to_le32 (ep->td_dma); + fill_dma_desc (ep, req, 1); + +#ifdef USE_DMA_CHAINING + writel ( (1 << VALID_BIT) + | (ep->is_in << DMA_DIRECTION) + | 0, &dma->dmacount); +#else + req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN); +#endif + + writel (req->td_dma, &dma->dmadesc); + writel (tmp, &dma->dmactl); + + /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ + (void) readl (&ep->dev->pci->pcimstctl); + + writel ((1 << DMA_START), &dma->dmastat); + + /* recover from previous short read; erratum 0112 workaround #1 */ + if (clear_nak) + writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); +} + +static inline void +queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid) +{ + struct net2280_dma *end; + dma_addr_t tmp; + + /* swap new dummy for old, link; fill and maybe activate */ + end = ep->dummy; + ep->dummy = req->td; + req->td = end; + + tmp = ep->td_dma; + ep->td_dma = req->td_dma; + req->td_dma = tmp; + + end->dmadesc = cpu_to_le32 (ep->td_dma); + + fill_dma_desc (ep, req, valid); +} + +static void +done (struct net2280_ep *ep, struct net2280_request *req, int status) +{ + struct net2280 *dev; + unsigned stopped = ep->stopped; + + list_del_init (&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + dev = ep->dev; + if (req->mapped) { + pci_unmap_single (dev->pdev, req->req.dma, req->req.length, + ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + req->req.dma = DMA_ADDR_INVALID; + req->mapped = 0; + } + + if (status && status != -ESHUTDOWN) + VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + spin_unlock (&dev->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dev->lock); + ep->stopped = stopped; +} + +/*-------------------------------------------------------------------------*/ + +static int +net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) +{ + struct net2280_request *req; + struct net2280_ep *ep; + struct net2280 *dev; + unsigned long flags; + + /* we always require a cpu-view buffer, so that we can + * always use pio (as fallback or whatever). + */ + req = container_of (_req, struct net2280_request, req); + if (!_req || !_req->complete || !_req->buf + || !list_empty (&req->queue)) + return -EINVAL; + if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) + return -EDOM; + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -EINVAL; + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + /* FIXME implement PIO fallback for ZLPs with DMA */ + if (ep->dma && _req->length == 0) + return -EOPNOTSUPP; + + /* set up dma mapping in case the caller didn't */ + if (ep->dma && _req->dma == DMA_ADDR_INVALID) { + _req->dma = pci_map_single (dev->pdev, _req->buf, _req->length, + ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + req->mapped = 1; + } + +#if 0 + VDEBUG (dev, "%s queue req %p, len %d buf %p\n", + _ep->name, _req, _req->length, _req->buf); +#endif + + spin_lock_irqsave (&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + req->dma_done = 0; + + /* kickstart this i/o queue? */ + if (list_empty (&ep->queue) && !ep->stopped) { + /* use DMA if the endpoint supports it, else pio */ + if (ep->dma) + start_dma (ep, req); + else { + /* maybe there's no control data, just status ack */ + if (ep->num == 0 && _req->length == 0) + goto done; + + /* PIO ... stuff the fifo, or unblock it. */ + if (ep->is_in) + write_fifo (ep, _req); + else if (list_empty (&ep->queue)) { + u32 s; + + /* OUT FIFO might have packet(s) buffered */ + s = readl (&ep->regs->ep_stat); + if ((s & (1 << FIFO_EMPTY)) == 0) { + /* note: _req->short_not_ok is + * ignored here since PIO _always_ + * stops queue advance here, and + * _req->status doesn't change for + * short reads (only _req->actual) + */ + if (read_fifo (ep, req)) { + done (ep, req, 0); + /* don't queue it */ + req = 0; + } else + s = readl (&ep->regs->ep_stat); + } + + /* don't NAK, let the fifo fill */ + if (req && (s & (1 << NAK_OUT_PACKETS))) + writel ((1 << CLEAR_NAK_OUT_PACKETS), + &ep->regs->ep_rsp); + } + } + + } else if (ep->dma) { + int valid = 1; + + if (ep->is_in) { + int expect; + + /* preventing magic zlps is per-engine state, not + * per-transfer; irq logic must recover hiccups. + */ + expect = likely (req->req.zero + || (req->req.length % ep->ep.maxpacket) != 0); + if (expect != ep->in_fifo_validate) + valid = 0; + } + queue_dma (ep, req, valid); + + } /* else the irq handler advances the queue. */ + + if (req) { +done: + list_add_tail (&req->queue, &ep->queue); + } + spin_unlock_irqrestore (&dev->lock, flags); + + /* pci writes may still be posted */ + return 0; +} + +static inline void +dma_done ( + struct net2280_ep *ep, + struct net2280_request *req, + u32 dmacount, + int status +) +{ + req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount); + rmb (); + done (ep, req, status); +} + +static void scan_dma_completions (struct net2280_ep *ep) +{ + /* only look at descriptors that were "naturally" retired, + * so fifo and list head state won't matter + */ + while (!list_empty (&ep->queue)) { + struct net2280_request *req; + u32 tmp; + + req = list_entry (ep->queue.next, + struct net2280_request, queue); + if (!req->valid) + break; + rmb (); + tmp = le32_to_cpup (&req->td->dmacount); + if ((tmp & (1 << VALID_BIT)) != 0) + break; + + /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short" + * packets, including overruns, even when the transfer was + * exactly the length requested (dmacount now zero). + */ + if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { + req->dma_done = 1; + break; + } + dma_done (ep, req, tmp, 0); + } +} + +static void restart_dma (struct net2280_ep *ep) +{ + struct net2280_request *req; + + if (ep->stopped) + return; + req = list_entry (ep->queue.next, struct net2280_request, queue); + +#ifdef USE_DMA_CHAINING + /* the 2280 will be processing the queue unless queue hiccups after + * the previous transfer: + * IN: wanted automagic zlp, head doesn't (or vice versa) + * OUT: was "usb-short", we must restart. + */ + if (!req->valid) { + struct net2280_request *entry, *prev = 0; + int qmode, reqmode, done = 0; + + DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); + qmode = likely (req->req.zero + || (req->req.length % ep->ep.maxpacket) != 0); + list_for_each_entry (entry, &ep->queue, queue) { + u32 dmacount; + + if (entry != req) + continue; + dmacount = entry->td->dmacount; + if (!done) { + reqmode = likely (entry->req.zero + || (entry->req.length + % ep->ep.maxpacket) != 0); + if (reqmode == qmode) { + entry->valid = 1; + dmacount |= valid_bit; + entry->td->dmacount = dmacount; + prev = entry; + continue; + } else { + prev->td->dmacount |= dma_done_ie; + done = 1; + } + } + + /* walk the rest of the queue so unlinks behave */ + entry->valid = 0; + dmacount &= ~valid_bit; + entry->td->dmacount = dmacount; + prev = entry; + } + start_dma (ep, req); + } else if (!ep->is_in + && (readl (&ep->regs->ep_stat) + & (1 << NAK_OUT_PACKETS)) != 0) + start_dma (ep, req); +#else + start_dma (ep, req); +#endif +} + +static inline void abort_dma (struct net2280_ep *ep) +{ + /* abort the current transfer */ + writel ((1 << DMA_ABORT), &ep->dma->dmastat); + + /* collect completed transfers (except the current one) */ + scan_dma_completions (ep); +} + +/* dequeue ALL requests */ +static void nuke (struct net2280_ep *ep) +{ + struct net2280_request *req; + + /* called with spinlock held */ + ep->stopped = 1; + if (ep->dma) + abort_dma (ep); + while (!list_empty (&ep->queue)) { + req = list_entry (ep->queue.next, + struct net2280_request, + queue); + done (ep, req, -ESHUTDOWN); + } +} + +/* dequeue JUST ONE request */ +static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) +{ + struct net2280_ep *ep; + struct net2280_request *req; + unsigned long flags; + u32 dmactl; + int stopped; + + ep = container_of (_ep, struct net2280_ep, ep); + req = container_of (_req, struct net2280_request, req); + if (!_ep || (!ep->desc && ep->num != 0) || !_req) + return -EINVAL; + + spin_lock_irqsave (&ep->dev->lock, flags); + stopped = ep->stopped; + + /* pause dma while we scan the queue */ + dmactl = 0; + ep->stopped = 1; + if (ep->dma) { + dmactl = readl (&ep->dma->dmactl); + writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl); + /* force synch, clean any completed requests */ + spin_stop_dma (ep->dma); + scan_dma_completions (ep); + } + + /* queue head may be partially complete. */ + if (ep->queue.next == &req->queue) { + if (ep->dma) { + DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name); + _req->status = -ECONNRESET; + abort_dma (ep); + if (likely (ep->queue.next == &req->queue)) + dma_done (ep, req, + le32_to_cpup (&req->td->dmacount), + -ECONNRESET); + } else { + DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name); + done (ep, req, -ECONNRESET); + } + req = 0; + +#ifdef USE_DMA_CHAINING + /* patch up hardware chaining data */ + } else if (ep->dma) { + if (req->queue.prev == ep->queue.next) { + writel (le32_to_cpu (req->td->dmadesc), + &ep->dma->dmadesc); + if (req->td->dmacount & dma_done_ie) + writel (readl (&ep->dma->dmacount) + | dma_done_ie, + &ep->dma->dmacount); + } else { + struct net2280_request *prev; + + prev = list_entry (req->queue.prev, + struct net2280_request, queue); + prev->td->dmadesc = req->td->dmadesc; + if (req->td->dmacount & dma_done_ie) + prev->td->dmacount |= dma_done_ie; + } +#endif + } + + if (req) + done (ep, req, -ECONNRESET); + ep->stopped = stopped; + + if (ep->dma) { + /* turn off dma on inactive queues */ + if (list_empty (&ep->queue)) + stop_dma (ep->dma); + else if (!ep->stopped) { + /* resume current request, or start new one */ + if (req) + writel (dmactl, &ep->dma->dmactl); + else + start_dma (ep, list_entry (ep->queue.next, + struct net2280_request, queue)); + } + } + + spin_unlock_irqrestore (&ep->dev->lock, flags); + return req ? 0 : -EOPNOTSUPP; +} + +/*-------------------------------------------------------------------------*/ + +static int +net2280_set_halt (struct usb_ep *_ep, int value) +{ + struct net2280_ep *ep; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -EINVAL; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + if ((ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC) + return -EINVAL; + + VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear"); + + /* set/clear, then synch memory views with the device */ + if (value) + set_halt (ep); + else + clear_halt (ep); + (void) readl (&ep->regs->ep_rsp); + + return 0; +} + +static int +net2280_fifo_status (struct usb_ep *_ep) +{ + struct net2280_ep *ep; + u32 avail; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return -EINVAL; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + avail = readl (&ep->regs->ep_avail); + if (ep->is_in) + avail = ep->fifo_size - avail; + return avail; +} + +static void +net2280_fifo_flush (struct usb_ep *_ep) +{ + struct net2280_ep *ep; + + ep = container_of (_ep, struct net2280_ep, ep); + if (!_ep || (!ep->desc && ep->num != 0)) + return; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return; + + writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); + (void) readl (&ep->regs->ep_rsp); +} + +static struct usb_ep_ops net2280_ep_ops = { + .enable = net2280_enable, + .disable = net2280_disable, + + .alloc_request = net2280_alloc_request, + .free_request = net2280_free_request, + + .alloc_buffer = net2280_alloc_buffer, + .free_buffer = net2280_free_buffer, + + .queue = net2280_queue, + .dequeue = net2280_dequeue, + + .set_halt = net2280_set_halt, + .fifo_status = net2280_fifo_status, + .fifo_flush = net2280_fifo_flush, +}; + +/*-------------------------------------------------------------------------*/ + +static int net2280_get_frame (struct usb_gadget *_gadget) +{ + struct net2280 *dev; + unsigned long flags; + u16 retval; + + if (!_gadget) + return -ENODEV; + dev = container_of (_gadget, struct net2280, gadget); + spin_lock_irqsave (&dev->lock, flags); + retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff; + spin_unlock_irqrestore (&dev->lock, flags); + return retval; +} + +static int net2280_wakeup (struct usb_gadget *_gadget) +{ + struct net2280 *dev; + + if (!_gadget) + return 0; + dev = container_of (_gadget, struct net2280, gadget); + writel (1 << GENERATE_RESUME, dev->usb->usbstat); + + /* pci writes may still be posted */ + return 0; +} + +static const struct usb_gadget_ops net2280_ops = { + .get_frame = net2280_get_frame, + .wakeup = net2280_wakeup, + + // .set_selfpowered = net2280_set_selfpowered, +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef USE_SYSFS_DEBUG_FILES + +/* "function" sysfs attribute */ +static ssize_t +show_function (struct device *_dev, char *buf) +{ + struct net2280 *dev = dev_get_drvdata (_dev); + + if (!dev->driver + || !dev->driver->function + || strlen (dev->driver->function) > PAGE_SIZE) + return 0; + return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function); +} +static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); + +static ssize_t +show_registers (struct device *_dev, char *buf) +{ + struct net2280 *dev; + char *next; + unsigned size, t; + unsigned long flags; + int i; + u32 t1, t2; + char *s; + + dev = dev_get_drvdata (_dev); + next = buf; + size = PAGE_SIZE; + spin_lock_irqsave (&dev->lock, flags); + + if (dev->driver) + s = dev->driver->driver.name; + else + s = "(none)"; + + /* Main Control Registers */ + t = snprintf (next, size, "%s " DRIVER_VERSION "\n" + "devinit %03x fifoctl %08x gadget '%s'\n" + "pci irqenb0 %02x irqenb1 %08x " + "irqstat0 %04x irqstat1 %08x\n", + driver_name, + readl (&dev->regs->devinit), + readl (&dev->regs->fifoctl), + s, + readl (&dev->regs->pciirqenb0), + readl (&dev->regs->pciirqenb1), + readl (&dev->regs->irqstat0), + readl (&dev->regs->irqstat1)); + size -= t; + next += t; + + /* USB Control Registers */ + t1 = readl (&dev->usb->usbctl); + t2 = readl (&dev->usb->usbstat); + if (t1 & (1 << VBUS_PIN)) { + if (t2 & (1 << HIGH_SPEED)) + s = "high speed"; + else if (dev->gadget.speed == USB_SPEED_UNKNOWN) + s = "powered"; + else + s = "full speed"; + /* full speed bit (6) not working?? */ + } else + s = "not attached"; + t = snprintf (next, size, + "stdrsp %08x usbctl %08x usbstat %08x " + "addr 0x%02x (%s)\n", + readl (&dev->usb->stdrsp), t1, t2, + readl (&dev->usb->ouraddr), s); + size -= t; + next += t; + + /* PCI Master Control Registers */ + + /* DMA Control Registers */ + + /* Configurable EP Control Registers */ + for (i = 0; i < 7; i++) { + struct net2280_ep *ep; + + ep = &dev->ep [i]; + if (i && !ep->desc) + continue; + + t1 = readl (&ep->regs->ep_cfg); + t = snprintf (next, size, + "%s\tcfg %05x rsp %02x enb %02x ", + ep->ep.name, t1, + readl (&ep->regs->ep_rsp) & 0xff, + readl (&ep->regs->ep_irqenb)); + size -= t; + next += t; + + t = snprintf (next, size, + "stat %08x avail %04x " + "(ep%d%s-%s)%s\n", + readl (&ep->regs->ep_stat), + readl (&ep->regs->ep_avail), + t1 & 0x0f, DIR_STRING (t1), + type_string (t1 >> 8), + ep->stopped ? "*" : ""); + size -= t; + next += t; + + if (!ep->dma) + continue; + + t = snprintf (next, size, + " dma\tctl %08x stat %08x count %08x\n" + "\taddr %08x desc %08x\n", + readl (&ep->dma->dmactl), + readl (&ep->dma->dmastat), + readl (&ep->dma->dmacount), + readl (&ep->dma->dmaaddr), + readl (&ep->dma->dmadesc)); + size -= t; + next += t; + + } + + /* Indexed Registers */ + // none yet + + /* Statistics */ + t = snprintf (next, size, "irqs: "); + size -= t; + next += t; + for (i = 0; i < 7; i++) { + struct net2280_ep *ep; + + ep = &dev->ep [i]; + if (i && !ep->irqs) + continue; + t = snprintf (next, size, " %s/%ld", ep->ep.name, ep->irqs); + size -= t; + next += t; + + } + t = snprintf (next, size, "\n"); + size -= t; + next += t; + + spin_unlock_irqrestore (&dev->lock, flags); + + return PAGE_SIZE - size; +} +static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL); + +static ssize_t +show_queues (struct device *_dev, char *buf) +{ + struct net2280 *dev; + char *next; + unsigned size; + unsigned long flags; + int i; + + dev = dev_get_drvdata (_dev); + next = buf; + size = PAGE_SIZE; + spin_lock_irqsave (&dev->lock, flags); + + for (i = 0; i < 7; i++) { + struct net2280_ep *ep = &dev->ep [i]; + struct net2280_request *req; + int t; + + if (i != 0) { + const struct usb_endpoint_descriptor *d; + + d = ep->desc; + if (!d) + continue; + t = d->bEndpointAddress; + t = snprintf (next, size, + "%s (ep%d%s-%s) max %04x %s\n", + ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, + (t & USB_DIR_IN) ? "in" : "out", + ({ char *val; + switch (d->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: + val = "bulk"; break; + case USB_ENDPOINT_XFER_INT: + val = "intr"; break; + default: + val = "iso"; break; + }; val; }), + le16_to_cpu (d->wMaxPacketSize) & 0x1fff, + ep->dma ? "dma" : "pio" + ); + } else /* ep0 should only have one transfer queued */ + t = snprintf (next, size, "ep0 max 64 pio %s\n", + ep->is_in ? "in" : "out"); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + + if (list_empty (&ep->queue)) { + t = snprintf (next, size, "\t(nothing queued)\n"); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + continue; + } + list_for_each_entry (req, &ep->queue, queue) { + if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc)) + t = snprintf (next, size, + "\treq %p len %d/%d " + "buf %p (dmacount %08x)\n", + &req->req, req->req.actual, + req->req.length, req->req.buf, + readl (&ep->dma->dmacount)); + else + t = snprintf (next, size, + "\treq %p len %d/%d buf %p\n", + &req->req, req->req.actual, + req->req.length, req->req.buf); + if (t <= 0 || t > size) + goto done; + size -= t; + next += t; + } + } + +done: + spin_unlock_irqrestore (&dev->lock, flags); + return PAGE_SIZE - size; +} +static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL); + + +#else + +#define device_create_file(a,b) do {} while (0) +#define device_remove_file device_create_file + +#endif + +/*-------------------------------------------------------------------------*/ + +/* another driver-specific mode might be a request type doing dma + * to/from another device fifo instead of to/from memory. + */ + +static void set_fifo_mode (struct net2280 *dev, int mode) +{ + /* keeping high bits preserves BAR2 */ + writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl); + + /* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */ + INIT_LIST_HEAD (&dev->gadget.ep_list); + list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list); + list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list); + switch (mode) { + case 0: + list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); + list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list); + dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024; + break; + case 1: + dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048; + break; + case 2: + list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); + dev->ep [1].fifo_size = 2048; + dev->ep [2].fifo_size = 1024; + break; + } + /* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */ + list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list); + list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); +} + +/** + * net2280_set_fifo_mode - change allocation of fifo buffers + * @gadget: access to the net2280 device that will be updated + * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); + * 1 for two 2kB buffers (ep-a and ep-b only); + * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). + * + * returns zero on success, else negative errno. when this succeeds, + * the contents of gadget->ep_list may have changed. + * + * you may only call this function when endpoints a-d are all disabled. + * use it whenever extra hardware buffering can help performance, such + * as before enabling "high bandwidth" interrupt endpoints that use + * maxpacket bigger than 512 (when double buffering would otherwise + * be unavailable). + */ +int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) +{ + int i; + struct net2280 *dev; + int status = 0; + unsigned long flags; + + if (!gadget) + return -ENODEV; + dev = container_of (gadget, struct net2280, gadget); + + spin_lock_irqsave (&dev->lock, flags); + + for (i = 1; i <= 4; i++) + if (dev->ep [i].desc) { + status = -EINVAL; + break; + } + if (mode < 0 || mode > 2) + status = -EINVAL; + if (status == 0) + set_fifo_mode (dev, mode); + spin_unlock_irqrestore (&dev->lock, flags); + + if (status == 0) { + if (mode == 1) + DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n"); + else if (mode == 2) + DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n"); + /* else all are 1K */ + } + return status; +} +EXPORT_SYMBOL (net2280_set_fifo_mode); + +/*-------------------------------------------------------------------------*/ + +/* keeping it simple: + * - one bus driver, initted first; + * - one function driver, initted second + * + * most of the work to support multiple net2280 controllers would + * be to associate this gadget driver (yes?) with all of them, or + * perhaps to bind specific drivers to specific devices. + */ + +static struct net2280 *the_controller; + +static void usb_reset (struct net2280 *dev) +{ + u32 tmp; + + /* force immediate bus disconnect, and synch through pci */ + writel (0, &dev->usb->usbctl); + dev->gadget.speed = USB_SPEED_UNKNOWN; + (void) readl (&dev->usb->usbctl); + + net2280_led_init (dev); + + /* disable automatic responses, and irqs */ + writel (0, &dev->usb->stdrsp); + writel (0, &dev->regs->pciirqenb0); + writel (0, &dev->regs->pciirqenb1); + + /* clear old dma and irq state */ + for (tmp = 0; tmp < 4; tmp++) { + writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat); + stop_dma (&dev->dma [tmp]); + } + writel (~0, &dev->regs->irqstat0), + writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), + + /* reset, and enable pci */ + tmp = readl (&dev->regs->devinit) + | (1 << PCI_ENABLE) + | (1 << FIFO_SOFT_RESET) + | (1 << USB_SOFT_RESET) + | (1 << M8051_RESET); + writel (tmp, &dev->regs->devinit); + + /* standard fifo and endpoint allocations */ + set_fifo_mode (dev, 0); +} + +static void usb_reinit (struct net2280 *dev) +{ + u32 tmp; + int init_dma; + + /* use_dma changes are ignored till next device re-init */ + init_dma = use_dma; + + /* basic endpoint init */ + for (tmp = 0; tmp < 7; tmp++) { + struct net2280_ep *ep = &dev->ep [tmp]; + + ep->ep.name = ep_name [tmp]; + ep->dev = dev; + ep->num = tmp; + + if (tmp > 0 && tmp <= 4) { + ep->fifo_size = 1024; + if (init_dma) + ep->dma = &dev->dma [tmp - 1]; + } else + ep->fifo_size = 64; + ep->regs = &dev->epregs [tmp]; + ep_reset (dev->regs, ep); + } + dev->ep [0].ep.maxpacket = 64; + dev->ep [5].ep.maxpacket = 64; + dev->ep [6].ep.maxpacket = 64; + + dev->gadget.ep0 = &dev->ep [0].ep; + dev->ep [0].stopped = 0; + INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); + + /* we want to prevent lowlevel/insecure access from the USB host, + * but erratum 0119 means this enable bit is ignored + */ + for (tmp = 0; tmp < 5; tmp++) + writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg); +} + +static void ep0_start (struct net2280 *dev) +{ + writel ( (1 << SET_EP_HIDE_STATUS_PHASE) + | (1 << CLEAR_NAK_OUT_PACKETS) + | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + , &dev->epregs [0].ep_rsp); + + /* + * hardware optionally handles a bunch of standard requests + * that the API hides from drivers anyway. have it do so. + * endpoint status/features are handled in software, to + * help pass tests for some dubious behavior. + */ + writel ( (1 << SET_TEST_MODE) + | (1 << SET_ADDRESS) + | (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) + | (1 << GET_DEVICE_STATUS) + | (1 << GET_INTERFACE_STATUS) + , &dev->usb->stdrsp); + writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) + | (1 << SELF_POWERED_USB_DEVICE) + | (1 << REMOTE_WAKEUP_SUPPORT) + | (1 << USB_DETECT_ENABLE) + | (1 << DEVICE_REMOTE_WAKEUP_ENABLE) + , &dev->usb->usbctl); + + /* enable irqs so we can see ep0 and general operation */ + writel ( (1 << SETUP_PACKET_INTERRUPT_ENABLE) + | (1 << ENDPOINT_0_INTERRUPT_ENABLE) + , &dev->regs->pciirqenb0); + writel ( (1 << PCI_INTERRUPT_ENABLE) + | (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) + | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) + | (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE) + | (1 << VBUS_INTERRUPT_ENABLE) + | (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) + , &dev->regs->pciirqenb1); + + /* don't leave any writes posted */ + (void) readl (&dev->usb->usbctl); +} + +/* when a driver is successfully registered, it will receive + * control requests including set_configuration(), which enables + * non-control requests. then usb traffic follows until a + * disconnect is reported. then a host may connect again, or + * the driver might get unbound. + */ +int usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + struct net2280 *dev = the_controller; + int retval; + unsigned i; + + /* insist on high speed support from the driver, since + * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) + * "must not be used in normal operation" + */ + if (!driver + || driver->speed != USB_SPEED_HIGH + || !driver->bind + || !driver->unbind + || !driver->setup) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + for (i = 0; i < 7; i++) + dev->ep [i].irqs = 0; + + /* hook up the driver ... */ + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + retval = driver->bind (&dev->gadget); + if (retval) { + DEBUG (dev, "bind to driver %s --> %d\n", + driver->driver.name, retval); + dev->driver = 0; + dev->gadget.dev.driver = 0; + return retval; + } + + // FIXME + // driver_register (&driver->driver); + // device_register (&dev->gadget.dev); + + device_create_file (&dev->pdev->dev, &dev_attr_function); + device_create_file (&dev->pdev->dev, &dev_attr_queues); + + /* ... then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + */ + net2280_led_active (dev, 1); + ep0_start (dev); + + DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n", + driver->driver.name, + readl (&dev->usb->usbctl), + readl (&dev->usb->stdrsp)); + + /* pci writes may still be posted */ + return 0; +} +EXPORT_SYMBOL (usb_gadget_register_driver); + +static void +stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) +{ + int i; + + /* don't disconnect if it's not connected */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = 0; + + /* stop hardware; prevent new request submissions; + * and kill any outstanding requests. + */ + usb_reset (dev); + for (i = 0; i < 7; i++) + nuke (&dev->ep [i]); + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock (&dev->lock); + driver->disconnect (&dev->gadget); + spin_lock (&dev->lock); + } + + usb_reinit (dev); +} + +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + struct net2280 *dev = the_controller; + unsigned long flags; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + + spin_lock_irqsave (&dev->lock, flags); + stop_activity (dev, driver); + spin_unlock_irqrestore (&dev->lock, flags); + + driver->unbind (&dev->gadget); + dev->driver = 0; + + net2280_led_active (dev, 0); + device_remove_file (&dev->pdev->dev, &dev_attr_function); + device_remove_file (&dev->pdev->dev, &dev_attr_queues); + + // FIXME + // device_unregister() + // driver_unregister (&driver->driver); + + DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); + return 0; +} +EXPORT_SYMBOL (usb_gadget_unregister_driver); + + +/*-------------------------------------------------------------------------*/ + +/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq. + * also works for dma-capable endpoints, in pio mode or just + * to manually advance the queue after short OUT transfers. + */ +static void handle_ep_small (struct net2280_ep *ep) +{ + struct net2280_request *req; + u32 t; + /* 0 error, 1 mid-data, 2 done */ + int mode = 1; + + if (!list_empty (&ep->queue)) + req = list_entry (ep->queue.next, + struct net2280_request, queue); + else + req = 0; + + /* ack all, and handle what we care about */ + t = readl (&ep->regs->ep_stat); + ep->irqs++; +#if 0 + VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", + ep->ep.name, t, req ? &req->req : 0); +#endif + writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + + /* for ep0, monitor token irqs to catch data stage length errors + * and to synchronize on status. + * + * also, to defer reporting of protocol stalls ... here's where + * data or status first appears, handling stalls here should never + * cause trouble on the host side.. + * + * control requests could be slightly faster without token synch for + * status, but status can jam up that way. + */ + if (unlikely (ep->num == 0)) { + if (ep->is_in) { + /* status; stop NAKing */ + if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) { + if (ep->dev->protocol_stall) + set_halt (ep); + mode = 2; + /* reply to extra IN tokens with a zlp */ + } else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { + if (ep->dev->protocol_stall) { + set_halt (ep); + mode = 2; + } else if (!req) + write_fifo (ep, 0); + } + } else { + /* status; stop NAKing */ + if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { + if (ep->dev->protocol_stall) + set_halt (ep); + mode = 2; + /* an extra OUT token is an error */ + } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) + && req + && req->req.actual == req->req.length) + || !req) { + ep->dev->protocol_stall = 1; + set_halt (ep); + ep->stopped = 1; + if (req) + done (ep, req, -EOVERFLOW); + req = 0; + } + } + } + + if (unlikely (!req)) + return; + + /* manual DMA queue advance after short OUT */ + if (likely (ep->dma != 0)) { + if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { + u32 count; + + /* TRANSFERRED works around OUT_DONE erratum 0112. + * we expect (N <= maxpacket) bytes; host wrote M. + * iff (M < N) we won't ever see a DMA interrupt. + */ + count = readl (&ep->dma->dmacount); + count &= DMA_BYTE_COUNT_MASK; + if (!req->dma_done) { + /* dma can finish with the FIFO non-empty, + * on (M > N) errors. + */ + while (count && (t & (1 << FIFO_EMPTY)) == 0) { + cpu_relax (); + t = readl (&ep->regs->ep_stat); + count = readl (&ep->dma->dmacount); + count &= DMA_BYTE_COUNT_MASK; + } + } + + /* stop DMA, leave ep NAKing */ + writel ((1 << DMA_ABORT), &ep->dma->dmastat); + spin_stop_dma (ep->dma); + + /* buffer might have been too small */ + t = readl (&ep->regs->ep_avail); + if (t != 0) + DEBUG (ep->dev, "%s dma, discard %d len %d\n", + ep->ep.name, t, count); + dma_done (ep, req, count, t ? -EOVERFLOW : 0); + + /* also flush to prevent erratum 0106 trouble */ + if (t || ep->dev->chiprev == 0x0100) + out_flush (ep); + + /* restart dma (still NAKing OUT!) if needed */ + if (!list_empty (&ep->queue)) + restart_dma (ep); + } else + DEBUG (ep->dev, "%s dma ep_stat %08x ??\n", + ep->ep.name, t); + return; + + /* data packet(s) received (in the fifo, OUT) */ + } else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) { + if (read_fifo (ep, req) && ep->num != 0) + mode = 2; + + /* data packet(s) transmitted (IN) */ + } else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) { + unsigned len; + + len = req->req.length - req->req.actual; + len = min (ep->ep.maxpacket, len); + req->req.actual += len; + + /* if we wrote it all, we're usually done */ + if (req->req.actual == req->req.length) { + if (ep->num == 0) { + /* wait for control status */ + if (mode != 2) + req = 0; + } else if (!req->req.zero || len != ep->ep.maxpacket) + mode = 2; + } + + /* there was nothing to do ... */ + } else if (mode == 1) + return; + + /* done */ + if (mode == 2) { + /* stream endpoints often resubmit/unlink in completion */ + done (ep, req, 0); + + /* maybe advance queue to next request */ + if (ep->num == 0) { + allow_status (ep); + req = 0; + } else { + if (!list_empty (&ep->queue) && !ep->stopped) + req = list_entry (ep->queue.next, + struct net2280_request, queue); + else + req = 0; + if (req && !ep->is_in) + stop_out_naking (ep); + } + } + + /* is there a buffer for the next packet? + * for best streaming performance, make sure there is one. + */ + if (req && !ep->stopped) { + + /* load IN fifo with next packet (may be zlp) */ + if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) + write_fifo (ep, &req->req); + } +} + +static struct net2280_ep * +get_ep_by_addr (struct net2280 *dev, u16 wIndex) +{ + struct net2280_ep *ep; + + if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) + return &dev->ep [0]; + list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) { + u8 bEndpointAddress; + + if (!ep->desc) + continue; + bEndpointAddress = ep->desc->bEndpointAddress; + if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) + continue; + if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) + return ep; + } + return 0; +} + +static void handle_stat0_irqs (struct net2280 *dev, u32 stat) +{ + struct net2280_ep *ep; + u32 num, scratch; + + /* most of these don't need individual acks */ + stat &= ~(1 << INTA_ASSERTED); + if (!stat) + return; + // DEBUG (dev, "irqstat0 %04x\n", stat); + + /* starting a control request? */ + if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) { + union { + u32 raw [2]; + struct usb_ctrlrequest r; + } u; + int tmp = 0; + struct net2280_request *req; + + if (dev->gadget.speed == USB_SPEED_UNKNOWN) { + if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED)) + dev->gadget.speed = USB_SPEED_HIGH; + else + dev->gadget.speed = USB_SPEED_FULL; + net2280_led_speed (dev, dev->gadget.speed); + DEBUG (dev, "%s speed\n", + (dev->gadget.speed == USB_SPEED_HIGH) + ? "high" : "full"); + } + + ep = &dev->ep [0]; + ep->irqs++; + + /* make sure any leftover request state is cleared */ + stat &= ~(1 << ENDPOINT_0_INTERRUPT); + while (!list_empty (&ep->queue)) { + req = list_entry (ep->queue.next, + struct net2280_request, queue); + done (ep, req, (req->req.actual == req->req.length) + ? 0 : -EPROTO); + } + ep->stopped = 0; + dev->protocol_stall = 0; + writel ( (1 << TIMEOUT) + | (1 << USB_STALL_SENT) + | (1 << USB_IN_NAK_SENT) + | (1 << USB_IN_ACK_RCVD) + | (1 << USB_OUT_PING_NAK_SENT) + | (1 << USB_OUT_ACK_SENT) + | (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW) + | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) + | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) + | (1 << DATA_PACKET_RECEIVED_INTERRUPT) + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) + | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + | (1 << DATA_IN_TOKEN_INTERRUPT) + , &ep->regs->ep_stat); + u.raw [0] = readl (&dev->usb->setup0123); + u.raw [1] = readl (&dev->usb->setup4567); + le16_to_cpus (&u.r.wValue); + le16_to_cpus (&u.r.wIndex); + le16_to_cpus (&u.r.wLength); + + /* ack the irq */ + writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); + stat ^= (1 << SETUP_PACKET_INTERRUPT); + + /* watch control traffic at the token level, and force + * synchronization before letting the status stage happen. + */ + ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; + if (ep->is_in) + scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) + | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + | (1 << DATA_IN_TOKEN_INTERRUPT); + else + scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT) + | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) + | (1 << DATA_IN_TOKEN_INTERRUPT); + writel (scratch, &dev->epregs [0].ep_irqenb); + + /* we made the hardware handle most lowlevel requests; + * everything else goes uplevel to the gadget code. + */ + switch (u.r.bRequest) { + case USB_REQ_GET_STATUS: { + struct net2280_ep *e; + u16 status; + + if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) + goto delegate; + if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0 + || u.r.wLength > 2) + goto do_stall; + + if (readl (&e->regs->ep_rsp) + & (1 << SET_ENDPOINT_HALT)) + status = __constant_cpu_to_le16 (1); + else + status = __constant_cpu_to_le16 (0); + + /* don't bother with a request object! */ + writel (0, &dev->epregs [0].ep_irqenb); + set_fifo_bytecount (ep, u.r.wLength); + writel (status, &dev->epregs [0].ep_data); + allow_status (ep); + goto next_endpoints; + } + break; + case USB_REQ_CLEAR_FEATURE: { + struct net2280_ep *e; + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wIndex != 0 /* HALT feature */ + || u.r.wLength != 0) + goto do_stall; + if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + goto do_stall; + clear_halt (e); + } + break; + case USB_REQ_SET_FEATURE: { + struct net2280_ep *e; + + if (u.r.bRequestType != USB_RECIP_ENDPOINT) + goto delegate; + if (u.r.wIndex != 0 /* HALT feature */ + || u.r.wLength != 0) + goto do_stall; + if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) + goto do_stall; + set_halt (e); + } + break; + default: +delegate: + VDEBUG (dev, "setup %02x.%02x v%04x i%04x " + "ep_cfg %08x\n", + u.r.bRequestType, u.r.bRequest, + u.r.wValue, u.r.wIndex, + readl (&ep->regs->ep_cfg)); + spin_unlock (&dev->lock); + tmp = dev->driver->setup (&dev->gadget, &u.r); + spin_lock (&dev->lock); + } + + /* stall ep0 on error */ + if (tmp < 0) { +do_stall: + VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n", + u.r.bRequestType, u.r.bRequest, tmp); + dev->protocol_stall = 1; + + /* when there's no data, queueing a response is optional */ + } else if (list_empty (&ep->queue)) { + if (u.r.wLength == 0) { + /* done() not possible/requested */ + allow_status (ep); + } else { + DEBUG (dev, "req %02x.%02x v%04x " + "gadget error, len %d, stat %d\n", + u.r.bRequestType, u.r.bRequest, + le16_to_cpu (u.r.wValue), + u.r.wLength, tmp); + dev->protocol_stall = 1; + } + } + + /* some in/out token irq should follow; maybe stall then. */ + } + +next_endpoints: + /* endpoint data irq ? */ + scratch = stat & 0x7f; + stat &= ~0x7f; + for (num = 0; scratch; num++) { + u32 t; + + /* do this endpoint's FIFO and queue need tending? */ + t = 1 << num; + if ((scratch & t) == 0) + continue; + scratch ^= t; + + ep = &dev->ep [num]; + handle_ep_small (ep); + } + + if (stat) + DEBUG (dev, "unhandled irqstat0 %08x\n", stat); +} + +#define DMA_INTERRUPTS ( \ + (1 << DMA_D_INTERRUPT) \ + | (1 << DMA_C_INTERRUPT) \ + | (1 << DMA_B_INTERRUPT) \ + | (1 << DMA_A_INTERRUPT)) +#define PCI_ERROR_INTERRUPTS ( \ + (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \ + | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \ + | (1 << PCI_RETRY_ABORT_INTERRUPT)) + +static void handle_stat1_irqs (struct net2280 *dev, u32 stat) +{ + struct net2280_ep *ep; + u32 tmp, num, scratch; + + /* after disconnect there's nothing else to do! */ + tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); + if (stat & tmp) { + writel (tmp, &dev->regs->irqstat1); + if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0 + || (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0 + ) && dev->gadget.speed != USB_SPEED_UNKNOWN) { + DEBUG (dev, "disconnect %s\n", + dev->driver->driver.name); + stop_activity (dev, dev->driver); + ep0_start (dev); + return; + } + stat &= ~tmp; + + /* vBUS can bounce ... one of many reasons to ignore the + * notion of hotplug events on bus connect/disconnect! + */ + if (!stat) + return; + } + + /* NOTE: we don't actually suspend the hardware; that starts to + * interact with PCI power management, and needs something like a + * controller->suspend() call to clear SUSPEND_REQUEST_INTERRUPT. + * we shouldn't see resume interrupts. + * for rev 0100, this also avoids erratum 0102. + */ + tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); + if (stat & tmp) { + if (dev->driver->suspend) + dev->driver->suspend (&dev->gadget); + stat &= ~tmp; + } + stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); + + /* clear any other status/irqs */ + if (stat) + writel (stat, &dev->regs->irqstat1); + + /* some status we can just ignore */ + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << RESUME_INTERRUPT) + | (1 << SOF_INTERRUPT)); + if (!stat) + return; + // DEBUG (dev, "irqstat1 %08x\n", stat); + + /* DMA status, for ep-{a,b,c,d} */ + scratch = stat & DMA_INTERRUPTS; + stat &= ~DMA_INTERRUPTS; + scratch >>= 9; + for (num = 0; scratch; num++) { + struct net2280_dma_regs *dma; + + tmp = 1 << num; + if ((tmp & scratch) == 0) + continue; + scratch ^= tmp; + + ep = &dev->ep [num + 1]; + dma = ep->dma; + + if (!dma) + continue; + + /* clear ep's dma status */ + tmp = readl (&dma->dmastat); + writel (tmp, &dma->dmastat); + +#ifdef USE_DMA_CHAINING + /* chaining should stop only on error (which?) + * or (stat0 codepath) short OUT transfer. + */ +#else + if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) { + DEBUG (ep->dev, "%s no xact done? %08x\n", + ep->ep.name, tmp); + continue; + } + stop_dma (ep->dma); +#endif + + /* OUT transfers terminate when the data from the + * host is in our memory. Process whatever's done. + * On this path, we know transfer's last packet wasn't + * less than req->length. NAK_OUT_PACKETS may be set, + * or the FIFO may already be holding new packets. + * + * IN transfers can linger in the FIFO for a very + * long time ... we ignore that for now, accounting + * precisely (like PIO does) needs per-packet irqs + */ + scan_dma_completions (ep); + + /* disable dma on inactive queues; else maybe restart */ + if (list_empty (&ep->queue)) { +#ifdef USE_DMA_CHAINING + stop_dma (ep->dma); +#endif + } else { + tmp = readl (&dma->dmactl); + if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0 + || (tmp & (1 << DMA_ENABLE)) == 0) + restart_dma (ep); + } + ep->irqs++; + } + + /* NOTE: there are other PCI errors we might usefully notice. + * if they appear very often, here's where to try recovering. + */ + if (stat & PCI_ERROR_INTERRUPTS) { + ERROR (dev, "pci dma error; stat %08x\n", stat); + stat &= ~PCI_ERROR_INTERRUPTS; + /* these are fatal errors, but "maybe" they won't + * happen again ... + */ + stop_activity (dev, dev->driver); + ep0_start (dev); + stat = 0; + } + + if (stat) + DEBUG (dev, "unhandled irqstat1 %08x\n", stat); +} + +static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r) +{ + struct net2280 *dev = _dev; + + spin_lock (&dev->lock); + + /* handle disconnect, dma, and more */ + handle_stat1_irqs (dev, readl (&dev->regs->irqstat1)); + + /* control requests and PIO */ + handle_stat0_irqs (dev, readl (&dev->regs->irqstat0)); + + spin_unlock (&dev->lock); + + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +/* tear down the binding between this driver and the pci device */ + +static void net2280_remove (struct pci_dev *pdev) +{ + struct net2280 *dev = pci_get_drvdata (pdev); + + /* start with the driver above us */ + if (dev->driver) { + /* should have been done already by driver model core */ + WARN (dev, "pci remove, driver '%s' is still registered\n", + dev->driver->driver.name); + usb_gadget_unregister_driver (dev->driver); + } + + /* then clean up the resources we allocated during probe() */ + net2280_led_shutdown (dev); + if (dev->requests) { + int i; + for (i = 1; i < 5; i++) { + if (!dev->ep [i].dummy) + continue; + pci_pool_free (dev->requests, dev->ep [i].dummy, + dev->ep [i].td_dma); + } + pci_pool_destroy (dev->requests); + } + if (dev->got_irq) + free_irq (pdev->irq, dev); + if (dev->regs) + iounmap (dev->regs); + if (dev->region) + release_mem_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + if (dev->enabled) + pci_disable_device (pdev); + device_remove_file (&pdev->dev, &dev_attr_registers); + pci_set_drvdata (pdev, 0); + + INFO (dev, "unbind from pci %s\n", pdev->slot_name); + + kfree (dev); + the_controller = 0; +} + +/* wrap this driver around the specified device, but + * don't respond over USB until a gadget driver binds to us. + */ + +static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net2280 *dev; + unsigned long resource, len; + void *base = 0; + int retval, i; + char buf [8], *bufp; + + /* if you want to support more than one controller in a system, + * usb_gadget_driver_{register,unregister}() must change. + */ + if (the_controller) { + WARN (the_controller, "ignoring %s\n", pdev->slot_name); + return -EBUSY; + } + + /* alloc, and start init */ + dev = kmalloc (sizeof *dev, SLAB_KERNEL); + if (dev == NULL){ + retval = -ENOMEM; + goto done; + } + + memset (dev, 0, sizeof *dev); + spin_lock_init (&dev->lock); + dev->pdev = pdev; + dev->gadget.ops = &net2280_ops; + + strcpy (dev->gadget.dev.bus_id, pdev->slot_name); + strcpy (dev->gadget.dev.name, pdev->dev.name); + dev->gadget.dev.parent = &pdev->dev; + dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + dev->gadget.name = driver_name; + + /* now all the pci goodies ... */ + if (pci_enable_device (pdev) < 0) { + retval = -ENODEV; + goto done; + } + dev->enabled = 1; + + /* BAR 0 holds all the registers + * BAR 1 is 8051 memory; unused here (note erratum 0103) + * BAR 2 is fifo memory; unused here + */ + resource = pci_resource_start (pdev, 0); + len = pci_resource_len (pdev, 0); + if (!request_mem_region (resource, len, driver_name)) { + DEBUG (dev, "controller already in use\n"); + retval = -EBUSY; + goto done; + } + dev->region = 1; + + base = ioremap_nocache (resource, len); + if (base == NULL) { + DEBUG (dev, "can't map memory\n"); + retval = -EFAULT; + goto done; + } + dev->regs = (struct net2280_regs *) base; + dev->usb = (struct net2280_usb_regs *) (base + 0x0080); + dev->pci = (struct net2280_pci_regs *) (base + 0x0100); + dev->dma = (struct net2280_dma_regs *) (base + 0x0180); + dev->dep = (struct net2280_dep_regs *) (base + 0x0200); + dev->epregs = (struct net2280_ep_regs *) (base + 0x0300); + + /* put into initial config, link up all endpoints */ + usb_reset (dev); + usb_reinit (dev); + + /* irq setup after old hardware is cleaned up */ + if (!pdev->irq) { + ERROR (dev, "No IRQ. Check PCI setup!\n"); + retval = -ENODEV; + goto done; + } +#ifndef __sparc__ + snprintf (buf, sizeof buf, "%d", pdev->irq); + bufp = buf; +#else + bufp = __irq_itoa(pdev->irq); +#endif + if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev) + != 0) { + ERROR (dev, "request interrupt %s failed\n", bufp); + retval = -EBUSY; + goto done; + } + dev->got_irq = 1; + + /* DMA setup */ + dev->requests = pci_pool_create ("requests", pdev, + sizeof (struct net2280_dma), + 0 /* no alignment requirements */, + 0 /* or page-crossing issues */); + if (!dev->requests) { + DEBUG (dev, "can't get request pool\n"); + retval = -ENOMEM; + goto done; + } + for (i = 1; i < 5; i++) { + struct net2280_dma *td; + + td = pci_pool_alloc (dev->requests, GFP_KERNEL, + &dev->ep [i].td_dma); + if (!td) { + DEBUG (dev, "can't get dummy %d\n", i); + retval = -ENOMEM; + goto done; + } + td->dmacount = 0; /* not VALID */ + td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID); + dev->ep [i].dummy = td; + } + + /* enable lower-overhead pci memory bursts during DMA */ + writel ((1 << PCI_RETRY_ABORT_ENABLE) + | (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) + | (1 << DMA_READ_MULTIPLE_ENABLE) + | (1 << DMA_READ_LINE_ENABLE) + , &dev->pci->pcimstctl); + /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */ + pci_set_master (pdev); + pci_set_mwi (pdev); + + /* ... also flushes any posted pci writes */ + dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff; + + /* done */ + pci_set_drvdata (pdev, dev); + INFO (dev, "%s\n", driver_desc); + INFO (dev, "irq %s, pci mem %p, chip rev %04x\n", + bufp, base, dev->chiprev); + bufp = DRIVER_VERSION +#ifndef USE_DMA_CHAINING + " (no dma chain)" +#endif +#ifdef NET2280_DMA_OUT_WORKAROUND + " (no dma out)" +#endif + ; + INFO (dev, "version: %s\n", bufp); + the_controller = dev; + + device_create_file (&pdev->dev, &dev_attr_registers); + + return 0; + +done: + if (dev) + net2280_remove (pdev); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +static const struct pci_device_id __devinitdata pci_ids [] = { { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x17cc, + .device = 0x2280, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + +}, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE (pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver net2280_pci_driver = { + .name = (char *) driver_name, + .id_table = pci_ids, + + .probe = net2280_probe, + .remove = net2280_remove, + + /* FIXME add power management support */ +}; + +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("GPL"); + +static int __init init (void) +{ + return pci_module_init (&net2280_pci_driver); +} +module_init (init); + +static void __exit cleanup (void) +{ + pci_unregister_driver (&net2280_pci_driver); +} +module_exit (cleanup); diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/net2280.h Mon May 12 20:55:49 2003 @@ -0,0 +1,709 @@ +/* + * NetChip 2280 high/full speed USB device controller. + * Unlike many such controllers, this one talks PCI. + */ + +/* + * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) + * Copyright (C) 2003 David Brownell + * + * 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 + */ + +/*-------------------------------------------------------------------------*/ + +/* NET2280 MEMORY MAPPED REGISTERS + * + * The register layout came from the chip documentation, and the bit + * number definitions were extracted from chip specification. + * + * Use the shift operator ('<<') to build bit masks, with readl/writel + * to access the registers through PCI. + */ + +/* main registers, BAR0 + 0x0000 */ +struct net2280_regs { + // offset 0x0000 + u32 devinit; +#define LOCAL_CLOCK_FREQUENCY 8 +#define FORCE_PCI_RESET 7 +#define PCI_ID 6 +#define PCI_ENABLE 5 +#define FIFO_SOFT_RESET 4 +#define CFG_SOFT_RESET 3 +#define PCI_SOFT_RESET 2 +#define USB_SOFT_RESET 1 +#define M8051_RESET 0 + u32 eectl; +#define EEPROM_ADDRESS_WIDTH 23 +#define EEPROM_CHIP_SELECT_ACTIVE 22 +#define EEPROM_PRESENT 21 +#define EEPROM_VALID 20 +#define EEPROM_BUSY 19 +#define EEPROM_CHIP_SELECT_ENABLE 18 +#define EEPROM_BYTE_READ_START 17 +#define EEPROM_BYTE_WRITE_START 16 +#define EEPROM_READ_DATA 8 +#define EEPROM_WRITE_DATA 0 + u32 eeclkfreq; + u32 _unused0; + // offset 0x0010 + + u32 pciirqenb0; /* interrupt PCI master ... */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + u32 pciirqenb1; +#define PCI_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + u32 cpu_irqenb0; /* ... or onboard 8051 */ +#define SETUP_PACKET_INTERRUPT_ENABLE 7 +#define ENDPOINT_F_INTERRUPT_ENABLE 6 +#define ENDPOINT_E_INTERRUPT_ENABLE 5 +#define ENDPOINT_D_INTERRUPT_ENABLE 4 +#define ENDPOINT_C_INTERRUPT_ENABLE 3 +#define ENDPOINT_B_INTERRUPT_ENABLE 2 +#define ENDPOINT_A_INTERRUPT_ENABLE 1 +#define ENDPOINT_0_INTERRUPT_ENABLE 0 + u32 cpu_irqenb1; +#define CPU_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + + // offset 0x0020 + u32 _unused1; + u32 usbirqenb1; +#define USB_INTERRUPT_ENABLE 31 +#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 +#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 +#define PCI_INTA_INTERRUPT_ENABLE 24 +#define PCI_PME_INTERRUPT_ENABLE 23 +#define PCI_SERR_INTERRUPT_ENABLE 22 +#define PCI_PERR_INTERRUPT_ENABLE 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 +#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 +#define GPIO_INTERRUPT_ENABLE 13 +#define DMA_D_INTERRUPT_ENABLE 12 +#define DMA_C_INTERRUPT_ENABLE 11 +#define DMA_B_INTERRUPT_ENABLE 10 +#define DMA_A_INTERRUPT_ENABLE 9 +#define EEPROM_DONE_INTERRUPT_ENABLE 8 +#define VBUS_INTERRUPT_ENABLE 7 +#define CONTROL_STATUS_INTERRUPT_ENABLE 6 +#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 +#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 +#define RESUME_INTERRUPT_ENABLE 1 +#define SOF_INTERRUPT_ENABLE 0 + u32 irqstat0; +#define INTA_ASSERTED 12 +#define SETUP_PACKET_INTERRUPT 7 +#define ENDPOINT_F_INTERRUPT 6 +#define ENDPOINT_E_INTERRUPT 5 +#define ENDPOINT_D_INTERRUPT 4 +#define ENDPOINT_C_INTERRUPT 3 +#define ENDPOINT_B_INTERRUPT 2 +#define ENDPOINT_A_INTERRUPT 1 +#define ENDPOINT_0_INTERRUPT 0 + u32 irqstat1; +#define POWER_STATE_CHANGE_INTERRUPT 27 +#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 +#define PCI_PARITY_ERROR_INTERRUPT 25 +#define PCI_INTA_INTERRUPT 24 +#define PCI_PME_INTERRUPT 23 +#define PCI_SERR_INTERRUPT 22 +#define PCI_PERR_INTERRUPT 21 +#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 +#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 +#define PCI_RETRY_ABORT_INTERRUPT 17 +#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 +#define GPIO_INTERRUPT 13 +#define DMA_D_INTERRUPT 12 +#define DMA_C_INTERRUPT 11 +#define DMA_B_INTERRUPT 10 +#define DMA_A_INTERRUPT 9 +#define EEPROM_DONE_INTERRUPT 8 +#define VBUS_INTERRUPT 7 +#define CONTROL_STATUS_INTERRUPT 6 +#define ROOT_PORT_RESET_INTERRUPT 4 +#define SUSPEND_REQUEST_INTERRUPT 3 +#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 +#define RESUME_INTERRUPT 1 +#define SOF_INTERRUPT 0 + // offset 0x0030 + u32 idxaddr; + u32 idxdata; + u32 fifoctl; +#define PCI_BASE2_RANGE 16 +#define IGNORE_FIFO_AVAILABILITY 3 +#define PCI_BASE2_SELECT 2 +#define FIFO_CONFIGURATION_SELECT 0 + u32 _unused2; + // offset 0x0040 + u32 memaddr; +#define START 28 +#define DIRECTION 27 +#define FIFO_DIAGNOSTIC_SELECT 24 +#define MEMORY_ADDRESS 0 + u32 memdata0; + u32 memdata1; + u32 _unused3; + // offset 0x0050 + u32 gpioctl; +#define GPIO3_LED_SELECT 12 +#define GPIO3_INTERRUPT_ENABLE 11 +#define GPIO2_INTERRUPT_ENABLE 10 +#define GPIO1_INTERRUPT_ENABLE 9 +#define GPIO0_INTERRUPT_ENABLE 8 +#define GPIO3_OUTPUT_ENABLE 7 +#define GPIO2_OUTPUT_ENABLE 6 +#define GPIO1_OUTPUT_ENABLE 5 +#define GPIO0_OUTPUT_ENABLE 4 +#define GPIO3_DATA 3 +#define GPIO2_DATA 2 +#define GPIO1_DATA 1 +#define GPIO0_DATA 0 + u32 gpiostat; +#define GPIO3_INTERRUPT 3 +#define GPIO2_INTERRUPT 2 +#define GPIO1_INTERRUPT 1 +#define GPIO0_INTERRUPT 0 +} __attribute__ ((packed)); + +/* usb control, BAR0 + 0x0080 */ +struct net2280_usb_regs { + // offset 0x0080 + u32 stdrsp; +#define STALL_UNSUPPORTED_REQUESTS 31 +#define SET_TEST_MODE 16 +#define GET_OTHER_SPEED_CONFIGURATION 15 +#define GET_DEVICE_QUALIFIER 14 +#define SET_ADDRESS 13 +#define ENDPOINT_SET_CLEAR_HALT 12 +#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 +#define GET_STRING_DESCRIPTOR_2 10 +#define GET_STRING_DESCRIPTOR_1 9 +#define GET_STRING_DESCRIPTOR_0 8 +#define GET_SET_INTERFACE 6 +#define GET_SET_CONFIGURATION 5 +#define GET_CONFIGURATION_DESCRIPTOR 4 +#define GET_DEVICE_DESCRIPTOR 3 +#define GET_ENDPOINT_STATUS 2 +#define GET_INTERFACE_STATUS 1 +#define GET_DEVICE_STATUS 0 + u32 prodvendid; +#define PRODUCT_ID 16 +#define VENDOR_ID 0 + u32 relnum; + u32 usbctl; +#define SERIAL_NUMBER_INDEX 16 +#define PRODUCT_ID_STRING_ENABLE 13 +#define VENDOR_ID_STRING_ENABLE 12 +#define USB_ROOT_PORT_WAKEUP_ENABLE 11 +#define VBUS_PIN 10 +#define TIMED_DISCONNECT 9 +#define SUSPEND_IMMEDIATELY 7 +#define SELF_POWERED_USB_DEVICE 6 +#define REMOTE_WAKEUP_SUPPORT 5 +#define PME_POLARITY 4 +#define USB_DETECT_ENABLE 3 +#define PME_WAKEUP_ENABLE 2 +#define DEVICE_REMOTE_WAKEUP_ENABLE 1 +#define SELF_POWERED_STATUS 0 + // offset 0x0090 + u32 usbstat; +#define HIGH_SPEED 7 +#define FULL_SPEED 6 +#define GENERATE_RESUME 5 +#define GENERATE_DEVICE_REMOTE_WAKEUP 4 + u32 xcvrdiag; +#define FORCE_HIGH_SPEED_MODE 31 +#define FORCE_FULL_SPEED_MODE 30 +#define USB_TEST_MODE 24 +#define LINE_STATE 16 +#define TRANSCEIVER_OPERATION_MODE 2 +#define TRANSCEIVER_SELECT 1 +#define TERMINATION_SELECT 0 + u32 setup0123; + u32 setup4567; + // offset 0x0090 + u32 _unused0; + u32 ouraddr; +#define FORCE_IMMEDIATE 7 +#define OUR_USB_ADDRESS 0 + u32 ourconfig; +} __attribute__ ((packed)); + +/* pci control, BAR0 + 0x0100 */ +struct net2280_pci_regs { + // offset 0x0100 + u32 pcimstctl; +#define PCI_ARBITER_PARK_SELECT 13 +#define PCI_MULTI LEVEL_ARBITER 12 +#define PCI_RETRY_ABORT_ENABLE 11 +#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 +#define DMA_READ_MULTIPLE_ENABLE 9 +#define DMA_READ_LINE_ENABLE 8 +#define PCI_MASTER_COMMAND_SELECT 6 +#define MEM_READ_OR_WRITE 0 +#define IO_READ_OR_WRITE 1 +#define CFG_READ_OR_WRITE 2 +#define PCI_MASTER_START 5 +#define PCI_MASTER_READ_WRITE 4 +#define PCI_MASTER_WRITE 0 +#define PCI_MASTER_READ 1 +#define PCI_MASTER_BYTE_WRITE_ENABLES 0 + u32 pcimstaddr; + u32 pcimstdata; + u32 pcimststat; +#define PCI_ARBITER_CLEAR 2 +#define PCI_EXTERNAL_ARBITER 1 +#define PCI_HOST_MODE 0 +} __attribute__ ((packed)); + +/* dma control, BAR0 + 0x0180 ... array of four structs like this, + * for channels 0..3. see also struct net2280_dma: descriptor + * that can be loaded into some of these registers. + */ +struct net2280_dma_regs { /* [11.7] */ + // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, + u32 dmactl; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 +#define DMA_CLEAR_COUNT_ENABLE 21 +#define DESCRIPTOR_POLLING_RATE 19 +#define POLL_CONTINUOUS 0 +#define POLL_1_USEC 1 +#define POLL_100_USEC 2 +#define POLL_1_MSEC 3 +#define DMA_VALID_BIT_POLLING_ENABLE 18 +#define DMA_VALID_BIT_ENABLE 17 +#define DMA_SCATTER_GATHER_ENABLE 16 +#define DMA_OUT_AUTO_START_ENABLE 4 +#define DMA_PREEMPT_ENABLE 3 +#define DMA_FIFO_VALIDATE 2 +#define DMA_ENABLE 1 +#define DMA_ADDRESS_HOLD 0 + u32 dmastat; +#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 +#define DMA_TRANSACTION_DONE_INTERRUPT 24 +#define DMA_ABORT 1 +#define DMA_START 0 + u32 _unused0 [2]; + // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, + u32 dmacount; +#define VALID_BIT 31 +#define DMA_DIRECTION 30 +#define DMA_DONE_INTERRUPT_ENABLE 29 +#define END_OF_CHAIN 28 +#define DMA_BYTE_COUNT_MASK ((1<<24)-1) +#define DMA_BYTE_COUNT 0 + u32 dmaaddr; + u32 dmadesc; + u32 _unused1; +} __attribute__ ((packed)); + +/* dedicated endpoint registers, BAR0 + 0x0200 */ + +struct net2280_dep_regs { /* [11.8] */ + // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 + u32 dep_cfg; + // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 + u32 dep_rsp; + u32 _unused [2]; +} __attribute__ ((packed)); + +/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs + * like this, for ep0 then the configurable endpoints A..F + * ep0 reserved for control; E and F have only 64 bytes of fifo + */ +struct net2280_ep_regs { /* [11.9] */ + // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 + u32 ep_cfg; +#define ENDPOINT_BYTE_COUNT 16 +#define ENDPOINT_ENABLE 10 +#define ENDPOINT_TYPE 8 +#define ENDPOINT_DIRECTION 7 +#define ENDPOINT_NUMBER 0 + u32 ep_rsp; +#define SET_NAK_OUT_PACKETS 15 +#define SET_EP_HIDE_STATUS_PHASE 14 +#define SET_INTERRUPT_MODE 12 +#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 +#define SET_NAK_OUT_PACKETS_MODE 10 +#define SET_ENDPOINT_TOGGLE 9 +#define SET_ENDPOINT_HALT 8 +#define CLEAR_NAK_OUT_PACKETS 7 +#define CLEAR_EP_HIDE_STATUS_PHASE 6 +#define CLEAR_INTERRUPT_MODE 4 +#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 +#define CLEAR_NAK_OUT_PACKETS_MODE 2 +#define CLEAR_ENDPOINT_TOGGLE 1 +#define CLEAR_ENDPOINT_HALT 0 + u32 ep_irqenb; +#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 +#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 +#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 + u32 ep_stat; +#define FIFO_VALID_COUNT 24 +#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 +#define TIMEOUT 21 +#define USB_STALL_SENT 20 +#define USB_IN_NAK_SENT 19 +#define USB_IN_ACK_RCVD 18 +#define USB_OUT_PING_NAK_SENT 17 +#define USB_OUT_ACK_SENT 16 +#define FIFO_OVERFLOW 13 +#define FIFO_UNDERFLOW 12 +#define FIFO_FULL 11 +#define FIFO_EMPTY 10 +#define FIFO_FLUSH 9 +#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 +#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 +#define NAK_OUT_PACKETS 4 +#define DATA_PACKET_RECEIVED_INTERRUPT 3 +#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 +#define DATA_OUT_PING_TOKEN_INTERRUPT 1 +#define DATA_IN_TOKEN_INTERRUPT 0 + // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 + u32 ep_avail; + u32 ep_data; + u32 _unused0 [2]; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* indexed registers [11.10] are accessed indirectly + * caller must own the device lock. + */ + +static inline u32 +get_idx_reg (struct net2280_regs *regs, u32 index) +{ + writel (index, ®s->idxaddr); + /* NOTE: synchs device/cpu memory views */ + return readl (®s->idxdata); +} + +static inline void +set_idx_reg (struct net2280_regs *regs, u32 index, u32 value) +{ + writel (index, ®s->idxaddr); + writel (value, ®s->idxdata); + /* posted, may not be visible yet */ +} + +#define REG_DIAG 0x0 +#define RETRY_COUNTER 16 +#define FORCE_PCI_SERR 11 +#define FORCE_PCI_INTERRUPT 10 +#define FORCE_USB_INTERRUPT 9 +#define FORCE_CPU_INTERRUPT 8 +#define ILLEGAL_BYTE_ENABLES 5 +#define FAST_TIMES 4 +#define FORCE_RECEIVE_ERROR 2 +#define FORCE_TRANSMIT_CRC_ERROR 0 +#define REG_FRAME 0x02 /* from last sof */ +#define REG_CHIPREV 0x03 /* in bcd */ +#define REG_HS_NAK_RATE 0x0a /* NAK per N uframes */ + +/* ep a-f highspeed and fullspeed maxpacket, addresses + * computed from ep->num + */ +#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \ + (((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1)) + +/*-------------------------------------------------------------------------*/ + +/* [8.3] for scatter/gather i/o + * use struct net2280_dma_regs bitfields + */ +struct net2280_dma { + u32 dmacount; + u32 dmaaddr; /* the buffer */ + u32 dmadesc; /* next dma descriptor */ + u32 _reserved; +} __attribute__ ((aligned (16))); + +/*-------------------------------------------------------------------------*/ + +/* DRIVER DATA STRUCTURES and UTILITIES */ + +struct net2280_ep { + struct usb_ep ep; + struct net2280_ep_regs *regs; + struct net2280_dma_regs *dma; + struct net2280_dma *dummy; + dma_addr_t td_dma; /* of dummy */ + struct net2280 *dev; + unsigned long irqs; + + /* analogous to a host-side qh */ + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + unsigned num : 8, + fifo_size : 12, + in_fifo_validate : 1, + stopped : 1, + is_in : 1, + is_iso : 1; +}; + +static inline void allow_status (struct net2280_ep *ep) +{ + /* ep0 only */ + writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + | (1 << CLEAR_NAK_OUT_PACKETS_MODE) + , &ep->regs->ep_rsp); +} + +static inline void set_halt (struct net2280_ep *ep) +{ + /* ep0 and bulk/intr endpoints */ + writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) + /* set NAK_OUT for erratum 0114 */ + | (1 << SET_NAK_OUT_PACKETS) + | (1 << SET_ENDPOINT_HALT) + , &ep->regs->ep_rsp); +} + +static inline void clear_halt (struct net2280_ep *ep) +{ + /* bulk/intr endpoints */ + writel ( (1 << CLEAR_ENDPOINT_HALT) + | (1 << CLEAR_ENDPOINT_TOGGLE) + , &ep->regs->ep_rsp); +} + +/* count (<= 4) bytes in the next fifo write will be valid */ +static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) +{ + writeb (count, 2 + (u8 *) &ep->regs->ep_cfg); +} + +struct net2280_request { + struct usb_request req; + struct net2280_dma *td; + dma_addr_t td_dma; + struct list_head queue; + unsigned mapped : 1, + dma_done : 1, + valid : 1; +}; + +struct net2280 { + /* each pci device provides one gadget, several endpoints */ + struct usb_gadget gadget; + spinlock_t lock; + struct net2280_ep ep [7]; + struct usb_gadget_driver *driver; + unsigned enabled : 1, + protocol_stall : 1, + got_irq : 1, + region : 1, + selfpowered : 1; + u16 chiprev; + + /* pci state used to access those endpoints */ + struct pci_dev *pdev; + struct net2280_regs *regs; + struct net2280_usb_regs *usb; + struct net2280_pci_regs *pci; + struct net2280_dma_regs *dma; + struct net2280_dep_regs *dep; + struct net2280_ep_regs *epregs; + + struct pci_pool *requests; + // statistics... +}; + +#ifdef USE_RDK_LEDS + +static inline void net2280_led_init (struct net2280 *dev) +{ + /* LED3 (green) is on during USB activity. note erratum 0113. */ + writel ((1 << GPIO3_LED_SELECT) + | (1 << GPIO3_OUTPUT_ENABLE) + | (1 << GPIO2_OUTPUT_ENABLE) + | (1 << GPIO1_OUTPUT_ENABLE) + | (1 << GPIO0_OUTPUT_ENABLE) + , &dev->regs->gpioctl); +} + +/* indicate speed with bi-color LED 0/1 */ +static inline +void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) +{ + u32 val = readl (&dev->regs->gpioctl); + switch (speed) { + case USB_SPEED_HIGH: /* green */ + val &= ~(1 << GPIO0_DATA); + val |= (1 << GPIO1_DATA); + break; + case USB_SPEED_FULL: /* red */ + val &= ~(1 << GPIO1_DATA); + val |= (1 << GPIO0_DATA); + break; + default: /* (off/black) */ + val &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA)); + break; + } + writel (val, &dev->regs->gpioctl); +} + +/* indicate power with LED 2 */ +static inline void net2280_led_active (struct net2280 *dev, int is_active) +{ + u32 val = readl (&dev->regs->gpioctl); + + // FIXME this LED never seems to turn on. + if (is_active) + val |= GPIO2_DATA; + else + val &= ~GPIO2_DATA; + writel (val, &dev->regs->gpioctl); +} +static inline void net2280_led_shutdown (struct net2280 *dev) +{ + /* turn off all four GPIO*_DATA bits */ + writel (readl (&dev->regs->gpioctl) & ~0x0f, + &dev->regs->gpioctl); +} + +#else + +#define net2280_led_init(dev) do { } while (0) +#define net2280_led_speed(dev, speed) do { } while (0) +#define net2280_led_shutdown(dev) do { } while (0) + +#endif + +/*-------------------------------------------------------------------------*/ + +#define xprintk(dev,level,fmt,args...) \ + printk(level "%s %s: " fmt , driver_name , \ + dev->pdev->slot_name , ## args) + +#ifdef DEBUG +#undef DEBUG +#define DEBUG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDEBUG DEBUG +#else +#define VDEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +static inline void start_out_naking (struct net2280_ep *ep) +{ + /* NOTE: hardware races lurk here, and PING protocol issues */ + writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + /* synch with device */ + readl (&ep->regs->ep_rsp); +} + +#ifdef DEBUG +static inline void assert_out_naking (struct net2280_ep *ep, const char *where) +{ + u32 tmp = readl (&ep->regs->ep_stat); + + if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { + DEBUG (ep->dev, "%s %s %08x !NAK\n", + ep->ep.name, where, tmp); + writel ((1 << SET_NAK_OUT_PACKETS), + &ep->regs->ep_rsp); + } +} +#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__FUNCTION__) +#else +#define ASSERT_OUT_NAKING(ep) do {} while (0) +#endif + +static inline void stop_out_naking (struct net2280_ep *ep) +{ + u32 tmp; + + tmp = readl (&ep->regs->ep_stat); + if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) + writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); +} + diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/usbstring.c Mon May 12 20:55:49 2003 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include + + +/** + * usb_gadget_get_string - fill out a string descriptor + * @table: of c strings using iso latin/1 characters + * @id: string id, from low byte of wValue in get string descriptor + * @buf: at least 256 bytes + * + * Finds the iso latin/1 string matching the ID, and converts it into a + * string descriptor in utf16-le. + * Returns length of descriptor (always even) or negative errno + * + * If your driver needs stings in multiple languages, you'll need to + * to use some alternate solution for languages where the ISO 8859/1 + * (latin/1) character set can't be used. For example, they can't be + * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other + * languages. You'd likely "switch (wIndex) { ... }" in your ep0 + * string descriptor logic, using this routine in cases where "western + * european" characters suffice for the strings being returned. + */ +int +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) +{ + struct usb_string *s; + int len; + + /* descriptor 0 has the language id */ + if (id == 0) { + buf [0] = 4; + buf [1] = USB_DT_STRING; + buf [2] = (u8) table->language; + buf [3] = (u8) (table->language >> 8); + return 4; + } + for (s = table->strings; s && s->s; s++) + if (s->id == id) + break; + + /* unrecognized: stall. */ + if (!s || !s->s) + return -EINVAL; + + /* string descriptors have length, tag, then UTF16-LE text */ + len = min ((size_t) 126, strlen (s->s)); + buf [0] = (len + 1) * 2; + buf [1] = USB_DT_STRING; + memset (buf + 2, 0, 2 * len); /* zero all the high bytes */ + while (len) { + buf [2 * len] = s->s [len - 1]; + len--; + } + return buf [0]; +} + diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/zero.c Mon May 12 20:55:49 2003 @@ -0,0 +1,1223 @@ +/* + * zero.c -- Gadget Zero, for USB development + * + * Copyright (C) 2003 David Brownell + * 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, + * without modification. + * 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. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + */ + + +/* + * Gadget Zero only needs two bulk endpoints, and is an example of how you + * can write a hardware-agnostic gadget driver running inside a USB device. + * + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't + * affect most of the driver. + * + * Use it with the Linux host/master side "usbtest" driver to get a basic + * functional test of your device-side usb stack, or with "usb-skeleton". + * + * It supports two similar configurations. One sinks whatever the usb host + * writes, and in return sources zeroes. The other loops whatever the host + * writes back, so the host can read it. Module options include: + * + * buflen=N default N=4096, buffer size used + * qlen=N default N=32, how many buffers in the loopback queue + * loopdefault default false, list loopback config first + * + * Many drivers will only have one configuration, letting them be much + * simpler if they also don't support high speed operation (like this + * driver does). + */ + +#define DEBUG 1 +// #define VERBOSE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VERSION "19 Feb 2003" + +static const char shortname [] = "zero"; +static const char longname [] = "Gadget Zero"; + +static const char source_sink [] = "source and sink data"; +static const char loopback [] = "loop input to output"; + +/*-------------------------------------------------------------------------*/ + +/* + * hardware-specific configuration, controlled by which device + * controller driver was configured. + * + * CHIP ... hardware identifier + * DRIVER_VERSION_NUM ... alerts the host side driver to differences + * EP0_MAXPACKET ... controls packetization of control requests + * EP_*_NAME ... which endpoints do we use for which purpose? + * EP_*_NUM ... numbers for them (often limited by hardware) + * HIGHSPEED ... define if ep0 and descriptors need high speed support + * MAX_USB_POWER ... define if we use other than 100 mA bus current + * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER + * WAKEUP ... if hardware supports remote wakeup AND we will issue the + * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP + * + * hw_optimize(gadget) ... for any hardware tweaks we want to kick in + * before we enable our endpoints + * + * add other defines for other portability issues, like hardware that + * for some reason doesn't handle full speed bulk maxpacket of 64. + */ + +/* + * DRIVER_VERSION_NUM 0x0000 (?): Martin Diehl's ezusb an21/fx code + */ + +/* + * NetChip 2280, PCI based. + * + * This has half a dozen configurable endpoints, four with dedicated + * DMA channels to manage their FIFOs. It supports high speed. + * Those endpoints can be arranged in any desired configuration. + */ +#ifdef CONFIG_USB_ZERO_NET2280 +#define CHIP "net2280" +#define DRIVER_VERSION_NUM 0x0101 +#define EP0_MAXPACKET 64 +static const char EP_OUT_NAME [] = "ep-a"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME [] = "ep-b"; +#define EP_IN_NUM 2 +#define HIGHSPEED +/* specific hardware configs could be bus-powered */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* supports remote wakeup, but this driver doesn't */ + +extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); + +static inline void hw_optimize (struct usb_gadget *gadget) +{ + /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets + * for highspeed bulk) because we're not using ep-c/ep-d. + */ + net2280_set_fifo_mode (gadget, 1); +} +#endif + +/* + * PXA-250 UDC: widely used in second gen Linux-capable PDAs. + * + * This has fifteen fixed-function full speed endpoints, and it + * can support all USB transfer types. + * + * It only supports three configurations (numbered 1, 2, or 3) + * with two interfaces each ... there's partial hardware support + * for set_configuration and set_interface, preventing some more + * interesting config/interface/endpoint arrangements. + */ +#ifdef CONFIG_USB_ZERO_PXA250 +#define CHIP "pxa250" +#define DRIVER_VERSION_NUM 0x0103 +#define EP0_MAXPACKET 16 +static const char EP_OUT_NAME [] = "ep12out-bulk"; +#define EP_OUT_NUM 12 +static const char EP_IN_NAME [] = "ep11in-bulk"; +#define EP_IN_NUM 11 +/* doesn't support bus-powered operation */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* supports remote wakeup, but this driver doesn't */ + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0); +#endif + +/* + * SA-1100 UDC: widely used in first gen Linux-capable PDAs. + * + * This has only two fixed function endpoints, which can only + * be used for bulk (or interrupt) transfers. (Plus control.) + * + * Since it can't flush its TX fifos without disabling the UDC, + * the current configuration or altsettings can't change except + * in special situations. So this is a case of "choose it right + * during enumeration" ... + */ +#ifdef CONFIG_USB_ZERO_SA1100 +#define CHIP "sa1100" +#define DRIVER_VERSION_NUM 0x0105 +#define EP0_MAXPACKET 8 +static const char EP_OUT_NAME [] = "ep1out-bulk"; +#define EP_OUT_NUM 1 +static const char EP_IN_NAME [] = "ep2in-bulk"; +#define EP_IN_NUM 2 +/* doesn't support bus-powered operation */ +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* doesn't support remote wakeup? */ + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0); +#endif + +/*-------------------------------------------------------------------------*/ + +#ifndef EP0_MAXPACKET +# error Configure some USB peripheral controller driver! +#endif + +/* power usage is config specific. + * hardware that supports remote wakeup defaults to disabling it. + */ + +#ifndef SELFPOWER +/* default: say we rely on bus power */ +#define SELFPOWER 0 +/* else: + * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER + * - MAX_USB_POWER may be nonzero. + */ +#endif + +#ifndef MAX_USB_POWER +/* any hub supports this steady state bus power consumption */ +#define MAX_USB_POWER 100 /* mA */ +#endif + +#ifndef WAKEUP +/* default: this driver won't do remote wakeup */ +#define WAKEUP 0 +/* else value must be USB_CONFIG_ATT_WAKEUP */ +#endif + +/*-------------------------------------------------------------------------*/ + +/* big enough to hold our biggest descriptor */ +#define USB_BUFSIZ 256 + +struct zero_dev { + spinlock_t lock; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + + /* when configured, we have one of two configs: + * - source data (in to host) and sink it (out from host) + * - or loop it back (out from host back in to host) + */ + u8 config; + struct usb_ep *in_ep, *out_ep; +}; + +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#undef DEBUG +#define DEBUG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDEBUG DEBUG +#else +#define VDEBUG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +static unsigned buflen = 4096; +static unsigned qlen = 32; + +module_param (buflen, uint, S_IRUGO|S_IWUSR); +module_param (qlen, uint, S_IRUGO|S_IWUSR); + +/* + * Normally the "loopback" configuration is second (index 1) so + * it's not the default. Here's where to change that order, to + * work better with hosts (like Linux ... for now!) where config + * changes are problematic. + */ +static int loopdefault = 0; + +module_param (loopdefault, bool, S_IRUGO|S_IWUSR); + +/*-------------------------------------------------------------------------*/ + +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) + * configuration descriptors are built on demand. + */ + +#define STRING_MANUFACTURER 25 +#define STRING_PRODUCT 42 +#define STRING_SERIAL 101 +#define STRING_SOURCE_SINK 250 +#define STRING_LOOPBACK 251 + +/* + * This device advertises two configurations; these numbers work + * on a pxa250 as well as more flexible hardware. + */ +#define CONFIG_SOURCE_SINK 3 +#define CONFIG_LOOPBACK 2 + +static const struct usb_device_descriptor +device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + .bMaxPacketSize0 = EP0_MAXPACKET, + + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), + .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIAL, + .bNumConfigurations = 2, +}; + +static const struct usb_config_descriptor +source_sink_config = { + .bLength = sizeof source_sink_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_SOURCE_SINK, + .iConfiguration = STRING_SOURCE_SINK, + .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, + .bMaxPower = (MAX_USB_POWER + 1) / 2, +}; + +static const struct usb_config_descriptor +loopback_config = { + .bLength = sizeof loopback_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 1, + .bConfigurationValue = CONFIG_LOOPBACK, + .iConfiguration = STRING_LOOPBACK, + .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, + .bMaxPower = (MAX_USB_POWER + 1) / 2, +}; + +/* one interface in each configuration */ + +static const struct usb_interface_descriptor +source_sink_intf = { + .bLength = sizeof source_sink_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = STRING_SOURCE_SINK, +}; + +static const struct usb_interface_descriptor +loopback_intf = { + .bLength = sizeof loopback_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = STRING_LOOPBACK, +}; + +/* two full speed bulk endpoints; their use is config-dependent */ + +static const struct usb_endpoint_descriptor +fs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (64), +}; + +static const struct usb_endpoint_descriptor +fs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (64), +}; + +#ifdef HIGHSPEED + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + * + * that means alternate endpoint descriptors (bigger packets) + * and a "device qualifier" ... plus more construction options + * for the config descriptor. + */ + +static const struct usb_endpoint_descriptor +hs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (512), +}; + +static const struct usb_endpoint_descriptor +hs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = EP_OUT_NUM, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16 (512), +}; + +static const struct usb_qualifier_descriptor +dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + /* assumes ep0 uses the same value for both speeds ... */ + .bMaxPacketSize0 = EP0_MAXPACKET, + + .bNumConfigurations = 2, +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,hs,fs) fs + +#endif /* !HIGHSPEED */ + +static char serial [40]; + +/* static strings, in iso 8859/1 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_PRODUCT, longname, }, + { STRING_SERIAL, serial, }, + { STRING_LOOPBACK, loopback, }, + { STRING_SOURCE_SINK, source_sink, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +/* + * config descriptors are also handcrafted. these must agree with code + * that sets configurations, and with code managing interface altsettings. + * other complexity may come from: + * + * - high speed support, including "other speed config" rules + * - multiple configurations + * - interfaces with alternate settings + * - embedded class or vendor-specific descriptors + * + * this handles high speed, and has a second config that could as easily + * have been an alternate interface setting. + * + * NOTE: to demonstrate (and test) more USB capabilities, this driver + * should include an altsetting to test interrupt transfers, including + * high bandwidth modes at high speed. (Maybe work like Intel's test + * device?) + */ +static int +config_buf (enum usb_device_speed speed, + u8 *buf, u8 type, unsigned index) +{ + int is_source_sink; + const unsigned config_len = USB_DT_CONFIG_SIZE + + USB_DT_INTERFACE_SIZE + + 2 * USB_DT_ENDPOINT_SIZE; +#ifdef HIGHSPEED + int hs; +#endif + /* two configurations will always be index 0 and index 1 */ + if (index > 1) + return -EINVAL; + if (config_len > USB_BUFSIZ) + return -EDOM; + is_source_sink = loopdefault ? (index == 1) : (index == 0); + + /* config (or other speed config) */ + if (is_source_sink) + memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE); + else + memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE); + buf [1] = type; + ((struct usb_config_descriptor *) buf)->wTotalLength + = __constant_cpu_to_le16 (config_len); + buf += USB_DT_CONFIG_SIZE; + + /* one interface */ + if (is_source_sink) + memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE); + else + memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE); + buf += USB_DT_INTERFACE_SIZE; + + /* the endpoints in that interface (at that speed) */ +#ifdef HIGHSPEED + hs = (speed == USB_SPEED_HIGH); + if (type == USB_DT_OTHER_SPEED_CONFIG) + hs = !hs; + if (hs) { + memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } else +#endif + { + memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); + buf += USB_DT_ENDPOINT_SIZE; + } + + return config_len; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +alloc_ep_req (struct usb_ep *ep, unsigned length) +{ + struct usb_request *req; + + req = usb_ep_alloc_request (ep, GFP_ATOMIC); + if (req) { + req->length = length; + req->buf = usb_ep_alloc_buffer (ep, length, + &req->dma, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request (ep, req); + req = 0; + } + } + return req; +} + +static void free_ep_req (struct usb_ep *ep, struct usb_request *req) +{ + if (req->buf) + usb_ep_free_buffer (ep, req->buf, req->dma, req->length); + usb_ep_free_request (ep, req); +} + +/*-------------------------------------------------------------------------*/ + +/* optionally require specific source/sink data patterns */ + +static inline int +check_read_data ( + struct zero_dev *dev, + struct usb_ep *ep, + struct usb_request *req +) +{ + int i; + + for (i = 0; i < req->actual; i++) { + if (((u8 *)req->buf) [i] != 0) { + ERROR (dev, "nonzero OUT byte from host, " + "buf [%d] = %d\n", + i, ((u8 *)req->buf) [i]); + usb_ep_set_halt (ep); + return -EINVAL; + } + } + return 0; +} + +static inline void +reinit_write_data ( + struct zero_dev *dev, + struct usb_ep *ep, + struct usb_request *req +) +{ + memset (req->buf, 0, req->length); +} + +/* if there is only one request in the queue, there'll always be an + * irq delay between end of one request and start of the next. + * that prevents using hardware dma queues. + */ +static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct zero_dev *dev = ep->driver_data; + int status = req->status; + + switch (status) { + + case 0: /* normal completion? */ + if (ep == dev->out_ep) + check_read_data (dev, ep, req); + else + reinit_write_data (dev, ep, req); + break; + + /* this endpoint is normally active while we're configured */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ + DEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, + req->actual, req->length); + free_ep_req (ep, req); + return; + + case -EOVERFLOW: /* buffer overrun on read means that + * we didn't provide a big enough + * buffer. + */ + default: +#if 1 + DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); +#endif + case -EREMOTEIO: /* short read */ + break; + } + + status = usb_ep_queue (ep, req, GFP_ATOMIC); + if (status) { + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n", + ep->name, req->length, status); + usb_ep_set_halt (ep); + /* FIXME recover later ... somehow */ + } +} + +static struct usb_request * +source_sink_start_ep (struct usb_ep *ep, int gfp_flags) +{ + struct usb_request *req; + int status; + + req = alloc_ep_req (ep, buflen); + if (!req) + return 0; + + memset (req->buf, 0, req->length); + req->complete = source_sink_complete; + + status = usb_ep_queue (ep, req, gfp_flags); + if (status) { + struct zero_dev *dev = ep->driver_data; + + ERROR (dev, "start %s --> %d\n", ep->name, status); + free_ep_req (ep, req); + req = 0; + } + + return req; +} + +static int +set_source_sink_config (struct zero_dev *dev, int gfp_flags) +{ + int result = 0; + struct usb_ep *ep; + struct usb_gadget *gadget = dev->gadget; + + gadget_for_each_ep (ep, gadget) { + const struct usb_endpoint_descriptor *d; + + /* one endpoint writes (sources) zeroes in (to the host) */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + if (source_sink_start_ep (ep, gfp_flags) != 0) { + dev->in_ep = ep; + continue; + } + usb_ep_disable (ep); + result = -EIO; + } + + /* one endpoint reads (sinks) anything out (from the host) */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + if (source_sink_start_ep (ep, gfp_flags) != 0) { + dev->out_ep = ep; + continue; + } + usb_ep_disable (ep); + result = -EIO; + } + + /* ignore any other endpoints */ + } else + continue; + + /* stop on error */ + ERROR (dev, "can't start %s, result %d\n", ep->name, result); + break; + } + if (result == 0) + DEBUG (dev, "buflen %d\n", buflen); + + /* caller is responsible for cleanup on error */ + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void loopback_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct zero_dev *dev = ep->driver_data; + int status = req->status; + + switch (status) { + + case 0: /* normal completion? */ + if (ep == dev->out_ep) { + /* loop this OUT packet back IN to the host */ + req->zero = (req->actual < req->length); + req->length = req->actual; + status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); + if (status == 0) + return; + + /* "should never get here" */ + ERROR (dev, "can't loop %s to %s: %d\n", + ep->name, dev->in_ep->name, + status); + } + + /* queue the buffer for some later OUT packet */ + req->length = buflen; + status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC); + if (status == 0) + return; + + /* "should never get here" */ + /* FALLTHROUGH */ + + default: + ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); + /* FALLTHROUGH */ + + /* NOTE: since this driver doesn't maintain an explicit record + * of requests it submitted (just maintains qlen count), we + * rely on the hardware driver to clean up on disconnect or + * endpoint disable. + */ + case -ESHUTDOWN: /* disconnect from host */ + free_ep_req (ep, req); + return; + } +} + +static int +set_loopback_config (struct zero_dev *dev, int gfp_flags) +{ + int result = 0; + struct usb_ep *ep; + struct usb_gadget *gadget = dev->gadget; + + gadget_for_each_ep (ep, gadget) { + const struct usb_endpoint_descriptor *d; + + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + dev->in_ep = ep; + continue; + } + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable (ep, d); + if (result == 0) { + ep->driver_data = dev; + dev->out_ep = ep; + continue; + } + + /* ignore any other endpoints */ + } else + continue; + + /* stop on error */ + ERROR (dev, "can't enable %s, result %d\n", ep->name, result); + break; + } + + /* allocate a bunch of read buffers and queue them all at once. + * we buffer at most 'qlen' transfers; fewer if any need more + * than 'buflen' bytes each. + */ + if (result == 0) { + struct usb_request *req; + unsigned i; + + ep = dev->out_ep; + for (i = 0; i < qlen && result == 0; i++) { + req = alloc_ep_req (ep, buflen); + if (req) { + req->complete = loopback_complete; + result = usb_ep_queue (ep, req, GFP_ATOMIC); + if (result) + DEBUG (dev, "%s queue req --> %d\n", + ep->name, result); + } else + result = -ENOMEM; + } + } + if (result == 0) + DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen); + + /* caller is responsible for cleanup on error */ + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void zero_reset_config (struct zero_dev *dev) +{ + if (dev->config == 0) + return; + + DEBUG (dev, "reset config\n"); + + /* just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + if (dev->in_ep) { + usb_ep_disable (dev->in_ep); + dev->in_ep = 0; + } + if (dev->out_ep) { + usb_ep_disable (dev->out_ep); + dev->out_ep = 0; + } + dev->config = 0; +} + +/* change our operational config. this code must agree with the code + * that returns config descriptors, and altsetting code. + * + * it's also responsible for power management interactions. some + * configurations might not work with our current power sources. + * + * note that some device controller hardware will constrain what this + * code can do, perhaps by disallowing more than one configuration or + * by limiting configuration choices (like the pxa250). + */ +static int +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + + if (number == dev->config) + return 0; + +#ifdef CONFIG_USB_ZERO_SA1100 + if (dev->config) { + /* tx fifo is full, but we can't clear it...*/ + INFO (dev, "can't change configurations\n"); + return -ESPIPE; + } +#endif + zero_reset_config (dev); + hw_optimize (gadget); + + switch (number) { + case CONFIG_SOURCE_SINK: + result = set_source_sink_config (dev, gfp_flags); + break; + case CONFIG_LOOPBACK: + result = set_loopback_config (dev, gfp_flags); + break; + default: + result = -EINVAL; + /* FALL THROUGH */ + case 0: + return result; + } + + if (!result && (!dev->in_ep || !dev->out_ep)) + result = -ENODEV; + if (result) + zero_reset_config (dev); + else { + char *speed; + + switch (gadget->speed) { + case USB_SPEED_LOW: speed = "low"; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + default: speed = "?"; break; + } + + dev->config = number; + INFO (dev, "%s speed config #%d: %s\n", speed, number, + (number == CONFIG_SOURCE_SINK) + ? source_sink : loopback); + } + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DEBUG ((struct zero_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver (like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config-specific setup. + */ +static int +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct zero_dev *dev = get_gadget_data (gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + + /* usually this stores reply data in the pre-allocated ep0 buffer, + * but config change events will reconfigure hardware. + */ + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + if (ctrl->bRequestType != USB_DIR_IN) + break; + switch (ctrl->wValue >> 8) { + + case USB_DT_DEVICE: + value = min (ctrl->wLength, (u16) sizeof device_desc); + memcpy (req->buf, &device_desc, value); + break; +#ifdef HIGHSPEED + case USB_DT_DEVICE_QUALIFIER: + value = min (ctrl->wLength, (u16) sizeof dev_qualifier); + memcpy (req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + // FALLTHROUGH +#endif /* HIGHSPEED */ + case USB_DT_CONFIG: + value = config_buf (gadget->speed, req->buf, + ctrl->wValue >> 8, + ctrl->wValue & 0xff); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + + case USB_DT_STRING: + /* wIndex == language code. + * this driver only handles one language, you can + * add others even if they don't use iso8859/1 + */ + value = usb_gadget_get_string (&stringtab, + ctrl->wValue & 0xff, req->buf); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + } + break; + + /* currently two configs, two speeds */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + break; + spin_lock (&dev->lock); + /* change hardware configuration! + * no response queued, just zero status == success + */ + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + break; + *(u8 *)req->buf = dev->config; + value = min (ctrl->wLength, (u16) 1); + break; + + /* until we add altsetting support, or other interfaces, + * only 0/0 are possible. + */ + case USB_REQ_SET_INTERFACE: + if (ctrl->bRequestType != USB_RECIP_INTERFACE) + break; + spin_lock (&dev->lock); + if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) { + u8 config = dev->config; + + /* resets interface configuration, forgets about + * previous transaction state (queued bufs, etc) + * and re-inits endpoint state (toggle etc) + * no response queued, just zero status == success. + * if we had more than one interface we couldn't + * use this "reset the config" shortcut. + */ + zero_reset_config (dev); + zero_set_config (dev, config, GFP_ATOMIC); + value = 0; + } + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_INTERFACE: + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) + break; + if (!dev->config) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + *(u8 *)req->buf = 0; + value = min (ctrl->wLength, (u16) 1); + break; + + default: + VDEBUG (dev, + "unknown control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + } + + /* respond with data transfer before status phase? */ + if (value > 0) { + req->length = value; + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DEBUG (dev, "ep_queue --> %d\n", value); + req->status = 0; + zero_setup_complete (gadget->ep0, req); + } + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void +zero_disconnect (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + unsigned long flags; + + spin_lock_irqsave (&dev->lock, flags); + zero_reset_config (dev); + + /* a more significant application might have some non-usb + * activities to quiesce here, saving resources like power + * or pushing the notification up a network stack. + */ + spin_unlock_irqrestore (&dev->lock, flags); + + /* next we may get setup() calls to enumerate new connections; + * or an unbind() during shutdown (including removing module). + */ +} + +/*-------------------------------------------------------------------------*/ + +static void +zero_unbind (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + DEBUG (dev, "unbind\n"); + + /* we've already been disconnected ... no i/o is active */ + if (dev->req) + free_ep_req (gadget->ep0, dev->req); + kfree (dev); + set_gadget_data (gadget, 0); +} + +static int +zero_bind (struct usb_gadget *gadget) +{ + struct zero_dev *dev; + + dev = kmalloc (sizeof *dev, SLAB_KERNEL); + if (!dev) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + spin_lock_init (&dev->lock); + dev->gadget = gadget; + set_gadget_data (gadget, dev); + + /* preallocate control response and buffer */ + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); + if (!dev->req) + goto enomem; + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) + goto enomem; + + dev->req->complete = zero_setup_complete; + + gadget->ep0->driver_data = dev; + + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); + return 0; + +enomem: + zero_unbind (gadget); + return -ENOMEM; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver zero_driver = { +#ifdef HIGHSPEED + .speed = USB_SPEED_HIGH, +#else + .speed = USB_SPEED_FULL, +#endif + .function = (char *) longname, + .bind = zero_bind, + .unbind = zero_unbind, + + .setup = zero_setup, + .disconnect = zero_disconnect, + + .driver = { + .name = (char *) shortname, + // .shutdown = ... + // .suspend = ... + // .resume = ... + }, +}; + +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("Dual BSD/GPL"); + + +static int __init init (void) +{ + /* a real value would likely come through some id prom + * or module option. this one takes at least two packets. + */ + strncpy (serial, "0123456789.0123456789.0123456789", sizeof serial); + serial [sizeof serial - 1] = 0; + + return usb_gadget_register_driver (&zero_driver); +} +module_init (init); + +static void __exit cleanup (void) +{ + usb_gadget_unregister_driver (&zero_driver); +} +module_exit (cleanup); + diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/host/ehci-hcd.c Mon May 12 20:55:47 2003 @@ -116,8 +116,10 @@ #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ +#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ +#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ /* Initial IRQ latency: lower than default */ static int log2_irq_thresh = 0; // 0 to 6 @@ -266,16 +268,13 @@ } } + /* stop async processing after it's idled a bit */ + if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) + start_unlink_async (ehci, ehci->async); + + /* ehci could run by timer, without IRQs ... */ ehci_work (ehci, NULL); - if (ehci->reclaim && !timer_pending (&ehci->watchdog)) - mod_timer (&ehci->watchdog, - jiffies + EHCI_WATCHDOG_JIFFIES); - /* stop async processing after it's idled a while */ - else if (ehci->async_idle) { - start_unlink_async (ehci, ehci->async); - ehci->async_idle = 0; - } spin_unlock_irqrestore (&ehci->lock, flags); } @@ -658,11 +657,18 @@ */ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) { + timer_action_done (ehci, TIMER_IO_WATCHDOG); if (ehci->reclaim_ready) end_unlink_async (ehci, regs); scan_async (ehci, regs); if (ehci->next_uframe != -1) scan_periodic (ehci, regs); + + /* the IO watchdog guards against hardware or driver bugs that + * misplace IRQs, and should let us run completely without IRQs. + */ + if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0)) + timer_action (ehci, TIMER_IO_WATCHDOG); } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Mon May 12 20:55:48 2003 +++ b/drivers/usb/host/ehci-q.c Mon May 12 20:55:48 2003 @@ -706,8 +706,7 @@ /* (re)start the async schedule? */ head = ehci->async; - if (ehci->async_idle) - del_timer (&ehci->watchdog); + timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { u32 cmd = readl (&ehci->regs->command); @@ -733,8 +732,6 @@ qh->qh_state = QH_STATE_LINKED; /* qtd completions reported later by interrupt */ - - ehci->async_idle = 0; } /*-------------------------------------------------------------------------*/ @@ -915,7 +912,7 @@ struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - del_timer (&ehci->watchdog); + timer_action_done (ehci, TIMER_IAA_WATCHDOG); // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -940,12 +937,8 @@ * active but idle for a while once it empties. */ if (HCD_IS_RUNNING (ehci->hcd.state) - && ehci->async->qh_next.qh == 0 - && !timer_pending (&ehci->watchdog)) { - ehci->async_idle = 1; - mod_timer (&ehci->watchdog, - jiffies + EHCI_ASYNC_JIFFIES); - } + && ehci->async->qh_next.qh == 0) + timer_action (ehci, TIMER_ASYNC_OFF); } if (next) @@ -980,6 +973,7 @@ wmb (); // handshake later, if we need to } + timer_action_done (ehci, TIMER_ASYNC_OFF); return; } @@ -1005,9 +999,8 @@ ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); - /* posted write need not be known to HC yet ... */ - - mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES); + (void) readl (&ehci->regs->command); + timer_action (ehci, TIMER_IAA_WATCHDOG); } /*-------------------------------------------------------------------------*/ @@ -1016,10 +1009,11 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) { struct ehci_qh *qh; - int unlink_delay = 0; + enum ehci_timer_action action = TIMER_IO_WATCHDOG; if (!++(ehci->stamp)) ehci->stamp++; + timer_action_done (ehci, TIMER_ASYNC_SHRINK); rescan: qh = ehci->async->qh_next.qh; if (likely (qh != 0)) { @@ -1051,17 +1045,14 @@ */ if (list_empty (&qh->qtd_list)) { if (qh->stamp == ehci->stamp) - unlink_delay = 1; - else if (!ehci->reclaim) { + action = TIMER_ASYNC_SHRINK; + else if (!ehci->reclaim) start_unlink_async (ehci, qh); - unlink_delay = 0; - } } qh = qh->qh_next.qh; } while (qh); } - - if (unlink_delay && !timer_pending (&ehci->watchdog)) - mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES/2); + if (action == TIMER_ASYNC_SHRINK) + timer_action (ehci, TIMER_ASYNC_SHRINK); } diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h Mon May 12 20:55:48 2003 +++ b/drivers/usb/host/ehci.h Mon May 12 20:55:48 2003 @@ -52,8 +52,7 @@ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; - int reclaim_ready : 1, - async_idle : 1; + int reclaim_ready : 1; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */ @@ -83,6 +82,7 @@ struct timer_list watchdog; struct notifier_block reboot_notifier; + unsigned long actions; unsigned stamp; /* irq statistics */ @@ -99,6 +99,53 @@ /* NOTE: urb->transfer_flags expected to not use this bit !!! */ #define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */ + +enum ehci_timer_action { + TIMER_IO_WATCHDOG, + TIMER_IAA_WATCHDOG, + TIMER_ASYNC_SHRINK, + TIMER_ASYNC_OFF, +}; + +static inline void +timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action) +{ + clear_bit (action, &ehci->actions); +} + +static inline void +timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) +{ + if (!test_and_set_bit (action, &ehci->actions)) { + unsigned long t; + + switch (action) { + case TIMER_IAA_WATCHDOG: + t = EHCI_IAA_JIFFIES; + break; + case TIMER_IO_WATCHDOG: + t = EHCI_IO_JIFFIES; + break; + case TIMER_ASYNC_OFF: + t = EHCI_ASYNC_JIFFIES; + break; + // case TIMER_ASYNC_SHRINK: + default: + t = EHCI_SHRINK_JIFFIES; + break; + } + t += jiffies; + // all timings except IAA watchdog can be overridden. + // async queue SHRINK often precedes IAA. while it's ready + // to go OFF neither can matter, and afterwards the IO + // watchdog stops unless there's still periodic traffic. + if (action != TIMER_IAA_WATCHDOG + && t > ehci->watchdog.expires + && timer_pending (&ehci->watchdog)) + return; + mod_timer (&ehci->watchdog, t); + } +} /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c --- a/drivers/usb/image/mdc800.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/image/mdc800.c Mon May 12 20:55:47 2003 @@ -118,12 +118,8 @@ #define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND #define TO_GET_READY TO_DEFAULT_COMMAND -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define MDC800_DEVICE_MINOR_BASE 0 -#else /* Minor Number of the device (create with mknod /dev/mustek c 180 32) */ #define MDC800_DEVICE_MINOR_BASE 32 -#endif /************************************************************************** @@ -401,6 +397,13 @@ static struct usb_driver mdc800_usb_driver; static struct file_operations mdc800_device_ops; +static struct usb_class_driver mdc800_class = { + .name = "usb/mdc800%d", + .fops = &mdc800_device_ops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = MDC800_DEVICE_MINOR_BASE, +}; + /* * Callback to search the Mustek MDC800 on the USB Bus @@ -477,8 +480,8 @@ down (&mdc800->io_lock); - retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, 1, &mdc800->minor); - if (retval && (retval != -ENODEV)) { + retval = usb_register_dev(intf, &mdc800_class); + if (retval) { err ("Not able to get a minor for this device."); return -ENODEV; } @@ -540,7 +543,7 @@ if (mdc800->state == NOT_CONNECTED) return; - usb_deregister_dev (1, mdc800->minor); + usb_deregister_dev(intf, &mdc800_class); mdc800->state=NOT_CONNECTED; diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c --- a/drivers/usb/image/scanner.c Mon May 12 20:55:45 2003 +++ b/drivers/usb/image/scanner.c Mon May 12 20:55:45 2003 @@ -397,7 +397,6 @@ */ -#include #include /* @@ -464,7 +463,7 @@ dbg("open_scanner: scn_minor:%d", scn_minor); - intf = usb_find_interface(&scanner_driver, mk_kdev(USB_MAJOR,scn_minor)); + intf = usb_find_interface(&scanner_driver, scn_minor); if (!intf) { up(&scn_mutex); err("open_scanner(%d): Unable to access minor data", scn_minor); @@ -843,9 +842,6 @@ kfree(scn->ibuf); kfree(scn->obuf); - dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor); - devfs_remove("usb/scanner%d", scn->scn_minor - SCN_BASE_MNR); - usb_deregister_dev(1, scn->scn_minor); usb_free_urb(scn->scn_irq); usb_put_dev(scn->scn_dev); up (&(scn->sem)); @@ -867,6 +863,13 @@ .release = close_scanner, }; +static struct usb_class_driver scanner_class = { + .name = "usb/scanner%d", + .fops = &usb_scanner_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, + .minor_base = SCN_BASE_MNR, +}; + static int probe_scanner(struct usb_interface *intf, const struct usb_device_id *id) @@ -878,7 +881,6 @@ int ep_cnt; int ix; - int scn_minor; int retval; char valid_device = 0; @@ -1011,14 +1013,14 @@ down(&scn_mutex); - retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, 1, &scn_minor); + retval = usb_register_dev(intf, &scanner_class); if (retval) { err ("Not able to get a minor for this device."); up(&scn_mutex); return -ENOMEM; } - dbg("probe_scanner: Allocated minor:%d", scn_minor); + dbg("probe_scanner: Allocated minor:%d", intf->minor); if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) { err("probe_scanner: Out of memory."); @@ -1038,11 +1040,11 @@ init_MUTEX(&(scn->sem)); /* Initializes to unlocked */ - dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn); + dbg ("probe_scanner(%d): Address of scn:%p", intf->minor, scn); /* Ok, if we detected an interrupt EP, setup a handler for it */ if (have_intr) { - dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr); + dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", intf->minor, have_intr); usb_fill_int_urb(scn->scn_irq, dev, usb_rcvintpipe(dev, have_intr), &scn->button, 1, irq_scanner, scn, @@ -1050,7 +1052,7 @@ 250); if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) { - err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor); + err("probe_scanner(%d): Unable to allocate INT URB.", intf->minor); kfree(scn); up(&scn_mutex); return -ENOMEM; @@ -1060,21 +1062,21 @@ /* Ok, now initialize all the relevant values */ if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { - err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor); + err("probe_scanner(%d): Not enough memory for the output buffer.", intf->minor); kfree(scn); up(&scn_mutex); return -ENOMEM; } - dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf); + dbg("probe_scanner(%d): obuf address:%p", intf->minor, scn->obuf); if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { - err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor); + err("probe_scanner(%d): Not enough memory for the input buffer.", intf->minor); kfree(scn->obuf); kfree(scn); up(&scn_mutex); return -ENOMEM; } - dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf); + dbg("probe_scanner(%d): ibuf address:%p", intf->minor, scn->ibuf); switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */ @@ -1101,17 +1103,9 @@ scn->intr_ep = have_intr; scn->present = 1; scn->scn_dev = dev; - scn->scn_minor = scn_minor; + scn->scn_minor = intf->minor; scn->isopen = 0; - sprintf(name, "usb/scanner%d", scn->scn_minor - SCN_BASE_MNR); - - devfs_register(NULL, name, - DEVFS_FL_DEFAULT, USB_MAJOR, - scn->scn_minor, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL); - info ("USB scanner device (0x%04x/0x%04x) now attached to %s", dev->descriptor.idVendor, dev->descriptor.idProduct, name); @@ -1119,9 +1113,6 @@ usb_set_intfdata(intf, scn); - /* add device id so the device works when advertised */ - intf->kdev = mk_kdev(USB_MAJOR,scn->scn_minor); - return 0; } @@ -1130,8 +1121,9 @@ { struct scn_usb_data *scn = usb_get_intfdata(intf); - /* remove device id to disable open() */ - intf->kdev = NODEV; + /* disable open() */ + dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor); + usb_deregister_dev(intf, &scanner_class); usb_set_intfdata(intf, NULL); if(scn->intr_ep) { diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h --- a/drivers/usb/image/scanner.h Mon May 12 20:55:46 2003 +++ b/drivers/usb/image/scanner.h Mon May 12 20:55:46 2003 @@ -323,13 +323,7 @@ USB - Vivid III */ #define SCN_CLASS_SCANJET 16 -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define SCN_MAX_MNR 256 -#define SCN_BASE_MNR 0 -#else -#define SCN_MAX_MNR 16 /* We're allocated 16 minors */ #define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */ -#endif static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */ diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/input/hiddev.c Mon May 12 20:55:46 2003 @@ -53,6 +53,7 @@ wait_queue_head_t wait; struct hid_device *hid; struct hiddev_list *list; + struct usb_interface intf; }; struct hiddev_list { @@ -226,10 +227,10 @@ /* * De-allocate a hiddev structure */ +static struct usb_class_driver hiddev_class; static void hiddev_cleanup(struct hiddev *hiddev) { - devfs_remove("usb/hid/hiddev%d", hiddev->minor); - usb_deregister_dev(1, hiddev->minor); + usb_deregister_dev(&hiddev->intf, &hiddev_class); hiddev_table[hiddev->minor] = NULL; kfree(hiddev); } @@ -675,15 +676,21 @@ .fasync = hiddev_fasync, }; +static struct usb_class_driver hiddev_class = { + .name = "usb/hid/hiddev%d", + .fops = &hiddev_fops, + .mode = S_IFCHR | S_IRUGO | S_IWUSR, + .minor_base = HIDDEV_MINOR_BASE, +}; + /* * This is where hid.c calls us to connect a hid device to the hiddev driver */ int hiddev_connect(struct hid_device *hid) { struct hiddev *hiddev; - int minor, i; + int i; int retval; - char devfs_name[24]; for (i = 0; i < hid->maxcollection; i++) if (hid->collection[i].type == @@ -694,31 +701,25 @@ if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0) return -1; - retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor); - if (retval) { - err("Not able to get a minor for this device."); + if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; - } + memset(hiddev, 0, sizeof(struct hiddev)); - if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) { - usb_deregister_dev (1, minor); + retval = usb_register_dev(&hiddev->intf, &hiddev_class); + if (retval) { + err("Not able to get a minor for this device."); return -1; } - memset(hiddev, 0, sizeof(struct hiddev)); init_waitqueue_head(&hiddev->wait); - hiddev->minor = minor; - hiddev_table[minor - HIDDEV_MINOR_BASE] = hiddev; + hiddev->minor = hiddev->intf.minor; + hiddev_table[hiddev->intf.minor - HIDDEV_MINOR_BASE] = hiddev; hiddev->hid = hid; hiddev->exist = 1; - sprintf(devfs_name, "usb/hid/hiddev%d", minor); - devfs_register(NULL, devfs_name, 0, - USB_MAJOR, minor + HIDDEV_MINOR_BASE, - S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL); - hid->minor = minor; + hid->minor = hiddev->intf.minor; hid->hiddev = hiddev; return 0; diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/input/xpad.c Mon May 12 20:55:46 2003 @@ -61,7 +61,6 @@ #include #include #include -#include #include #define DRIVER_VERSION "v0.0.5" diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c --- a/drivers/usb/media/dabusb.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/media/dabusb.c Mon May 12 20:55:47 2003 @@ -712,12 +712,19 @@ .release = dabusb_release, }; +static struct usb_class_driver dabusb_class = { + .name = "usb/dabusb%d", + .fops = &dabusb_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = DABUSB_MINOR, +}; + + /* --------------------------------------------------------------------- */ static int dabusb_probe (struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usbdev = interface_to_usbdev(intf); - int devnum; int retval; pdabusb_t s; @@ -731,16 +738,16 @@ if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999) return -ENODEV; - retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, 1, &devnum); + retval = usb_register_dev(intf, &dabusb_class); if (retval) return -ENOMEM; - s = &dabusb[devnum]; + s = &dabusb[intf->minor]; down (&s->mutex); s->remove_pending = 0; s->usbdev = usbdev; - s->devnum = devnum; + s->devnum = intf->minor; if (usb_set_configuration (usbdev, usbdev->config[0].desc.bConfigurationValue) < 0) { err("set_configuration failed"); @@ -778,7 +785,7 @@ usb_set_intfdata (intf, NULL); if (s) { - usb_deregister_dev (1, s->devnum); + usb_deregister_dev (intf, &dabusb_class); s->remove_pending = 1; wake_up (&s->wait); if (s->state == _started) diff -Nru a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h --- a/drivers/usb/media/dabusb.h Mon May 12 20:55:44 2003 +++ b/drivers/usb/media/dabusb.h Mon May 12 20:55:44 2003 @@ -6,11 +6,7 @@ unsigned int pipe; }bulk_transfer_t,*pbulk_transfer_t; -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define DABUSB_MINOR 0 -#else #define DABUSB_MINOR 240 /* some unassigned USB minor */ -#endif #define DABUSB_VERSION 0x1000 #define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t) #define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int) diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Mon May 12 20:55:45 2003 +++ b/drivers/usb/media/vicam.c Mon May 12 20:55:45 2003 @@ -1101,28 +1101,6 @@ ((struct vicam_camera *)data)->gain); } -static int vicam_write_proc_shutter(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct vicam_camera *cam = (struct vicam_camera *)data; - - cam->shutter_speed = simple_strtoul(buffer, NULL, 10); - - return count; -} - -static int vicam_write_proc_gain(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct vicam_camera *cam = (struct vicam_camera *)data; - - cam->gain = simple_strtoul(buffer, NULL, 10); - - return count; -} - - - static void vicam_create_proc_root(void) { @@ -1164,21 +1142,17 @@ if ( !cam->proc_dir ) return; // We should probably return an error here ent = - create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); + create_proc_entry("shutter", S_IFREG | S_IRUGO, cam->proc_dir); if (ent) { ent->data = cam; ent->read_proc = vicam_read_proc_shutter; - ent->write_proc = vicam_write_proc_shutter; ent->size = 64; } - ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR, - cam->proc_dir); + ent = create_proc_entry("gain", S_IFREG | S_IRUGO , cam->proc_dir); if ( ent ) { ent->data = cam; ent->read_proc = vicam_read_proc_gain; - ent->write_proc = vicam_write_proc_gain; ent->size = 64; } } diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c --- a/drivers/usb/misc/auerswald.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/misc/auerswald.c Mon May 12 20:55:46 2003 @@ -29,7 +29,6 @@ #include #include #include -#include #undef DEBUG /* include debug macros until it's done */ #include @@ -60,16 +59,10 @@ /* Auerswald Vendor ID */ #define ID_AUERSWALD 0x09BF -#ifdef CONFIG_USB_DYNAMIC_MINORS -/* we can have up to 256 devices at once */ -#define AUER_MINOR_BASE 0 -#define AUER_MAX_DEVICES 256 -#else #define AUER_MINOR_BASE 112 /* auerswald driver minor number */ /* we can have up to this number of device plugged in at once */ #define AUER_MAX_DEVICES 16 -#endif /* Number of read buffers for each device */ @@ -256,12 +249,6 @@ wait_queue_head_t bufferwait; /* wait for a control buffer */ } auerswald_t,*pauerswald_t; -/* array of pointers to our devices that are currently connected */ -static pauerswald_t dev_table[AUER_MAX_DEVICES]; - -/* lock to protect the dev_table structure */ -static struct semaphore dev_table_mutex; - /* ................................................................... */ /* character device context */ typedef struct @@ -1384,29 +1371,29 @@ /* Open a new character device */ static int auerchar_open (struct inode *inode, struct file *file) { - int dtindex = minor(inode->i_rdev) - AUER_MINOR_BASE; + int dtindex = minor(inode->i_rdev); pauerswald_t cp = NULL; pauerchar_t ccp = NULL; + struct usb_interface *intf; int ret; /* minor number in range? */ - if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) { + if (dtindex < 0) { return -ENODEV; } - /* usb device available? */ - if (down_interruptible (&dev_table_mutex)) { - return -ERESTARTSYS; + intf = usb_find_interface(&auerswald_driver, dtindex); + if (!intf) { + return -ENODEV; } - cp = dev_table[dtindex]; + + /* usb device available? */ + cp = usb_get_intfdata (intf); if (cp == NULL) { - up (&dev_table_mutex); return -ENODEV; } if (down_interruptible (&cp->mutex)) { - up (&dev_table_mutex); return -ERESTARTSYS; } - up (&dev_table_mutex); /* we have access to the device. Now lets allocate memory */ ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); @@ -1895,6 +1882,13 @@ .release = auerchar_release, }; +static struct usb_class_driver auerswald_class = { + .name = "usb/auer%d", + .fops = &auerswald_fops, + .mode = S_IFCHR | S_IRUGO | S_IWUGO, + .minor_base = AUER_MINOR_BASE, +}; + /* --------------------------------------------------------------------- */ /* Special USB driver functions */ @@ -1923,7 +1917,6 @@ struct usb_device *usbdev = interface_to_usbdev(intf); pauerswald_t cp = NULL; DECLARE_WAIT_QUEUE_HEAD (wqh); - unsigned int dtindex; unsigned int u = 0; char *pbuf; int ret; @@ -1954,27 +1947,17 @@ auerbuf_init (&cp->bufctl); init_waitqueue_head (&cp->bufferwait); - down (&dev_table_mutex); - ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, 1, &dtindex); + ret = usb_register_dev(intf, &auerswald_class); if (ret) { err ("Not able to get a minor for this device."); - up (&dev_table_mutex); goto pfail; } /* Give the device a name */ - sprintf (cp->name, "usb/auer%d", dtindex); + sprintf (cp->name, "usb/auer%d", intf->minor); /* Store the index */ - cp->dtindex = dtindex; - dev_table[dtindex] = cp; - up (&dev_table_mutex); - - /* initialize the devfs node for this device and register it */ - devfs_register(NULL, cp->name, 0, USB_MAJOR, - AUER_MINOR_BASE + dtindex, - S_IFCHR | S_IRUGO | S_IWUGO, - &auerswald_fops, NULL); + cp->dtindex = intf->minor; /* Get the usb version of the device */ cp->version = cp->usbdev->descriptor.bcdDevice; @@ -2083,18 +2066,8 @@ down (&cp->mutex); info ("device /dev/%s now disconnecting", cp->name); - /* remove from device table */ - /* Nobody can open() this device any more */ - down (&dev_table_mutex); - dev_table[cp->dtindex] = NULL; - up (&dev_table_mutex); - - /* remove our devfs node */ - /* Nobody can see this device any more */ - devfs_remove(cp->name); - /* give back our USB minor number */ - usb_deregister_dev (1, cp->dtindex); + usb_deregister_dev(intf, &auerswald_class); /* Stop the interrupt endpoint */ auerswald_int_release (cp); @@ -2162,10 +2135,6 @@ { int result; dbg ("init"); - - /* initialize the device table */ - memset (&dev_table, 0, sizeof(dev_table)); - init_MUTEX (&dev_table_mutex); /* register driver at the USB subsystem */ result = usb_register (&auerswald_driver); diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c --- a/drivers/usb/misc/brlvger.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/misc/brlvger.c Mon May 12 20:55:46 2003 @@ -50,7 +50,6 @@ #include #include #include -#include #include MODULE_AUTHOR( DRIVER_AUTHOR ); @@ -180,12 +179,6 @@ /* Globals */ -/* Table of connected devices, a different minor for each. */ -static struct brlvger_priv *display_table[ MAX_NR_BRLVGER_DEVS ]; - -/* Mutex for the operation of removing a device from display_table */ -static DECLARE_MUTEX(disconnect_sem); - /* For blocking open */ static DECLARE_WAIT_QUEUE_HEAD(open_wait); @@ -237,6 +230,13 @@ .poll = brlvger_poll, }; +static struct usb_class_driver brlvger_class = { + .name = "usb/brlvger%d", + .fops = &brlvger_fops, + .mode = S_IFCHR | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = BRLVGER_MINOR, +}; + static struct usb_driver brlvger_driver = { .owner = THIS_MODULE, @@ -254,8 +254,6 @@ if(stall_tries < 1 || write_repeats < 1) return -EINVAL; - memset(display_table, 0, sizeof(display_table)); - if (usb_register(&brlvger_driver)) { err("USB registration failed"); return -ENOSYS; @@ -284,14 +282,12 @@ { struct usb_device *dev = interface_to_usbdev(intf); struct brlvger_priv *priv = NULL; - int i; int retval; struct usb_endpoint_descriptor *endpoint; struct usb_host_interface *actifsettings; /* protects against reentrance: once we've found a free slot we reserve it.*/ static DECLARE_MUTEX(reserve_sem); - char devfs_name[20]; actifsettings = dev->actconfig->interface->altsetting; @@ -311,7 +307,7 @@ down(&reserve_sem); - retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, 1, &i); + retval = usb_register_dev(intf, &brlvger_class); if (retval) { err("Not able to get a minor for this device."); goto error; @@ -331,7 +327,7 @@ init_MUTEX(&priv->open_sem); init_MUTEX(&priv->dev_sem); - priv->subminor = i; + priv->subminor = intf->minor; /* we found a interrupt in endpoint */ priv->in_interrupt = endpoint; @@ -372,17 +368,9 @@ }; dbg("Display length: %d", priv->plength); - sprintf(devfs_name, "usb/brlvger%d", priv->subminor); - devfs_register(NULL, devfs_name, - DEVFS_FL_DEFAULT, USB_MAJOR, - BRLVGER_MINOR+priv->subminor, - S_IFCHR |S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP, - &brlvger_fops, NULL); - - display_table[i] = priv; - + usb_set_intfdata (intf, priv); info( "Braille display %d is device major %d minor %d", - i, USB_MAJOR, BRLVGER_MINOR + i); + intf->minor, USB_MAJOR, BRLVGER_MINOR + intf->minor); /* Tell anyone waiting on a blocking open */ wake_up_interruptible(&open_wait); @@ -414,12 +402,7 @@ if(priv){ info("Display %d disconnecting", priv->subminor); - devfs_remove("usb/brlvger%d", priv->subminor); - usb_deregister_dev(1, priv->subminor); - - down(&disconnect_sem); - display_table[priv->subminor] = NULL; - up(&disconnect_sem); + usb_deregister_dev(intf, &brlvger_class); down(&priv->open_sem); down(&priv->dev_sem); @@ -450,21 +433,18 @@ brlvger_open(struct inode *inode, struct file *file) { int devnum = minor (inode->i_rdev); - struct brlvger_priv *priv; + struct usb_interface *intf = NULL; + struct brlvger_priv *priv = NULL; int n, ret; - if (devnum < BRLVGER_MINOR - || devnum >= (BRLVGER_MINOR + MAX_NR_BRLVGER_DEVS)) + if (devnum < 0) return -ENXIO; n = devnum - BRLVGER_MINOR; do { - down(&disconnect_sem); - priv = display_table[n]; - - if(!priv) { - up(&disconnect_sem); + intf = usb_find_interface(&brlvger_driver, devnum); + if (!intf) { if (file->f_flags & O_NONBLOCK) { dbg3("Failing non-blocking open: " "device %d not connected", n); @@ -475,19 +455,18 @@ minor is connected. */ dbg2("Waiting for device %d to be connected", n); ret = wait_event_interruptible(open_wait, - display_table[n] - != NULL); - if(ret) { + (intf = usb_find_interface(&brlvger_driver, devnum))); + if (ret) { dbg2("Interrupted wait for device %d", n); return ret; } } - } while(!priv); - /* We grabbed an existing device. */ + } while(!intf); + priv = usb_get_intfdata(intf); + /* We grabbed an existing device. */ if(down_interruptible(&priv->open_sem)) return -ERESTARTSYS; - up(&disconnect_sem); /* Only one process can open each device, no sharing. */ ret = -EBUSY; diff -Nru a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c --- a/drivers/usb/misc/rio500.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/misc/rio500.c Mon May 12 20:55:47 2003 @@ -38,7 +38,6 @@ #include #include #include -#include #include "rio500_usb.h" @@ -49,11 +48,7 @@ #define DRIVER_AUTHOR "Cesar Miquel " #define DRIVER_DESC "USB Rio 500 driver" -#ifdef CONFIG_USB_DYNAMIC_MINORS - #define RIO_MINOR 0 -#else - #define RIO_MINOR 64 -#endif +#define RIO_MINOR 64 /* stall/wait timeout for rio */ #define NAK_TIMEOUT (HZ) @@ -68,7 +63,6 @@ unsigned int ifnum; /* Interface number of the USB device */ int isopen; /* nz if open */ int present; /* Device is present on the bus */ - int minor; /* minor number assigned to us */ char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ wait_queue_head_t wait_q; /* for timeouts */ @@ -444,6 +438,13 @@ .release = close_rio, }; +static struct usb_class_driver usb_rio_class = { + .name = "usb/rio500%d", + .fops = &usb_rio_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = RIO_MINOR, +}; + static int probe_rio(struct usb_interface *intf, const struct usb_device_id *id) { @@ -453,7 +454,7 @@ info("USB Rio found at address %d", dev->devnum); - retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, 1, &rio->minor); + retval = usb_register_dev(intf, &usb_rio_class); if (retval) { err("Not able to get a minor for this device."); return -ENOMEM; @@ -464,23 +465,19 @@ if (!(rio->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) { err("probe_rio: Not enough memory for the output buffer"); + usb_deregister_dev(intf, &usb_rio_class); return -ENOMEM; } dbg("probe_rio: obuf address:%p", rio->obuf); if (!(rio->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) { err("probe_rio: Not enough memory for the input buffer"); + usb_deregister_dev(intf, &usb_rio_class); kfree(rio->obuf); return -ENOMEM; } dbg("probe_rio: ibuf address:%p", rio->ibuf); - devfs_register(NULL, "usb/rio500", - DEVFS_FL_DEFAULT, USB_MAJOR, - RIO_MINOR, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP, &usb_rio_fops, NULL); - init_MUTEX(&(rio->lock)); usb_set_intfdata (intf, rio); @@ -493,8 +490,7 @@ usb_set_intfdata (intf, NULL); if (rio) { - devfs_remove("usb/rio500"); - usb_deregister_dev(1, rio->minor); + usb_deregister_dev(intf, &usb_rio_class); down(&(rio->lock)); if (rio->isopen) { diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c --- a/drivers/usb/misc/speedtch.c Mon May 12 20:55:49 2003 +++ b/drivers/usb/misc/speedtch.c Mon May 12 20:55:49 2003 @@ -74,6 +74,7 @@ #include #include #include +#include /* #define DEBUG 1 diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c --- a/drivers/usb/misc/tiglusb.c Mon May 12 20:55:44 2003 +++ b/drivers/usb/misc/tiglusb.c Mon May 12 20:55:44 2003 @@ -327,7 +327,6 @@ int minor = -1; int i; ptiglusb_t s; - char name[32]; dbg ("probing vendor id 0x%x, device id 0x%x", dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -371,12 +370,9 @@ up (&s->mutex); dbg ("bound to interface"); - sprintf (name, "ticables/usb/%d", s->minor); - dbg ("registering to devfs : major = %d, minor = %d, node = %s", - TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name); - devfs_register(NULL, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR, - TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO, - &tiglusb_fops, NULL); + devfs_mk_cdev(MKDEV(TIUSB_MAJOR, TIUSB_MINOR) + s->minor, + S_IFCHR | S_IRUGO | S_IWUGO, + "ticables/usb/%d", s->minor); /* Display firmware version */ info ("firmware revision %i.%02x", @@ -390,8 +386,6 @@ static void tiglusb_disconnect (struct usb_interface *intf) { - char name[32]; - ptiglusb_t s = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); @@ -408,7 +402,7 @@ s->dev = NULL; s->opened = 0; - devfs_remove (name, "ticables/usb/%d", s->minor); + devfs_remove("ticables/usb/%d", s->minor); info ("device %d removed", s->minor); diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c --- a/drivers/usb/misc/usblcd.c Mon May 12 20:55:44 2003 +++ b/drivers/usb/misc/usblcd.c Mon May 12 20:55:44 2003 @@ -34,7 +34,6 @@ struct lcd_usb_data { struct usb_device *lcd_dev; /* init: probe_lcd */ unsigned int ifnum; /* Interface number of the USB device */ - int minor; /* minor number for this device */ int isopen; /* nz if open */ int present; /* Device is present on the bus */ char *obuf, *ibuf; /* transfer buffers */ @@ -245,6 +244,13 @@ .release = close_lcd, }; +static struct usb_class_driver usb_lcd_class = { + .name = "usb/lcd%d", + .fops = &usb_lcd_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, + .minor_base = USBLCD_MINOR, +}; + static int probe_lcd(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); @@ -268,23 +274,25 @@ (i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF), dev->devnum); - retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, 1, &lcd->minor); + retval = usb_register_dev(intf, &usb_lcd_class); if (retval) { err("Not able to get a minor for this device."); return -ENOMEM; } - + lcd->present = 1; lcd->lcd_dev = dev; if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) { err("probe_lcd: Not enough memory for the output buffer"); + usb_deregister_dev(intf, &usb_lcd_class); return -ENOMEM; } dbg("probe_lcd: obuf address:%p", lcd->obuf); if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) { err("probe_lcd: Not enough memory for the input buffer"); + usb_deregister_dev(intf, &usb_lcd_class); kfree(lcd->obuf); return -ENOMEM; } @@ -300,7 +308,7 @@ usb_set_intfdata (intf, NULL); if (lcd) { - usb_deregister_dev(1, lcd->minor); + usb_deregister_dev(intf, &usb_lcd_class); if (lcd->isopen) { lcd->isopen = 0; diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Mon May 12 20:55:47 2003 +++ b/drivers/usb/net/rtl8150.c Mon May 12 20:55:47 2003 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -106,7 +105,6 @@ typedef struct rtl8150 rtl8150_t; -/* the global usb devfs handle */ unsigned long multicast_filter_limit = 32; static void fill_skb_pool(rtl8150_t *); @@ -160,7 +158,7 @@ clear_bit(RX_REG_SET, &dev->flags); } -static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) +static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) { int ret; @@ -537,7 +535,8 @@ warn("%s - device reset failed", __FUNCTION__); } /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ - dev->rx_creg = rcr = 0x9e; + rcr = 0x9e; /* bit7=1 attach Rx info at the end */ + dev->rx_creg = cpu_to_le16(rcr); tcr = 0xd8; cr = 0x0c; if (!(rcr & 0x80)) @@ -584,18 +583,18 @@ dev = netdev->priv; netif_stop_queue(netdev); if (netdev->flags & IFF_PROMISC) { - dev->rx_creg |= 0x0001; + dev->rx_creg |= cpu_to_le16(0x0001); info("%s: promiscuous mode", netdev->name); } else if ((netdev->mc_count > multicast_filter_limit) || (netdev->flags & IFF_ALLMULTI)) { - dev->rx_creg &= 0xfffe; - dev->rx_creg |= 0x0002; + dev->rx_creg &= cpu_to_le16(0xfffe); + dev->rx_creg |= cpu_to_le16(0x0002); info("%s: allmulti set", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ - dev->rx_creg &= 0x00fc; + dev->rx_creg &= cpu_to_le16(0x00fc); } - async_set_registers(dev, RCR, 2, &dev->rx_creg); + async_set_registers(dev, RCR, 2); netif_wake_queue(netdev); } diff -Nru a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c --- a/drivers/usb/serial/bus.c Mon May 12 20:55:49 2003 +++ b/drivers/usb/serial/bus.c Mon May 12 20:55:49 2003 @@ -23,18 +23,6 @@ #include "usb-serial.h" -static ssize_t show_dev (struct device *dev, char *buf) -{ - struct usb_serial_port *port= to_usb_serial_port(dev); - dev_t base; - - port = to_usb_serial_port(dev); - - base = MKDEV(SERIAL_TTY_MAJOR, port->number); - return sprintf(buf, "%04x\n", base); -} -static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - static int usb_serial_device_match (struct device *dev, struct device_driver *drv) { struct usb_serial_device_type *driver; @@ -88,10 +76,7 @@ } minor = port->number; - - tty_register_device (&usb_serial_tty_driver, minor); - device_create_file (dev, &dev_attr_dev); - + tty_register_device (&usb_serial_tty_driver, minor, dev); dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n", driver->name, minor, minor); diff -Nru a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c --- a/drivers/usb/serial/console.c Mon May 12 20:55:48 2003 +++ b/drivers/usb/serial/console.c Mon May 12 20:55:48 2003 @@ -133,7 +133,7 @@ co->cflag = cflag; /* grab the first serial port that happens to be connected */ - serial = usb_serial_get_by_minor (0); + serial = usb_serial_get_by_index(0); if (serial_paranoia_check (serial, __FUNCTION__)) { /* no device is connected yet, sorry :( */ err ("No USB device connected to ttyUSB0"); diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/serial/usb-serial.c Mon May 12 20:55:46 2003 @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2000 Peter Berger (pberger@brimson.com) * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com) * diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h --- a/drivers/usb/serial/usb-serial.h Mon May 12 20:55:49 2003 +++ b/drivers/usb/serial/usb-serial.h Mon May 12 20:55:49 2003 @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2002 + * Copyright (C) 1999 - 2003 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -280,7 +280,7 @@ #endif /* Functions needed by other parts of the usbserial core */ -extern struct usb_serial *usb_serial_get_by_minor (unsigned int minor); +extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); extern int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h --- a/drivers/usb/serial/visor.h Mon May 12 20:55:48 2003 +++ b/drivers/usb/serial/visor.h Mon May 12 20:55:48 2003 @@ -1,7 +1,7 @@ /* * USB HandSpring Visor driver * - * Copyright (C) 1999 - 2002 + * Copyright (C) 1999 - 2003 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Mon May 12 20:55:48 2003 +++ b/drivers/usb/storage/unusual_devs.h Mon May 12 20:55:48 2003 @@ -98,6 +98,18 @@ "Nex II Digital", US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), +/* Patch submitted by Philipp Friedrich */ +UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, + "Kyocera", + "Finecam S3x", + US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY), + +/* Patch submitted by Philipp Friedrich */ +UNUSUAL_DEV( 0x0482, 0x0101, 0x0100, 0x0100, + "Kyocera", + "Finecam S4", + US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY), + /* Reported by Paul Stewart * This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, @@ -237,14 +249,6 @@ US_SC_8070, US_PR_BULK, NULL, US_FL_FIX_INQUIRY | US_FL_START_STOP ), -/* Submitted by Lars Gemeinhardt - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0547, 0x2810, 0x0001, 0x0001, - "Mello", - "MP3 Player", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP), - /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, "Sony", @@ -626,6 +630,26 @@ US_SC_SCSI, US_PR_BULK, NULL, US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), +/* This Pentax still camera is not conformant + * to the USB storage specification: - + * - It does not like the INQUIRY command. So we must handle this command + * of the SCSI layer ourselves. + * Tested on Rev. 10.00 (0x1000) + * Submitted by James Courtier-Dutton + */ +UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, + "Pentax", + "Optio 2/3/400", + US_SC_8070, US_PR_CBI, NULL, + US_FL_FIX_INQUIRY ), + +/* Submitted by Per Winkvist */ +UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, + "Pentax", + "Optio S", + US_SC_8070, US_PR_CBI, NULL, + US_FL_FIX_INQUIRY ), + /* Submitted by Brian Hall * Needed for START_STOP flag */ UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, @@ -657,3 +681,13 @@ US_SC_SCSI, US_PR_SDDR55, NULL, US_FL_SINGLE_LUN), #endif + +/* Aiptek PocketCAM 3Mega + * Nicolas DUPEUX + */ +UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999, + "AIPTEK", + "PocketCAM 3Mega", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_MODE_XLATE | US_FL_START_STOP), + diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Mon May 12 20:55:46 2003 +++ b/drivers/usb/usb-skeleton.c Mon May 12 20:55:46 2003 @@ -1,7 +1,7 @@ /* - * USB Skeleton driver - 1.0 + * USB Skeleton driver - 1.1 * - * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,6 +18,7 @@ * * History: * + * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev() * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and * disconnect. Fix transfer amount in read(). Use * macros instead of magic numbers in probe(). Change @@ -47,7 +48,6 @@ #include #include #include -#include #include #include @@ -87,12 +87,8 @@ MODULE_DEVICE_TABLE (usb, skel_table); -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define USB_SKEL_MINOR_BASE 0 -#else /* Get a minor range for your devices from the usb maintainer */ #define USB_SKEL_MINOR_BASE 192 -#endif /* Structure to hold all of our device specific stuff */ struct usb_skel { @@ -153,16 +149,6 @@ * This also means that the kernel can decrement * the use-counter again before calling release() * or should the open() function fail. - * - * Not all device structures have an "owner" field - * yet. "struct file_operations" and "struct net_device" - * do, while "struct tty_driver" does not. If the struct - * has an "owner" field, then initialize it to the value - * THIS_MODULE and the kernel will handle all module - * locking for you automatically. Otherwise, you must - * increment the use-counter in the open() function - * and decrement it again in the release() function - * yourself. */ .owner = THIS_MODULE, @@ -173,6 +159,16 @@ .release = skel_release, }; +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver skell_class = { + .name = "usb/skel%d", + .fops = &skel_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + .minor_base = USB_SKEL_MINOR_BASE, +}; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver skel_driver = { @@ -236,8 +232,7 @@ /* prevent disconnects */ down (&disconnect_sem); - interface = usb_find_interface (&skel_driver, - mk_kdev(USB_MAJOR, subminor)); + interface = usb_find_interface (&skel_driver, subminor); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); @@ -508,7 +503,6 @@ struct usb_skel *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - int minor; size_t buffer_size; int i; int retval; @@ -521,7 +515,7 @@ return -ENODEV; } - retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, 1, &minor); + retval = usb_register_dev (intf, &skel_class); if (retval) { /* something prevented us from registering this driver */ err ("Not able to get a minor for this device."); @@ -539,7 +533,7 @@ init_MUTEX (&dev->sem); dev->udev = udev; dev->interface = interface; - dev->minor = minor; + dev->minor = intf->minor; /* set up the endpoint information */ /* check out the endpoints */ @@ -606,22 +600,9 @@ goto error; } - /* initialize the devfs node for this device and register it */ - sprintf(name, "usb/skel%d", dev->minor); - - devfs = devfs_register(NULL, name, - DEVFS_FL_DEFAULT, USB_MAJOR, - dev->minor, - S_IFCHR | S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP | S_IROTH, - &skel_fops, NULL); - /* let the user know what node this device is now attached to */ info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); - /* add device id so the device works when advertised */ - interface->kdev = mk_kdev(USB_MAJOR, dev->minor); - goto exit; error: @@ -629,7 +610,7 @@ dev = NULL; exit_minor: - usb_deregister_dev (1, minor); + usb_deregister_dev (intf, &skel_class); exit: if (dev) { @@ -667,16 +648,13 @@ down (&dev->sem); - /* remove device id to disable open() */ - interface->kdev = NODEV; + /* disable open() */ + interface->minor = -1; minor = dev->minor; - /* remove our devfs node */ - devfs_remove("usb/skel%d", dev->minor); - - /* give back our dynamic minor */ - usb_deregister_dev (1, minor); + /* give back our minor */ + usb_deregister_dev (intf, &skel_class); /* terminate an ongoing write */ if (atomic_read (&dev->write_busy)) { diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c --- a/drivers/video/fbmem.c Mon May 12 20:55:44 2003 +++ b/drivers/video/fbmem.c Mon May 12 20:55:44 2003 @@ -1214,7 +1214,6 @@ int register_framebuffer(struct fb_info *fb_info) { - char name_buf[12]; int i; if (num_registered_fb == FB_MAX) @@ -1242,10 +1241,9 @@ spin_lock_init(&fb_info->pixmap.lock); registered_fb[i] = fb_info; - sprintf(name_buf, "fb/%d", i); - devfs_register(NULL, name_buf, DEVFS_FL_DEFAULT, - FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, - &fb_fops, NULL); + + devfs_mk_cdev(MKDEV(FB_MAJOR, i), + S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); return 0; } diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig Mon May 12 20:55:47 2003 +++ b/fs/Kconfig Mon May 12 20:55:47 2003 @@ -73,6 +73,18 @@ If you don't know what Access Control Lists are, say N +config EXT2_FS_SECURITY + bool "Ext2 Security Labels" + depends on EXT2_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ext2 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. + config EXT3_FS tristate "Ext3 journalling file system support" help @@ -130,6 +142,18 @@ Linux website . If you don't know what Access Control Lists are, say N + +config EXT3_FS_SECURITY + bool "Ext3 Security Labels" + depends on EXT3_FS_XATTR + help + Security labels support alternative access control models + implemented by security modules like SELinux. This option + enables an extended attribute handler for file security + labels in the ext3 filesystem. + + If you are not using a security module that requires using + extended attributes for file security labels, say N. config JBD # CONFIG_JBD could be its own option (even modular), but until there are diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c --- a/fs/bfs/dir.c Mon May 12 20:55:48 2003 +++ b/fs/bfs/dir.c Mon May 12 20:55:48 2003 @@ -65,7 +65,7 @@ brelse(bh); } - UPDATE_ATIME(dir); + update_atime(dir); unlock_kernel(); return 0; } diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Mon May 12 20:55:46 2003 +++ b/fs/binfmt_elf.c Mon May 12 20:55:46 2003 @@ -1105,7 +1105,7 @@ i = p->state ? ffz(~p->state) + 1 : 0; psinfo->pr_state = i; - psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; + psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDTZW"[i]; psinfo->pr_zomb = psinfo->pr_sname == 'Z'; psinfo->pr_nice = task_nice(p); psinfo->pr_flag = p->flags; diff -Nru a/fs/bio.c b/fs/bio.c --- a/fs/bio.c Mon May 12 20:55:47 2003 +++ b/fs/bio.c Mon May 12 20:55:47 2003 @@ -728,6 +728,7 @@ } bio->bi_size -= bytes_done; + bio->bi_sector += (bytes_done >> 9); if (bio->bi_end_io) bio->bi_end_io(bio, bytes_done, error); diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Mon May 12 20:55:47 2003 +++ b/fs/buffer.c Mon May 12 20:55:47 2003 @@ -244,16 +244,26 @@ * sync everything. Start out by waking pdflush, because that writes back * all queues in parallel. */ -asmlinkage long sys_sync(void) +static void do_sync(unsigned long wait) { wakeup_bdflush(0); sync_inodes(0); /* All mappings, inodes and their blockdevs */ DQUOT_SYNC(NULL); sync_supers(); /* Write the superblocks */ sync_filesystems(0); /* Start syncing the filesystems */ - sync_filesystems(1); /* Waitingly sync the filesystems */ - sync_inodes(1); /* Mappings, inodes and blockdevs, again. */ + sync_filesystems(wait); /* Waitingly sync the filesystems */ + sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ +} + +asmlinkage long sys_sync(void) +{ + do_sync(1); return 0; +} + +void emergency_sync(void) +{ + pdflush_operation(do_sync, 0); } /* diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c Mon May 12 20:55:46 2003 +++ b/fs/cifs/cifs_debug.c Mon May 12 20:55:46 2003 @@ -56,7 +56,7 @@ } } -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS int cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, int count, int *eof, void *data) diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Mon May 12 20:55:47 2003 +++ b/fs/cifs/cifsfs.c Mon May 12 20:55:47 2003 @@ -465,7 +465,7 @@ init_cifs(void) { int rc = 0; -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS cifs_proc_init(); #endif INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ @@ -503,7 +503,7 @@ } cifs_destroy_inodecache(); } -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS cifs_proc_clean(); #endif return rc; @@ -513,7 +513,7 @@ exit_cifs(void) { cFYI(0, ("In unregister ie exit_cifs")); -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS cifs_proc_clean(); #endif unregister_filesystem(&cifs_fs_type); diff -Nru a/fs/coda/psdev.c b/fs/coda/psdev.c --- a/fs/coda/psdev.c Mon May 12 20:55:47 2003 +++ b/fs/coda/psdev.c Mon May 12 20:55:47 2003 @@ -373,16 +373,10 @@ } devfs_mk_dir ("coda"); for (i = 0; i < MAX_CODADEVS; i++) { - char name[16]; - sprintf(name, "coda/%d", i); - devfs_register(NULL, name, DEVFS_FL_NONE, - CODA_PSDEV_MAJOR, i, - S_IFCHR | S_IRUSR | S_IWUSR, - &coda_psdev_fops, NULL); + devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), + S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); } - coda_sysctl_init(); - return 0; } diff -Nru a/fs/coda/sysctl.c b/fs/coda/sysctl.c --- a/fs/coda/sysctl.c Mon May 12 20:55:45 2003 +++ b/fs/coda/sysctl.c Mon May 12 20:55:45 2003 @@ -244,7 +244,7 @@ } #endif -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS remove_proc_entry("cache_inv_stats", proc_fs_coda); remove_proc_entry("vfs_stats", proc_fs_coda); remove_proc_entry("coda", proc_root_fs); diff -Nru a/fs/dcache.c b/fs/dcache.c --- a/fs/dcache.c Mon May 12 20:55:44 2003 +++ b/fs/dcache.c Mon May 12 20:55:44 2003 @@ -770,12 +770,12 @@ void d_instantiate(struct dentry *entry, struct inode * inode) { if (!list_empty(&entry->d_alias)) BUG(); - security_d_instantiate(entry, inode); spin_lock(&dcache_lock); if (inode) list_add(&entry->d_alias, &inode->i_dentry); entry->d_inode = inode; spin_unlock(&dcache_lock); + security_d_instantiate(entry, inode); } /** @@ -903,12 +903,12 @@ struct dentry *new = NULL; if (inode && S_ISDIR(inode->i_mode)) { - security_d_instantiate(dentry, inode); spin_lock(&dcache_lock); if (!list_empty(&inode->i_dentry)) { new = list_entry(inode->i_dentry.next, struct dentry, d_alias); __dget_locked(new); spin_unlock(&dcache_lock); + security_d_instantiate(dentry, inode); d_rehash(dentry); d_move(new, dentry); iput(inode); @@ -917,6 +917,7 @@ list_add(&dentry->d_alias, &inode->i_dentry); dentry->d_inode = inode; spin_unlock(&dcache_lock); + security_d_instantiate(dentry, inode); d_rehash(dentry); } } else diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c --- a/fs/devfs/base.c Mon May 12 20:55:45 2003 +++ b/fs/devfs/base.c Mon May 12 20:55:45 2003 @@ -1562,6 +1562,52 @@ EXPORT_SYMBOL(devfs_mk_bdev); +int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) +{ + struct devfs_entry *dir = NULL, *de; + char buf[64]; + va_list args; + int error, n; + + if (!S_ISCHR(mode)) { + printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", + __FUNCTION__, mode, buf); + return -EINVAL; + } + + va_start(args, fmt); + n = vsnprintf(buf, 64, fmt, args); + if (n >= 64 || !buf[0]) { + printk(KERN_WARNING "%s: invalid format string\n", + __FUNCTION__); + return -EINVAL; + } + + de = _devfs_prepare_leaf(&dir, buf, mode); + if (!de) { + printk(KERN_WARNING "%s: could not prepare leaf for %s\n", + __FUNCTION__, buf); + return -ENOMEM; /* could be more accurate... */ + } + + de->u.cdev.dev = dev; + + error = _devfs_append_entry(dir, de, NULL); + if (error) { + printk(KERN_WARNING "%s: could not append to parent for %s\n", + __FUNCTION__, buf); + goto out; + } + + devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); + out: + devfs_put(dir); + return error; +} + +EXPORT_SYMBOL(devfs_mk_cdev); + + /** * _devfs_unhook - Unhook a device entry from its parents list * @de: The entry to unhook. diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile --- a/fs/ext2/Makefile Mon May 12 20:55:48 2003 +++ b/fs/ext2/Makefile Mon May 12 20:55:48 2003 @@ -14,3 +14,7 @@ ifeq ($(CONFIG_EXT2_FS_POSIX_ACL),y) ext2-objs += acl.o endif + +ifeq ($(CONFIG_EXT2_FS_SECURITY),y) +ext2-objs += xattr_security.o +endif diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c --- a/fs/ext2/dir.c Mon May 12 20:55:47 2003 +++ b/fs/ext2/dir.c Mon May 12 20:55:47 2003 @@ -310,7 +310,7 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; filp->f_version = inode->i_version; - UPDATE_ATIME(inode); + update_atime(inode); return 0; } diff -Nru a/fs/ext2/xattr.c b/fs/ext2/xattr.c --- a/fs/ext2/xattr.c Mon May 12 20:55:47 2003 +++ b/fs/ext2/xattr.c Mon May 12 20:55:47 2003 @@ -1102,22 +1102,33 @@ &ext2_xattr_trusted_handler); if (err) goto out; +#ifdef CONFIG_EXT2_FS_SECURITY + err = ext2_xattr_register(EXT2_XATTR_INDEX_SECURITY, + &ext2_xattr_security_handler); + if (err) + goto out1; +#endif #ifdef CONFIG_EXT2_FS_POSIX_ACL err = init_ext2_acl(); if (err) - goto out1; + goto out2; #endif ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL, sizeof(struct mb_cache_entry) + sizeof(struct mb_cache_entry_index), 1, 6); if (!ext2_xattr_cache) { err = -ENOMEM; - goto out2; + goto out3; } return 0; -out2: +out3: #ifdef CONFIG_EXT2_FS_POSIX_ACL exit_ext2_acl(); +out2: +#endif +#ifdef CONFIG_EXT2_FS_SECURITY + ext2_xattr_unregister(EXT2_XATTR_INDEX_SECURITY, + &ext2_xattr_security_handler); out1: #endif ext2_xattr_unregister(EXT2_XATTR_INDEX_TRUSTED, @@ -1134,6 +1145,10 @@ mb_cache_destroy(ext2_xattr_cache); #ifdef CONFIG_EXT2_FS_POSIX_ACL exit_ext2_acl(); +#endif +#ifdef CONFIG_EXT2_FS_SECURITY + ext2_xattr_unregister(EXT2_XATTR_INDEX_SECURITY, + &ext2_xattr_security_handler); #endif ext2_xattr_unregister(EXT2_XATTR_INDEX_TRUSTED, &ext2_xattr_trusted_handler); diff -Nru a/fs/ext2/xattr.h b/fs/ext2/xattr.h --- a/fs/ext2/xattr.h Mon May 12 20:55:47 2003 +++ b/fs/ext2/xattr.h Mon May 12 20:55:47 2003 @@ -22,6 +22,7 @@ #define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 #define EXT2_XATTR_INDEX_TRUSTED 4 +#define EXT2_XATTR_INDEX_SECURITY 6 struct ext2_xattr_header { __u32 h_magic; /* magic number for identification */ @@ -134,4 +135,5 @@ extern struct ext2_xattr_handler ext2_xattr_user_handler; extern struct ext2_xattr_handler ext2_xattr_trusted_handler; +extern struct ext2_xattr_handler ext2_xattr_security_handler; diff -Nru a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/xattr_security.c Mon May 12 20:55:49 2003 @@ -0,0 +1,54 @@ +/* + * linux/fs/ext2/xattr_security.c + * Handler for storing security labels as extended attributes. + */ + +#include +#include +#include +#include +#include +#include "xattr.h" + +#define XATTR_SECURITY_PREFIX "security." + +static size_t +ext2_xattr_security_list(char *list, struct inode *inode, + const char *name, int name_len) +{ + const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; + + if (list) { + memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return prefix_len + name_len + 1; +} + +static int +ext2_xattr_security_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext2_xattr_get(inode, EXT2_XATTR_INDEX_SECURITY, name, + buffer, size); +} + +static int +ext2_xattr_security_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY, name, + value, size, flags); +} + +struct ext2_xattr_handler ext2_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = ext2_xattr_security_list, + .get = ext2_xattr_security_get, + .set = ext2_xattr_security_set, +}; diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile --- a/fs/ext3/Makefile Mon May 12 20:55:44 2003 +++ b/fs/ext3/Makefile Mon May 12 20:55:44 2003 @@ -14,3 +14,7 @@ ifeq ($(CONFIG_EXT3_FS_POSIX_ACL),y) ext3-objs += acl.o endif + +ifeq ($(CONFIG_EXT3_FS_SECURITY),y) +ext3-objs += xattr_security.o +endif diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c --- a/fs/ext3/dir.c Mon May 12 20:55:47 2003 +++ b/fs/ext3/dir.c Mon May 12 20:55:47 2003 @@ -216,7 +216,7 @@ offset = 0; brelse (bh); } - UPDATE_ATIME(inode); + update_atime(inode); out: return ret; } @@ -489,7 +489,7 @@ } finished: info->last_pos = filp->f_pos; - UPDATE_ATIME(inode); + update_atime(inode); return 0; } diff -Nru a/fs/ext3/fsync.c b/fs/ext3/fsync.c --- a/fs/ext3/fsync.c Mon May 12 20:55:49 2003 +++ b/fs/ext3/fsync.c Mon May 12 20:55:49 2003 @@ -27,8 +27,6 @@ #include #include #include -#include -#include /* * akpm: A new design for ext3_sync_file(). diff -Nru a/fs/ext3/xattr.c b/fs/ext3/xattr.c --- a/fs/ext3/xattr.c Mon May 12 20:55:47 2003 +++ b/fs/ext3/xattr.c Mon May 12 20:55:47 2003 @@ -1142,22 +1142,33 @@ &ext3_xattr_trusted_handler); if (err) goto out; +#ifdef CONFIG_EXT3_FS_SECURITY + err = ext3_xattr_register(EXT3_XATTR_INDEX_SECURITY, + &ext3_xattr_security_handler); + if (err) + goto out1; +#endif #ifdef CONFIG_EXT3_FS_POSIX_ACL err = init_ext3_acl(); if (err) - goto out1; + goto out2; #endif ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, sizeof(struct mb_cache_entry) + sizeof(struct mb_cache_entry_index), 1, 6); if (!ext3_xattr_cache) { err = -ENOMEM; - goto out2; + goto out3; } return 0; -out2: +out3: #ifdef CONFIG_EXT3_FS_POSIX_ACL exit_ext3_acl(); +out2: +#endif +#ifdef CONFIG_EXT3_FS_SECURITY + ext3_xattr_unregister(EXT3_XATTR_INDEX_SECURITY, + &ext3_xattr_security_handler); out1: #endif ext3_xattr_unregister(EXT3_XATTR_INDEX_TRUSTED, @@ -1176,6 +1187,10 @@ ext3_xattr_cache = NULL; #ifdef CONFIG_EXT3_FS_POSIX_ACL exit_ext3_acl(); +#endif +#ifdef CONFIG_EXT3_FS_SECURITY + ext3_xattr_unregister(EXT3_XATTR_INDEX_SECURITY, + &ext3_xattr_security_handler); #endif ext3_xattr_unregister(EXT3_XATTR_INDEX_TRUSTED, &ext3_xattr_trusted_handler); diff -Nru a/fs/ext3/xattr.h b/fs/ext3/xattr.h --- a/fs/ext3/xattr.h Mon May 12 20:55:49 2003 +++ b/fs/ext3/xattr.h Mon May 12 20:55:49 2003 @@ -21,6 +21,7 @@ #define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 #define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 #define EXT3_XATTR_INDEX_TRUSTED 4 +#define EXT3_XATTR_INDEX_SECURITY 6 struct ext3_xattr_header { __u32 h_magic; /* magic number for identification */ @@ -141,3 +142,4 @@ extern struct ext3_xattr_handler ext3_xattr_user_handler; extern struct ext3_xattr_handler ext3_xattr_trusted_handler; +extern struct ext3_xattr_handler ext3_xattr_security_handler; diff -Nru a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/xattr_security.c Mon May 12 20:55:49 2003 @@ -0,0 +1,55 @@ +/* + * linux/fs/ext3/xattr_security.c + * Handler for storing security labels as extended attributes. + */ + +#include +#include +#include +#include +#include +#include +#include "xattr.h" + +#define XATTR_SECURITY_PREFIX "security." + +static size_t +ext3_xattr_security_list(char *list, struct inode *inode, + const char *name, int name_len) +{ + const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; + + if (list) { + memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + list[prefix_len + name_len] = '\0'; + } + return prefix_len + name_len + 1; +} + +static int +ext3_xattr_security_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name, + buffer, size); +} + +static int +ext3_xattr_security_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name, + value, size, flags); +} + +struct ext3_xattr_handler ext3_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .list = ext3_xattr_security_list, + .get = ext3_xattr_security_get, + .set = ext3_xattr_security_set, +}; diff -Nru a/fs/file_table.c b/fs/file_table.c --- a/fs/file_table.c Mon May 12 20:55:44 2003 +++ b/fs/file_table.c Mon May 12 20:55:44 2003 @@ -141,7 +141,7 @@ security_file_free(file); } -void fput(struct file * file) +void fput(struct file *file) { if (atomic_dec_and_test(&file->f_count)) __fput(file); @@ -189,6 +189,34 @@ spin_unlock(&files->file_lock); return file; } + +/* + * Lightweight file lookup - no refcnt increment if fd table isn't shared. + * You can use this only if it is guranteed that the current task already + * holds a refcnt to that file. That check has to be done at fget() only + * and a flag is returned to be passed to the corresponding fput_light(). + * There must not be a cloning between an fget_light/fput_light pair. + */ +struct file *fget_light(unsigned int fd, int *fput_needed) +{ + struct file *file; + struct files_struct *files = current->files; + + *fput_needed = 0; + if (likely((atomic_read(&files->count) == 1))) { + file = fcheck(fd); + } else { + spin_lock(&files->file_lock); + file = fcheck(fd); + if (file) { + get_file(file); + *fput_needed = 1; + } + spin_unlock(&files->file_lock); + } + return file; +} + void put_filp(struct file *file) { diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c --- a/fs/fs-writeback.c Mon May 12 20:55:49 2003 +++ b/fs/fs-writeback.c Mon May 12 20:55:49 2003 @@ -367,7 +367,8 @@ }; get_page_state(&ps); - wbc.nr_to_write = ps.nr_dirty + ps.nr_dirty / 4; + wbc.nr_to_write = ps.nr_dirty + ps.nr_unstable + + (ps.nr_dirty + ps.nr_unstable) / 4; spin_lock(&inode_lock); sync_sb_inodes(sb, &wbc); spin_unlock(&inode_lock); diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c --- a/fs/hugetlbfs/inode.c Mon May 12 20:55:48 2003 +++ b/fs/hugetlbfs/inode.c Mon May 12 20:55:48 2003 @@ -62,7 +62,7 @@ down(&inode->i_sem); - UPDATE_ATIME(inode); + update_atime(inode); vma->vm_flags |= VM_HUGETLB | VM_RESERVED; vma->vm_ops = &hugetlb_vm_ops; ret = hugetlb_prefault(mapping, vma); diff -Nru a/fs/intermezzo/methods.c b/fs/intermezzo/methods.c --- a/fs/intermezzo/methods.c Mon May 12 20:55:48 2003 +++ b/fs/intermezzo/methods.c Mon May 12 20:55:48 2003 @@ -145,7 +145,7 @@ { if ( strlen(cache_type) == strlen("ext2") && memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) { -#if CONFIG_EXT2_FS +#ifdef CONFIG_EXT2_FS ops->o_trops = &presto_ext2_journal_ops; #else ops->o_trops = NULL; diff -Nru a/fs/intermezzo/sysctl.c b/fs/intermezzo/sysctl.c --- a/fs/intermezzo/sysctl.c Mon May 12 20:55:45 2003 +++ b/fs/intermezzo/sysctl.c Mon May 12 20:55:45 2003 @@ -358,7 +358,7 @@ */ PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries); -#if CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS remove_proc_entry("mounts", proc_fs_intermezzo); remove_proc_entry("intermezzo", proc_root_fs); #endif diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c --- a/fs/jffs/inode-v23.c Mon May 12 20:55:47 2003 +++ b/fs/jffs/inode-v23.c Mon May 12 20:55:47 2003 @@ -55,7 +55,7 @@ #include "jffs_fm.h" #include "intrep.h" -#if CONFIG_JFFS_PROC_FS +#ifdef CONFIG_JFFS_PROC_FS #include "jffs_proc.h" #endif diff -Nru a/fs/lockd/host.c b/fs/lockd/host.c --- a/fs/lockd/host.c Mon May 12 20:55:47 2003 +++ b/fs/lockd/host.c Mon May 12 20:55:47 2003 @@ -187,15 +187,7 @@ host->h_nextrebind - jiffies); } } else { - uid_t saved_fsuid = current->fsuid; - kernel_cap_t saved_cap = current->cap_effective; - - /* Create RPC socket as root user so we get a priv port */ - current->fsuid = 0; - cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE); xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); - current->fsuid = saved_fsuid; - current->cap_effective = saved_cap; if (xprt == NULL) goto forgetit; @@ -209,6 +201,7 @@ } clnt->cl_autobind = 1; /* turn on pmap queries */ xprt->nocong = 1; /* No congestion control for NLM */ + xprt->resvport = 1; /* NLM requires a reserved port */ host->h_rpcclnt = clnt; } @@ -276,7 +269,7 @@ dprintk("lockd: nuking all hosts...\n"); for (i = 0; i < NLM_HOST_NRHASH; i++) { for (host = nlm_hosts[i]; host; host = host->h_next) - host->h_expires = 0; + host->h_expires = jiffies - 1; } /* Then, perform a garbage collection pass */ @@ -323,6 +316,9 @@ while ((host = *q) != NULL) { if (host->h_count || host->h_inuse || time_before(jiffies, host->h_expires)) { + dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n", + host->h_name, host->h_count, + host->h_inuse, host->h_expires); q = &host->h_next; continue; } diff -Nru a/fs/lockd/mon.c b/fs/lockd/mon.c --- a/fs/lockd/mon.c Mon May 12 20:55:48 2003 +++ b/fs/lockd/mon.c Mon May 12 20:55:48 2003 @@ -123,6 +123,7 @@ clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; + xprt->resvport = 1; /* NSM requires a reserved port */ out: return clnt; diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c --- a/fs/minix/dir.c Mon May 12 20:55:48 2003 +++ b/fs/minix/dir.c Mon May 12 20:55:48 2003 @@ -127,7 +127,7 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; - UPDATE_ATIME(inode); + update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Mon May 12 20:55:45 2003 +++ b/fs/namei.c Mon May 12 20:55:45 2003 @@ -405,7 +405,7 @@ goto loop; current->link_count++; current->total_link_count++; - UPDATE_ATIME(dentry->d_inode); + update_atime(dentry->d_inode); err = dentry->d_inode->i_op->follow_link(dentry, nd); current->link_count--; return err; @@ -1327,7 +1327,7 @@ error = security_inode_follow_link(dentry, nd); if (error) goto exit_dput; - UPDATE_ATIME(dentry->d_inode); + update_atime(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); if (error) diff -Nru a/fs/namespace.c b/fs/namespace.c --- a/fs/namespace.c Mon May 12 20:55:47 2003 +++ b/fs/namespace.c Mon May 12 20:55:47 2003 @@ -24,7 +24,6 @@ #include extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data); -extern int do_remount_sb(struct super_block *sb, int flags, void * data); extern int __init init_rootfs(void); extern int __init fs_subsys_init(void); @@ -326,7 +325,7 @@ down_write(&sb->s_umount); if (!(sb->s_flags & MS_RDONLY)) { lock_kernel(); - retval = do_remount_sb(sb, MS_RDONLY, 0); + retval = do_remount_sb(sb, MS_RDONLY, 0, 0); unlock_kernel(); } up_write(&sb->s_umount); @@ -555,7 +554,7 @@ return -EINVAL; down_write(&sb->s_umount); - err = do_remount_sb(sb, flags, data); + err = do_remount_sb(sb, flags, data, 0); if (!err) nd->mnt->mnt_flags=mnt_flags; up_write(&sb->s_umount); diff -Nru a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c --- a/fs/ncpfs/ncplib_kernel.c Mon May 12 20:55:46 2003 +++ b/fs/ncpfs/ncplib_kernel.c Mon May 12 20:55:46 2003 @@ -695,7 +695,7 @@ __u32 dirent; if (!inode) { -#if CONFIG_NCPFS_DEBUGDENTRY +#ifdef CONFIG_NCPFS_DEBUGDENTRY PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n"); #endif return 0xFF; /* Any error */ diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c Mon May 12 20:55:46 2003 +++ b/fs/nfs/dir.c Mon May 12 20:55:46 2003 @@ -83,7 +83,7 @@ lock_kernel(); /* Do cto revalidation */ - if (server->flags & NFS_MOUNT_NOCTO) + if (!(server->flags & NFS_MOUNT_NOCTO)) res = __nfs_revalidate_inode(server, inode); /* Call generic open code in order to cache credentials */ if (!res) diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c --- a/fs/nfs/file.c Mon May 12 20:55:47 2003 +++ b/fs/nfs/file.c Mon May 12 20:55:47 2003 @@ -83,7 +83,7 @@ if ((open = server->rpc_ops->file_open) != NULL) res = open(inode, filp); /* Do cto revalidation */ - else if (server->flags & NFS_MOUNT_NOCTO) + else if (!(server->flags & NFS_MOUNT_NOCTO)) res = __nfs_revalidate_inode(server, inode); /* Call generic open code in order to cache credentials */ if (!res) diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Mon May 12 20:55:48 2003 +++ b/fs/nfs/inode.c Mon May 12 20:55:48 2003 @@ -682,7 +682,7 @@ * such as stat(2) */ inode->i_ino = hash; - /* We can't support UPDATE_ATIME(), since the server will reset it */ + /* We can't support update_atime(), since the server will reset it */ inode->i_flags |= S_NOATIME; inode->i_mode = fattr->mode; /* Why so? Because we want revalidate for devices/FIFOs, and diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c --- a/fs/nfs/write.c Mon May 12 20:55:48 2003 +++ b/fs/nfs/write.c Mon May 12 20:55:48 2003 @@ -280,8 +280,6 @@ err = nfs_wb_all(inode); } else nfs_commit_file(inode, NULL, 0, 0, 0); - /* Avoid races. Tell upstream we've done all we were told to do */ - wbc->nr_to_write = 0; out: return err; } @@ -490,7 +488,6 @@ int res; res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages); nfsi->ncommit -= res; - sub_page_state(nr_unstable,res); if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); return res; @@ -1009,6 +1006,7 @@ { struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; struct nfs_page *req; + int res = 0; dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); @@ -1043,7 +1041,9 @@ nfs_mark_request_dirty(req); next: nfs_unlock_request(req); + res++; } + sub_page_state(nr_unstable,res); } #endif diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c --- a/fs/nfsd/nfssvc.c Mon May 12 20:55:47 2003 +++ b/fs/nfsd/nfssvc.c Mon May 12 20:55:47 2003 @@ -103,7 +103,7 @@ if (error < 0) goto failure; -#if CONFIG_NFSD_TCP +#ifdef CONFIG_NFSD_TCP error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); if (error < 0) goto failure; diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c --- a/fs/nfsd/vfs.c Mon May 12 20:55:46 2003 +++ b/fs/nfsd/vfs.c Mon May 12 20:55:46 2003 @@ -1124,7 +1124,7 @@ if (!inode->i_op || !inode->i_op->readlink) goto out; - UPDATE_ATIME(inode); + update_atime(inode); /* N.B. Why does this call need a get_fs()?? * Remove the set_fs and watch the fireworks:-) --okir */ diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c --- a/fs/ntfs/inode.c Mon May 12 20:55:48 2003 +++ b/fs/ntfs/inode.c Mon May 12 20:55:48 2003 @@ -1736,7 +1736,7 @@ * @vi: inode to mark dirty * * This is called from fs/inode.c::__mark_inode_dirty(), when the inode itself - * is being marked dirty. An example is when UPDATE_ATIME() is invoked. + * is being marked dirty. An example is when update_atime() is invoked. * * We mark the inode dirty by setting both the page in which the mft record * resides and the buffer heads in that page which correspond to the mft record diff -Nru a/fs/open.c b/fs/open.c --- a/fs/open.c Mon May 12 20:55:44 2003 +++ b/fs/open.c Mon May 12 20:55:44 2003 @@ -280,7 +280,7 @@ * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ -long do_utimes(char __user * filename, struct timeval __user * times) +long do_utimes(char __user * filename, struct timeval * times) { int error; struct nameidata nd; diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c --- a/fs/partitions/check.c Mon May 12 20:55:48 2003 +++ b/fs/partitions/check.c Mon May 12 20:55:48 2003 @@ -38,7 +38,7 @@ #include "ultrix.h" #include "efi.h" -#if CONFIG_BLK_DEV_MD +#ifdef CONFIG_BLK_DEV_MD extern void md_autodetect_dev(dev_t dev); #endif @@ -96,19 +96,6 @@ char *disk_name(struct gendisk *hd, int part, char *buf) { -#ifdef CONFIG_DEVFS_FS - if (hd->devfs_name[0] != '\0') { - if (part) - snprintf(buf, BDEVNAME_SIZE, "%s/part%d", - hd->devfs_name, part); - else if (hd->minors != 1) - snprintf(buf, BDEVNAME_SIZE, "%s/disc", hd->devfs_name); - else - snprintf(buf, BDEVNAME_SIZE, "%s", hd->devfs_name); - return buf; - } -#endif - if (!part) snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) @@ -353,7 +340,7 @@ if (!size) continue; add_partition(disk, j, from, size); -#if CONFIG_BLK_DEV_MD +#ifdef CONFIG_BLK_DEV_MD if (!state->parts[j].flags) continue; md_autodetect_dev(bdev->bd_dev+j); @@ -387,7 +374,7 @@ if (!size) continue; add_partition(disk, p, from, size); -#if CONFIG_BLK_DEV_MD +#ifdef CONFIG_BLK_DEV_MD if (state->parts[p].flags) md_autodetect_dev(bdev->bd_dev+p); #endif @@ -443,53 +430,3 @@ } kobject_del(&disk->kobj); } - -struct dev_name { - struct list_head list; - dev_t dev; - char namebuf[BDEVNAME_SIZE]; - char *name; -}; - -static LIST_HEAD(device_names); - -char *partition_name(dev_t dev) -{ - struct gendisk *hd; - static char nomem [] = ""; - char b[BDEVNAME_SIZE]; - struct dev_name *dname; - struct list_head *tmp; - int part; - - list_for_each(tmp, &device_names) { - dname = list_entry(tmp, struct dev_name, list); - if (dname->dev == dev) - return dname->name; - } - - dname = kmalloc(sizeof(*dname), GFP_KERNEL); - - if (!dname) - return nomem; - /* - * ok, add this new device name to the list - */ - hd = get_gendisk(dev, &part); - dname->name = NULL; - if (hd) { - dname->name = disk_name(hd, part, dname->namebuf); - module_put(hd->fops->owner); - put_disk(hd); - } - if (!dname->name) { - sprintf(dname->namebuf, "[dev %s]", __bdevname(dev, b)); - dname->name = dname->namebuf; - } - - dname->dev = dev; - list_add(&dname->list, &device_names); - - return dname->name; -} - diff -Nru a/fs/pipe.c b/fs/pipe.c --- a/fs/pipe.c Mon May 12 20:55:47 2003 +++ b/fs/pipe.c Mon May 12 20:55:47 2003 @@ -121,7 +121,7 @@ kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } if (ret > 0) - UPDATE_ATIME(inode); + update_atime(inode); return ret; } diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c --- a/fs/qnx4/dir.c Mon May 12 20:55:47 2003 +++ b/fs/qnx4/dir.c Mon May 12 20:55:47 2003 @@ -76,7 +76,7 @@ } brelse(bh); } - UPDATE_ATIME(inode); + update_atime(inode); out: unlock_kernel(); diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Mon May 12 20:55:47 2003 +++ b/fs/read_write.c Mon May 12 20:55:47 2003 @@ -115,9 +115,10 @@ { off_t retval; struct file * file; + int fput_needed; retval = -EBADF; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (!file) goto bad; @@ -128,7 +129,7 @@ if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } - fput(file); + fput_light(file, fput_needed); bad: return retval; } @@ -141,9 +142,10 @@ int retval; struct file * file; loff_t offset; + int fput_needed; retval = -EBADF; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (!file) goto bad; @@ -161,7 +163,7 @@ retval = 0; } out_putf: - fput(file); + fput_light(file, fput_needed); bad: return retval; } @@ -251,11 +253,12 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_read(file, buf, count, &file->f_pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -265,11 +268,12 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_write(file, buf, count, &file->f_pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -280,14 +284,15 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; if (pos < 0) return -EINVAL; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_read(file, buf, count, &pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -298,14 +303,15 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; if (pos < 0) return -EINVAL; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_write(file, buf, count, &pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -479,11 +485,12 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_readv(file, vec, vlen, &file->f_pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -494,11 +501,12 @@ { struct file *file; ssize_t ret = -EBADF; + int fput_needed; - file = fget(fd); + file = fget_light(fd, &fput_needed); if (file) { ret = vfs_writev(file, vec, vlen, &file->f_pos); - fput(file); + fput_light(file, fput_needed); } return ret; @@ -511,12 +519,13 @@ struct inode * in_inode, * out_inode; loff_t pos; ssize_t retval; + int fput_needed_in, fput_needed_out; /* * Get input file, and verify that it is ok.. */ retval = -EBADF; - in_file = fget(in_fd); + in_file = fget_light(in_fd, &fput_needed_in); if (!in_file) goto out; if (!(in_file->f_mode & FMODE_READ)) @@ -539,7 +548,7 @@ * Get output file, and verify that it is ok.. */ retval = -EBADF; - out_file = fget(out_fd); + out_file = fget_light(out_fd, &fput_needed_out); if (!out_file) goto fput_in; if (!(out_file->f_mode & FMODE_WRITE)) @@ -579,9 +588,9 @@ retval = -EOVERFLOW; fput_out: - fput(out_file); + fput_light(out_file, fput_needed_out); fput_in: - fput(in_file); + fput_light(in_file, fput_needed_in); out: return retval; } diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c --- a/fs/reiserfs/dir.c Mon May 12 20:55:47 2003 +++ b/fs/reiserfs/dir.c Mon May 12 20:55:47 2003 @@ -185,7 +185,7 @@ filp->f_pos = next_pos; pathrelse (&path_to_entry); reiserfs_check_path(&path_to_entry) ; - UPDATE_ATIME(inode) ; + update_atime(inode) ; out: reiserfs_write_unlock(inode->i_sb); return ret; diff -Nru a/fs/select.c b/fs/select.c --- a/fs/select.c Mon May 12 20:55:44 2003 +++ b/fs/select.c Mon May 12 20:55:44 2003 @@ -176,7 +176,7 @@ { struct poll_wqueues table; poll_table *wait; - int retval, i, off; + int retval, i; long __timeout = *timeout; spin_lock(¤t->files->file_lock); @@ -193,38 +193,58 @@ wait = NULL; retval = 0; for (;;) { + unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; + set_current_state(TASK_INTERRUPTIBLE); - for (i = 0 ; i < n; i++) { - unsigned long bit = BIT(i); - unsigned long mask; - struct file *file; - off = i / __NFDBITS; - if (!(bit & BITS(fds, off))) + inp = fds->in; outp = fds->out; exp = fds->ex; + rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex; + + for (i = 0; i < n; ++rinp, ++routp, ++rexp) { + unsigned long in, out, ex, all_bits, bit = 1, mask, j; + unsigned long res_in = 0, res_out = 0, res_ex = 0; + struct file_operations *f_op = NULL; + struct file *file = NULL; + + in = *inp++; out = *outp++; ex = *exp++; + all_bits = in | out | ex; + if (all_bits == 0) { + i += __NFDBITS; continue; - file = fget(i); - mask = POLLNVAL; - if (file) { - mask = DEFAULT_POLLMASK; - if (file->f_op && file->f_op->poll) - mask = file->f_op->poll(file, wait); - fput(file); } - if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) { - SET(bit, __RES_IN(fds,off)); - retval++; - wait = NULL; - } - if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) { - SET(bit, __RES_OUT(fds,off)); - retval++; - wait = NULL; - } - if ((mask & POLLEX_SET) && ISSET(bit, __EX(fds,off))) { - SET(bit, __RES_EX(fds,off)); - retval++; - wait = NULL; + + for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) { + if (i >= n) + break; + if (!(bit & all_bits)) + continue; + file = fget(i); + if (file) { + f_op = file->f_op; + mask = DEFAULT_POLLMASK; + if (f_op && f_op->poll) + mask = (*f_op->poll)(file, retval ? NULL : wait); + fput(file); + if ((mask & POLLIN_SET) && (in & bit)) { + res_in |= bit; + retval++; + } + if ((mask & POLLOUT_SET) && (out & bit)) { + res_out |= bit; + retval++; + } + if ((mask & POLLEX_SET) && (ex & bit)) { + res_ex |= bit; + retval++; + } + } } + if (res_in) + *rinp = res_in; + if (res_out) + *routp = res_out; + if (res_ex) + *rexp = res_ex; } wait = NULL; if (retval || !__timeout || signal_pending(current)) diff -Nru a/fs/seq_file.c b/fs/seq_file.c --- a/fs/seq_file.c Mon May 12 20:55:48 2003 +++ b/fs/seq_file.c Mon May 12 20:55:48 2003 @@ -338,3 +338,13 @@ kfree(op); return res; } + +int seq_release_private(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + + kfree(seq->private); + seq->private = NULL; + return seq_release(inode, file); +} + diff -Nru a/fs/stat.c b/fs/stat.c --- a/fs/stat.c Mon May 12 20:55:45 2003 +++ b/fs/stat.c Mon May 12 20:55:45 2003 @@ -244,7 +244,7 @@ if (inode->i_op && inode->i_op->readlink) { error = security_inode_readlink(nd.dentry); if (!error) { - UPDATE_ATIME(inode); + update_atime(inode); error = inode->i_op->readlink(nd.dentry, buf, bufsiz); } } diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Mon May 12 20:55:46 2003 +++ b/fs/super.c Mon May 12 20:55:46 2003 @@ -31,6 +31,7 @@ #include #include #include +#include /* for the emergency remount stuff */ #include @@ -431,6 +432,18 @@ return err; } +static void mark_files_ro(struct super_block *sb) +{ + struct file *f; + + file_list_lock(); + list_for_each_entry(f, &sb->s_files, f_list) { + if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f)) + f->f_mode &= ~FMODE_WRITE; + } + file_list_unlock(); +} + /** * do_remount_sb - asks filesystem to change mount options. * @sb: superblock in question @@ -439,21 +452,25 @@ * * Alters the mount options of a mounted file system. */ -int do_remount_sb(struct super_block *sb, int flags, void *data) +int do_remount_sb(struct super_block *sb, int flags, void *data, int force) { int retval; if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) return -EACCES; - /*flags |= MS_RDONLY;*/ if (flags & MS_RDONLY) acct_auto_close(sb); shrink_dcache_sb(sb); fsync_super(sb); + /* If we are remounting RDONLY, make sure there are no rw files open */ - if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) - if (!fs_may_remount_ro(sb)) + if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { + if (force) + mark_files_ro(sb); + else if (!fs_may_remount_ro(sb)) return -EBUSY; + } + if (sb->s_op->remount_fs) { lock_super(sb); retval = sb->s_op->remount_fs(sb, &flags, data); @@ -465,6 +482,28 @@ return 0; } +static void do_emergency_remount(unsigned long foo) +{ + struct super_block *sb; + + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { + sb->s_count++; + spin_unlock(&sb_lock); + down_read(&sb->s_umount); + if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) + do_remount_sb(sb, MS_RDONLY, NULL, 1); + drop_super(sb); + spin_lock(&sb_lock); + } + spin_unlock(&sb_lock); +} + +void emergency_remount(void) +{ + pdflush_operation(do_emergency_remount, 0); +} + /* * Unnamed block devices are dummy devices used by virtual * filesystems which don't use real block-devices. -- jrs @@ -618,7 +657,7 @@ } s->s_flags |= MS_ACTIVE; } - do_remount_sb(s, flags, data); + do_remount_sb(s, flags, data, 0); return s; } diff -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c --- a/fs/sysv/dir.c Mon May 12 20:55:45 2003 +++ b/fs/sysv/dir.c Mon May 12 20:55:45 2003 @@ -116,7 +116,7 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; - UPDATE_ATIME(inode); + update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c --- a/fs/udf/dir.c Mon May 12 20:55:45 2003 +++ b/fs/udf/dir.c Mon May 12 20:55:45 2003 @@ -98,7 +98,7 @@ } result = do_udf_readdir(dir, filp, filldir, dirent); - UPDATE_ATIME(dir); + update_atime(dir); unlock_kernel(); return result; } diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c --- a/fs/ufs/dir.c Mon May 12 20:55:48 2003 +++ b/fs/ufs/dir.c Mon May 12 20:55:48 2003 @@ -166,7 +166,7 @@ offset = 0; brelse (bh); } - UPDATE_ATIME(inode); + update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/xattr.c b/fs/xattr.c --- a/fs/xattr.c Mon May 12 20:55:46 2003 +++ b/fs/xattr.c Mon May 12 20:55:46 2003 @@ -79,15 +79,16 @@ error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { + down(&d->d_inode->i_sem); error = security_inode_setxattr(d, kname, kvalue, size, flags); if (error) goto out; - down(&d->d_inode->i_sem); error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); + if (!error) + security_inode_post_setxattr(d, kname, kvalue, size, flags); +out: up(&d->d_inode->i_sem); } - -out: xattr_free(kvalue, size); return error; } diff -Nru a/include/asm-alpha/elf.h b/include/asm-alpha/elf.h --- a/include/asm-alpha/elf.h Mon May 12 20:55:46 2003 +++ b/include/asm-alpha/elf.h Mon May 12 20:55:46 2003 @@ -2,6 +2,49 @@ #define __ASM_ALPHA_ELF_H /* + * Alpha ELF relocation types + */ +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_BRSGP 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ + +/* * ELF register definitions.. */ diff -Nru a/include/asm-alpha/hardirq.h b/include/asm-alpha/hardirq.h --- a/include/asm-alpha/hardirq.h Mon May 12 20:55:47 2003 +++ b/include/asm-alpha/hardirq.h Mon May 12 20:55:47 2003 @@ -79,7 +79,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT #define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-alpha/kmap_types.h b/include/asm-alpha/kmap_types.h --- a/include/asm-alpha/kmap_types.h Mon May 12 20:55:49 2003 +++ b/include/asm-alpha/kmap_types.h Mon May 12 20:55:49 2003 @@ -5,7 +5,7 @@ #include -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM # define D(n) __KM_FENCE_##n , #else # define D(n) diff -Nru a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h --- a/include/asm-alpha/spinlock.h Mon May 12 20:55:47 2003 +++ b/include/asm-alpha/spinlock.h Mon May 12 20:55:47 2003 @@ -16,7 +16,7 @@ typedef struct { volatile unsigned int lock /*__attribute__((aligned(32))) */; -#if CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_DEBUG_SPINLOCK int on_cpu; int line_no; void *previous; @@ -25,7 +25,7 @@ #endif } spinlock_t; -#if CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_DEBUG_SPINLOCK #define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, 0, 0, 0} #define spin_lock_init(x) \ ((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = 0, (x)->task = 0) @@ -37,7 +37,7 @@ #define spin_is_locked(x) ((x)->lock != 0) #define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); }) -#if CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_DEBUG_SPINLOCK extern void _raw_spin_unlock(spinlock_t * lock); extern void debug_spin_lock(spinlock_t * lock, const char *, int); extern int debug_spin_trylock(spinlock_t * lock, const char *, int); @@ -102,7 +102,7 @@ #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *)(x) != 0) -#if CONFIG_DEBUG_RWLOCK +#ifdef CONFIG_DEBUG_RWLOCK extern void _raw_write_lock(rwlock_t * lock); extern void _raw_read_lock(rwlock_t * lock); #else diff -Nru a/include/asm-arm/elf.h b/include/asm-arm/elf.h --- a/include/asm-arm/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-arm/elf.h Mon May 12 20:55:48 2003 @@ -16,6 +16,10 @@ #define EM_ARM 40 #define EF_ARM_APCS26 0x08 +#define R_ARM_NONE 0 +#define R_ARM_PC24 1 +#define R_ARM_ABS32 2 + #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; diff -Nru a/include/asm-generic/rmap.h b/include/asm-generic/rmap.h --- a/include/asm-generic/rmap.h Mon May 12 20:55:47 2003 +++ b/include/asm-generic/rmap.h Mon May 12 20:55:47 2003 @@ -61,7 +61,7 @@ return page->index + low_bits; } -#if CONFIG_HIGHPTE +#ifdef CONFIG_HIGHPTE static inline pte_addr_t ptep_to_paddr(pte_t *ptep) { pte_addr_t paddr; diff -Nru a/include/asm-h8300/hardirq.h b/include/asm-h8300/hardirq.h --- a/include/asm-h8300/hardirq.h Mon May 12 20:55:47 2003 +++ b/include/asm-h8300/hardirq.h Mon May 12 20:55:47 2003 @@ -74,13 +74,13 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h --- a/include/asm-i386/apicdef.h Mon May 12 20:55:47 2003 +++ b/include/asm-i386/apicdef.h Mon May 12 20:55:47 2003 @@ -11,13 +11,6 @@ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 -#ifdef CONFIG_X86_SUMMIT - #define APIC_ID_MASK (0xFF<<24) - #define GET_APIC_ID(x) (((x)>>24)&0xFF) -#else - #define APIC_ID_MASK (0x0F<<24) - #define GET_APIC_ID(x) (((x)>>24)&0x0F) -#endif #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) diff -Nru a/include/asm-i386/edd.h b/include/asm-i386/edd.h --- a/include/asm-i386/edd.h Mon May 12 20:55:44 2003 +++ b/include/asm-i386/edd.h Mon May 12 20:55:44 2003 @@ -141,7 +141,7 @@ u32 array_number; u32 reserved1; u64 reserved2; - } __attribute((packed)) raid; + } __attribute__ ((packed)) raid; struct { u8 device; u8 reserved1; diff -Nru a/include/asm-i386/elf.h b/include/asm-i386/elf.h --- a/include/asm-i386/elf.h Mon May 12 20:55:47 2003 +++ b/include/asm-i386/elf.h Mon May 12 20:55:47 2003 @@ -12,6 +12,19 @@ #include +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + typedef unsigned long elf_greg_t; #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h --- a/include/asm-i386/fixmap.h Mon May 12 20:55:44 2003 +++ b/include/asm-i386/fixmap.h Mon May 12 20:55:44 2003 @@ -60,7 +60,7 @@ #ifdef CONFIG_X86_F00F_BUG FIX_F00F_IDT, /* Virtual mapping for IDT */ #endif -#ifdef CONFIG_X86_SUMMIT +#ifdef CONFIG_X86_CYCLONE_TIMER FIX_CYCLONE_TIMER, /*cyclone timer register*/ #endif #ifdef CONFIG_HIGHMEM diff -Nru a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/genapic.h Mon May 12 20:55:49 2003 @@ -0,0 +1,106 @@ +#ifndef _ASM_GENAPIC_H +#define _ASM_GENAPIC_H 1 + +/* + * Generic APIC driver interface. + * + * An straight forward mapping of the APIC related parts of the + * x86 subarchitecture interface to a dynamic object. + * + * This is used by the "generic" x86 subarchitecture. + * + * Copyright 2003 Andi Kleen, SuSE Labs. + */ + +struct mpc_config_translation; +struct mpc_config_bus; +struct mp_config_table; +struct mpc_config_processor; + +struct genapic { + char *name; + int (*probe)(void); + + int (*apic_id_registered)(void); + unsigned long (*target_cpus)(void); + int int_delivery_mode; + int int_dest_mode; + int apic_broadcast_id; + int esr_disable; + unsigned long (*check_apicid_used)(unsigned long bitmap, int apicid); + unsigned long (*check_apicid_present)(int apicid); + int no_balance_irq; + void (*init_apic_ldr)(void); + unsigned long (*ioapic_phys_id_map)(unsigned long map); + + void (*clustered_apic_check)(void); + int (*multi_timer_check)(int apic, int irq); + int (*apicid_to_node)(int logical_apicid); + int (*cpu_to_logical_apicid)(int cpu); + int (*cpu_present_to_apicid)(int mps_cpu); + unsigned long (*apicid_to_cpu_present)(int phys_apicid); + int (*mpc_apic_id)(struct mpc_config_processor *m, + struct mpc_config_translation *t); + void (*setup_portio_remap)(void); + int (*check_phys_apicid_present)(int boot_cpu_physical_apicid); + + /* mpparse */ + void (*mpc_oem_bus_info)(struct mpc_config_bus *, char *, + struct mpc_config_translation *); + void (*mpc_oem_pci_bus)(struct mpc_config_bus *, + struct mpc_config_translation *); + + /* When one of the next two hooks returns 1 the genapic + is switched to this. Essentially they are additional probe + functions. */ + int (*mps_oem_check)(struct mp_config_table *mpc, char *oem, + char *productid); + int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id); + + unsigned (*get_apic_id)(unsigned long x); + unsigned long apic_id_mask; + + /* ipi */ + void (*send_IPI_mask)(int mask, int vector); + void (*send_IPI_allbutself)(int vector); + void (*send_IPI_all)(int vector); +}; + +#define APICFUNC(x) .x = x + +#define APIC_INIT(aname, aprobe) { \ + .name = aname, \ + .probe = aprobe, \ + .int_delivery_mode = INT_DELIVERY_MODE, \ + .int_dest_mode = INT_DEST_MODE, \ + .apic_broadcast_id = APIC_BROADCAST_ID, \ + .no_balance_irq = NO_BALANCE_IRQ, \ + APICFUNC(apic_id_registered), \ + APICFUNC(target_cpus), \ + APICFUNC(check_apicid_used), \ + APICFUNC(check_apicid_present), \ + APICFUNC(init_apic_ldr), \ + APICFUNC(ioapic_phys_id_map), \ + APICFUNC(clustered_apic_check), \ + APICFUNC(multi_timer_check), \ + APICFUNC(apicid_to_node), \ + APICFUNC(cpu_to_logical_apicid), \ + APICFUNC(cpu_present_to_apicid), \ + APICFUNC(apicid_to_cpu_present), \ + APICFUNC(mpc_apic_id), \ + APICFUNC(setup_portio_remap), \ + APICFUNC(check_phys_apicid_present), \ + APICFUNC(mpc_oem_bus_info), \ + APICFUNC(mpc_oem_pci_bus), \ + APICFUNC(mps_oem_check), \ + APICFUNC(get_apic_id), \ + .apic_id_mask = APIC_ID_MASK, \ + APICFUNC(acpi_madt_oem_check), \ + APICFUNC(send_IPI_mask), \ + APICFUNC(send_IPI_allbutself), \ + APICFUNC(send_IPI_all), \ + } + +extern struct genapic *genapic; + +#endif diff -Nru a/include/asm-i386/i387.h b/include/asm-i386/i387.h --- a/include/asm-i386/i387.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/i387.h Mon May 12 20:55:48 2003 @@ -87,15 +87,15 @@ /* * ptrace request handers... */ -extern int get_fpregs( struct user_i387_struct *buf, +extern int get_fpregs( struct user_i387_struct __user *buf, struct task_struct *tsk ); extern int set_fpregs( struct task_struct *tsk, - struct user_i387_struct *buf ); + struct user_i387_struct __user *buf ); -extern int get_fpxregs( struct user_fxsr_struct *buf, +extern int get_fpxregs( struct user_fxsr_struct __user *buf, struct task_struct *tsk ); extern int set_fpxregs( struct task_struct *tsk, - struct user_fxsr_struct *buf ); + struct user_fxsr_struct __user *buf ); /* * FPU state for core dumps... diff -Nru a/include/asm-i386/ipc.h b/include/asm-i386/ipc.h --- a/include/asm-i386/ipc.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/ipc.h Mon May 12 20:55:48 2003 @@ -7,7 +7,7 @@ * See arch/i386/kernel/sys_i386.c for ugly details.. */ struct ipc_kludge { - struct msgbuf *msgp; + struct msgbuf __user *msgp; long msgtyp; }; diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h --- a/include/asm-i386/kmap_types.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/kmap_types.h Mon May 12 20:55:48 2003 @@ -3,7 +3,7 @@ #include -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM # define D(n) __KM_FENCE_##n , #else # define D(n) diff -Nru a/include/asm-i386/mach-bigsmp/mach_apic.h b/include/asm-i386/mach-bigsmp/mach_apic.h --- a/include/asm-i386/mach-bigsmp/mach_apic.h Mon May 12 20:55:49 2003 +++ b/include/asm-i386/mach-bigsmp/mach_apic.h Mon May 12 20:55:49 2003 @@ -15,18 +15,28 @@ static inline int apic_id_registered(void) { - return (1); + return (1); } #define APIC_DFR_VALUE (APIC_DFR_CLUSTER) -#define TARGET_CPUS ((cpu_online_map < 0xf)?cpu_online_map:0xf) +static inline unsigned long target_cpus(void) +{ + return ((cpu_online_map < 0xf)?cpu_online_map:0xf); +} +#define TARGET_CPUS (target_cpus()) #define INT_DELIVERY_MODE dest_LowestPrio #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define APIC_BROADCAST_ID (0x0f) -#define check_apicid_used(bitmap, apicid) (0) -#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit)) +static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) +{ + return 0; +} +static inline unsigned long check_apicid_present(int bit) +{ + return (phys_cpu_present_map & (1 << bit)); +} static inline unsigned long calculate_ldr(unsigned long old) { @@ -114,5 +124,14 @@ { return (1); } + +#define APIC_ID_MASK (0x0F<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0x0F); +} + +#define GET_APIC_ID(x) get_apic_id(x) #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-bigsmp/mach_ipi.h b/include/asm-i386/mach-bigsmp/mach_ipi.h --- a/include/asm-i386/mach-bigsmp/mach_ipi.h Mon May 12 20:55:46 2003 +++ b/include/asm-i386/mach-bigsmp/mach_ipi.h Mon May 12 20:55:46 2003 @@ -1,7 +1,7 @@ #ifndef __ASM_MACH_IPI_H #define __ASM_MACH_IPI_H -static inline void send_IPI_mask_sequence(int mask, int vector); +inline void send_IPI_mask_sequence(int mask, int vector); static inline void send_IPI_mask(int mask, int vector) { diff -Nru a/include/asm-i386/mach-default/mach_apic.h b/include/asm-i386/mach-default/mach_apic.h --- a/include/asm-i386/mach-default/mach_apic.h Mon May 12 20:55:49 2003 +++ b/include/asm-i386/mach-default/mach_apic.h Mon May 12 20:55:49 2003 @@ -3,11 +3,15 @@ #define APIC_DFR_VALUE (APIC_DFR_FLAT) +static inline unsigned long target_cpus(void) +{ #ifdef CONFIG_SMP - #define TARGET_CPUS (cpu_online_map) + return cpu_online_map; #else - #define TARGET_CPUS 0x01 + return 1; #endif +} +#define TARGET_CPUS (target_cpus()) #define NO_BALANCE_IRQ (0) #define esr_disable (0) @@ -16,13 +20,15 @@ #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define APIC_BROADCAST_ID 0x0F -#define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid)) -#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit)) -static inline int apic_id_registered(void) +static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) +{ + return (bitmap & (1UL << apicid)); +} + +static inline unsigned long check_apicid_present(int bit) { - return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), - &phys_cpu_present_map)); + return (phys_cpu_present_map & (1UL << bit)); } /* @@ -42,7 +48,7 @@ apic_write_around(APIC_LDR, val); } -static inline ulong ioapic_phys_id_map(ulong phys_map) +static inline unsigned long ioapic_phys_id_map(unsigned long phys_map) { return phys_map; } @@ -97,6 +103,21 @@ static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) { return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map); +} + +#define APIC_ID_MASK (0xF<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0xF); +} + +#define GET_APIC_ID(x) get_apic_id(x) + +static inline int apic_id_registered(void) +{ + return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), + &phys_cpu_present_map)); } #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-i386/mach-default/mach_ipi.h --- a/include/asm-i386/mach-default/mach_ipi.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/mach-default/mach_ipi.h Mon May 12 20:55:48 2003 @@ -1,8 +1,8 @@ #ifndef __ASM_MACH_IPI_H #define __ASM_MACH_IPI_H -static inline void send_IPI_mask_bitmask(int mask, int vector); -static inline void __send_IPI_shortcut(unsigned int shortcut, int vector); +inline void send_IPI_mask_bitmask(int mask, int vector); +inline void __send_IPI_shortcut(unsigned int shortcut, int vector); static inline void send_IPI_mask(int mask, int vector) { diff -Nru a/include/asm-i386/mach-default/mach_mpparse.h b/include/asm-i386/mach-default/mach_mpparse.h --- a/include/asm-i386/mach-default/mach_mpparse.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/mach-default/mach_mpparse.h Mon May 12 20:55:48 2003 @@ -12,14 +12,16 @@ { } -static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, +static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { + return 0; } /* Hook from generic ACPI tables.c */ -static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) +static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { + return 0; } diff -Nru a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/mach-generic/mach_apic.h Mon May 12 20:55:49 2003 @@ -0,0 +1,30 @@ +#ifndef __ASM_MACH_APIC_H +#define __ASM_MACH_APIC_H + +#include + +#define esr_disable (genapic->esr_disable) +#define NO_BALANCE_IRQ (genapic->no_balance_irq) +#define APIC_BROADCAST_ID (genapic->apic_broadcast_id) +#define INT_DELIVERY_MODE (genapic->int_delivery_mode) +#define INT_DEST_MODE (genapic->int_dest_mode) +#define TARGET_CPUS (genapic->target_cpus()) +#define apic_id_registered (genapic->apic_id_registered) +#define apic_id_registered (genapic->apic_id_registered) +#define init_apic_ldr (genapic->init_apic_ldr) +#define ioapic_phys_id_map (genapic->ioapic_phys_id_map) +#define clustered_apic_check (genapic->clustered_apic_check) +#define multi_timer_check (genapic->multi_timer_check) +#define apicid_to_node (genapic->apicid_to_node) +#define cpu_to_logical_apicid (genapic->cpu_to_logical_apicid) +#define cpu_present_to_apicid (genapic->cpu_present_to_apicid) +#define apicid_to_cpu_present (genapic->apicid_to_cpu_present) +#define mpc_apic_id (genapic->mpc_apic_id) +#define setup_portio_remap (genapic->setup_portio_remap) +#define check_apicid_present (genapic->check_apicid_present) +#define check_phys_apicid_present (genapic->check_phys_apicid_present) +#define check_apicid_used (genapic->check_apicid_used) +#define GET_APIC_ID (genapic->get_apic_id) +#define APIC_ID_MASK (genapic->apic_id_mask) + +#endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-generic/mach_ipi.h b/include/asm-i386/mach-generic/mach_ipi.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/mach-generic/mach_ipi.h Mon May 12 20:55:49 2003 @@ -0,0 +1,10 @@ +#ifndef _MACH_IPI_H +#define _MACH_IPI_H 1 + +#include + +#define send_IPI_mask (genapic->send_IPI_mask) +#define send_IPI_allbutself (genapic->send_IPI_allbutself) +#define send_IPI_all (genapic->send_IPI_all) + +#endif diff -Nru a/include/asm-i386/mach-generic/mach_mpparse.h b/include/asm-i386/mach-generic/mach_mpparse.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/mach-generic/mach_mpparse.h Mon May 12 20:55:49 2003 @@ -0,0 +1,12 @@ +#ifndef _MACH_MPPARSE_H +#define _MACH_MPPARSE_H 1 + +#include + +#define mpc_oem_bus_info (genapic->mpc_oem_bus_info) +#define mpc_oem_pci_bus (genapic->mpc_oem_pci_bus) + +int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid); +int acpi_madt_oem_check(char *oem_id, char *oem_table_id); + +#endif diff -Nru a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h --- a/include/asm-i386/mach-numaq/mach_apic.h Mon May 12 20:55:46 2003 +++ b/include/asm-i386/mach-numaq/mach_apic.h Mon May 12 20:55:46 2003 @@ -1,6 +1,9 @@ #ifndef __ASM_MACH_APIC_H #define __ASM_MACH_APIC_H +#include +#include + #define APIC_DFR_VALUE (APIC_DFR_CLUSTER) #define TARGET_CPUS (0xf) @@ -102,5 +105,14 @@ { return (1); } + +#define APIC_ID_MASK (0xF<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0x0F); +} + +#define GET_APIC_ID(x) get_apic_id(x) #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h --- a/include/asm-i386/mach-summit/mach_apic.h Mon May 12 20:55:47 2003 +++ b/include/asm-i386/mach-summit/mach_apic.h Mon May 12 20:55:47 2003 @@ -1,7 +1,13 @@ #ifndef __ASM_MACH_APIC_H #define __ASM_MACH_APIC_H +#include + +#ifdef CONFIG_X86_GENERICARCH +#define x86_summit 1 /* must be an constant expressiona for generic arch */ +#else extern int x86_summit; +#endif #define esr_disable (x86_summit ? 1 : 0) #define NO_BALANCE_IRQ (0) @@ -9,20 +15,34 @@ #define XAPIC_DEST_CPUS_MASK 0x0Fu #define XAPIC_DEST_CLUSTER_MASK 0xF0u -#define xapic_phys_to_log_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) |\ - ((phys_apic) & XAPIC_DEST_CLUSTER_MASK) ) +static inline unsigned long xapic_phys_to_log_apicid(int phys_apic) +{ + return ( (1ul << ((phys_apic) & 0x3)) | + ((phys_apic) & XAPIC_DEST_CLUSTER_MASK) ); +} #define APIC_DFR_VALUE (x86_summit ? APIC_DFR_CLUSTER : APIC_DFR_FLAT) -#define TARGET_CPUS (x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map) + +static inline unsigned long target_cpus(void) +{ + return (x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map); +} +#define TARGET_CPUS (target_cpus()) #define INT_DELIVERY_MODE (x86_summit ? dest_Fixed : dest_LowestPrio) #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ -#define APIC_BROADCAST_ID (x86_summit ? 0xFF : 0x0F) -#define check_apicid_used(bitmap, apicid) (x86_summit ? 0 : (bitmap & (1 << apicid))) +#define APIC_BROADCAST_ID (0x0F) +static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) +{ + return (x86_summit ? 0 : (bitmap & (1 << apicid))); +} /* we don't use the phys_cpu_present_map to indicate apicid presence */ -#define check_apicid_present(bit) (x86_summit ? 1 : (phys_cpu_present_map & (1 << bit))) +static inline unsigned long check_apicid_present(int bit) +{ + return (x86_summit ? 1 : (phys_cpu_present_map & (1 << bit))); +} extern u8 bios_cpu_apicid[]; @@ -112,5 +132,14 @@ else return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map); } + +#define APIC_ID_MASK (0xFF<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0xFF); +} + +#define GET_APIC_ID(x) get_apic_id(x) #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-summit/mach_ipi.h b/include/asm-i386/mach-summit/mach_ipi.h --- a/include/asm-i386/mach-summit/mach_ipi.h Mon May 12 20:55:45 2003 +++ b/include/asm-i386/mach-summit/mach_ipi.h Mon May 12 20:55:45 2003 @@ -1,7 +1,7 @@ #ifndef __ASM_MACH_IPI_H #define __ASM_MACH_IPI_H -static inline void send_IPI_mask_sequence(int mask, int vector); +inline void send_IPI_mask_sequence(int mask, int vector); static inline void send_IPI_mask(int mask, int vector) { diff -Nru a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h --- a/include/asm-i386/mach-summit/mach_mpparse.h Mon May 12 20:55:46 2003 +++ b/include/asm-i386/mach-summit/mach_mpparse.h Mon May 12 20:55:46 2003 @@ -14,26 +14,34 @@ { } -static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, +static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { if (!strncmp(oem, "IBM ENSW", 8) && (!strncmp(productid, "VIGIL SMP", 9) || !strncmp(productid, "EXA", 3) || !strncmp(productid, "RUTHLESS SMP", 12))){ +#ifndef CONFIG_X86_GENERICARCH x86_summit = 1; +#endif use_cyclone = 1; /*enable cyclone-timer*/ + return 1; } + return 0; } /* Hook from generic ACPI tables.c */ -static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) +static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { if (!strncmp(oem_id, "IBM", 3) && (!strncmp(oem_table_id, "SERVIGIL", 8) || !strncmp(oem_table_id, "EXA", 3))){ +#ifndef CONFIG_X86_GENERICARCH x86_summit = 1; +#endif use_cyclone = 1; /*enable cyclone-timer*/ + return 1; } + return 0; } #endif /* __ASM_MACH_MPPARSE_H */ diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h --- a/include/asm-i386/mmzone.h Mon May 12 20:55:46 2003 +++ b/include/asm-i386/mmzone.h Mon May 12 20:55:46 2003 @@ -120,7 +120,7 @@ #ifdef CONFIG_X86_NUMAQ #include -#elif CONFIG_X86_SUMMIT +#elif CONFIG_NUMA /* summit or generic arch */ #include #elif CONFIG_X86_PC #define get_memcfg_numa get_memcfg_numa_flat diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h --- a/include/asm-i386/mpspec.h Mon May 12 20:55:44 2003 +++ b/include/asm-i386/mpspec.h Mon May 12 20:55:44 2003 @@ -16,7 +16,7 @@ /* * a maximum of 16 APICs with the current APIC ID architecture. */ -#if defined(CONFIG_X86_NUMAQ) || defined (CONFIG_X86_SUMMIT) +#if defined(CONFIG_X86_NUMAQ) || defined (CONFIG_X86_SUMMIT) || defined(CONFIG_X86_GENERICARCH) #define MAX_APICS 256 #else #define MAX_APICS 16 diff -Nru a/include/asm-i386/numnodes.h b/include/asm-i386/numnodes.h --- a/include/asm-i386/numnodes.h Mon May 12 20:55:45 2003 +++ b/include/asm-i386/numnodes.h Mon May 12 20:55:45 2003 @@ -5,7 +5,7 @@ #ifdef CONFIG_X86_NUMAQ #include -#elif CONFIG_X86_SUMMIT +#elif CONFIG_NUMA #include #else #define MAX_NUMNODES 1 diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h --- a/include/asm-i386/processor.h Mon May 12 20:55:44 2003 +++ b/include/asm-i386/processor.h Mon May 12 20:55:44 2003 @@ -400,7 +400,7 @@ /* floating point info */ union i387_union i387; /* virtual 86 mode info */ - struct vm86_struct * vm86_info; + struct vm86_struct __user * vm86_info; unsigned long screen_bitmap; unsigned long v86flags, v86mask, saved_esp0; unsigned int saved_fs, saved_gs; @@ -536,7 +536,7 @@ #define ASM_NOP6 K8_NOP6 #define ASM_NOP7 K8_NOP7 #define ASM_NOP8 K8_NOP8 -#elif CONFIG_MK7 +#elif defined(CONFIG_MK7) #define ASM_NOP1 K7_NOP1 #define ASM_NOP2 K7_NOP2 #define ASM_NOP3 K7_NOP3 diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h --- a/include/asm-i386/smp.h Mon May 12 20:55:47 2003 +++ b/include/asm-i386/smp.h Mon May 12 20:55:47 2003 @@ -87,11 +87,17 @@ return -1; } #ifdef CONFIG_X86_LOCAL_APIC -static __inline int hard_smp_processor_id(void) + +#ifdef APIC_DEFINITION +extern int hard_smp_processor_id(void); +#else +#include +static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)); } +#endif static __inline int logical_smp_processor_id(void) { diff -Nru a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h --- a/include/asm-i386/suspend.h Mon May 12 20:55:48 2003 +++ b/include/asm-i386/suspend.h Mon May 12 20:55:48 2003 @@ -30,18 +30,14 @@ unsigned long return_address; } __attribute__((packed)); -/* We'll access these from assembly, so we'd better have them outside struct */ -extern unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx; -extern unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi; -extern unsigned long saved_context_eflags; - - #define loaddebug(thread,register) \ __asm__("movl %0,%%db" #register \ : /* no output */ \ :"r" ((thread)->debugreg[register])) -extern void fix_processor_context(void); +extern void save_processor_state(void); +extern void restore_processor_state(void); + extern void do_magic(int resume); #ifdef CONFIG_ACPI_SLEEP diff -Nru a/include/asm-i386/system.h b/include/asm-i386/system.h --- a/include/asm-i386/system.h Mon May 12 20:55:44 2003 +++ b/include/asm-i386/system.h Mon May 12 20:55:44 2003 @@ -474,5 +474,6 @@ #define BROKEN_ACPI_Sx 0x0001 #define BROKEN_INIT_AFTER_S1 0x0002 #define BROKEN_PNP_BIOS 0x0004 +#define BROKEN_CPUFREQ 0x0008 #endif diff -Nru a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h --- a/include/asm-i386/uaccess.h Mon May 12 20:55:45 2003 +++ b/include/asm-i386/uaccess.h Mon May 12 20:55:45 2003 @@ -62,8 +62,6 @@ :"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \ flag; }) -#ifdef CONFIG_X86_WP_WORKS_OK - /** * access_ok: - Checks if a user space pointer is valid * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that @@ -85,14 +83,6 @@ */ #define access_ok(type,addr,size) (__range_ok(addr,size) == 0) -#else - -#define access_ok(type,addr,size) ( (__range_ok(addr,size) == 0) && \ - ((type) == VERIFY_READ || boot_cpu_data.wp_works_ok || \ - __verify_write((void *)(addr),(size)))) - -#endif - /** * verify_area: - Obsolete, use access_ok() * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE @@ -191,14 +181,8 @@ __ret_gu; \ }) -extern void __put_user_1(void); -extern void __put_user_2(void); -extern void __put_user_4(void); -extern void __put_user_8(void); - extern void __put_user_bad(void); - /** * put_user: - Write a simple value into user space. * @x: Value to copy to user space. @@ -299,6 +283,8 @@ : "=r"(err) \ : "A" (x), "r" (addr), "i"(-EFAULT), "0"(err)) +#ifdef CONFIG_X86_WP_WORKS_OK + #define __put_user_size(x,ptr,size,retval,errret) \ do { \ retval = 0; \ @@ -311,6 +297,18 @@ } \ } while (0) +#else + +#define __put_user_size(x,ptr,size,retval,errret) \ +do { \ + __typeof__(*(ptr)) __pus_tmp = x; \ + retval = 0; \ + \ + if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0)) \ + retval = errret; \ +} while (0) + +#endif struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h --- a/include/asm-i386/unistd.h Mon May 12 20:55:47 2003 +++ b/include/asm-i386/unistd.h Mon May 12 20:55:47 2003 @@ -399,6 +399,8 @@ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), * but it doesn't work on all toolchains, so we just do it by hand */ +#ifndef cond_syscall #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); +#endif #endif /* _ASM_I386_UNISTD_H_ */ diff -Nru a/include/asm-ia64/acpi-ext.h b/include/asm-ia64/acpi-ext.h --- a/include/asm-ia64/acpi-ext.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/acpi-ext.h Mon May 12 20:55:44 2003 @@ -3,30 +3,15 @@ * * Copyright (C) 2003 Hewlett-Packard * Copyright (C) Alex Williamson + * Copyright (C) Bjorn Helgaas * - * Vendor specific extensions to ACPI. The HP-specific extensiosn are also used by NEC. + * Vendor specific extensions to ACPI. */ #ifndef _ASM_IA64_ACPI_EXT_H #define _ASM_IA64_ACPI_EXT_H #include -#define HP_CCSR_LENGTH 0x21 -#define HP_CCSR_TYPE 0x2 -#define HP_CCSR_GUID EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \ - 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad) - -struct acpi_hp_vendor_long { - u8 guid_id; - u8 guid[16]; - u8 csr_base[8]; - u8 csr_length[8]; -}; - extern acpi_status hp_acpi_csr_space (acpi_handle, u64 *base, u64 *length); -extern acpi_status acpi_get_crs (acpi_handle, struct acpi_buffer *); -extern struct acpi_resource *acpi_get_crs_next (struct acpi_buffer *, int *); -extern union acpi_resource_data *acpi_get_crs_type (struct acpi_buffer *, int *, int); -extern void acpi_dispose_crs (struct acpi_buffer *); #endif /* _ASM_IA64_ACPI_EXT_H */ diff -Nru a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h --- a/include/asm-ia64/atomic.h Mon May 12 20:55:45 2003 +++ b/include/asm-ia64/atomic.h Mon May 12 20:55:45 2003 @@ -56,11 +56,16 @@ } #define atomic_add_return(i,v) \ - ((__builtin_constant_p(i) && \ - ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ - || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ - ? ia64_fetch_and_add(i, &(v)->counter) \ - : ia64_atomic_add(i, v)) +({ \ + int __ia64_aar_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ + || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ + || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ + || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ + ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ + : ia64_atomic_add(__ia64_aar_i, v); \ +}) /* * Atomically add I to V and return TRUE if the resulting value is @@ -72,13 +77,17 @@ return atomic_add_return(i, v) < 0; } - #define atomic_sub_return(i,v) \ - ((__builtin_constant_p(i) && \ - ( (i == 1) || (i == 4) || (i == 8) || (i == 16) \ - || (i == -1) || (i == -4) || (i == -8) || (i == -16))) \ - ? ia64_fetch_and_add(-(i), &(v)->counter) \ - : ia64_atomic_sub(i, v)) +({ \ + int __ia64_asr_i = (i); \ + (__builtin_constant_p(i) \ + && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ + || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ + || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ + || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ + ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ + : ia64_atomic_sub(__ia64_asr_i, v); \ +}) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) diff -Nru a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h --- a/include/asm-ia64/bitops.h Mon May 12 20:55:48 2003 +++ b/include/asm-ia64/bitops.h Mon May 12 20:55:48 2003 @@ -450,15 +450,15 @@ #ifdef __KERNEL__ -#define __clear_bit(nr, addr) clear_bit(nr, addr) +#define __clear_bit(nr, addr) clear_bit(nr, addr) -#define ext2_set_bit test_and_set_bit -#define ext2_set_atomic(l,n,a) test_and_set_bit(n,a) -#define ext2_clear_bit test_and_clear_bit -#define ext2_clear_atomic(l,n,a) test_and_clear_bit(n,a) -#define ext2_test_bit test_bit -#define ext2_find_first_zero_bit find_first_zero_bit -#define ext2_find_next_zero_bit find_next_zero_bit +#define ext2_set_bit test_and_set_bit +#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) +#define ext2_clear_bit test_and_clear_bit +#define ext2_clear_bit_atomic(l,n,a) test_and_clear_bit(n,a) +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit /* Bitmap functions for the minix filesystem. */ #define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) diff -Nru a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h --- a/include/asm-ia64/compat.h Mon May 12 20:55:49 2003 +++ b/include/asm-ia64/compat.h Mon May 12 20:55:49 2003 @@ -102,6 +102,9 @@ int f_spare[6]; }; +#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff +#define COMPAT_RLIM_INFINITY 0xffffffff + typedef u32 compat_old_sigset_t; /* at least 32 bits */ #define _COMPAT_NSIG 64 diff -Nru a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h --- a/include/asm-ia64/dma-mapping.h Mon May 12 20:55:48 2003 +++ b/include/asm-ia64/dma-mapping.h Mon May 12 20:55:48 2003 @@ -1 +1,63 @@ -#include +#ifndef _ASM_IA64_DMA_MAPPING_H +#define _ASM_IA64_DMA_MAPPING_H + +/* + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + */ + +#define dma_alloc_coherent platform_dma_alloc_coherent +#define dma_alloc_noncoherent platform_dma_alloc_coherent /* coherent mem. is cheap */ +#define dma_free_coherent platform_dma_free_coherent +#define dma_free_noncoherent platform_dma_free_coherent +#define dma_map_single platform_dma_map_single +#define dma_map_sg platform_dma_map_sg +#define dma_unmap_single platform_dma_unmap_single +#define dma_unmap_sg platform_dma_unmap_sg +#define dma_sync_single platform_dma_sync_single +#define dma_sync_sg platform_dma_sync_sg + +#define dma_map_page(dev, pg, off, size, dir) \ + dma_map_single(dev, page_address(pg) + (off), (size), (dir)) +#define dma_unmap_page(dev, dma_addr, size, dir) \ + dma_unmap_single(dev, dma_addr, size, dir) + +/* + * Rest of this file is part of the "Advanced DMA API". Use at your own risk. + * See Documentation/DMA-API.txt for details. + */ + +#define dma_sync_single_range(dev, dma_handle, offset, size, dir) \ + dma_sync_single(dev, dma_handle, size, dir) + +#define dma_supported platform_dma_supported + +static inline int +dma_set_mask (struct device *dev, u64 mask) +{ + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + *dev->dma_mask = mask; + return 0; +} + +static inline int +dma_get_cache_alignment (void) +{ + extern int ia64_max_cacheline_size; + return ia64_max_cacheline_size; +} + +static inline void +dma_cache_sync (void *vaddr, size_t size, enum dma_data_direction dir) +{ + /* + * IA-64 is cache-coherent, so this is mostly a no-op. However, we do need to + * ensure that dma_cache_sync() enforces order, hence the mb(). + */ + mb(); +} + +#define dma_is_consistent(dma_handle) (1) /* all we do is coherent memory... */ + +#endif /* _ASM_IA64_DMA_MAPPING_H */ diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h --- a/include/asm-ia64/hardirq.h Mon May 12 20:55:45 2003 +++ b/include/asm-ia64/hardirq.h Mon May 12 20:55:45 2003 @@ -85,7 +85,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h --- a/include/asm-ia64/ia32.h Mon May 12 20:55:49 2003 +++ b/include/asm-ia64/ia32.h Mon May 12 20:55:49 2003 @@ -453,8 +453,6 @@ struct linux_binprm; extern void ia32_gdt_init (void); -extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs); extern void ia32_init_addr_space (struct pt_regs *regs); extern int ia32_setup_arg_pages (struct linux_binprm *bprm); extern int ia32_exception (struct pt_regs *regs, unsigned long isr); @@ -475,5 +473,9 @@ } while(0) #endif /* !CONFIG_IA32_SUPPORT */ + +/* Declare this uncondiontally, so we don't get warnings for unreachable code. */ +extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs); #endif /* _ASM_IA64_IA32_H */ diff -Nru a/include/asm-ia64/intrinsics.h b/include/asm-ia64/intrinsics.h --- a/include/asm-ia64/intrinsics.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/intrinsics.h Mon May 12 20:55:47 2003 @@ -17,16 +17,16 @@ extern unsigned long __bad_size_for_ia64_fetch_and_add (void); extern unsigned long __bad_increment_for_ia64_fetch_and_add (void); -#define IA64_FETCHADD(tmp,v,n,sz) \ +#define IA64_FETCHADD(tmp,v,n,sz,sem) \ ({ \ switch (sz) { \ case 4: \ - __asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2" \ + __asm__ __volatile__ ("fetchadd4."sem" %0=[%1],%2" \ : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ break; \ \ case 8: \ - __asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2" \ + __asm__ __volatile__ ("fetchadd8."sem" %0=[%1],%2" \ : "=r"(tmp) : "r"(v), "i"(n) : "memory"); \ break; \ \ @@ -35,32 +35,34 @@ } \ }) -#define ia64_fetch_and_add(i,v) \ +#define ia64_fetchadd(i,v,sem) \ ({ \ __u64 _tmp; \ volatile __typeof__(*(v)) *_v = (v); \ /* Can't use a switch () here: gcc isn't always smart enough for that... */ \ if ((i) == -16) \ - IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v)), sem); \ else if ((i) == -8) \ - IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v)), sem); \ else if ((i) == -4) \ - IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v)), sem); \ else if ((i) == -1) \ - IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v)), sem); \ else if ((i) == 1) \ - IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v)), sem); \ else if ((i) == 4) \ - IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v)), sem); \ else if ((i) == 8) \ - IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v)), sem); \ else if ((i) == 16) \ - IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v))); \ + IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v)), sem); \ else \ _tmp = __bad_increment_for_ia64_fetch_and_add(); \ - (__typeof__(*(v))) (_tmp + (i)); /* return new value */ \ + (__typeof__(*(v))) (_tmp); /* return old value */ \ }) +#define ia64_fetch_and_add(i,v) (ia64_fetchadd(i, v, "rel") + (i)) /* return new value */ + /* * This function doesn't exist, so you'll get a linker error if * something tries to do an invalid xchg(). @@ -127,7 +129,7 @@ case 8: _o_ = (__u64) (long) (old); break; \ default: break; \ } \ - __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ + __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \ switch (size) { \ case 1: \ __asm__ __volatile__ ("cmpxchg1."sem" %0=[%1],%2,ar.ccv" \ diff -Nru a/include/asm-ia64/io.h b/include/asm-ia64/io.h --- a/include/asm-ia64/io.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/io.h Mon May 12 20:55:44 2003 @@ -13,7 +13,7 @@ * over and over again with slight variations and possibly making a * mistake somewhere. * - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 1999 Asit Mallick * Copyright (C) 1999 Don Dugger @@ -32,6 +32,24 @@ */ #define IO_SPACE_LIMIT 0xffffffffffffffffUL +#define MAX_IO_SPACES 16 +#define IO_SPACE_BITS 24 +#define IO_SPACE_SIZE (1UL << IO_SPACE_BITS) + +#define IO_SPACE_NR(port) ((port) >> IO_SPACE_BITS) +#define IO_SPACE_BASE(space) ((space) << IO_SPACE_BITS) +#define IO_SPACE_PORT(port) ((port) & (IO_SPACE_SIZE - 1)) + +#define IO_SPACE_SPARSE_ENCODING(p) ((((p) >> 2) << 12) | (p & 0xfff)) + +struct io_space { + unsigned long mmio_base; /* base in MMIO space */ + int sparse; +}; + +extern struct io_space io_space[]; +extern unsigned int num_io_spaces; + # ifdef __KERNEL__ #include @@ -80,12 +98,33 @@ static inline void* __ia64_mk_io_addr (unsigned long port) { - const unsigned long io_base = __ia64_get_io_port_base(); - unsigned long addr; + struct io_space *space; + unsigned long offset; - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - return (void *) addr; -} + space = &io_space[IO_SPACE_NR(port)]; + port = IO_SPACE_PORT(port); + if (space->sparse) + offset = IO_SPACE_SPARSE_ENCODING(port); + else + offset = port; + + return (void *) (space->mmio_base | offset); +} + +#define __ia64_inb ___ia64_inb +#define __ia64_inw ___ia64_inw +#define __ia64_inl ___ia64_inl +#define __ia64_outb ___ia64_outb +#define __ia64_outw ___ia64_outw +#define __ia64_outl ___ia64_outl +#define __ia64_readb ___ia64_readb +#define __ia64_readw ___ia64_readw +#define __ia64_readl ___ia64_readl +#define __ia64_readq ___ia64_readq +#define __ia64_writeb ___ia64_writeb +#define __ia64_writew ___ia64_writew +#define __ia64_writel ___ia64_writel +#define __ia64_writeq ___ia64_writeq /* * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure @@ -96,7 +135,7 @@ */ static inline unsigned int -__ia64_inb (unsigned long port) +___ia64_inb (unsigned long port) { volatile unsigned char *addr = __ia64_mk_io_addr(port); unsigned char ret; @@ -107,7 +146,7 @@ } static inline unsigned int -__ia64_inw (unsigned long port) +___ia64_inw (unsigned long port) { volatile unsigned short *addr = __ia64_mk_io_addr(port); unsigned short ret; @@ -118,7 +157,7 @@ } static inline unsigned int -__ia64_inl (unsigned long port) +___ia64_inl (unsigned long port) { volatile unsigned int *addr = __ia64_mk_io_addr(port); unsigned int ret; @@ -129,7 +168,7 @@ } static inline void -__ia64_outb (unsigned char val, unsigned long port) +___ia64_outb (unsigned char val, unsigned long port) { volatile unsigned char *addr = __ia64_mk_io_addr(port); @@ -138,7 +177,7 @@ } static inline void -__ia64_outw (unsigned short val, unsigned long port) +___ia64_outw (unsigned short val, unsigned long port) { volatile unsigned short *addr = __ia64_mk_io_addr(port); @@ -147,7 +186,7 @@ } static inline void -__ia64_outl (unsigned int val, unsigned long port) +___ia64_outl (unsigned int val, unsigned long port) { volatile unsigned int *addr = __ia64_mk_io_addr(port); @@ -160,17 +199,8 @@ { unsigned char *dp = dst; - if (platform_inb == __ia64_inb) { - volatile unsigned char *addr = __ia64_mk_io_addr(port); - - __ia64_mf_a(); - while (count--) - *dp++ = *addr; - __ia64_mf_a(); - } else - while (count--) - *dp++ = platform_inb(port); - return; + while (count--) + *dp++ = platform_inb(port); } static inline void @@ -178,17 +208,8 @@ { unsigned short *dp = dst; - if (platform_inw == __ia64_inw) { - volatile unsigned short *addr = __ia64_mk_io_addr(port); - - __ia64_mf_a(); - while (count--) - *dp++ = *addr; - __ia64_mf_a(); - } else - while (count--) - *dp++ = platform_inw(port); - return; + while (count--) + *dp++ = platform_inw(port); } static inline void @@ -196,17 +217,8 @@ { unsigned int *dp = dst; - if (platform_inl == __ia64_inl) { - volatile unsigned int *addr = __ia64_mk_io_addr(port); - - __ia64_mf_a(); - while (count--) - *dp++ = *addr; - __ia64_mf_a(); - } else - while (count--) - *dp++ = platform_inl(port); - return; + while (count--) + *dp++ = platform_inl(port); } static inline void @@ -214,16 +226,8 @@ { const unsigned char *sp = src; - if (platform_outb == __ia64_outb) { - volatile unsigned char *addr = __ia64_mk_io_addr(port); - - while (count--) - *addr = *sp++; - __ia64_mf_a(); - } else - while (count--) - platform_outb(*sp++, port); - return; + while (count--) + platform_outb(*sp++, port); } static inline void @@ -231,16 +235,8 @@ { const unsigned short *sp = src; - if (platform_outw == __ia64_outw) { - volatile unsigned short *addr = __ia64_mk_io_addr(port); - - while (count--) - *addr = *sp++; - __ia64_mf_a(); - } else - while (count--) - platform_outw(*sp++, port); - return; + while (count--) + platform_outw(*sp++, port); } static inline void @@ -248,16 +244,8 @@ { const unsigned int *sp = src; - if (platform_outl == __ia64_outl) { - volatile unsigned int *addr = __ia64_mk_io_addr(port); - - while (count--) - *addr = *sp++; - __ia64_mf_a(); - } else - while (count--) - platform_outl(*sp++, port); - return; + while (count--) + platform_outl(*sp++, port); } /* @@ -294,25 +282,25 @@ * hopefully it'll stay that way). */ static inline unsigned char -__ia64_readb (void *addr) +___ia64_readb (void *addr) { return *(volatile unsigned char *)addr; } static inline unsigned short -__ia64_readw (void *addr) +___ia64_readw (void *addr) { return *(volatile unsigned short *)addr; } static inline unsigned int -__ia64_readl (void *addr) +___ia64_readl (void *addr) { return *(volatile unsigned int *) addr; } static inline unsigned long -__ia64_readq (void *addr) +___ia64_readq (void *addr) { return *(volatile unsigned long *) addr; } diff -Nru a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h --- a/include/asm-ia64/iosapic.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/iosapic.h Mon May 12 20:55:47 2003 @@ -57,6 +57,7 @@ extern int gsi_to_vector (unsigned int gsi); extern int gsi_to_irq (unsigned int gsi); extern void __init iosapic_parse_prt (void); +extern void iosapic_enable_intr (unsigned int vector); extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity, unsigned long trigger); extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, diff -Nru a/include/asm-ia64/kmap_types.h b/include/asm-ia64/kmap_types.h --- a/include/asm-ia64/kmap_types.h Mon May 12 20:55:46 2003 +++ b/include/asm-ia64/kmap_types.h Mon May 12 20:55:46 2003 @@ -3,7 +3,7 @@ #include -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM # define D(n) __KM_FENCE_##n , #else # define D(n) diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h --- a/include/asm-ia64/machvec.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/machvec.h Mon May 12 20:55:47 2003 @@ -4,7 +4,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Srinivasa Thirumalachar * Copyright (C) Vijay Chander - * Copyright (C) 1999-2001 Hewlett-Packard Co. + * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co. * David Mosberger-Tang */ #ifndef _ASM_IA64_MACHVEC_H @@ -14,7 +14,7 @@ #include /* forward declarations: */ -struct pci_dev; +struct device; struct pt_regs; struct scatterlist; struct irq_desc; @@ -33,17 +33,17 @@ typedef u8 ia64_mv_irq_to_vector (u8); typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector); -/* PCI-DMA interface: */ -typedef void ia64_mv_pci_dma_init (void); -typedef void *ia64_mv_pci_alloc_consistent (struct pci_dev *, size_t, dma_addr_t *); -typedef void ia64_mv_pci_free_consistent (struct pci_dev *, size_t, void *, dma_addr_t); -typedef dma_addr_t ia64_mv_pci_map_single (struct pci_dev *, void *, size_t, int); -typedef void ia64_mv_pci_unmap_single (struct pci_dev *, dma_addr_t, size_t, int); -typedef int ia64_mv_pci_map_sg (struct pci_dev *, struct scatterlist *, int, int); -typedef void ia64_mv_pci_unmap_sg (struct pci_dev *, struct scatterlist *, int, int); -typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int); -typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int); -typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64); +/* DMA-mapping interface: */ +typedef void ia64_mv_dma_init (void); +typedef void *ia64_mv_dma_alloc_coherent (struct device *, size_t, dma_addr_t *, int); +typedef void ia64_mv_dma_free_coherent (struct device *, size_t, void *, dma_addr_t); +typedef dma_addr_t ia64_mv_dma_map_single (struct device *, void *, size_t, int); +typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int); +typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, int); +typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, int); +typedef void ia64_mv_dma_sync_single (struct device *, dma_addr_t, size_t, int); +typedef void ia64_mv_dma_sync_sg (struct device *, struct scatterlist *, int, int); +typedef int ia64_mv_dma_supported (struct device *, u64); /* * WARNING: The legacy I/O space is _architected_. Platforms are @@ -66,6 +66,7 @@ typedef unsigned long ia64_mv_readq_t (void *); extern void machvec_noop (void); +extern void machvec_memory_fence (void); # if defined (CONFIG_IA64_HP_SIM) # include @@ -92,16 +93,16 @@ # define platform_log_print ia64_mv.log_print # define platform_send_ipi ia64_mv.send_ipi # define platform_global_tlb_purge ia64_mv.global_tlb_purge -# define platform_pci_dma_init ia64_mv.dma_init -# define platform_pci_alloc_consistent ia64_mv.alloc_consistent -# define platform_pci_free_consistent ia64_mv.free_consistent -# define platform_pci_map_single ia64_mv.map_single -# define platform_pci_unmap_single ia64_mv.unmap_single -# define platform_pci_map_sg ia64_mv.map_sg -# define platform_pci_unmap_sg ia64_mv.unmap_sg -# define platform_pci_dma_sync_single ia64_mv.sync_single -# define platform_pci_dma_sync_sg ia64_mv.sync_sg -# define platform_pci_dma_supported ia64_mv.dma_supported +# define platform_dma_init ia64_mv.dma_init +# define platform_dma_alloc_coherent ia64_mv.dma_alloc_coherent +# define platform_dma_free_coherent ia64_mv.dma_free_coherent +# define platform_dma_map_single ia64_mv.dma_map_single +# define platform_dma_unmap_single ia64_mv.dma_unmap_single +# define platform_dma_map_sg ia64_mv.dma_map_sg +# define platform_dma_unmap_sg ia64_mv.dma_unmap_sg +# define platform_dma_sync_single ia64_mv.dma_sync_single +# define platform_dma_sync_sg ia64_mv.dma_sync_sg +# define platform_dma_supported ia64_mv.dma_supported # define platform_irq_desc ia64_mv.irq_desc # define platform_irq_to_vector ia64_mv.irq_to_vector # define platform_local_vector_to_irq ia64_mv.local_vector_to_irq @@ -119,7 +120,7 @@ /* __attribute__((__aligned__(16))) is required to make size of the * structure multiple of 16 bytes. - * This will fillup the holes created because of section 3.3.1 in + * This will fillup the holes created because of section 3.3.1 in * Software Conventions guide. */ struct ia64_machine_vector { @@ -133,16 +134,16 @@ ia64_mv_log_print_t *log_print; ia64_mv_send_ipi_t *send_ipi; ia64_mv_global_tlb_purge_t *global_tlb_purge; - ia64_mv_pci_dma_init *dma_init; - ia64_mv_pci_alloc_consistent *alloc_consistent; - ia64_mv_pci_free_consistent *free_consistent; - ia64_mv_pci_map_single *map_single; - ia64_mv_pci_unmap_single *unmap_single; - ia64_mv_pci_map_sg *map_sg; - ia64_mv_pci_unmap_sg *unmap_sg; - ia64_mv_pci_dma_sync_single *sync_single; - ia64_mv_pci_dma_sync_sg *sync_sg; - ia64_mv_pci_dma_supported *dma_supported; + ia64_mv_dma_init *dma_init; + ia64_mv_dma_alloc_coherent *dma_alloc_coherent; + ia64_mv_dma_free_coherent *dma_free_coherent; + ia64_mv_dma_map_single *dma_map_single; + ia64_mv_dma_unmap_single *dma_unmap_single; + ia64_mv_dma_map_sg *dma_map_sg; + ia64_mv_dma_unmap_sg *dma_unmap_sg; + ia64_mv_dma_sync_single *dma_sync_single; + ia64_mv_dma_sync_sg *dma_sync_sg; + ia64_mv_dma_supported *dma_supported; ia64_mv_irq_desc *irq_desc; ia64_mv_irq_to_vector *irq_to_vector; ia64_mv_local_vector_to_irq *local_vector_to_irq; @@ -170,16 +171,16 @@ platform_log_print, \ platform_send_ipi, \ platform_global_tlb_purge, \ - platform_pci_dma_init, \ - platform_pci_alloc_consistent, \ - platform_pci_free_consistent, \ - platform_pci_map_single, \ - platform_pci_unmap_single, \ - platform_pci_map_sg, \ - platform_pci_unmap_sg, \ - platform_pci_dma_sync_single, \ - platform_pci_dma_sync_sg, \ - platform_pci_dma_supported, \ + platform_dma_init, \ + platform_dma_alloc_coherent, \ + platform_dma_free_coherent, \ + platform_dma_map_single, \ + platform_dma_unmap_single, \ + platform_dma_map_sg, \ + platform_dma_unmap_sg, \ + platform_dma_sync_single, \ + platform_dma_sync_sg, \ + platform_dma_supported, \ platform_irq_desc, \ platform_irq_to_vector, \ platform_local_vector_to_irq, \ @@ -205,16 +206,16 @@ /* * Declare default routines which aren't declared anywhere else: */ -extern ia64_mv_pci_dma_init swiotlb_init; -extern ia64_mv_pci_alloc_consistent swiotlb_alloc_consistent; -extern ia64_mv_pci_free_consistent swiotlb_free_consistent; -extern ia64_mv_pci_map_single swiotlb_map_single; -extern ia64_mv_pci_unmap_single swiotlb_unmap_single; -extern ia64_mv_pci_map_sg swiotlb_map_sg; -extern ia64_mv_pci_unmap_sg swiotlb_unmap_sg; -extern ia64_mv_pci_dma_sync_single swiotlb_sync_single; -extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg; -extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported; +extern ia64_mv_dma_init swiotlb_init; +extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent; +extern ia64_mv_dma_free_coherent swiotlb_free_coherent; +extern ia64_mv_dma_map_single swiotlb_map_single; +extern ia64_mv_dma_unmap_single swiotlb_unmap_single; +extern ia64_mv_dma_map_sg swiotlb_map_sg; +extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg; +extern ia64_mv_dma_sync_single swiotlb_sync_single; +extern ia64_mv_dma_sync_sg swiotlb_sync_sg; +extern ia64_mv_dma_supported swiotlb_dma_supported; /* * Define default versions so we can extend machvec for new platforms without having @@ -247,35 +248,35 @@ #ifndef platform_global_tlb_purge # define platform_global_tlb_purge ia64_global_tlb_purge /* default to architected version */ #endif -#ifndef platform_pci_dma_init -# define platform_pci_dma_init swiotlb_init +#ifndef platform_dma_init +# define platform_dma_init swiotlb_init #endif -#ifndef platform_pci_alloc_consistent -# define platform_pci_alloc_consistent swiotlb_alloc_consistent +#ifndef platform_dma_alloc_coherent +# define platform_dma_alloc_coherent swiotlb_alloc_coherent #endif -#ifndef platform_pci_free_consistent -# define platform_pci_free_consistent swiotlb_free_consistent +#ifndef platform_dma_free_coherent +# define platform_dma_free_coherent swiotlb_free_coherent #endif -#ifndef platform_pci_map_single -# define platform_pci_map_single swiotlb_map_single +#ifndef platform_dma_map_single +# define platform_dma_map_single swiotlb_map_single #endif -#ifndef platform_pci_unmap_single -# define platform_pci_unmap_single swiotlb_unmap_single +#ifndef platform_dma_unmap_single +# define platform_dma_unmap_single swiotlb_unmap_single #endif -#ifndef platform_pci_map_sg -# define platform_pci_map_sg swiotlb_map_sg +#ifndef platform_dma_map_sg +# define platform_dma_map_sg swiotlb_map_sg #endif -#ifndef platform_pci_unmap_sg -# define platform_pci_unmap_sg swiotlb_unmap_sg +#ifndef platform_dma_unmap_sg +# define platform_dma_unmap_sg swiotlb_unmap_sg #endif -#ifndef platform_pci_dma_sync_single -# define platform_pci_dma_sync_single swiotlb_sync_single +#ifndef platform_dma_sync_single +# define platform_dma_sync_single swiotlb_sync_single #endif -#ifndef platform_pci_dma_sync_sg -# define platform_pci_dma_sync_sg swiotlb_sync_sg +#ifndef platform_dma_sync_sg +# define platform_dma_sync_sg swiotlb_sync_sg #endif -#ifndef platform_pci_dma_supported -# define platform_pci_dma_supported swiotlb_pci_dma_supported +#ifndef platform_dma_supported +# define platform_dma_supported swiotlb_dma_supported #endif #ifndef platform_irq_desc # define platform_irq_desc __ia64_irq_desc diff -Nru a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h --- a/include/asm-ia64/machvec_hpzx1.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/machvec_hpzx1.h Mon May 12 20:55:44 2003 @@ -2,13 +2,13 @@ #define _ASM_IA64_MACHVEC_HPZX1_h extern ia64_mv_setup_t dig_setup; -extern ia64_mv_pci_alloc_consistent sba_alloc_consistent; -extern ia64_mv_pci_free_consistent sba_free_consistent; -extern ia64_mv_pci_map_single sba_map_single; -extern ia64_mv_pci_unmap_single sba_unmap_single; -extern ia64_mv_pci_map_sg sba_map_sg; -extern ia64_mv_pci_unmap_sg sba_unmap_sg; -extern ia64_mv_pci_dma_supported sba_dma_supported; +extern ia64_mv_dma_alloc_coherent sba_alloc_coherent; +extern ia64_mv_dma_free_coherent sba_free_coherent; +extern ia64_mv_dma_map_single sba_map_single; +extern ia64_mv_dma_unmap_single sba_unmap_single; +extern ia64_mv_dma_map_sg sba_map_sg; +extern ia64_mv_dma_unmap_sg sba_unmap_sg; +extern ia64_mv_dma_supported sba_dma_supported; /* * This stuff has dual use! @@ -19,15 +19,15 @@ */ #define platform_name "hpzx1" #define platform_setup dig_setup -#define platform_pci_dma_init ((ia64_mv_pci_dma_init *) machvec_noop) -#define platform_pci_alloc_consistent sba_alloc_consistent -#define platform_pci_free_consistent sba_free_consistent -#define platform_pci_map_single sba_map_single -#define platform_pci_unmap_single sba_unmap_single -#define platform_pci_map_sg sba_map_sg -#define platform_pci_unmap_sg sba_unmap_sg -#define platform_pci_dma_sync_single ((ia64_mv_pci_dma_sync_single *) machvec_noop) -#define platform_pci_dma_sync_sg ((ia64_mv_pci_dma_sync_sg *) machvec_noop) -#define platform_pci_dma_supported sba_dma_supported +#define platform_dma_init ((ia64_mv_dma_init *) machvec_noop) +#define platform_dma_alloc_coherent sba_alloc_coherent +#define platform_dma_free_coherent sba_free_coherent +#define platform_dma_map_single sba_map_single +#define platform_dma_unmap_single sba_unmap_single +#define platform_dma_map_sg sba_map_sg +#define platform_dma_unmap_sg sba_unmap_sg +#define platform_dma_sync_single ((ia64_mv_dma_sync_single *) machvec_memory_fence) +#define platform_dma_sync_sg ((ia64_mv_dma_sync_sg *) machvec_memory_fence) +#define platform_dma_supported sba_dma_supported #endif /* _ASM_IA64_MACHVEC_HPZX1_h */ diff -Nru a/include/asm-ia64/machvec_init.h b/include/asm-ia64/machvec_init.h --- a/include/asm-ia64/machvec_init.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/machvec_init.h Mon May 12 20:55:44 2003 @@ -1,7 +1,3 @@ -#define __MACHVEC_HDR(n) -#define __MACHVEC_EXPAND(n) __MACHVEC_HDR(n) -#define MACHVEC_PLATFORM_HEADER __MACHVEC_EXPAND(MACHVEC_PLATFORM_NAME) - #include extern ia64_mv_send_ipi_t ia64_send_ipi; @@ -16,6 +12,10 @@ extern ia64_mv_outb_t __ia64_outb; extern ia64_mv_outw_t __ia64_outw; extern ia64_mv_outl_t __ia64_outl; +extern ia64_mv_readb_t __ia64_readb; +extern ia64_mv_readw_t __ia64_readw; +extern ia64_mv_readl_t __ia64_readl; +extern ia64_mv_readq_t __ia64_readq; #define MACHVEC_HELPER(name) \ struct ia64_machine_vector machvec_##name __attribute__ ((unused, __section__ (".machvec"))) \ diff -Nru a/include/asm-ia64/machvec_sn1.h b/include/asm-ia64/machvec_sn1.h --- a/include/asm-ia64/machvec_sn1.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/machvec_sn1.h Mon May 12 20:55:47 2003 @@ -44,14 +44,14 @@ extern ia64_mv_outb_t sn1_outb; extern ia64_mv_outw_t sn1_outw; extern ia64_mv_outl_t sn1_outl; -extern ia64_mv_pci_alloc_consistent sn1_pci_alloc_consistent; -extern ia64_mv_pci_free_consistent sn1_pci_free_consistent; -extern ia64_mv_pci_map_single sn1_pci_map_single; -extern ia64_mv_pci_unmap_single sn1_pci_unmap_single; -extern ia64_mv_pci_map_sg sn1_pci_map_sg; -extern ia64_mv_pci_unmap_sg sn1_pci_unmap_sg; -extern ia64_mv_pci_dma_sync_single sn1_pci_dma_sync_single; -extern ia64_mv_pci_dma_sync_sg sn1_pci_dma_sync_sg; +extern ia64_mv_dma_alloc_coherent sn1_dma_alloc_coherent; +extern ia64_mv_dma_free_coherent sn1_dma_free_coherent; +extern ia64_mv_dma_map_single sn1_dma_map_single; +extern ia64_mv_dma_unmap_single sn1_dma_unmap_single; +extern ia64_mv_dma_map_sg sn1_dma_map_sg; +extern ia64_mv_dma_unmap_sg sn1_dma_unmap_sg; +extern ia64_mv_dma_sync_single sn1_dma_sync_single; +extern ia64_mv_dma_sync_sg sn1_dma_sync_sg; /* * This stuff has dual use! @@ -72,14 +72,14 @@ #define platform_outb sn1_outb #define platform_outw sn1_outw #define platform_outl sn1_outl -#define platform_pci_dma_init machvec_noop -#define platform_pci_alloc_consistent sn1_pci_alloc_consistent -#define platform_pci_free_consistent sn1_pci_free_consistent -#define platform_pci_map_single sn1_pci_map_single -#define platform_pci_unmap_single sn1_pci_unmap_single -#define platform_pci_map_sg sn1_pci_map_sg -#define platform_pci_unmap_sg sn1_pci_unmap_sg -#define platform_pci_dma_sync_single sn1_pci_dma_sync_single -#define platform_pci_dma_sync_sg sn1_pci_dma_sync_sg +#define platform_dma_init machvec_noop +#define platform_dma_alloc_coherent sn1_dma_alloc_coherent +#define platform_dma_free_coherent sn1_dma_free_coherent +#define platform_dma_map_single sn1_dma_map_single +#define platform_dma_unmap_single sn1_dma_unmap_single +#define platform_dma_map_sg sn1_dma_map_sg +#define platform_dma_unmap_sg sn1_dma_unmap_sg +#define platform_dma_sync_single sn1_dma_sync_single +#define platform_dma_sync_sg sn1_dma_sync_sg #endif /* _ASM_IA64_MACHVEC_SN1_h */ diff -Nru a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h --- a/include/asm-ia64/machvec_sn2.h Mon May 12 20:55:46 2003 +++ b/include/asm-ia64/machvec_sn2.h Mon May 12 20:55:46 2003 @@ -51,15 +51,15 @@ extern ia64_mv_readw_t __sn_readw; extern ia64_mv_readl_t __sn_readl; extern ia64_mv_readq_t __sn_readq; -extern ia64_mv_pci_alloc_consistent sn_pci_alloc_consistent; -extern ia64_mv_pci_free_consistent sn_pci_free_consistent; -extern ia64_mv_pci_map_single sn_pci_map_single; -extern ia64_mv_pci_unmap_single sn_pci_unmap_single; -extern ia64_mv_pci_map_sg sn_pci_map_sg; -extern ia64_mv_pci_unmap_sg sn_pci_unmap_sg; -extern ia64_mv_pci_dma_sync_single sn_pci_dma_sync_single; -extern ia64_mv_pci_dma_sync_sg sn_pci_dma_sync_sg; -extern ia64_mv_pci_dma_supported sn_pci_dma_supported; +extern ia64_mv_dma_alloc_coherent sn_dma_alloc_coherent; +extern ia64_mv_dma_free_coherent sn_dma_free_coherent; +extern ia64_mv_dma_map_single sn_dma_map_single; +extern ia64_mv_dma_unmap_single sn_dma_unmap_single; +extern ia64_mv_dma_map_sg sn_dma_map_sg; +extern ia64_mv_dma_unmap_sg sn_dma_unmap_sg; +extern ia64_mv_dma_sync_single sn_dma_sync_single; +extern ia64_mv_dma_sync_sg sn_dma_sync_sg; +extern ia64_mv_dma_supported sn_dma_supported; /* * This stuff has dual use! @@ -88,15 +88,15 @@ #define platform_irq_desc sn_irq_desc #define platform_irq_to_vector sn_irq_to_vector #define platform_local_vector_to_irq sn_local_vector_to_irq -#define platform_pci_dma_init machvec_noop -#define platform_pci_alloc_consistent sn_pci_alloc_consistent -#define platform_pci_free_consistent sn_pci_free_consistent -#define platform_pci_map_single sn_pci_map_single -#define platform_pci_unmap_single sn_pci_unmap_single -#define platform_pci_map_sg sn_pci_map_sg -#define platform_pci_unmap_sg sn_pci_unmap_sg -#define platform_pci_dma_sync_single sn_pci_dma_sync_single -#define platform_pci_dma_sync_sg sn_pci_dma_sync_sg -#define platform_pci_dma_supported sn_pci_dma_supported +#define platform_dma_init machvec_noop +#define platform_dma_alloc_coherent sn_dma_alloc_coherent +#define platform_dma_free_coherent sn_dma_free_coherent +#define platform_dma_map_single sn_dma_map_single +#define platform_dma_unmap_single sn_dma_unmap_single +#define platform_dma_map_sg sn_dma_map_sg +#define platform_dma_unmap_sg sn_dma_unmap_sg +#define platform_dma_sync_single sn_dma_sync_single +#define platform_dma_sync_sg sn_dma_sync_sg +#define platform_dma_supported sn_dma_supported #endif /* _ASM_IA64_MACHVEC_SN2_H */ diff -Nru a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h --- a/include/asm-ia64/mca.h Mon May 12 20:55:45 2003 +++ b/include/asm-ia64/mca.h Mon May 12 20:55:45 2003 @@ -11,7 +11,10 @@ #define _ASM_IA64_MCA_H #if !defined(__ASSEMBLY__) + +#include #include + #include #include #include @@ -129,10 +132,10 @@ extern void ia64_mca_ucmc_handler(void); extern void ia64_monarch_init_handler(void); extern void ia64_slave_init_handler(void); -extern void ia64_mca_rendez_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cmc_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cpe_int_handler(int,void *,struct pt_regs *); +extern irqreturn_t ia64_mca_rendez_int_handler(int,void *,struct pt_regs *); +extern irqreturn_t ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *); +extern irqreturn_t ia64_mca_cmc_int_handler(int,void *,struct pt_regs *); +extern irqreturn_t ia64_mca_cpe_int_handler(int,void *,struct pt_regs *); extern int ia64_log_print(int,prfunc_t); extern void ia64_mca_cmc_vector_setup(void); extern int ia64_mca_check_errors(void); diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h --- a/include/asm-ia64/page.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/page.h Mon May 12 20:55:44 2003 @@ -37,6 +37,8 @@ # if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB) # define HPAGE_SHIFT 32 +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1GB) +# define HPAGE_SHIFT 30 # elif defined(CONFIG_HUGETLB_PAGE_SIZE_256MB) # define HPAGE_SHIFT 28 # elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) @@ -89,7 +91,12 @@ #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) #ifndef CONFIG_DISCONTIGMEM -#define pfn_valid(pfn) ((pfn) < max_mapnr) +# ifdef CONFIG_VIRTUAL_MEM_MAP + extern int ia64_pfn_valid (unsigned long pfn); +# define pfn_valid(pfn) (((pfn) < max_mapnr) && ia64_pfn_valid(pfn)) +# else +# define pfn_valid(pfn) ((pfn) < max_mapnr) +# endif #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define page_to_pfn(page) ((unsigned long) (page - mem_map)) #define pfn_to_page(pfn) (mem_map + (pfn)) diff -Nru a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h --- a/include/asm-ia64/pal.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/pal.h Mon May 12 20:55:47 2003 @@ -622,7 +622,8 @@ u64 pmsa_xip; /* previous iip */ u64 pmsa_xpsr; /* previous psr */ u64 pmsa_xfs; /* previous ifs */ - u64 pmsa_reserved[71]; /* pal_min_state_area should total to 1KB */ + u64 pmsa_br1; /* branch register 1 */ + u64 pmsa_reserved[70]; /* pal_min_state_area should total to 1KB */ } pal_min_state_area_t; diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h --- a/include/asm-ia64/pci.h Mon May 12 20:55:48 2003 +++ b/include/asm-ia64/pci.h Mon May 12 20:55:48 2003 @@ -47,18 +47,7 @@ #define HAVE_ARCH_PCI_MWI 1 extern int pcibios_prep_mwi (struct pci_dev *); -/* - * Dynamic DMA mapping API. See Documentation/DMA-mapping.txt for details. - */ -#define pci_alloc_consistent platform_pci_alloc_consistent -#define pci_free_consistent platform_pci_free_consistent -#define pci_map_single platform_pci_map_single -#define pci_unmap_single platform_pci_unmap_single -#define pci_map_sg platform_pci_map_sg -#define pci_unmap_sg platform_pci_unmap_sg -#define pci_dma_sync_single platform_pci_dma_sync_single -#define pci_dma_sync_sg platform_pci_dma_sync_sg -#define pci_dma_supported platform_pci_dma_supported +#include /* pci_unmap_{single,page} is not a nop, thus... */ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ @@ -74,18 +63,12 @@ #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -#define pci_map_page(dev,pg,off,size,dir) \ - pci_map_single((dev), page_address(pg) + (off), (size), (dir)) -#define pci_unmap_page(dev,dma_addr,size,dir) \ - pci_unmap_single((dev), (dma_addr), (size), (dir)) - /* The ia64 platform always supports 64-bit addressing. */ -#define pci_dac_dma_supported(pci_dev, mask) (1) - -#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma_addr_t) page_to_bus(pg) + (off)) -#define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr))) -#define pci_dac_dma_to_offset(dev,dma_addr) ((dma_addr) & ~PAGE_MASK) -#define pci_dac_dma_sync_single(dev,dma_addr,len,dir) do { /* nothing */ } while (0) +#define pci_dac_dma_supported(pci_dev, mask) (1) +#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma_addr_t) page_to_bus(pg) + (off)) +#define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr))) +#define pci_dac_dma_to_offset(dev,dma_addr) ((dma_addr) & ~PAGE_MASK) +#define pci_dac_dma_sync_single(dev,dma_addr,len,dir) do { mb(); } while (0) /* Return the index of the PCI controller for device PDEV. */ #define pci_controller_num(PDEV) (0) @@ -97,12 +80,18 @@ extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); +struct pci_window { + struct resource resource; + u64 offset; +}; + struct pci_controller { void *acpi_handle; void *iommu; int segment; - u64 mem_offset; + unsigned int windows; + struct pci_window *window; }; #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata) diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h --- a/include/asm-ia64/percpu.h Mon May 12 20:55:48 2003 +++ b/include/asm-ia64/percpu.h Mon May 12 20:55:48 2003 @@ -5,7 +5,7 @@ #include /* - * Copyright (C) 2002 Hewlett-Packard Co + * Copyright (C) 2002-2003 Hewlett-Packard Co * David Mosberger-Tang */ @@ -34,6 +34,8 @@ #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(var##__per_cpu) #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(var##__per_cpu) + +extern void setup_per_cpu_areas (void); #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h --- a/include/asm-ia64/perfmon.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/perfmon.h Mon May 12 20:55:47 2003 @@ -41,6 +41,7 @@ #define PFM_FL_NOTIFY_BLOCK 0x04 /* block task on user level notifications */ #define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ #define PFM_FL_EXCL_IDLE 0x20 /* exclude idle task from system wide session */ +#define PFM_FL_UNSECURE 0x40 /* allow unsecure monitoring for non self-monitoring task */ /* * PMC flags @@ -125,7 +126,7 @@ * Define the version numbers for both perfmon as a whole and the sampling buffer format. */ #define PFM_VERSION_MAJ 1U -#define PFM_VERSION_MIN 3U +#define PFM_VERSION_MIN 4U #define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) #define PFM_SMPL_VERSION_MAJ 1U diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h Mon May 12 20:55:45 2003 +++ b/include/asm-ia64/processor.h Mon May 12 20:55:45 2003 @@ -39,6 +39,14 @@ #define TASK_SIZE (current->thread.task_size) /* + * MM_VM_SIZE(mm) gives the maximum address (plus 1) which may contain a mapping for + * address-space MM. Note that with 32-bit tasks, this is still DEFAULT_TASK_SIZE, + * because the kernel may have installed helper-mappings above TASK_SIZE. For example, + * for x86 emulation, the LDT and GDT are mapped above TASK_SIZE. + */ +#define MM_VM_SIZE(mm) DEFAULT_TASK_SIZE + +/* * This decides where the kernel will search for a free chunk of vm * space during mmap's. */ @@ -291,7 +299,7 @@ #define start_thread(regs,new_ip,new_sp) do { \ set_fs(USER_DS); \ - regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP)) \ + regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL)) \ & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS)); \ regs->cr_iip = new_ip; \ regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h --- a/include/asm-ia64/ptrace.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/ptrace.h Mon May 12 20:55:47 2003 @@ -227,8 +227,10 @@ }) struct task_struct; /* forward decl */ + struct unw_frame_info; /* forward decl */ extern void show_regs (struct pt_regs *); + extern void ia64_do_show_stack (struct unw_frame_info *, void *); extern unsigned long ia64_get_user_rbs_end (struct task_struct *, struct pt_regs *, unsigned long *); extern long ia64_peek (struct task_struct *, struct switch_stack *, unsigned long, diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h Mon May 12 20:55:49 2003 +++ b/include/asm-ia64/sal.h Mon May 12 20:55:49 2003 @@ -226,7 +226,7 @@ /* Encodings for machine check parameter types */ enum { - SAL_MC_PARAM_RENDEZ_INT = 1, /* Rendezevous interrupt */ + SAL_MC_PARAM_RENDEZ_INT = 1, /* Rendezvous interrupt */ SAL_MC_PARAM_RENDEZ_WAKEUP = 2, /* Wakeup */ SAL_MC_PARAM_CPE_INT = 3 /* Corrected Platform Error Int */ }; diff -Nru a/include/asm-ia64/serial.h b/include/asm-ia64/serial.h --- a/include/asm-ia64/serial.h Mon May 12 20:55:46 2003 +++ b/include/asm-ia64/serial.h Mon May 12 20:55:46 2003 @@ -59,7 +59,6 @@ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ - #ifdef CONFIG_SERIAL_MANY_PORTS #define EXTRA_SERIAL_PORT_DEFNS \ { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \ diff -Nru a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h --- a/include/asm-ia64/sn/addrs.h Mon May 12 20:55:48 2003 +++ b/include/asm-ia64/sn/addrs.h Mon May 12 20:55:48 2003 @@ -215,7 +215,7 @@ #define REMOTE_HUB_ADDR(_n, _x) (HUBREG_CAST (NODE_SWIN_BASE(_n, 1) + \ 0x800000 + (_x))) #endif -#if CONFIG_IA64_SGI_SN1 +#ifdef CONFIG_IA64_SGI_SN1 #define REMOTE_HUB_PI_ADDR(_n, _sn, _x) (HUBREG_CAST (NODE_SWIN_BASE(_n, 1) + \ 0x800000 + PIREG(_x, _sn))) #endif diff -Nru a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h --- a/include/asm-ia64/spinlock.h Mon May 12 20:55:44 2003 +++ b/include/asm-ia64/spinlock.h Mon May 12 20:55:44 2003 @@ -22,26 +22,72 @@ #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(x) ((x)->lock = 0) -#define DEBUG_SPIN_LOCK 0 +#define NEW_LOCK +#ifdef NEW_LOCK -#if DEBUG_SPIN_LOCK - -#include +/* + * Try to get the lock. If we fail to get the lock, make a non-standard call to + * ia64_spinlock_contention(). We do not use a normal call because that would force all + * callers of spin_lock() to be non-leaf routines. Instead, ia64_spinlock_contention() is + * carefully coded to touch only those registers that spin_lock() marks "clobbered". + */ -#define _raw_spin_lock(x) \ -do { \ - unsigned long _timeout = 1000000000; \ - volatile unsigned int _old = 0, _new = 1, *_ptr = &((x)->lock); \ - do { \ - if (_timeout-- == 0) { \ - extern void dump_stack (void); \ - printk("kernel DEADLOCK at %s:%d?\n", __FILE__, __LINE__); \ - dump_stack(); \ - } \ - } while (__sync_val_compare_and_swap(_ptr, _old, _new) != _old); \ -} while (0) +#define IA64_SPINLOCK_CLOBBERS "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory" +static inline void +_raw_spin_lock (spinlock_t *lock) +{ + register volatile unsigned int *ptr asm ("r31") = &lock->lock; + +#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +# ifdef CONFIG_ITANIUM + /* don't use brl on Itanium... */ + asm volatile ("{\n\t" + " mov ar.ccv = r0\n\t" + " mov r28 = ip\n\t" + " mov r30 = 1;;\n\t" + "}\n\t" + "cmpxchg4.acq r30 = [%1], r30, ar.ccv\n\t" + "movl r29 = ia64_spinlock_contention_pre3_4;;\n\t" + "cmp4.ne p14, p0 = r30, r0\n\t" + "mov b6 = r29;;\n" + "(p14) br.cond.spnt.many b6" + : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS); +# else + asm volatile ("{\n\t" + " mov ar.ccv = r0\n\t" + " mov r28 = ip\n\t" + " mov r30 = 1;;\n\t" + "}\n\t" + "cmpxchg4.acq r30 = [%1], r30, ar.ccv;;\n\t" + "cmp4.ne p14, p0 = r30, r0\n" + "(p14) brl.cond.spnt.many ia64_spinlock_contention_pre3_4" + : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS); +# endif /* CONFIG_MCKINLEY */ #else +# ifdef CONFIG_ITANIUM + /* don't use brl on Itanium... */ + /* mis-declare, so we get the entry-point, not it's function descriptor: */ + asm volatile ("mov r30 = 1\n\t" + "mov ar.ccv = r0;;\n\t" + "cmpxchg4.acq r30 = [%0], r30, ar.ccv\n\t" + "movl r29 = ia64_spinlock_contention;;\n\t" + "cmp4.ne p14, p0 = r30, r0\n\t" + "mov b6 = r29;;\n" + "(p14) br.call.spnt.many b6 = b6" + : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS); +# else + asm volatile ("mov r30 = 1\n\t" + "mov ar.ccv = r0;;\n\t" + "cmpxchg4.acq r30 = [%0], r30, ar.ccv;;\n\t" + "cmp4.ne p14, p0 = r30, r0\n\t" + "(p14) brl.call.spnt.many b6=ia64_spinlock_contention" + : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS); +# endif /* CONFIG_MCKINLEY */ +#endif +} + +#else /* !NEW_LOCK */ /* * Streamlined test_and_set_bit(0, (x)). We use test-and-test-and-set @@ -64,7 +110,7 @@ ";;\n" \ :: "r"(&(x)->lock) : "ar.ccv", "p7", "r2", "r29", "memory") -#endif /* !DEBUG_SPIN_LOCK */ +#endif /* !NEW_LOCK */ #define spin_is_locked(x) ((x)->lock != 0) #define _raw_spin_unlock(x) do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0) @@ -72,43 +118,31 @@ #define spin_unlock_wait(x) do { barrier(); } while ((x)->lock) typedef struct { - volatile int read_counter:31; - volatile int write_lock:1; + volatile int read_counter : 31; + volatile int write_lock : 1; } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #define rwlock_is_locked(x) (*(volatile int *) (x) != 0) -#define _raw_read_lock(rw) \ -do { \ - int __read_lock_tmp = 0; \ - __asm__ __volatile__ ("1:\tfetchadd4.acq %0 = [%1], 1\n" \ - ";;\n" \ - "tbit.nz p6,p0 = %0, 31\n" \ - "(p6) br.cond.sptk.few 2f\n" \ - ".section .text.lock,\"ax\"\n" \ - "2:\tfetchadd4.rel %0 = [%1], -1\n" \ - ";;\n" \ - "3:\tld4.acq %0 = [%1]\n" \ - ";;\n" \ - "tbit.nz p6,p0 = %0, 31\n" \ - "(p6) br.cond.sptk.few 3b\n" \ - "br.cond.sptk.few 1b\n" \ - ";;\n" \ - ".previous\n" \ - : "=&r" (__read_lock_tmp) \ - : "r" (rw) : "p6", "memory"); \ -} while(0) - -#define _raw_read_unlock(rw) \ -do { \ - int __read_unlock_tmp = 0; \ - __asm__ __volatile__ ("fetchadd4.rel %0 = [%1], -1\n" \ - : "=r" (__read_unlock_tmp) \ - : "r" (rw) \ - : "memory"); \ -} while(0) +#define _raw_read_lock(rw) \ +do { \ + rwlock_t *__read_lock_ptr = (rw); \ + \ + while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, "acq") < 0)) { \ + ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel"); \ + while (*(volatile int *)__read_lock_ptr < 0) \ + barrier(); \ + \ + } \ +} while (0) + +#define _raw_read_unlock(rw) \ +do { \ + rwlock_t *__read_lock_ptr = (rw); \ + ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel"); \ +} while (0) #define _raw_write_lock(rw) \ do { \ diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h --- a/include/asm-ia64/system.h Mon May 12 20:55:46 2003 +++ b/include/asm-ia64/system.h Mon May 12 20:55:46 2003 @@ -212,48 +212,39 @@ # define PERFMON_IS_SYSWIDE() (0) #endif -#define __switch_to(prev,next,last) do { \ - if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \ - || IS_IA32_PROCESS(ia64_task_regs(prev)) || PERFMON_IS_SYSWIDE()) \ - ia64_save_extra(prev); \ - if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)) \ - || IS_IA32_PROCESS(ia64_task_regs(next)) || PERFMON_IS_SYSWIDE()) \ - ia64_load_extra(next); \ - (last) = ia64_switch_to((next)); \ +#define IA64_HAS_EXTRA_STATE(t) \ + ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID) \ + || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE()) + +#define __switch_to(prev,next,last) do { \ + struct task_struct *__fpu_owner = ia64_get_fpu_owner(); \ + if (IA64_HAS_EXTRA_STATE(prev)) \ + ia64_save_extra(prev); \ + if (IA64_HAS_EXTRA_STATE(next)) \ + ia64_load_extra(next); \ + ia64_psr(ia64_task_regs(next))->dfh = \ + !(__fpu_owner == (next) && ((next)->thread.last_fph_cpu == smp_processor_id())); \ + (last) = ia64_switch_to((next)); \ } while (0) #ifdef CONFIG_SMP - /* - * In the SMP case, we save the fph state when context-switching - * away from a thread that modified fph. This way, when the thread - * gets scheduled on another CPU, the CPU can pick up the state from - * task->thread.fph, avoiding the complication of having to fetch - * the latest fph state from another CPU. + * In the SMP case, we save the fph state when context-switching away from a thread that + * modified fph. This way, when the thread gets scheduled on another CPU, the CPU can + * pick up the state from task->thread.fph, avoiding the complication of having to fetch + * the latest fph state from another CPU. In other words: eager save, lazy restore. */ -# define switch_to(prev,next,last) do { \ - if (ia64_psr(ia64_task_regs(prev))->mfh) { \ - ia64_psr(ia64_task_regs(prev))->mfh = 0; \ - (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ - __ia64_save_fpu((prev)->thread.fph); \ - (prev)->thread.last_fph_cpu = smp_processor_id(); \ - } \ - if ((next)->thread.flags & IA64_THREAD_FPH_VALID) { \ - if (((next)->thread.last_fph_cpu == smp_processor_id()) \ - && (ia64_get_fpu_owner() == next)) \ - { \ - ia64_psr(ia64_task_regs(next))->dfh = 0; \ - ia64_psr(ia64_task_regs(next))->mfh = 0; \ - } else \ - ia64_psr(ia64_task_regs(next))->dfh = 1; \ - } \ - __switch_to(prev,next,last); \ - } while (0) -#else # define switch_to(prev,next,last) do { \ - ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next)); \ - __switch_to(prev,next,last); \ + if (ia64_psr(ia64_task_regs(prev))->mfh) { \ + ia64_psr(ia64_task_regs(prev))->mfh = 0; \ + (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ + __ia64_save_fpu((prev)->thread.fph); \ + (prev)->thread.last_fph_cpu = smp_processor_id(); \ + } \ + __switch_to(prev, next, last); \ } while (0) +#else +# define switch_to(prev,next,last) __switch_to(prev, next, last) #endif /* diff -Nru a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h --- a/include/asm-ia64/uaccess.h Mon May 12 20:55:45 2003 +++ b/include/asm-ia64/uaccess.h Mon May 12 20:55:45 2003 @@ -8,7 +8,7 @@ * addresses. Thus, we need to be careful not to let the user to * trick us into accessing kernel memory that would normally be * inaccessible. This code is also fairly performance sensitive, - * so we want to spend as little time doing saftey checks as + * so we want to spend as little time doing safety checks as * possible. * * To make matters a bit more interesting, these macros sometimes also diff -Nru a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h --- a/include/asm-ia64/unwind.h Mon May 12 20:55:47 2003 +++ b/include/asm-ia64/unwind.h Mon May 12 20:55:47 2003 @@ -2,8 +2,8 @@ #define _ASM_IA64_UNWIND_H /* - * Copyright (C) 1999-2000 Hewlett-Packard Co - * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co + * David Mosberger-Tang * * A simple API for unwinding kernel stacks. This is used for * debugging and error reporting purposes. The kernel doesn't need @@ -106,6 +106,13 @@ * Prepare to unwind blocked task t. */ extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t); + +/* + * Prepare to unwind from interruption. The pt-regs and switch-stack structures must have + * be "adjacent" (no state modifications between pt-regs and switch-stack). + */ +extern void unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t, + struct pt_regs *pt, struct switch_stack *sw); extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw); diff -Nru a/include/asm-m68k/elf.h b/include/asm-m68k/elf.h --- a/include/asm-m68k/elf.h Mon May 12 20:55:45 2003 +++ b/include/asm-m68k/elf.h Mon May 12 20:55:45 2003 @@ -9,6 +9,33 @@ #include #include +/* + * 68k ELF relocation types + */ +#define R_68K_NONE 0 +#define R_68K_32 1 +#define R_68K_16 2 +#define R_68K_8 3 +#define R_68K_PC32 4 +#define R_68K_PC16 5 +#define R_68K_PC8 6 +#define R_68K_GOT32 7 +#define R_68K_GOT16 8 +#define R_68K_GOT8 9 +#define R_68K_GOT32O 10 +#define R_68K_GOT16O 11 +#define R_68K_GOT8O 12 +#define R_68K_PLT32 13 +#define R_68K_PLT16 14 +#define R_68K_PLT8 15 +#define R_68K_PLT32O 16 +#define R_68K_PLT16O 17 +#define R_68K_PLT8O 18 +#define R_68K_COPY 19 +#define R_68K_GLOB_DAT 20 +#define R_68K_JMP_SLOT 21 +#define R_68K_RELATIVE 22 + typedef unsigned long elf_greg_t; #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) diff -Nru a/include/asm-m68k/hardirq.h b/include/asm-m68k/hardirq.h --- a/include/asm-m68k/hardirq.h Mon May 12 20:55:46 2003 +++ b/include/asm-m68k/hardirq.h Mon May 12 20:55:46 2003 @@ -73,7 +73,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-m68knommu/hardirq.h b/include/asm-m68knommu/hardirq.h --- a/include/asm-m68knommu/hardirq.h Mon May 12 20:55:44 2003 +++ b/include/asm-m68knommu/hardirq.h Mon May 12 20:55:44 2003 @@ -72,13 +72,13 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-mips/elf.h b/include/asm-mips/elf.h --- a/include/asm-mips/elf.h Mon May 12 20:55:46 2003 +++ b/include/asm-mips/elf.h Mon May 12 20:55:46 2003 @@ -6,6 +6,91 @@ #ifndef __ASM_ELF_H #define __ASM_ELF_H +#define PT_MIPS_REGINFO 0x70000000 + +/* Flags in the e_flags field of the header */ +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ARCH 0xf0000000 + +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + +#define SHN_MIPS_ACCOMON 0xff00 + +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 + +#define SHF_MIPS_GPREL 0x10000000 + /* ELF register definitions */ #define ELF_NGREG 45 #define ELF_NFPREG 33 diff -Nru a/include/asm-mips64/elf.h b/include/asm-mips64/elf.h --- a/include/asm-mips64/elf.h Mon May 12 20:55:44 2003 +++ b/include/asm-mips64/elf.h Mon May 12 20:55:44 2003 @@ -9,6 +9,91 @@ #include #include +#define PT_MIPS_REGINFO 0x70000000 + +/* Flags in the e_flags field of the header */ +#define EF_MIPS_NOREORDER 0x00000001 +#define EF_MIPS_PIC 0x00000002 +#define EF_MIPS_CPIC 0x00000004 +#define EF_MIPS_ARCH 0xf0000000 + +#define DT_MIPS_RLD_VERSION 0x70000001 +#define DT_MIPS_TIME_STAMP 0x70000002 +#define DT_MIPS_ICHECKSUM 0x70000003 +#define DT_MIPS_IVERSION 0x70000004 +#define DT_MIPS_FLAGS 0x70000005 + #define RHF_NONE 0 + #define RHF_HARDWAY 1 + #define RHF_NOTPOT 2 +#define DT_MIPS_BASE_ADDRESS 0x70000006 +#define DT_MIPS_CONFLICT 0x70000008 +#define DT_MIPS_LIBLIST 0x70000009 +#define DT_MIPS_LOCAL_GOTNO 0x7000000a +#define DT_MIPS_CONFLICTNO 0x7000000b +#define DT_MIPS_LIBLISTNO 0x70000010 +#define DT_MIPS_SYMTABNO 0x70000011 +#define DT_MIPS_UNREFEXTNO 0x70000012 +#define DT_MIPS_GOTSYM 0x70000013 +#define DT_MIPS_HIPAGENO 0x70000014 +#define DT_MIPS_RLD_MAP 0x70000016 + +#define R_MIPS_NONE 0 +#define R_MIPS_16 1 +#define R_MIPS_32 2 +#define R_MIPS_REL32 3 +#define R_MIPS_26 4 +#define R_MIPS_HI16 5 +#define R_MIPS_LO16 6 +#define R_MIPS_GPREL16 7 +#define R_MIPS_LITERAL 8 +#define R_MIPS_GOT16 9 +#define R_MIPS_PC16 10 +#define R_MIPS_CALL16 11 +#define R_MIPS_GPREL32 12 +/* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ +#define R_MIPS_UNUSED1 13 +#define R_MIPS_UNUSED2 14 +#define R_MIPS_UNUSED3 15 +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_GOTHI16 22 +#define R_MIPS_GOTLO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +/* + * The following two relocation types are specified in the MIPS ABI + * conformance guide version 1.2 but not yet in the psABI. + */ +#define R_MIPS_CALLHI16 30 +#define R_MIPS_CALLLO16 31 +/* + * This range is reserved for vendor specific relocations. + */ +#define R_MIPS_LOVENDOR 100 +#define R_MIPS_HIVENDOR 127 + +#define SHN_MIPS_ACCOMON 0xff00 + +#define SHT_MIPS_LIST 0x70000000 +#define SHT_MIPS_CONFLICT 0x70000002 +#define SHT_MIPS_GPTAB 0x70000003 +#define SHT_MIPS_UCODE 0x70000004 + +#define SHF_MIPS_GPREL 0x10000000 + #ifndef ELF_ARCH /* ELF register definitions */ #define ELF_NGREG 45 diff -Nru a/include/asm-parisc/elf.h b/include/asm-parisc/elf.h --- a/include/asm-parisc/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-parisc/elf.h Mon May 12 20:55:48 2003 @@ -9,6 +9,174 @@ #define EM_PARISC 15 +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + /* * The following definitions are those for 32-bit ELF binaries on a 32-bit kernel * and for 64-bit binaries on a 64-bit kernel. To run 32-bit binaries on a 64-bit diff -Nru a/include/asm-parisc/hardirq.h b/include/asm-parisc/hardirq.h --- a/include/asm-parisc/hardirq.h Mon May 12 20:55:48 2003 +++ b/include/asm-parisc/hardirq.h Mon May 12 20:55:48 2003 @@ -87,7 +87,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # error CONFIG_PREEMT currently not supported. # define in_atomic() BUG() # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) diff -Nru a/include/asm-parisc/kmap_types.h b/include/asm-parisc/kmap_types.h --- a/include/asm-parisc/kmap_types.h Mon May 12 20:55:47 2003 +++ b/include/asm-parisc/kmap_types.h Mon May 12 20:55:47 2003 @@ -3,7 +3,7 @@ #include -#if CONFIG_DEBUG_HIGHMEM +#ifdef CONFIG_DEBUG_HIGHMEM # define D(n) __KM_FENCE_##n , #else # define D(n) diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h --- a/include/asm-ppc/elf.h Mon May 12 20:55:44 2003 +++ b/include/asm-ppc/elf.h Mon May 12 20:55:44 2003 @@ -8,6 +8,47 @@ #include #include +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + #define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ #define ELF_NFPREG 33 /* includes fpscr */ #define ELF_NVRREG 33 /* includes vscr */ diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h --- a/include/asm-ppc/hardirq.h Mon May 12 20:55:44 2003 +++ b/include/asm-ppc/hardirq.h Mon May 12 20:55:44 2003 @@ -82,7 +82,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h --- a/include/asm-ppc/spinlock.h Mon May 12 20:55:46 2003 +++ b/include/asm-ppc/spinlock.h Mon May 12 20:55:46 2003 @@ -17,7 +17,7 @@ } spinlock_t; #ifdef __KERNEL__ -#if CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_DEBUG_SPINLOCK #define SPINLOCK_DEBUG_INIT , 0, 0 #else #define SPINLOCK_DEBUG_INIT /* */ @@ -86,7 +86,7 @@ #endif } rwlock_t; -#if CONFIG_DEBUG_SPINLOCK +#ifdef CONFIG_DEBUG_SPINLOCK #define RWLOCK_DEBUG_INIT , 0 #else #define RWLOCK_DEBUG_INIT /* */ diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h --- a/include/asm-ppc64/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-ppc64/elf.h Mon May 12 20:55:48 2003 @@ -1,6 +1,47 @@ #ifndef __PPC64_ELF_H #define __PPC64_ELF_H +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + /* * ELF register definitions.. * diff -Nru a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h --- a/include/asm-ppc64/io.h Mon May 12 20:55:49 2003 +++ b/include/asm-ppc64/io.h Mon May 12 20:55:49 2003 @@ -107,7 +107,6 @@ #define IO_SPACE_LIMIT ~(0UL) -#define MEM_SPACE_LIMIT ~(0UL) #ifdef __KERNEL__ diff -Nru a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h --- a/include/asm-ppc64/mmu.h Mon May 12 20:55:47 2003 +++ b/include/asm-ppc64/mmu.h Mon May 12 20:55:47 2003 @@ -221,6 +221,13 @@ #endif /* __ASSEMBLY__ */ +/* + * Location of cpu0's segment table + */ +#define STAB0_PAGE 0x9 +#define STAB0_PHYS_ADDR (STAB0_PAGE< +#include + +#ifndef __ASSEMBLY__ struct naca_struct { - void *xItVpdAreas; - void *xRamDisk; - u64 xRamDiskSize; /* In pages */ - struct paca_struct *paca; /* Ptr to an array of pacas */ - u64 debug_switch; /* Bits to control debug printing */ - u16 dCacheL1LineSize; /* Line size of L1 DCache in bytes */ - u16 dCacheL1LogLineSize; /* Log-2 of DCache line size */ - u16 dCacheL1LinesPerPage; /* DCache lines per page */ - u16 iCacheL1LineSize; /* Line size of L1 ICache in bytes */ - u16 iCacheL1LogLineSize; /* Log-2 of ICache line size */ - u16 iCacheL1LinesPerPage; /* ICache lines per page */ - u16 slb_size; /* SLB size in entries */ - u64 physicalMemorySize; /* Size of real memory in bytes */ - u64 pftSize; /* Log base 2 of page table size */ - u64 serialPortAddr; /* Phyical address of serial port */ - u8 interrupt_controller; /* Type of interrupt controller */ - u8 resv0; /* Type of interrupt controller */ - u16 platform; /* Platform flags */ - u8 resv1[12]; /* Padding */ + /*================================================================== + * Cache line 1: 0x0000 - 0x007F + * Kernel only data - undefined for user space + *================================================================== + */ + void *xItVpdAreas; /* VPD Data 0x00 */ + void *xRamDisk; /* iSeries ramdisk 0x08 */ + u64 xRamDiskSize; /* In pages 0x10 */ + struct paca_struct *paca; /* Ptr to an array of pacas 0x18 */ + u64 debug_switch; /* Debug print control 0x20 */ + u64 banner; /* Ptr to banner string 0x28 */ + u64 log; /* Ptr to log buffer 0x30 */ + u64 serialPortAddr; /* Phy addr of serial port 0x38 */ + u64 interrupt_controller; /* Type of int controller 0x40 */ + u64 slb_size; /* SLB size in entries 0x48 */ + u64 pftSize; /* Log 2 of page table size 0x50 */ + void *systemcfg; /* Pointer to systemcfg data 0x58 */ + u32 dCacheL1LogLineSize; /* L1 d-cache line size Log2 0x60 */ + u32 dCacheL1LinesPerPage; /* L1 d-cache lines / page 0x64 */ + u32 iCacheL1LogLineSize; /* L1 i-cache line size Log2 0x68 */ + u32 iCacheL1LinesPerPage; /* L1 i-cache lines / page 0x6c */ + u64 resv0[2]; /* Reserved 0x70 - 0x7F */ }; extern struct naca_struct *naca; + +#endif /* __ASSEMBLY__ */ + +#define NACA_PAGE 0x4 +#define NACA_PHYS_ADDR (NACA_PAGE<> SID_SHIFT) & SID_MASK) +/* align addr on a size boundary - adjust address up/down if needed */ +#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) +#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1))) + +/* align addr on a size boundary - adjust address up if needed */ +#define _ALIGN(addr,size) _ALIGN_UP(addr,size) + +/* to align the pointer to the (next) double word boundary */ +#define DOUBLEWORD_ALIGN(addr) _ALIGN(addr,sizeof(unsigned long)) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE) + #ifdef __KERNEL__ #ifndef __ASSEMBLY__ #include @@ -37,7 +54,7 @@ { unsigned long lines, line_size; - line_size = naca->dCacheL1LineSize; + line_size = systemcfg->dCacheL1LineSize; lines = naca->dCacheL1LinesPerPage; __asm__ __volatile__( @@ -113,19 +130,6 @@ #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #endif /* __ASSEMBLY__ */ - -/* align addr on a size boundary - adjust address up/down if needed */ -#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1))) -#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1))) - -/* align addr on a size boundary - adjust address up if needed */ -#define _ALIGN(addr,size) _ALIGN_UP(addr,size) - -/* to align the pointer to the (next) double word boundary */ -#define DOUBLEWORD_ALIGN(addr) _ALIGN(addr,sizeof(unsigned long)) - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE) #ifdef MODULE #define __page_aligned __attribute__((__aligned__(PAGE_SIZE))) diff -Nru a/include/asm-ppc64/proc_fs.h b/include/asm-ppc64/proc_fs.h --- a/include/asm-ppc64/proc_fs.h Mon May 12 20:55:46 2003 +++ b/include/asm-ppc64/proc_fs.h Mon May 12 20:55:46 2003 @@ -25,9 +25,14 @@ #include -void pmc_proc_init(struct proc_dir_entry *iSeries_proc); -void proc_ppc64_init(void); +struct proc_ppc64_t { + struct proc_dir_entry *root; + struct proc_dir_entry *naca; + struct proc_dir_entry *paca; + struct proc_dir_entry *systemcfg; + struct proc_dir_entry *rtas; +}; -#include +extern struct proc_ppc64_t proc_ppc64; -#endif +#endif /* _PPC64_PROC_FS_H */ diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h --- a/include/asm-ppc64/processor.h Mon May 12 20:55:44 2003 +++ b/include/asm-ppc64/processor.h Mon May 12 20:55:44 2003 @@ -469,8 +469,6 @@ #define IOCR_SPC 0x00000001 -/* Processor Version Register */ - /* Processor Version Register (PVR) field extraction */ #define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ @@ -595,6 +593,8 @@ asm volatile("mfasr %0" : "=r" (rval)); rval;}) #ifndef __ASSEMBLY__ +extern unsigned long *_get_SP(void); + extern int have_of; struct task_struct; @@ -654,8 +654,10 @@ struct pt_regs *regs; /* Pointer to saved register state */ mm_segment_t fs; /* for get_fs() validation */ double fpr[32]; /* Complete floating point set */ - unsigned long fpscr; /* Floating point status */ - unsigned int fpexc_mode; /* Floating-point exception mode */ + unsigned long fpscr; /* Floating point status (plus pad) */ + unsigned long fpexc_mode; /* Floating-point exception mode */ + unsigned long saved_msr; /* Save MSR across signal handlers */ + unsigned long saved_softe; /* Ditto for Soft Enable/Disable */ }; #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack) @@ -702,7 +704,7 @@ return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8); } -static inline unsigned int __pack_fe01(unsigned int fpmode) +static inline unsigned long __pack_fe01(unsigned int fpmode) { return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1); } @@ -739,6 +741,15 @@ #define cpu_has_noexecute() (processor_type() == PV_POWER4 || \ processor_type() == PV_POWER4p) + +/* XXX we have to call HV to set when in LPAR */ +#define cpu_has_dabr() (1) + +#define cpu_has_iabr() (processor_type() != PV_POWER4 && \ + processor_type() != PV_POWER4p) + +#define cpu_alignexc_sets_dsisr() (processor_type() != PV_POWER4 && \ + processor_type() != PV_POWER4p) #endif /* ASSEMBLY */ diff -Nru a/include/asm-ppc64/ptrace.h b/include/asm-ppc64/ptrace.h --- a/include/asm-ppc64/ptrace.h Mon May 12 20:55:47 2003 +++ b/include/asm-ppc64/ptrace.h Mon May 12 20:55:47 2003 @@ -64,9 +64,8 @@ #define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ -/* Size of stack frame allocated when calling signal handler. */ -/* FIXME: What should this be on 64-bit kernel (64 for 32-bit) */ -#define __SIGNAL_FRAMESIZE 64 +/* Size of dummy stack frame allocated when calling signal handler. */ +#define __SIGNAL_FRAMESIZE 128 #define __SIGNAL_FRAMESIZE32 64 #define instruction_pointer(regs) ((regs)->nip) diff -Nru a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h --- a/include/asm-ppc64/rtas.h Mon May 12 20:55:49 2003 +++ b/include/asm-ppc64/rtas.h Mon May 12 20:55:49 2003 @@ -166,8 +166,6 @@ extern void rtas_power_off(void); extern void rtas_halt(void); -extern struct proc_dir_entry *rtas_proc_dir; - /* Some RTAS ops require a data buffer and that buffer must be < 4G. * Rather than having a memory allocator, just use this buffer * (get the lock first), make the RTAS call. Copy the data instead diff -Nru a/include/asm-ppc64/sigcontext.h b/include/asm-ppc64/sigcontext.h --- a/include/asm-ppc64/sigcontext.h Mon May 12 20:55:45 2003 +++ b/include/asm-ppc64/sigcontext.h Mon May 12 20:55:45 2003 @@ -9,6 +9,8 @@ */ #include +#include + struct sigcontext { unsigned long _unused[4]; @@ -16,7 +18,9 @@ int _pad0; unsigned long handler; unsigned long oldmask; - struct pt_regs *regs; + struct pt_regs *regs; + elf_gregset_t gp_regs; + elf_fpregset_t fp_regs; }; #endif /* _ASM_PPC64_SIGCONTEXT_H */ diff -Nru a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ppc64/systemcfg.h Mon May 12 20:55:49 2003 @@ -0,0 +1,109 @@ +#ifndef _SYSTEMCFG_H +#define _SYSTEMCFG_H + +/* + * Copyright (C) 2002 Peter Bergner , IBM + * + * 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. + */ + +/* Change Activity: + * 2002/09/30 : bergner : Created + * End Change Activity + */ + + +#ifndef __KERNEL__ +#include +#include +#include +#include +#endif + +/* + * If the major version changes we are incompatible. + * Minor version changes are a hint. + */ +#define SYSTEMCFG_MAJOR 1 +#define SYSTEMCFG_MINOR 0 + +#ifndef __ASSEMBLY__ + +struct systemcfg { + __u8 eye_catcher[16]; /* Eyecatcher: SYSTEMCFG:PPC64 0x00 */ + struct { /* Systemcfg version numbers */ + __u32 major; /* Major number 0x10 */ + __u32 minor; /* Minor number 0x14 */ + } version; + + __u32 platform; /* Platform flags 0x18 */ + __u32 processor; /* Processor type 0x1C */ + __u64 processorCount; /* # of physical processors 0x20 */ + __u64 physicalMemorySize; /* Size of real memory(B) 0x28 */ + __u64 tb_orig_stamp; /* Timebase at boot 0x30 */ + __u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */ + __u64 tb_to_xs; /* Inverse of TB to 2^20 0x40 */ + __u64 stamp_xsec; /* 0x48 */ + __u64 tb_update_count; /* Timebase atomicity ctr 0x50 */ + __u32 tz_minuteswest; /* Minutes west of Greenwich 0x58 */ + __u32 tz_dsttime; /* Type of dst correction 0x5C */ + __u32 dCacheL1Size; /* L1 d-cache size 0x60 */ + __u32 dCacheL1LineSize; /* L1 d-cache line size 0x64 */ + __u32 iCacheL1Size; /* L1 i-cache size 0x68 */ + __u32 iCacheL1LineSize; /* L1 i-cache line size 0x6C */ + __u8 reserved0[3984]; /* Reserve rest of page 0x70 */ +}; + +#ifdef __KERNEL__ +extern struct systemcfg *systemcfg; +#else + +/* Processor Version Register (PVR) field extraction */ +#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */ +#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */ + +/* Processor Version Numbers */ +#define PV_NORTHSTAR 0x0033 +#define PV_PULSAR 0x0034 +#define PV_POWER4 0x0035 +#define PV_ICESTAR 0x0036 +#define PV_SSTAR 0x0037 +#define PV_POWER4p 0x0038 +#define PV_630 0x0040 +#define PV_630p 0x0041 + +/* Platforms supported by PPC64 */ +#define PLATFORM_PSERIES 0x0100 +#define PLATFORM_PSERIES_LPAR 0x0101 +#define PLATFORM_ISERIES_LPAR 0x0201 + + +static inline volatile struct systemcfg *systemcfg_init(void) +{ + int fd = open("/proc/ppc64/systemcfg", O_RDONLY); + volatile struct systemcfg *ret; + + if (fd == -1) + return 0; + ret = mmap(0, sizeof(struct systemcfg), PROT_READ, MAP_SHARED, fd, 0); + close(fd); + if (!ret) + return 0; + if (ret->version.major != SYSTEMCFG_MAJOR || ret->version.minor < SYSTEMCFG_MINOR) { + munmap((void *)ret, sizeof(struct systemcfg)); + return 0; + } + return ret; +} +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#define SYSTEMCFG_PAGE 0x5 +#define SYSTEMCFG_PHYS_ADDR (SYSTEMCFG_PAGE< + +/* * 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 @@ -13,8 +14,9 @@ unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + sigset_t uc_sigmask; + sigset_t __unsued[15]; /* Allow for uc_sigmask growth */ + struct sigcontext uc_mcontext; /* last for extensibility */ }; #endif /* _ASMPPC64_UCONTEXT_H */ diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h --- a/include/asm-ppc64/unistd.h Mon May 12 20:55:44 2003 +++ b/include/asm-ppc64/unistd.h Mon May 12 20:55:44 2003 @@ -260,7 +260,7 @@ #define __NR_clock_getres 247 #define __NR_clock_nanosleep 248 -#define __NR_syscalls 249 +#define __NR_syscalls 239 #ifdef __KERNEL__ #define NR_syscalls __NR_syscalls #endif diff -Nru a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h --- a/include/asm-ppc64/xics.h Mon May 12 20:55:46 2003 +++ b/include/asm-ppc64/xics.h Mon May 12 20:55:46 2003 @@ -12,7 +12,17 @@ #ifndef _PPC64_KERNEL_XICS_H #define _PPC64_KERNEL_XICS_H +#include + void xics_init_IRQ(void); int xics_get_irq(struct pt_regs *); +void xics_setup_cpu(void); +void xics_cause_IPI(int cpu); + +struct xics_ipi_struct { + volatile unsigned long value; +} ____cacheline_aligned; + +extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; #endif /* _PPC64_KERNEL_XICS_H */ diff -Nru a/include/asm-s390/elf.h b/include/asm-s390/elf.h --- a/include/asm-s390/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-s390/elf.h Mon May 12 20:55:48 2003 @@ -9,6 +9,84 @@ #ifndef __ASMS390_ELF_H #define __ASMS390_ELF_H +/* s390 relocations defined by the ABIs */ +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LD code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS + block. */ +/* Keep this the last entry. */ +#define R_390_NUM 57 + /* * ELF register definitions.. */ diff -Nru a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h --- a/include/asm-s390/hardirq.h Mon May 12 20:55:49 2003 +++ b/include/asm-s390/hardirq.h Mon May 12 20:55:49 2003 @@ -82,7 +82,7 @@ #define invoke_softirq() do_call_softirq() -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (in_interrupt() || preempt_count() == PREEMPT_ACTIVE) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h --- a/include/asm-sparc/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-sparc/elf.h Mon May 12 20:55:48 2003 @@ -11,6 +11,63 @@ #include #include +/* + * Sparc section types + */ +#define STT_REGISTER 13 + +/* + * Sparc ELF relocation types + */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 + /* For the most part we present code dumps in the format * Solaris does. */ diff -Nru a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h --- a/include/asm-sparc/hardirq.h Mon May 12 20:55:49 2003 +++ b/include/asm-sparc/hardirq.h Mon May 12 20:55:49 2003 @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -90,7 +89,7 @@ #ifndef CONFIG_SMP #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else @@ -116,7 +115,7 @@ #define irq_exit() br_read_unlock(BR_GLOBALIRQ_LOCK) #endif -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) #else # define in_atomic() (preempt_count() != 0) diff -Nru a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h --- a/include/asm-sparc64/elf.h Mon May 12 20:55:45 2003 +++ b/include/asm-sparc64/elf.h Mon May 12 20:55:45 2003 @@ -13,6 +13,63 @@ #endif /* + * Sparc section types + */ +#define STT_REGISTER 13 + +/* + * Sparc ELF relocation types + */ +#define R_SPARC_NONE 0 +#define R_SPARC_8 1 +#define R_SPARC_16 2 +#define R_SPARC_32 3 +#define R_SPARC_DISP8 4 +#define R_SPARC_DISP16 5 +#define R_SPARC_DISP32 6 +#define R_SPARC_WDISP30 7 +#define R_SPARC_WDISP22 8 +#define R_SPARC_HI22 9 +#define R_SPARC_22 10 +#define R_SPARC_13 11 +#define R_SPARC_LO10 12 +#define R_SPARC_GOT10 13 +#define R_SPARC_GOT13 14 +#define R_SPARC_GOT22 15 +#define R_SPARC_PC10 16 +#define R_SPARC_PC22 17 +#define R_SPARC_WPLT30 18 +#define R_SPARC_COPY 19 +#define R_SPARC_GLOB_DAT 20 +#define R_SPARC_JMP_SLOT 21 +#define R_SPARC_RELATIVE 22 +#define R_SPARC_UA32 23 +#define R_SPARC_PLT32 24 +#define R_SPARC_HIPLT22 25 +#define R_SPARC_LOPLT10 26 +#define R_SPARC_PCPLT32 27 +#define R_SPARC_PCPLT22 28 +#define R_SPARC_PCPLT10 29 +#define R_SPARC_10 30 +#define R_SPARC_11 31 +#define R_SPARC_64 32 +#define R_SPARC_OLO10 33 +#define R_SPARC_WDISP16 40 +#define R_SPARC_WDISP19 41 +#define R_SPARC_7 43 +#define R_SPARC_5 44 +#define R_SPARC_6 45 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 +#define HWCAP_SPARC_ULTRA3 32 + +/* * These are used to set parameters in the core dumps. */ #ifndef ELF_ARCH diff -Nru a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h --- a/include/asm-sparc64/hardirq.h Mon May 12 20:55:48 2003 +++ b/include/asm-sparc64/hardirq.h Mon May 12 20:55:48 2003 @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -85,7 +84,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h --- a/include/asm-um/pgtable.h Mon May 12 20:55:49 2003 +++ b/include/asm-um/pgtable.h Mon May 12 20:55:49 2003 @@ -71,7 +71,7 @@ #define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) #else # define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) diff -Nru a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h --- a/include/asm-v850/hardirq.h Mon May 12 20:55:44 2003 +++ b/include/asm-v850/hardirq.h Mon May 12 20:55:44 2003 @@ -72,7 +72,7 @@ #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() (preempt_count() != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h --- a/include/asm-x86_64/elf.h Mon May 12 20:55:48 2003 +++ b/include/asm-x86_64/elf.h Mon May 12 20:55:48 2003 @@ -9,6 +9,27 @@ #include #include +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + typedef unsigned long elf_greg_t; #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) diff -Nru a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h --- a/include/asm-x86_64/hardirq.h Mon May 12 20:55:45 2003 +++ b/include/asm-x86_64/hardirq.h Mon May 12 20:55:45 2003 @@ -81,7 +81,7 @@ #define nmi_exit() (preempt_count() -= HARDIRQ_OFFSET) -#if CONFIG_PREEMPT +#ifdef CONFIG_PREEMPT # define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) #else diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h --- a/include/linux/agp_backend.h Mon May 12 20:55:48 2003 +++ b/include/linux/agp_backend.h Mon May 12 20:55:48 2003 @@ -1,5 +1,6 @@ /* - * AGPGART module version 0.99 + * AGPGART module version 0.100 + * Copyright (C) 2002-2003 Dave Jones * Copyright (C) 1999 Jeff Hartmann * Copyright (C) 1999 Precision Insight, Inc. * Copyright (C) 1999 Xi Graphics, Inc. @@ -37,45 +38,7 @@ enum chipset_type { NOT_SUPPORTED, - INTEL_GENERIC, - INTEL_LX, - INTEL_BX, - INTEL_GX, - INTEL_I810, - INTEL_I815, - INTEL_I820, - INTEL_I830_M, - INTEL_I845_G, - INTEL_I855_PM, - INTEL_I865_G, - INTEL_I840, - INTEL_I845, - INTEL_I850, - INTEL_I860, - INTEL_460GX, - INTEL_E7505, - VIA_GENERIC, - SIS_GENERIC, - AMD_GENERIC, - AMD_IRONGATE, - AMD_761, - AMD_762, - AMD_8151, - ALI_M1541, - ALI_M1621, - ALI_M1631, - ALI_M1632, - ALI_M1641, - ALI_M1644, - ALI_M1647, - ALI_M1651, - ALI_M1671, - ALI_GENERIC, - SVWRKS_HE, - SVWRKS_LE, - SVWRKS_GENERIC, - HP_ZX1, - ALPHA_CORE_AGP, + SUPPORTED, }; struct agp_version { @@ -98,16 +61,11 @@ } agp_kern_info; /* - * The agp_memory structure has information - * about the block of agp memory allocated. - * A caller may manipulate the next and prev - * pointers to link each allocated item into - * a list. These pointers are ignored by the - * backend. Everything else should never be - * written to, but the caller may read any of - * the items to detrimine the status of this - * block of agp memory. - * + * The agp_memory structure has information about the block of agp memory + * allocated. A caller may manipulate the next and prev pointers to link + * each allocated item into a list. These pointers are ignored by the backend. + * Everything else should never be written to, but the caller may read any of + * the items to detrimine the status of this block of agp memory. */ typedef struct _agp_memory { @@ -127,126 +85,19 @@ #define AGP_NORMAL_MEMORY 0 extern void agp_free_memory(agp_memory *); - -/* - * agp_free_memory : - * - * This function frees memory associated with - * an agp_memory pointer. It is the only function - * that can be called when the backend is not owned - * by the caller. (So it can free memory on client - * death.) - * - * It takes an agp_memory pointer as an argument. - * - */ - extern agp_memory *agp_allocate_memory(size_t, u32); - -/* - * agp_allocate_memory : - * - * This function allocates a group of pages of - * a certain type. - * - * It takes a size_t argument of the number of pages, and - * an u32 argument of the type of memory to be allocated. - * Every agp bridge device will allow you to allocate - * AGP_NORMAL_MEMORY which maps to physical ram. Any other - * type is device dependent. - * - * It returns NULL whenever memory is unavailable. - * - */ - extern int agp_copy_info(agp_kern_info *); - -/* - * agp_copy_info : - * - * This function copies information about the - * agp bridge device and the state of the agp - * backend into an agp_kern_info pointer. - * - * It takes an agp_kern_info pointer as an - * argument. The caller should insure that - * this pointer is valid. - * - */ - extern int agp_bind_memory(agp_memory *, off_t); - -/* - * agp_bind_memory : - * - * This function binds an agp_memory structure - * into the graphics aperture translation table. - * - * It takes an agp_memory pointer and an offset into - * the graphics aperture translation table as arguments - * - * It returns -EINVAL if the pointer == NULL. - * It returns -EBUSY if the area of the table - * requested is already in use. - * - */ - extern int agp_unbind_memory(agp_memory *); - -/* - * agp_unbind_memory : - * - * This function removes an agp_memory structure - * from the graphics aperture translation table. - * - * It takes an agp_memory pointer as an argument. - * - * It returns -EINVAL if this piece of agp_memory - * is not currently bound to the graphics aperture - * translation table or if the agp_memory - * pointer == NULL - * - */ - extern void agp_enable(u32); - -/* - * agp_enable : - * - * This function initializes the agp point-to-point - * connection. - * - * It takes an agp mode register as an argument - * - */ - extern int agp_backend_acquire(void); - -/* - * agp_backend_acquire : - * - * This Function attempts to acquire the agp - * backend. - * - * returns -EBUSY if agp is in use, - * returns 0 if the caller owns the agp backend - */ - extern void agp_backend_release(void); /* - * agp_backend_release : - * - * This Function releases the lock on the agp - * backend. - * - * The caller must insure that the graphics - * aperture translation table is read for use - * by another entity. (Ensure that all memory - * it bound is unbound.) - * + * Interface between drm and agp code. When agp initializes, it makes + * the below structure available via inter_module_register(), drm might + * use it. Keith Owens 28 Oct 2000. */ - typedef struct { void (*free_memory)(agp_memory *); agp_memory *(*allocate_memory)(size_t, u32); @@ -259,11 +110,5 @@ } drm_agp_t; extern const drm_agp_t *drm_agp_p; - -/* - * Interface between drm and agp code. When agp initializes, it makes - * the above structure available via inter_module_register(), drm might - * use it. Keith Owens 28 Oct 2000. - */ #endif /* _AGP_BACKEND_H */ diff -Nru a/include/linux/agpgart.h b/include/linux/agpgart.h --- a/include/linux/agpgart.h Mon May 12 20:55:44 2003 +++ b/include/linux/agpgart.h Mon May 12 20:55:44 2003 @@ -27,17 +27,19 @@ #ifndef _AGP_H #define _AGP_H 1 +#include + #define AGPIOC_BASE 'A' -#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, agp_info*) +#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, struct agp_info*) #define AGPIOC_ACQUIRE _IO (AGPIOC_BASE, 1) #define AGPIOC_RELEASE _IO (AGPIOC_BASE, 2) -#define AGPIOC_SETUP _IOW (AGPIOC_BASE, 3, agp_setup*) -#define AGPIOC_RESERVE _IOW (AGPIOC_BASE, 4, agp_region*) -#define AGPIOC_PROTECT _IOW (AGPIOC_BASE, 5, agp_region*) -#define AGPIOC_ALLOCATE _IOWR(AGPIOC_BASE, 6, agp_allocate*) +#define AGPIOC_SETUP _IOW (AGPIOC_BASE, 3, struct agp_setup*) +#define AGPIOC_RESERVE _IOW (AGPIOC_BASE, 4, struct agp_region*) +#define AGPIOC_PROTECT _IOW (AGPIOC_BASE, 5, struct agp_region*) +#define AGPIOC_ALLOCATE _IOWR(AGPIOC_BASE, 6, struct agp_allocate*) #define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int) -#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, agp_bind*) -#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, agp_unbind*) +#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, struct agp_bind*) +#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, struct agp_unbind*) #define AGP_DEVICE "/dev/agpgart" @@ -112,19 +114,7 @@ #define AGPGART_MINOR 175 -#define AGP_UNLOCK() up(&(agp_fe.agp_mutex)); -#define AGP_LOCK() down(&(agp_fe.agp_mutex)); -#define AGP_LOCK_INIT() sema_init(&(agp_fe.agp_mutex), 1) - -#ifndef _AGP_BACKEND_H -struct _agp_version { - u16 major; - u16 minor; -} agp_version; - -#endif - -typedef struct _agp_info { +struct agp_info { struct agp_version version; /* version of the driver */ u32 bridge_id; /* bridge vendor/device */ u32 agp_mode; /* mode info of bridge */ @@ -133,34 +123,34 @@ size_t pg_total; /* max pages (swap + system) */ size_t pg_system; /* max pages (system) */ size_t pg_used; /* current pages used */ -} agp_info; +}; -typedef struct _agp_setup { +struct agp_setup { u32 agp_mode; /* mode info of bridge */ -} agp_setup; +}; /* * The "prot" down below needs still a "sleep" flag somehow ... */ -typedef struct _agp_segment { +struct agp_segment { off_t pg_start; /* starting page to populate */ size_t pg_count; /* number of pages */ int prot; /* prot flags for mmap */ -} agp_segment; +}; -typedef struct _agp_segment_priv { +struct agp_segment_priv { off_t pg_start; size_t pg_count; pgprot_t prot; -} agp_segment_priv; +}; -typedef struct _agp_region { +struct agp_region { pid_t pid; /* pid of process */ size_t seg_count; /* number of segments */ - struct _agp_segment *seg_list; -} agp_region; + struct agp_segment *seg_list; +}; -typedef struct _agp_allocate { +struct agp_allocate { int key; /* tag of allocation */ size_t pg_count; /* number of pages */ u32 type; /* 0 == normal, other devspec */ @@ -168,34 +158,34 @@ * need a phys address of the * actual page behind the gatt * table) */ -} agp_allocate; +}; -typedef struct _agp_bind { +struct agp_bind { int key; /* tag of allocation */ off_t pg_start; /* starting page to populate */ -} agp_bind; +}; -typedef struct _agp_unbind { +struct agp_unbind { int key; /* tag of allocation */ u32 priority; /* priority for paging out */ -} agp_unbind; +}; -typedef struct _agp_client { - struct _agp_client *next; - struct _agp_client *prev; +struct agp_client { + struct agp_client *next; + struct agp_client *prev; pid_t pid; int num_segments; - agp_segment_priv **segments; -} agp_client; + struct agp_segment_priv **segments; +}; -typedef struct _agp_controller { - struct _agp_controller *next; - struct _agp_controller *prev; +struct agp_controller { + struct agp_controller *next; + struct agp_controller *prev; pid_t pid; int num_clients; agp_memory *pool; - agp_client *clients; -} agp_controller; + struct agp_client *clients; +}; #define AGP_FF_ALLOW_CLIENT 0 #define AGP_FF_ALLOW_CONTROLLER 1 @@ -203,18 +193,18 @@ #define AGP_FF_IS_CONTROLLER 3 #define AGP_FF_IS_VALID 4 -typedef struct _agp_file_private { - struct _agp_file_private *next; - struct _agp_file_private *prev; +struct agp_file_private { + struct agp_file_private *next; + struct agp_file_private *prev; pid_t my_pid; long access_flags; /* long req'd for set_bit --RR */ -} agp_file_private; +}; struct agp_front_data { struct semaphore agp_mutex; - agp_controller *current_controller; - agp_controller *controllers; - agp_file_private *file_priv_list; + struct agp_controller *current_controller; + struct agp_controller *controllers; + struct agp_file_private *file_priv_list; u8 used_by_controller; u8 backend_acquired; }; diff -Nru a/include/linux/atm_he.h b/include/linux/atm_he.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/atm_he.h Mon May 12 20:55:49 2003 @@ -0,0 +1,20 @@ +/* atm_he.h */ + +#ifndef LINUX_ATM_HE_H +#define LINUX_ATM_HE_H + +#include + +#define HE_GET_REG _IOW('a', ATMIOC_SARPRV, struct atmif_sioc) + +#define HE_REGTYPE_PCI 1 +#define HE_REGTYPE_RCM 2 +#define HE_REGTYPE_TCM 3 +#define HE_REGTYPE_MBOX 4 + +struct he_ioctl_reg { + unsigned addr, val; + char type; +}; + +#endif /* LINUX_ATM_HE_H */ diff -Nru a/include/linux/atmbr2684.h b/include/linux/atmbr2684.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/atmbr2684.h Mon May 12 20:55:49 2003 @@ -0,0 +1,101 @@ +#ifndef _LINUX_ATMBR2684_H +#define _LINUX_ATMBR2684_H + +#include +#include /* For IFNAMSIZ */ + +/* + * Type of media we're bridging (ethernet, token ring, etc) Currently only + * ethernet is supported + */ +#define BR2684_MEDIA_ETHERNET (0) /* 802.3 */ +#define BR2684_MEDIA_802_4 (1) /* 802.4 */ +#define BR2684_MEDIA_TR (2) /* 802.5 - token ring */ +#define BR2684_MEDIA_FDDI (3) +#define BR2684_MEDIA_802_6 (4) /* 802.6 */ + +/* + * Is there FCS inbound on this VC? This currently isn't supported. + */ +#define BR2684_FCSIN_NO (0) +#define BR2684_FCSIN_IGNORE (1) +#define BR2684_FCSIN_VERIFY (2) + +/* + * Is there FCS outbound on this VC? This currently isn't supported. + */ +#define BR2684_FCSOUT_NO (0) +#define BR2684_FCSOUT_SENDZERO (1) +#define BR2684_FCSOUT_GENERATE (2) + +/* + * Does this VC include LLC encapsulation? + */ +#define BR2684_ENCAPS_VC (0) /* VC-mux */ +#define BR2684_ENCAPS_LLC (1) +#define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */ + +/* + * This is for the ATM_NEWBACKENDIF call - these are like socket families: + * the first element of the structure is the backend number and the rest + * is per-backend specific + */ +struct atm_newif_br2684 { + atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ + int media; /* BR2684_MEDIA_* */ + char ifname[IFNAMSIZ]; + int mtu; +}; + +/* + * This structure is used to specify a br2684 interface - either by a + * positive integer (returned by ATM_NEWBACKENDIF) or the interfaces name + */ +#define BR2684_FIND_BYNOTHING (0) +#define BR2684_FIND_BYNUM (1) +#define BR2684_FIND_BYIFNAME (2) +struct br2684_if_spec { + int method; /* BR2684_FIND_* */ + union { + char ifname[IFNAMSIZ]; + int devnum; + } spec; +}; + +/* + * This is for the ATM_SETBACKEND call - these are like socket families: + * the first element of the structure is the backend number and the rest + * is per-backend specific + */ +struct atm_backend_br2684 { + atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ + struct br2684_if_spec ifspec; + int fcs_in; /* BR2684_FCSIN_* */ + int fcs_out; /* BR2684_FCSOUT_* */ + int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */ + int encaps; /* BR2684_ENCAPS_* */ + int has_vpiid; /* 1: use vpn_id - Unsupported */ + __u8 vpn_id[7]; + int send_padding; /* unsupported */ + int min_size; /* we will pad smaller packets than this */ +}; + +/* + * The BR2684_SETFILT ioctl is an experimental mechanism for folks + * terminating a large number of IP-only vcc's. When netfilter allows + * efficient per-if in/out filters, this support will be removed + */ +struct br2684_filter { + __u32 prefix; /* network byte order */ + __u32 netmask; /* 0 = disable filter */ +}; + +struct br2684_filter_set { + struct br2684_if_spec ifspec; + struct br2684_filter filter; +}; + +#define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \ + struct br2684_filter_set) + +#endif /* _LINUX_ATMBR2684_H */ diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h --- a/include/linux/atmdev.h Mon May 12 20:55:48 2003 +++ b/include/linux/atmdev.h Mon May 12 20:55:48 2003 @@ -30,9 +30,6 @@ #define ATM_DS3_PCR (8000*12) /* DS3: 12 cells in a 125 usec time slot */ -#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer - quota per PDU */ - #define atm_sk(__sk) ((struct atm_vcc *)(__sk)->protinfo) #define ATM_SD(s) (atm_sk((s)->sk)) @@ -96,6 +93,8 @@ /* enable or disable single-copy */ #define ATM_SETBACKEND _IOW('a',ATMIOC_SPECIAL+2,atm_backend_t) /* set backend handler */ +#define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t) + /* use backend to make new if */ /* * These are backend handkers that can be set via the ATM_SETBACKEND call @@ -104,7 +103,7 @@ */ #define ATM_BACKEND_RAW 0 #define ATM_BACKEND_PPP 1 /* PPPoATM - RFC2364 */ -#define ATM_BACKEND_BR_2684 2 /* Bridged RFC1483/2684 */ +#define ATM_BACKEND_BR2684 2 /* Bridged RFC1483/2684 */ /* for ATM_GETTYPE */ #define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */ @@ -287,10 +286,6 @@ struct atm_sap sap; /* SAP */ void (*push)(struct atm_vcc *vcc,struct sk_buff *skb); void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */ - struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size); - /* TX allocation routine - can be */ - /* modified by protocol or by driver.*/ - /* NOTE: this interface will change */ int (*push_oam)(struct atm_vcc *vcc,void *cell); int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); void *dev_data; /* per-device data */ @@ -304,9 +299,6 @@ struct sockaddr_atmsvc local; struct sockaddr_atmsvc remote; void (*callback)(struct atm_vcc *vcc); - struct sk_buff_head listenq; - int backlog_quota; /* number of connection requests we */ - /* can still accept */ int reply; /* also used by ATMTCP */ /* Multipoint part ------------------------------------------------- */ struct atm_vcc *session; /* session VCC descriptor */ @@ -379,8 +371,6 @@ void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb, unsigned long start,unsigned long dest,int len); int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags); - void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb); - /* @@@ temporary hack */ int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page); struct module *owner; }; @@ -395,7 +385,6 @@ struct atm_skb_data { struct atm_vcc *vcc; /* ATM VCC */ - int iovcnt; /* 0 for "normal" operation */ unsigned long atm_options; /* ATM layer options */ }; @@ -422,19 +411,19 @@ static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize) { - atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc); + atomic_add(truesize, &vcc->sk->rmem_alloc); } static __inline__ void atm_return(struct atm_vcc *vcc,int truesize) { - atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc); + atomic_sub(truesize, &vcc->sk->rmem_alloc); } static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size) { - return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf; + return (size + atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf; } diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Mon May 12 20:55:45 2003 +++ b/include/linux/blkdev.h Mon May 12 20:55:45 2003 @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -18,10 +19,12 @@ struct elevator_s; typedef struct elevator_s elevator_t; +#define BLKDEV_MIN_RQ 4 +#define BLKDEV_MAX_RQ 128 + struct request_list { - unsigned int count; - struct list_head free; - wait_queue_head_t wait; + int count[2]; + mempool_t *rq_pool; }; /* @@ -180,7 +183,7 @@ /* * the queue request freelist, one for reads and one for writes */ - struct request_list rq[2]; + struct request_list rq; request_fn_proc *request_fn; merge_request_fn *back_merge_fn; @@ -301,7 +304,7 @@ #define BLK_BOUNCE_ANY ((u64)blk_max_pfn << PAGE_SHIFT) #define BLK_BOUNCE_ISA (ISA_DMA_THRESHOLD) -#if CONFIG_MMU +#ifdef CONFIG_MMU extern int init_emergency_isa_pool(void); extern void blk_queue_bounce(request_queue_t *q, struct bio **bio); #else @@ -329,7 +332,6 @@ extern void blk_attempt_remerge(request_queue_t *, struct request *); extern void __blk_attempt_remerge(request_queue_t *, struct request *); extern struct request *blk_get_request(request_queue_t *, int, int); -extern struct request *__blk_get_request(request_queue_t *, int); extern void blk_put_request(struct request *); extern void blk_insert_request(request_queue_t *, struct request *, int, void *); extern void blk_plug_device(request_queue_t *); diff -Nru a/include/linux/blkpg.h b/include/linux/blkpg.h --- a/include/linux/blkpg.h Mon May 12 20:55:46 2003 +++ b/include/linux/blkpg.h Mon May 12 20:55:46 2003 @@ -54,10 +54,4 @@ char volname[BLKPG_VOLNAMELTH]; /* volume label */ }; -#ifdef __KERNEL__ - -extern char * partition_name(dev_t dev); - -#endif /* __KERNEL__ */ - #endif /* _LINUX_BLKPG_H */ diff -Nru a/include/linux/brlock.h b/include/linux/brlock.h --- a/include/linux/brlock.h Mon May 12 20:55:46 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,222 +0,0 @@ -#ifndef __LINUX_BRLOCK_H -#define __LINUX_BRLOCK_H - -/* - * 'Big Reader' read-write spinlocks. - * - * super-fast read/write locks, with write-side penalty. The point - * is to have a per-CPU read/write lock. Readers lock their CPU-local - * readlock, writers must lock all locks to get write access. These - * CPU-read-write locks are semantically identical to normal rwlocks. - * Memory usage is higher as well. (NR_CPUS*L1_CACHE_BYTES bytes) - * - * The most important feature is that these spinlocks do not cause - * cacheline ping-pong in the 'most readonly data' case. - * - * Copyright 2000, Ingo Molnar - * - * Registry idea and naming [ crutial! :-) ] by: - * - * David S. Miller - * - * David has an implementation that doesn't use atomic operations in - * the read branch via memory ordering tricks - i guess we need to - * split this up into a per-arch thing? The atomicity issue is a - * secondary item in profiles, at least on x86 platforms. - * - * The atomic op version overhead is indeed a big deal on - * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and - * compare-and-swap cpus (Sparc64). So we control which - * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM - * - */ - -/* Register bigreader lock indices here. */ -enum brlock_indices { - BR_NETPROTO_LOCK, - __BR_END -}; - -#include - -#ifdef CONFIG_SMP - -#include -#include - -#if defined(__i386__) || defined(__ia64__) || defined(__x86_64__) -#define __BRLOCK_USE_ATOMICS -#else -#undef __BRLOCK_USE_ATOMICS -#endif - -#ifdef __BRLOCK_USE_ATOMICS -typedef rwlock_t brlock_read_lock_t; -#else -typedef unsigned int brlock_read_lock_t; -#endif - -/* - * align last allocated index to the next cacheline: - */ -#define __BR_IDX_MAX \ - (((sizeof(brlock_read_lock_t)*__BR_END + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) / sizeof(brlock_read_lock_t)) - -extern brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX]; - -#ifndef __BRLOCK_USE_ATOMICS -struct br_wrlock { - spinlock_t lock; -} __attribute__ ((__aligned__(SMP_CACHE_BYTES))); - -extern struct br_wrlock __br_write_locks[__BR_IDX_MAX]; -#endif - -extern void __br_lock_usage_bug (void); - -#ifdef __BRLOCK_USE_ATOMICS - -static inline void br_read_lock (enum brlock_indices idx) -{ - /* - * This causes a link-time bug message if an - * invalid index is used: - */ - if (idx >= __BR_END) - __br_lock_usage_bug(); - - preempt_disable(); - _raw_read_lock(&__brlock_array[smp_processor_id()][idx]); -} - -static inline void br_read_unlock (enum brlock_indices idx) -{ - if (idx >= __BR_END) - __br_lock_usage_bug(); - - read_unlock(&__brlock_array[smp_processor_id()][idx]); -} - -#else /* ! __BRLOCK_USE_ATOMICS */ -static inline void br_read_lock (enum brlock_indices idx) -{ - unsigned int *ctr; - spinlock_t *lock; - - /* - * This causes a link-time bug message if an - * invalid index is used: - */ - if (idx >= __BR_END) - __br_lock_usage_bug(); - - preempt_disable(); - ctr = &__brlock_array[smp_processor_id()][idx]; - lock = &__br_write_locks[idx].lock; -again: - (*ctr)++; - mb(); - if (spin_is_locked(lock)) { - (*ctr)--; - wmb(); /* - * The release of the ctr must become visible - * to the other cpus eventually thus wmb(), - * we don't care if spin_is_locked is reordered - * before the releasing of the ctr. - * However IMHO this wmb() is superflous even in theory. - * It would not be superflous only if on the - * other CPUs doing a ldl_l instead of an ldl - * would make a difference and I don't think this is - * the case. - * I'd like to clarify this issue further - * but for now this is a slow path so adding the - * wmb() will keep us on the safe side. - */ - while (spin_is_locked(lock)) - barrier(); - goto again; - } -} - -static inline void br_read_unlock (enum brlock_indices idx) -{ - unsigned int *ctr; - - if (idx >= __BR_END) - __br_lock_usage_bug(); - - ctr = &__brlock_array[smp_processor_id()][idx]; - - wmb(); - (*ctr)--; - preempt_enable(); -} -#endif /* __BRLOCK_USE_ATOMICS */ - -/* write path not inlined - it's rare and larger */ - -extern void FASTCALL(__br_write_lock (enum brlock_indices idx)); -extern void FASTCALL(__br_write_unlock (enum brlock_indices idx)); - -static inline void br_write_lock (enum brlock_indices idx) -{ - if (idx >= __BR_END) - __br_lock_usage_bug(); - __br_write_lock(idx); -} - -static inline void br_write_unlock (enum brlock_indices idx) -{ - if (idx >= __BR_END) - __br_lock_usage_bug(); - __br_write_unlock(idx); -} - -#else -# define br_read_lock(idx) ({ (void)(idx); preempt_disable(); }) -# define br_read_unlock(idx) ({ (void)(idx); preempt_enable(); }) -# define br_write_lock(idx) ({ (void)(idx); preempt_disable(); }) -# define br_write_unlock(idx) ({ (void)(idx); preempt_enable(); }) -#endif /* CONFIG_SMP */ - -/* - * Now enumerate all of the possible sw/hw IRQ protected - * versions of the interfaces. - */ -#define br_read_lock_irqsave(idx, flags) \ - do { local_irq_save(flags); br_read_lock(idx); } while (0) - -#define br_read_lock_irq(idx) \ - do { local_irq_disable(); br_read_lock(idx); } while (0) - -#define br_read_lock_bh(idx) \ - do { local_bh_disable(); br_read_lock(idx); } while (0) - -#define br_write_lock_irqsave(idx, flags) \ - do { local_irq_save(flags); br_write_lock(idx); } while (0) - -#define br_write_lock_irq(idx) \ - do { local_irq_disable(); br_write_lock(idx); } while (0) - -#define br_write_lock_bh(idx) \ - do { local_bh_disable(); br_write_lock(idx); } while (0) - -#define br_read_unlock_irqrestore(idx, flags) \ - do { br_read_unlock(irx); local_irq_restore(flags); } while (0) - -#define br_read_unlock_irq(idx) \ - do { br_read_unlock(idx); local_irq_enable(); } while (0) - -#define br_read_unlock_bh(idx) \ - do { br_read_unlock(idx); local_bh_enable(); } while (0) - -#define br_write_unlock_irqrestore(idx, flags) \ - do { br_write_unlock(irx); local_irq_restore(flags); } while (0) - -#define br_write_unlock_irq(idx) \ - do { br_write_unlock(idx); local_irq_enable(); } while (0) - -#define br_write_unlock_bh(idx) \ - do { br_write_unlock(idx); local_bh_enable(); } while (0) - -#endif /* __LINUX_BRLOCK_H */ diff -Nru a/include/linux/brlvger.h b/include/linux/brlvger.h --- a/include/linux/brlvger.h Mon May 12 20:55:45 2003 +++ b/include/linux/brlvger.h Mon May 12 20:55:45 2003 @@ -30,16 +30,8 @@ #define BRLVGER_DISPLAY_OFF 3 #define BRLVGER_BUZZ 4 -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define MAX_NR_BRLVGER_DEVS 256 -#define BRLVGER_MINOR 0 -#else -/* Number of supported devices, and range of covered minors */ -#define MAX_NR_BRLVGER_DEVS 4 - /* Base minor for the char devices */ #define BRLVGER_MINOR 128 -#endif /* Size of some fields */ #define BRLVGER_HWVER_SIZE 2 diff -Nru a/include/linux/capability.h b/include/linux/capability.h --- a/include/linux/capability.h Mon May 12 20:55:45 2003 +++ b/include/linux/capability.h Mon May 12 20:55:45 2003 @@ -14,6 +14,7 @@ #define _LINUX_CAPABILITY_H #include +#include /* User-level do most of the mapping between kernel and user capabilities based on the version tag given by the kernel. The @@ -31,13 +32,13 @@ typedef struct __user_cap_header_struct { __u32 version; int pid; -} *cap_user_header_t; +} __user *cap_user_header_t; typedef struct __user_cap_data_struct { __u32 effective; __u32 permitted; __u32 inheritable; -} *cap_user_data_t; +} __user *cap_user_data_t; #ifdef __KERNEL__ diff -Nru a/include/linux/cpu.h b/include/linux/cpu.h --- a/include/linux/cpu.h Mon May 12 20:55:45 2003 +++ b/include/linux/cpu.h Mon May 12 20:55:45 2003 @@ -29,6 +29,7 @@ }; extern int register_cpu(struct cpu *, int, struct node *); +extern struct class cpu_class; /* Stop CPUs going up and down. */ extern struct semaphore cpucontrol; diff -Nru a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h --- a/include/linux/devfs_fs_kernel.h Mon May 12 20:55:48 2003 +++ b/include/linux/devfs_fs_kernel.h Mon May 12 20:55:48 2003 @@ -27,6 +27,8 @@ umode_t mode, void *ops, void *info); extern int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) __attribute__((format (printf, 3, 4))); +extern int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) + __attribute__((format (printf, 3, 4))); extern int devfs_mk_symlink(const char *name, const char *link); extern int devfs_mk_dir(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@ -48,6 +50,10 @@ return NULL; } static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) +{ + return 0; +} +static inline int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) { return 0; } diff -Nru a/include/linux/efi.h b/include/linux/efi.h --- a/include/linux/efi.h Mon May 12 20:55:49 2003 +++ b/include/linux/efi.h Mon May 12 20:55:49 2003 @@ -7,7 +7,7 @@ * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999, 2002 Hewlett-Packard Co. + * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. * David Mosberger-Tang * Stephane Eranian */ @@ -21,12 +21,12 @@ #include #define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR (1L | (1L << 63)) -#define EFI_INVALID_PARAMETER (2L | (1L << 63)) -#define EFI_UNSUPPORTED (3L | (1L << 63)) -#define EFI_BAD_BUFFER_SIZE (4L | (1L << 63)) -#define EFI_BUFFER_TOO_SMALL (5L | (1L << 63)) -#define EFI_NOT_FOUND (14L | (1L << 63)) +#define EFI_LOAD_ERROR ( 1 | (1UL << 63)) +#define EFI_INVALID_PARAMETER ( 2 | (1UL << 63)) +#define EFI_UNSUPPORTED ( 3 | (1UL << 63)) +#define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << 63)) +#define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << 63)) +#define EFI_NOT_FOUND (14 | (1UL << 63)) typedef unsigned long efi_status_t; typedef u8 efi_bool_t; @@ -260,7 +260,7 @@ extern void efi_init (void); extern void efi_map_pal_code (void); extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); -extern void efi_gettimeofday (struct timeval *tv); +extern void efi_gettimeofday (struct timespec *ts); extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ extern u64 efi_get_iobase (void); extern u32 efi_mem_type (unsigned long phys_addr); diff -Nru a/include/linux/elevator.h b/include/linux/elevator.h --- a/include/linux/elevator.h Mon May 12 20:55:44 2003 +++ b/include/linux/elevator.h Mon May 12 20:55:44 2003 @@ -15,6 +15,8 @@ typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *); typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *); typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *); +typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int); +typedef void (elevator_put_req_fn) (request_queue_t *, struct request *); typedef int (elevator_init_fn) (request_queue_t *, elevator_t *); typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *); @@ -34,6 +36,9 @@ elevator_request_list_fn *elevator_former_req_fn; elevator_request_list_fn *elevator_latter_req_fn; + elevator_set_req_fn *elevator_set_req_fn; + elevator_put_req_fn *elevator_put_req_fn; + elevator_init_fn *elevator_init_fn; elevator_exit_fn *elevator_exit_fn; @@ -59,6 +64,8 @@ extern struct request *elv_latter_request(request_queue_t *, struct request *); extern int elv_register_queue(struct gendisk *); extern void elv_unregister_queue(struct gendisk *); +extern int elv_set_request(request_queue_t *, struct request *, int); +extern void elv_put_request(request_queue_t *, struct request *); #define __elv_add_request_pos(q, rq, pos) \ (q)->elevator.elevator_add_req_fn((q), (rq), (pos)) diff -Nru a/include/linux/elf.h b/include/linux/elf.h --- a/include/linux/elf.h Mon May 12 20:55:45 2003 +++ b/include/linux/elf.h Mon May 12 20:55:45 2003 @@ -34,13 +34,6 @@ #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7fffffff #define PT_GNU_EH_FRAME 0x6474e550 -#define PT_MIPS_REGINFO 0x70000000 - -/* Flags in the e_flags field of the header */ -#define EF_MIPS_NOREORDER 0x00000001 -#define EF_MIPS_PIC 0x00000002 -#define EF_MIPS_CPIC 0x00000004 -#define EF_MIPS_ARCH 0xf0000000 /* These constants define the different elf file types */ #define ET_NONE 0 @@ -130,25 +123,6 @@ #define DT_JMPREL 23 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7fffffff -#define DT_MIPS_RLD_VERSION 0x70000001 -#define DT_MIPS_TIME_STAMP 0x70000002 -#define DT_MIPS_ICHECKSUM 0x70000003 -#define DT_MIPS_IVERSION 0x70000004 -#define DT_MIPS_FLAGS 0x70000005 - #define RHF_NONE 0 - #define RHF_HARDWAY 1 - #define RHF_NOTPOT 2 -#define DT_MIPS_BASE_ADDRESS 0x70000006 -#define DT_MIPS_CONFLICT 0x70000008 -#define DT_MIPS_LIBLIST 0x70000009 -#define DT_MIPS_LOCAL_GOTNO 0x7000000a -#define DT_MIPS_CONFLICTNO 0x7000000b -#define DT_MIPS_LIBLISTNO 0x70000010 -#define DT_MIPS_SYMTABNO 0x70000011 -#define DT_MIPS_UNREFEXTNO 0x70000012 -#define DT_MIPS_GOTSYM 0x70000013 -#define DT_MIPS_HIPAGENO 0x70000014 -#define DT_MIPS_RLD_MAP 0x70000016 /* This info is needed when parsing the symbol table */ #define STB_LOCAL 0 @@ -212,508 +186,6 @@ #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define R_ARM_NONE 0 -#define R_ARM_PC24 1 -#define R_ARM_ABS32 2 - -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GOT32 3 -#define R_386_PLT32 4 -#define R_386_COPY 5 -#define R_386_GLOB_DAT 6 -#define R_386_JMP_SLOT 7 -#define R_386_RELATIVE 8 -#define R_386_GOTOFF 9 -#define R_386_GOTPC 10 -#define R_386_NUM 11 - -#define R_MIPS_NONE 0 -#define R_MIPS_16 1 -#define R_MIPS_32 2 -#define R_MIPS_REL32 3 -#define R_MIPS_26 4 -#define R_MIPS_HI16 5 -#define R_MIPS_LO16 6 -#define R_MIPS_GPREL16 7 -#define R_MIPS_LITERAL 8 -#define R_MIPS_GOT16 9 -#define R_MIPS_PC16 10 -#define R_MIPS_CALL16 11 -#define R_MIPS_GPREL32 12 -/* The remaining relocs are defined on Irix, although they are not - in the MIPS ELF ABI. */ -#define R_MIPS_UNUSED1 13 -#define R_MIPS_UNUSED2 14 -#define R_MIPS_UNUSED3 15 -#define R_MIPS_SHIFT5 16 -#define R_MIPS_SHIFT6 17 -#define R_MIPS_64 18 -#define R_MIPS_GOT_DISP 19 -#define R_MIPS_GOT_PAGE 20 -#define R_MIPS_GOT_OFST 21 -/* - * The following two relocation types are specified in the MIPS ABI - * conformance guide version 1.2 but not yet in the psABI. - */ -#define R_MIPS_GOTHI16 22 -#define R_MIPS_GOTLO16 23 -#define R_MIPS_SUB 24 -#define R_MIPS_INSERT_A 25 -#define R_MIPS_INSERT_B 26 -#define R_MIPS_DELETE 27 -#define R_MIPS_HIGHER 28 -#define R_MIPS_HIGHEST 29 -/* - * The following two relocation types are specified in the MIPS ABI - * conformance guide version 1.2 but not yet in the psABI. - */ -#define R_MIPS_CALLHI16 30 -#define R_MIPS_CALLLO16 31 -/* - * This range is reserved for vendor specific relocations. - */ -#define R_MIPS_LOVENDOR 100 -#define R_MIPS_HIVENDOR 127 - -/* - * Sparc section types - */ -#define STT_REGISTER 13 - -/* - * Sparc ELF relocation types - */ -#define R_SPARC_NONE 0 -#define R_SPARC_8 1 -#define R_SPARC_16 2 -#define R_SPARC_32 3 -#define R_SPARC_DISP8 4 -#define R_SPARC_DISP16 5 -#define R_SPARC_DISP32 6 -#define R_SPARC_WDISP30 7 -#define R_SPARC_WDISP22 8 -#define R_SPARC_HI22 9 -#define R_SPARC_22 10 -#define R_SPARC_13 11 -#define R_SPARC_LO10 12 -#define R_SPARC_GOT10 13 -#define R_SPARC_GOT13 14 -#define R_SPARC_GOT22 15 -#define R_SPARC_PC10 16 -#define R_SPARC_PC22 17 -#define R_SPARC_WPLT30 18 -#define R_SPARC_COPY 19 -#define R_SPARC_GLOB_DAT 20 -#define R_SPARC_JMP_SLOT 21 -#define R_SPARC_RELATIVE 22 -#define R_SPARC_UA32 23 -#define R_SPARC_PLT32 24 -#define R_SPARC_HIPLT22 25 -#define R_SPARC_LOPLT10 26 -#define R_SPARC_PCPLT32 27 -#define R_SPARC_PCPLT22 28 -#define R_SPARC_PCPLT10 29 -#define R_SPARC_10 30 -#define R_SPARC_11 31 -#define R_SPARC_64 32 -#define R_SPARC_OLO10 33 -#define R_SPARC_WDISP16 40 -#define R_SPARC_WDISP19 41 -#define R_SPARC_7 43 -#define R_SPARC_5 44 -#define R_SPARC_6 45 - -/* Bits present in AT_HWCAP, primarily for Sparc32. */ - -#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */ -#define HWCAP_SPARC_STBAR 2 -#define HWCAP_SPARC_SWAP 4 -#define HWCAP_SPARC_MULDIV 8 -#define HWCAP_SPARC_V9 16 -#define HWCAP_SPARC_ULTRA3 32 - -/* - * 68k ELF relocation types - */ -#define R_68K_NONE 0 -#define R_68K_32 1 -#define R_68K_16 2 -#define R_68K_8 3 -#define R_68K_PC32 4 -#define R_68K_PC16 5 -#define R_68K_PC8 6 -#define R_68K_GOT32 7 -#define R_68K_GOT16 8 -#define R_68K_GOT8 9 -#define R_68K_GOT32O 10 -#define R_68K_GOT16O 11 -#define R_68K_GOT8O 12 -#define R_68K_PLT32 13 -#define R_68K_PLT16 14 -#define R_68K_PLT8 15 -#define R_68K_PLT32O 16 -#define R_68K_PLT16O 17 -#define R_68K_PLT8O 18 -#define R_68K_COPY 19 -#define R_68K_GLOB_DAT 20 -#define R_68K_JMP_SLOT 21 -#define R_68K_RELATIVE 22 - -/* - * Alpha ELF relocation types - */ -#define R_ALPHA_NONE 0 /* No reloc */ -#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ -#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ -#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ -#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ -#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ -#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ -#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ -#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ -#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ -#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ -#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ -#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ -#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ -#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ -#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ -#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ -#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ -#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ -#define R_ALPHA_BRSGP 28 -#define R_ALPHA_TLSGD 29 -#define R_ALPHA_TLS_LDM 30 -#define R_ALPHA_DTPMOD64 31 -#define R_ALPHA_GOTDTPREL 32 -#define R_ALPHA_DTPREL64 33 -#define R_ALPHA_DTPRELHI 34 -#define R_ALPHA_DTPRELLO 35 -#define R_ALPHA_DTPREL16 36 -#define R_ALPHA_GOTTPREL 37 -#define R_ALPHA_TPREL64 38 -#define R_ALPHA_TPRELHI 39 -#define R_ALPHA_TPRELLO 40 -#define R_ALPHA_TPREL16 41 - -#define SHF_ALPHA_GPREL 0x10000000 - - -/* PowerPC relocations defined by the ABIs */ -#define R_PPC_NONE 0 -#define R_PPC_ADDR32 1 /* 32bit absolute address */ -#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ -#define R_PPC_ADDR16 3 /* 16bit absolute address */ -#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ -#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ -#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ -#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ -#define R_PPC_ADDR14_BRTAKEN 8 -#define R_PPC_ADDR14_BRNTAKEN 9 -#define R_PPC_REL24 10 /* PC relative 26 bit */ -#define R_PPC_REL14 11 /* PC relative 16 bit */ -#define R_PPC_REL14_BRTAKEN 12 -#define R_PPC_REL14_BRNTAKEN 13 -#define R_PPC_GOT16 14 -#define R_PPC_GOT16_LO 15 -#define R_PPC_GOT16_HI 16 -#define R_PPC_GOT16_HA 17 -#define R_PPC_PLTREL24 18 -#define R_PPC_COPY 19 -#define R_PPC_GLOB_DAT 20 -#define R_PPC_JMP_SLOT 21 -#define R_PPC_RELATIVE 22 -#define R_PPC_LOCAL24PC 23 -#define R_PPC_UADDR32 24 -#define R_PPC_UADDR16 25 -#define R_PPC_REL32 26 -#define R_PPC_PLT32 27 -#define R_PPC_PLTREL32 28 -#define R_PPC_PLT16_LO 29 -#define R_PPC_PLT16_HI 30 -#define R_PPC_PLT16_HA 31 -#define R_PPC_SDAREL16 32 -#define R_PPC_SECTOFF 33 -#define R_PPC_SECTOFF_LO 34 -#define R_PPC_SECTOFF_HI 35 -#define R_PPC_SECTOFF_HA 36 -/* Keep this the last entry. */ -#define R_PPC_NUM 37 - -/* s390 relocations defined by the ABIs */ -#define R_390_NONE 0 /* No reloc. */ -#define R_390_8 1 /* Direct 8 bit. */ -#define R_390_12 2 /* Direct 12 bit. */ -#define R_390_16 3 /* Direct 16 bit. */ -#define R_390_32 4 /* Direct 32 bit. */ -#define R_390_PC32 5 /* PC relative 32 bit. */ -#define R_390_GOT12 6 /* 12 bit GOT offset. */ -#define R_390_GOT32 7 /* 32 bit GOT offset. */ -#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ -#define R_390_COPY 9 /* Copy symbol at runtime. */ -#define R_390_GLOB_DAT 10 /* Create GOT entry. */ -#define R_390_JMP_SLOT 11 /* Create PLT entry. */ -#define R_390_RELATIVE 12 /* Adjust by program base. */ -#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ -#define R_390_GOTPC 14 /* 32 bit PC rel. offset to GOT. */ -#define R_390_GOT16 15 /* 16 bit GOT offset. */ -#define R_390_PC16 16 /* PC relative 16 bit. */ -#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ -#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ -#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ -#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ -#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ -#define R_390_64 22 /* Direct 64 bit. */ -#define R_390_PC64 23 /* PC relative 64 bit. */ -#define R_390_GOT64 24 /* 64 bit GOT offset. */ -#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ -#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ -#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ -#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ -#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ -#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ -#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ -#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ -#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ -#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ -#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ -#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ -#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ -#define R_390_TLS_GDCALL 38 /* Tag for function call in general - dynamic TLS code. */ -#define R_390_TLS_LDCALL 39 /* Tag for function call in local - dynamic TLS code. */ -#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic - thread local data. */ -#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic - thread local data. */ -#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS - block offset. */ -#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic - thread local data in LD code. */ -#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic - thread local data in LD code. */ -#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for - negated static TLS block offset. */ -#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to - static TLS block. */ -#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS - block. */ -#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS - block. */ -#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ -#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ -#define R_390_TLS_TPOFF 56 /* Negate offset in static TLS - block. */ -/* Keep this the last entry. */ -#define R_390_NUM 57 - -/* x86-64 relocation types */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_COPY 5 /* Copy symbol at runtime */ -#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ -#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative - offset to GOT */ -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define R_X86_64_16 12 /* Direct 16 bit zero extended */ -#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ -#define R_X86_64_8 14 /* Direct 8 bit sign extended */ -#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ - -#define R_X86_64_NUM 16 - -/* Legal values for e_flags field of Elf64_Ehdr. */ - -#define EF_ALPHA_32BIT 1 /* All addresses are below 2GB */ - -/* HPPA specific definitions. */ - -/* Legal values for e_flags field of Elf32_Ehdr. */ - -#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ -#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ -#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ -#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ -#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch - prediction. */ -#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ -#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ - -/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ - -#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ -#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ -#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ - -/* Additional section indeces. */ - -#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared - symbols in ANSI C. */ -#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ - -/* Legal values for sh_type field of Elf32_Shdr. */ - -#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ -#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ -#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ - -/* Legal values for sh_flags field of Elf32_Shdr. */ - -#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ -#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ -#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ - -/* Legal values for ST_TYPE subfield of st_info (symbol type). */ - -#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ - -#define STT_HP_OPAQUE (STT_LOOS + 0x1) -#define STT_HP_STUB (STT_LOOS + 0x2) - -/* HPPA relocs. */ - -#define R_PARISC_NONE 0 /* No reloc. */ -#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ -#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ -#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ -#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ -#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ -#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ -#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ -#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ -#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ -#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ -#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ -#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ -#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ -#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ -#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ -#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ -#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ -#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ -#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ -#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ -#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ -#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ -#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ -#define R_PARISC_FPTR64 64 /* 64 bits function address. */ -#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ -#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ -#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ -#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ -#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ -#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ -#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ -#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ -#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ -#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ -#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ -#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ -#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ -#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ -#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ -#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ -#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ -#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ -#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ -#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ -#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ -#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ -#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ -#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ -#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ -#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ -#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ -#define R_PARISC_LORESERVE 128 -#define R_PARISC_COPY 128 /* Copy relocation. */ -#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ -#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ -#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ -#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ -#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ -#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ -#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ -#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ -#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ -#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ -#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ -#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ -#define R_PARISC_HIRESERVE 255 - -/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ - -#define PT_HP_TLS (PT_LOOS + 0x0) -#define PT_HP_CORE_NONE (PT_LOOS + 0x1) -#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) -#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) -#define PT_HP_CORE_COMM (PT_LOOS + 0x4) -#define PT_HP_CORE_PROC (PT_LOOS + 0x5) -#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) -#define PT_HP_CORE_STACK (PT_LOOS + 0x7) -#define PT_HP_CORE_SHM (PT_LOOS + 0x8) -#define PT_HP_CORE_MMF (PT_LOOS + 0x9) -#define PT_HP_PARALLEL (PT_LOOS + 0x10) -#define PT_HP_FASTBIND (PT_LOOS + 0x11) -#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) -#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) -#define PT_HP_STACK (PT_LOOS + 0x14) - -#define PT_PARISC_ARCHEXT 0x70000000 -#define PT_PARISC_UNWIND 0x70000001 - -/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ - -#define PF_PARISC_SBP 0x08000000 - -#define PF_HP_PAGE_SIZE 0x00100000 -#define PF_HP_FAR_SHARED 0x00200000 -#define PF_HP_NEAR_SHARED 0x00400000 -#define PF_HP_CODE 0x01000000 -#define PF_HP_MODIFY 0x02000000 -#define PF_HP_LAZYSWAP 0x04000000 -#define PF_HP_SBP 0x08000000 - - typedef struct elf32_rel { Elf32_Addr r_offset; Elf32_Word r_info; @@ -837,17 +309,12 @@ #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xffffffff -#define SHT_MIPS_LIST 0x70000000 -#define SHT_MIPS_CONFLICT 0x70000002 -#define SHT_MIPS_GPTAB 0x70000003 -#define SHT_MIPS_UCODE 0x70000004 /* sh_flags */ #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MASKPROC 0xf0000000 -#define SHF_MIPS_GPREL 0x10000000 /* special section indexes */ #define SHN_UNDEF 0 @@ -857,7 +324,6 @@ #define SHN_ABS 0xfff1 #define SHN_COMMON 0xfff2 #define SHN_HIRESERVE 0xffff -#define SHN_MIPS_ACCOMON 0xff00 typedef struct { Elf32_Word sh_name; diff -Nru a/include/linux/file.h b/include/linux/file.h --- a/include/linux/file.h Mon May 12 20:55:44 2003 +++ b/include/linux/file.h Mon May 12 20:55:44 2003 @@ -35,7 +35,15 @@ extern void FASTCALL(__fput(struct file *)); extern void FASTCALL(fput(struct file *)); + +static inline void fput_light(struct file *file, int fput_needed) +{ + if (unlikely(fput_needed)) + fput(file); +} + extern struct file * FASTCALL(fget(unsigned int fd)); +extern struct file * FASTCALL(fget_light(unsigned int fd, int *fput_needed)); extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag)); extern void put_filp(struct file *); extern int get_unused_fd(void); diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Mon May 12 20:55:45 2003 +++ b/include/linux/fs.h Mon May 12 20:55:45 2003 @@ -206,8 +206,8 @@ #include #include +/* Used to be a macro which just called the function, now just a function */ extern void update_atime (struct inode *); -#define UPDATE_ATIME(inode) update_atime (inode) extern void inode_init(unsigned long); extern void mnt_init(unsigned long); @@ -691,7 +691,7 @@ typedef struct { size_t written; size_t count; - char * buf; + char __user * buf; int error; } read_descriptor_t; @@ -722,7 +722,7 @@ int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); - ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *); + ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void __user *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; @@ -1017,7 +1017,7 @@ /* fs/open.c */ -asmlinkage long sys_open(const char *, int, int); +asmlinkage long sys_open(const char __user *, int, int); asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */ extern int do_truncate(struct dentry *, loff_t start); @@ -1113,6 +1113,10 @@ extern int filemap_fdatawait(struct address_space *); extern void sync_supers(void); extern void sync_filesystems(int wait); +extern void emergency_sync(void); +extern void emergency_remount(void); +extern int do_remount_sb(struct super_block *sb, int flags, + void *data, int force); extern sector_t bmap(struct inode *, sector_t); extern int setattr_mask(unsigned int); extern int notify_change(struct dentry *, struct iattr *); @@ -1203,15 +1207,15 @@ int generic_write_checks(struct inode *inode, struct file *file, loff_t *pos, size_t *count, int isblk); extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t generic_file_aio_read(struct kiocb *, char *, size_t, loff_t); -extern ssize_t generic_file_aio_write(struct kiocb *, const char *, size_t, loff_t); +extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t); +extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t); extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *, unsigned long, loff_t *); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos); -extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *); +extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void __user *); extern void do_generic_mapping_read(struct address_space *, struct file_ra_state *, struct file *, loff_t *, read_descriptor_t *, read_actor_t); extern void diff -Nru a/include/linux/futex.h b/include/linux/futex.h --- a/include/linux/futex.h Mon May 12 20:55:47 2003 +++ b/include/linux/futex.h Mon May 12 20:55:47 2003 @@ -6,6 +6,6 @@ #define FUTEX_WAKE (1) #define FUTEX_FD (2) -extern asmlinkage long sys_futex(u32 *uaddr, int op, int val, struct timespec *utime); +extern asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, struct timespec __user *utime); #endif diff -Nru a/include/linux/i2c.h b/include/linux/i2c.h --- a/include/linux/i2c.h Mon May 12 20:55:45 2003 +++ b/include/linux/i2c.h Mon May 12 20:55:45 2003 @@ -39,12 +39,6 @@ /* --- General options ------------------------------------------------ */ -#define I2C_ALGO_MAX 4 /* control memory consumption */ -#define I2C_ADAP_MAX 16 -#define I2C_DRIVER_MAX 16 -#define I2C_CLIENT_MAX 32 -#define I2C_DUMMY_MAX 4 - struct i2c_msg; struct i2c_algorithm; struct i2c_adapter; @@ -131,6 +125,7 @@ * i2c_attach_client. */ int (*attach_adapter)(struct i2c_adapter *); + int (*detach_adapter)(struct i2c_adapter *); /* tells the driver that a client is about to be deleted & gives it * the chance to remove its private data. Also, if the client struct @@ -145,6 +140,7 @@ int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); struct device_driver driver; + struct list_head list; }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) @@ -169,6 +165,7 @@ int usage_count; /* How many accesses currently */ /* to the client */ struct device dev; /* the device structure */ + struct list_head list; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -228,6 +225,7 @@ struct module *owner; unsigned int id;/* == is algo->id | hwdep.struct->id, */ /* for registered values see below */ + unsigned int class; struct i2c_algorithm *algo;/* the algorithm to access the bus */ void *algo_data; @@ -236,20 +234,23 @@ int (*client_unregister)(struct i2c_client *); /* data fields that are valid for all devices */ - struct semaphore bus; - struct semaphore list; + struct semaphore bus_lock; + struct semaphore clist_lock; unsigned int flags;/* flags specifying div. data */ - struct i2c_client *clients[I2C_CLIENT_MAX]; - int timeout; int retries; - struct device dev; /* the adapter device */ + struct device dev; /* the adapter device */ + struct class_device class_dev; /* the class device */ #ifdef CONFIG_PROC_FS /* No need to set this when you initialize the adapter */ int inode; #endif /* def CONFIG_PROC_FS */ + + int nr; + struct list_head clients; + struct list_head list; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -265,7 +266,11 @@ /*flags for the driver struct: */ #define I2C_DF_NOTIFY 0x01 /* notify on bus (de/a)ttaches */ -#define I2C_DF_DUMMY 0x02 /* do not connect any clients */ +#if 0 +/* this flag is gone -- there is a (optional) driver->detach_adapter + * callback now which can be used instead */ +# define I2C_DF_DUMMY 0x02 +#endif /*flags for the client struct: */ #define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */ @@ -275,6 +280,14 @@ #define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ /* Must equal I2C_M_TEN below */ +/* i2c adapter classes (bitmask) */ +#define I2C_ADAP_CLASS_SMBUS (1<<0) /* lm_sensors, ... */ +#define I2C_ADAP_CLASS_TV_ANALOG (1<<1) /* bttv + friends */ +#define I2C_ADAP_CLASS_TV_DIGITAL (1<<2) /* dbv cards */ +#define I2C_ADAP_CLASS_DDC (1<<3) /* i2c-matroxfb ? */ +#define I2C_ADAP_CLASS_CAM_ANALOG (1<<4) /* camera with analog CCD */ +#define I2C_ADAP_CLASS_CAM_DIGITAL (1<<5) /* most webcams */ + /* i2c_client_address_data is the struct for holding default client * addresses for a driver and for the parameters supplied on the * command line @@ -331,6 +344,11 @@ extern int i2c_use_client(struct i2c_client *); extern int i2c_release_client(struct i2c_client *); +/* call the i2c_client->command() of all attached clients with + * the given arguments */ +extern void i2c_clients_command(struct i2c_adapter *adap, + unsigned int cmd, void *arg); + /* returns -EBUSY if address has been taken, 0 if not. Note that the only other place at which this is called is within i2c_attach_client; so you can cheat by simply not registering. Not recommended, of course! */ @@ -352,7 +370,8 @@ * or -1 if the adapter was not registered. */ extern int i2c_adapter_id(struct i2c_adapter *adap); - +extern struct i2c_adapter* i2c_get_adapter(int id); +extern void i2c_put_adapter(struct i2c_adapter *adap); /* Return the functionality mask */ diff -Nru a/include/linux/if_ether.h b/include/linux/if_ether.h --- a/include/linux/if_ether.h Mon May 12 20:55:47 2003 +++ b/include/linux/if_ether.h Mon May 12 20:55:47 2003 @@ -61,6 +61,8 @@ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ #define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ #define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ +#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ +#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ #define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ #define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport * over Ethernet diff -Nru a/include/linux/if_frad.h b/include/linux/if_frad.h --- a/include/linux/if_frad.h Mon May 12 20:55:44 2003 +++ b/include/linux/if_frad.h Mon May 12 20:55:44 2003 @@ -192,7 +192,7 @@ int register_frad(const char *name); int unregister_frad(const char *name); -extern int (*dlci_ioctl_hook)(unsigned int, void *); +extern void dlci_ioctl_set(int (*hook)(unsigned int, void *)); #endif /* __KERNEL__ */ diff -Nru a/include/linux/input.h b/include/linux/input.h --- a/include/linux/input.h Mon May 12 20:55:46 2003 +++ b/include/linux/input.h Mon May 12 20:55:46 2003 @@ -894,9 +894,6 @@ int input_accept_process(struct input_handle *handle, struct file *file); int input_flush_device(struct input_handle* handle, struct file* file); -/* will go away once devfs_register gets sanitized */ -void input_register_minor(char *name, int minor, int minor_base); - void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h --- a/include/linux/ipv6.h Mon May 12 20:55:47 2003 +++ b/include/linux/ipv6.h Mon May 12 20:55:47 2003 @@ -121,6 +121,7 @@ #include #include /* struct ipv6_mc_socklist */ #include +#include /* This structure contains results of exthdrs parsing @@ -178,6 +179,11 @@ struct ipv6_txoptions *opt; struct sk_buff *pktoptions; + struct { + struct ipv6_txoptions *opt; + struct rt6_info *rt; + struct flowi *fl; + } cork; }; struct raw6_opt { @@ -200,6 +206,7 @@ struct sock sk; struct ipv6_pinfo *pinet6; struct inet_opt inet; + struct udp_opt udp; struct ipv6_pinfo inet6; }; diff -Nru a/include/linux/ipx.h b/include/linux/ipx.h --- a/include/linux/ipx.h Mon May 12 20:55:48 2003 +++ b/include/linux/ipx.h Mon May 12 20:55:48 2003 @@ -5,8 +5,7 @@ #define IPX_NODE_LEN 6 #define IPX_MTU 576 -struct sockaddr_ipx -{ +struct sockaddr_ipx { sa_family_t sipx_family; __u16 sipx_port; __u32 sipx_network; @@ -16,9 +15,8 @@ }; /* - * So we can fit the extra info for SIOCSIFADDR into the address nicely + * So we can fit the extra info for SIOCSIFADDR into the address nicely */ - #define sipx_special sipx_port #define sipx_action sipx_zero #define IPX_DLTITF 0 @@ -56,14 +54,13 @@ * OLD Route Definition for backward compatibility. */ -struct ipx_route_def -{ - __u32 ipx_network; - __u32 ipx_router_network; +struct ipx_route_def { + __u32 ipx_network; + __u32 ipx_router_network; #define IPX_ROUTE_NO_ROUTER 0 - unsigned char ipx_router_node[IPX_NODE_LEN]; - unsigned char ipx_device[16]; - unsigned short ipx_flags; + unsigned char ipx_router_node[IPX_NODE_LEN]; + unsigned char ipx_device[16]; + unsigned short ipx_flags; #define IPX_RT_SNAP 8 #define IPX_RT_8022 4 #define IPX_RT_BLUEBOOK 2 @@ -71,7 +68,7 @@ }; #define SIOCAIPXITFCRT (SIOCPROTOPRIVATE) -#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE+1) -#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE+2) -#define SIOCIPXNCPCONN (SIOCPROTOPRIVATE+3) -#endif /* def _IPX_H_ */ +#define SIOCAIPXPRISLT (SIOCPROTOPRIVATE + 1) +#define SIOCIPXCFGDATA (SIOCPROTOPRIVATE + 2) +#define SIOCIPXNCPCONN (SIOCPROTOPRIVATE + 3) +#endif /* _IPX_H_ */ diff -Nru a/include/linux/list.h b/include/linux/list.h --- a/include/linux/list.h Mon May 12 20:55:47 2003 +++ b/include/linux/list.h Mon May 12 20:55:47 2003 @@ -297,6 +297,19 @@ prefetch(pos->member.next)) /** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** * list_for_each_rcu - iterate over an rcu-protected list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. diff -Nru a/include/linux/major.h b/include/linux/major.h --- a/include/linux/major.h Mon May 12 20:55:45 2003 +++ b/include/linux/major.h Mon May 12 20:55:45 2003 @@ -27,6 +27,7 @@ #define MUX_MAJOR 11 /* PA-RISC only */ #define QIC02_TAPE_MAJOR 12 #define XT_DISK_MAJOR 13 +#define INPUT_MAJOR 13 #define SOUND_MAJOR 14 #define CDU31A_CDROM_MAJOR 15 #define JOYSTICK_MAJOR 15 diff -Nru a/include/linux/msg.h b/include/linux/msg.h --- a/include/linux/msg.h Mon May 12 20:55:47 2003 +++ b/include/linux/msg.h Mon May 12 20:55:47 2003 @@ -94,9 +94,9 @@ }; asmlinkage long sys_msgget (key_t key, int msgflg); -asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); -asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); -asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); +asmlinkage long sys_msgsnd (int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg); +asmlinkage long sys_msgrcv (int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg); +asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf); #endif /* __KERNEL__ */ diff -Nru a/include/linux/net.h b/include/linux/net.h --- a/include/linux/net.h Mon May 12 20:55:46 2003 +++ b/include/linux/net.h Mon May 12 20:55:46 2003 @@ -96,18 +96,18 @@ struct module *owner; int (*release) (struct socket *sock); int (*bind) (struct socket *sock, - struct sockaddr *umyaddr, + struct sockaddr *myaddr, int sockaddr_len); int (*connect) (struct socket *sock, - struct sockaddr *uservaddr, + struct sockaddr *vaddr, int sockaddr_len, int flags); int (*socketpair)(struct socket *sock1, struct socket *sock2); int (*accept) (struct socket *sock, struct socket *newsock, int flags); int (*getname) (struct socket *sock, - struct sockaddr *uaddr, - int *usockaddr_len, int peer); + struct sockaddr *addr, + int *sockaddr_len, int peer); unsigned int (*poll) (struct file *file, struct socket *sock, struct poll_table_struct *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, @@ -115,9 +115,9 @@ int (*listen) (struct socket *sock, int len); int (*shutdown) (struct socket *sock, int flags); int (*setsockopt)(struct socket *sock, int level, - int optname, char *optval, int optlen); + int optname, char __user *optval, int optlen); int (*getsockopt)(struct socket *sock, int level, - int optname, char *optval, int *optlen); + int optname, char __user *optval, int __user *optlen); int (*sendmsg) (struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len); int (*recvmsg) (struct kiocb *iocb, struct socket *sock, diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Mon May 12 20:55:49 2003 +++ b/include/linux/netdevice.h Mon May 12 20:55:49 2003 @@ -456,7 +456,7 @@ int (*func) (struct sk_buff *, struct net_device *, struct packet_type *); void *data; /* Private to the packet type */ - struct packet_type *next; + struct list_head list; }; @@ -472,6 +472,7 @@ extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr); extern void dev_add_pack(struct packet_type *pt); extern void dev_remove_pack(struct packet_type *pt); +extern void __dev_remove_pack(struct packet_type *pt); extern int dev_get(const char *name); extern struct net_device *dev_get_by_flags(unsigned short flags, unsigned short mask); diff -Nru a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h --- a/include/linux/netfilter_ipv4/ip_nat_core.h Mon May 12 20:55:44 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_core.h Mon May 12 20:55:44 2003 @@ -16,10 +16,10 @@ extern struct list_head protos; -extern unsigned int icmp_reply_translation(struct sk_buff *skb, - struct ip_conntrack *conntrack, - unsigned int hooknum, - int dir); +extern int icmp_reply_translation(struct sk_buff **pskb, + struct ip_conntrack *conntrack, + unsigned int hooknum, + int dir); extern void replace_in_hashes(struct ip_conntrack *conntrack, struct ip_nat_info *info); @@ -30,4 +30,10 @@ extern struct ip_nat_protocol ip_nat_protocol_tcp; extern struct ip_nat_protocol ip_nat_protocol_udp; extern struct ip_nat_protocol ip_nat_protocol_icmp; + +/* Call this before modifying an existing IP packet: ensures it is + modifiable and linear to the point you care about (writable_len). + Returns true or false. */ +extern int skb_ip_make_writable(struct sk_buff **pskb, + unsigned int writable_len); #endif /* _IP_NAT_CORE_H */ diff -Nru a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h --- a/include/linux/netfilter_ipv4/ip_nat_helper.h Mon May 12 20:55:45 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_helper.h Mon May 12 20:55:45 2003 @@ -43,22 +43,23 @@ extern int ip_nat_helper_register(struct ip_nat_helper *me); extern void ip_nat_helper_unregister(struct ip_nat_helper *me); + +/* These return true or false. */ extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, - char *rep_buffer, + const char *rep_buffer, unsigned int rep_len); extern int ip_nat_mangle_udp_packet(struct sk_buff **skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, - char *rep_buffer, + const char *rep_buffer, unsigned int rep_len); -extern int ip_nat_seq_adjust(struct sk_buff *skb, - struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo); -extern void ip_nat_delete_sack(struct sk_buff *skb); +extern int ip_nat_seq_adjust(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo); #endif diff -Nru a/include/linux/netfilter_ipv4/ip_nat_protocol.h b/include/linux/netfilter_ipv4/ip_nat_protocol.h --- a/include/linux/netfilter_ipv4/ip_nat_protocol.h Mon May 12 20:55:47 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_protocol.h Mon May 12 20:55:47 2003 @@ -18,10 +18,11 @@ unsigned int protonum; /* Do a packet translation according to the ip_nat_proto_manip - * and manip type. */ - void (*manip_pkt)(struct iphdr *iph, size_t len, - const struct ip_conntrack_manip *manip, - enum ip_nat_manip_type maniptype); + * and manip type. Return true if succeeded. */ + int (*manip_pkt)(struct sk_buff **pskb, + unsigned int hdroff, + const struct ip_conntrack_manip *manip, + enum ip_nat_manip_type maniptype); /* Is the manipable part of the tuple between min and max incl? */ int (*in_range)(const struct ip_conntrack_tuple *tuple, diff -Nru a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h --- a/include/linux/nfs_fs_sb.h Mon May 12 20:55:49 2003 +++ b/include/linux/nfs_fs_sb.h Mon May 12 20:55:49 2003 @@ -27,7 +27,7 @@ char * hostname; /* remote hostname */ struct nfs_fh fh; struct sockaddr_in addr; -#if CONFIG_NFS_V4 +#ifdef CONFIG_NFS_V4 /* Our own IP address, as a null-terminated string. * This is used to generate the clientid, and the callback address. */ diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h --- a/include/linux/pagemap.h Mon May 12 20:55:44 2003 +++ b/include/linux/pagemap.h Mon May 12 20:55:44 2003 @@ -172,7 +172,7 @@ * This assumes that two userspace pages are always sufficient. That's * not true if PAGE_CACHE_SIZE > PAGE_SIZE. */ -static inline int fault_in_pages_writeable(char *uaddr, int size) +static inline int fault_in_pages_writeable(char __user *uaddr, int size) { int ret; @@ -182,7 +182,7 @@ */ ret = __put_user(0, uaddr); if (ret == 0) { - char *end = uaddr + size - 1; + char __user *end = uaddr + size - 1; /* * If the page was already mapped, this will get a cache miss @@ -195,14 +195,14 @@ return ret; } -static inline void fault_in_pages_readable(const char *uaddr, int size) +static inline void fault_in_pages_readable(const char __user *uaddr, int size) { volatile char c; int ret; ret = __get_user(c, (char *)uaddr); if (ret == 0) { - const char *end = uaddr + size - 1; + const char __user *end = uaddr + size - 1; if (((unsigned long)uaddr & PAGE_MASK) != ((unsigned long)end & PAGE_MASK)) diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Mon May 12 20:55:46 2003 +++ b/include/linux/pci_ids.h Mon May 12 20:55:46 2003 @@ -605,6 +605,7 @@ #define PCI_DEVICE_ID_HP_ZX1_SBA 0x1229 #define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a #define PCI_DEVICE_ID_HP_ZX1_LBA 0x122e +#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 @@ -1007,7 +1008,9 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B #define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 @@ -1902,10 +1905,13 @@ #define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 #define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 #define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 +#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 +#define PCI_DEVICE_ID_INTEL_82875_IG 0x257b +#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -#define PCI_DEVICE_ID_INTEL_82855_HB 0x3580 -#define PCI_DEVICE_ID_INTEL_82855_IG 0x3582 +#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 +#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 #define PCI_DEVICE_ID_INTEL_80310 0x530d #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 diff -Nru a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h --- a/include/linux/pfkeyv2.h Mon May 12 20:55:48 2003 +++ b/include/linux/pfkeyv2.h Mon May 12 20:55:48 2003 @@ -275,8 +275,8 @@ /* Encryption algorithms */ #define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 1 -#define SADB_EALG_3DESCBC 2 +#define SADB_EALG_DESCBC 2 +#define SADB_EALG_3DESCBC 3 #define SADB_X_EALG_CASTCBC 6 #define SADB_X_EALG_BLOWFISHCBC 7 #define SADB_EALG_NULL 11 diff -Nru a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h --- a/include/linux/ppp_defs.h Mon May 12 20:55:45 2003 +++ b/include/linux/ppp_defs.h Mon May 12 20:55:45 2003 @@ -74,12 +74,15 @@ #define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ #define PPP_COMPFRAG 0xfb /* fragment compressed below bundle */ #define PPP_COMP 0xfd /* compressed packet */ +#define PPP_MPLS_UC 0x0281 /* Multi Protocol Label Switching - Unicast */ +#define PPP_MPLS_MC 0x0283 /* Multi Protocol Label Switching - Multicast */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ #define PPP_IPXCP 0x802b /* IPX Control Protocol */ #define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #define PPP_CCPFRAG 0x80fb /* CCP at link level (below MP bundle) */ #define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_MPLSCP 0x80fd /* MPLS Control Protocol */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #define PPP_LQR 0xc025 /* Link Quality Report protocol */ diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h --- a/include/linux/proc_fs.h Mon May 12 20:55:44 2003 +++ b/include/linux/proc_fs.h Mon May 12 20:55:44 2003 @@ -48,7 +48,7 @@ typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data); -typedef int (write_proc_t)(struct file *file, const char *buffer, +typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data); typedef int (get_info_t)(char *, char **, off_t, int); @@ -163,6 +163,15 @@ return create_proc_info_entry(name,mode,proc_net,get_info); } +static inline struct proc_dir_entry *proc_net_fops_create(const char *name, + mode_t mode, struct file_operations *fops) +{ + struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net); + if (res) + res->proc_fops = fops; + return res; +} + static inline void proc_net_remove(const char *name) { remove_proc_entry(name,proc_net); @@ -171,7 +180,7 @@ #else #define proc_root_driver NULL - +#define proc_net_fops_create(name,mode,fops) do {} while(0) static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, get_info_t *get_info) {return NULL;} static inline void proc_net_remove(const char *name) {} diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h --- a/include/linux/ptrace.h Mon May 12 20:55:44 2003 +++ b/include/linux/ptrace.h Mon May 12 20:55:44 2003 @@ -69,8 +69,8 @@ #include /* For unlikely. */ #include /* For struct task_struct. */ -extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); -extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); +extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); +extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_attach(struct task_struct *tsk); extern int ptrace_detach(struct task_struct *, unsigned int); extern void ptrace_disable(struct task_struct *); diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h --- a/include/linux/raid/md.h Mon May 12 20:55:44 2003 +++ b/include/linux/raid/md.h Mon May 12 20:55:44 2003 @@ -61,9 +61,20 @@ #define MD_MINOR_VERSION 90 #define MD_PATCHLEVEL_VERSION 0 -extern inline char * bdev_partition_name (struct block_device *bdev) +/* + * XXX(hch): This function is broken. Someone who understands the md + * code needs to go through all callers, check whether bdev could + * be NULL and replace it with direct calls to bdevmame. + * + * This would also fix the returns buffer on stack issue nicely :) + */ +static inline const char *bdev_partition_name (struct block_device *bdev) { - return partition_name(bdev ? bdev->bd_dev : 0); + char b[BDEVNAME_SIZE]; + + if (!bdev) + return __bdevname(0, b); + return bdevname(bdev, b); } extern int register_md_personality (int p_num, mdk_personality_t *p); extern int unregister_md_personality (int p_num); diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h --- a/include/linux/rtnetlink.h Mon May 12 20:55:48 2003 +++ b/include/linux/rtnetlink.h Mon May 12 20:55:48 2003 @@ -78,7 +78,7 @@ /****************************************************************************** - * Definitions used in routing table administation. + * Definitions used in routing table administration. ****/ struct rtmsg @@ -129,14 +129,14 @@ #define RTPROT_STATIC 4 /* Route installed by administrator */ /* Values of protocol >= RTPROT_STATIC are not interpreted by kernel; - they just passed from user and back as is. + they are just passed from user and back as is. It will be used by hypothetical multiple routing daemons. Note that protocol values should be standardized in order to avoid conflicts. */ #define RTPROT_GATED 8 /* Apparently, GateD */ -#define RTPROT_RA 9 /* RDISC/ND router advertisments */ +#define RTPROT_RA 9 /* RDISC/ND router advertisements */ #define RTPROT_MRT 10 /* Merit MRT */ #define RTPROT_ZEBRA 11 /* Zebra */ #define RTPROT_BIRD 12 /* BIRD */ @@ -201,17 +201,18 @@ RTA_FLOW, RTA_CACHEINFO, RTA_SESSION, + RTA_HOPLIMIT, }; -#define RTA_MAX RTA_SESSION +#define RTA_MAX RTA_HOPLIMIT #define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))) #define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) /* RTM_MULTIPATH --- array of struct rtnexthop. * - * "struct rtnexthop" describres all necessary nexthop information, - * i.e. parameters of path to a destination via this nextop. + * "struct rtnexthop" describes all necessary nexthop information, + * i.e. parameters of path to a destination via this nexthop. * * At the moment it is impossible to set different prefsrc, mtu, window * and rtt for different paths from multipath. @@ -485,7 +486,7 @@ Comments: - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid - - If neiher of these three flags are set; + - If neither of these three flags are set; the interface is NBMA. - IFF_MULTICAST does not mean anything special: diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Mon May 12 20:55:44 2003 +++ b/include/linux/sched.h Mon May 12 20:55:44 2003 @@ -294,6 +294,7 @@ typedef struct prio_array prio_array_t; struct backing_dev_info; +struct reclaim_state; /* POSIX.1b interval timer structure. */ struct k_itimer { @@ -370,8 +371,8 @@ wait_queue_head_t wait_chldexit; /* for wait4() */ struct completion *vfork_done; /* for vfork() */ - int *set_child_tid; /* CLONE_CHILD_SETTID */ - int *clear_child_tid; /* CLONE_CHILD_CLEARTID */ + int __user *set_child_tid; /* CLONE_CHILD_SETTID */ + int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ unsigned long rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; @@ -433,6 +434,10 @@ /* journalling filesystem info */ void *journal_info; + +/* VM state */ + struct reclaim_state *reclaim_state; + struct dentry *proc_dentry; struct backing_dev_info *backing_dev_info; @@ -558,7 +563,7 @@ extern int kill_sl(pid_t, int, int); extern int kill_proc(pid_t, int, int); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); -extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); +extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); /* These can be the second arg to send_sig_info/send_group_sig_info. */ #define SEND_SIG_NOINFO ((struct siginfo *) 0) @@ -631,7 +636,7 @@ extern task_t *child_reaper; extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *); -extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int *, int *); +extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); #ifdef CONFIG_SMP extern void wait_task_inactive(task_t * p); diff -Nru a/include/linux/security.h b/include/linux/security.h --- a/include/linux/security.h Mon May 12 20:55:48 2003 +++ b/include/linux/security.h Mon May 12 20:55:48 2003 @@ -361,6 +361,9 @@ * Check permission before setting the extended attributes * @value identified by @name for @dentry. * Return 0 if permission is granted. + * @inode_post_setxattr: + * Update inode security field after successful setxattr operation. + * @value identified by @name for @dentry. * @inode_getxattr: * Check permission before obtaining the extended attributes * identified by @name for @dentry. @@ -1036,6 +1039,8 @@ void (*inode_delete) (struct inode *inode); int (*inode_setxattr) (struct dentry *dentry, char *name, void *value, size_t size, int flags); + void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value, + size_t size, int flags); int (*inode_getxattr) (struct dentry *dentry, char *name); int (*inode_listxattr) (struct dentry *dentry); int (*inode_removexattr) (struct dentry *dentry, char *name); @@ -1464,6 +1469,12 @@ return security_ops->inode_setxattr (dentry, name, value, size, flags); } +static inline void security_inode_post_setxattr (struct dentry *dentry, char *name, + void *value, size_t size, int flags) +{ + security_ops->inode_post_setxattr (dentry, name, value, size, flags); +} + static inline int security_inode_getxattr (struct dentry *dentry, char *name) { return security_ops->inode_getxattr (dentry, name); @@ -1718,7 +1729,7 @@ } static inline int security_shm_shmat (struct shmid_kernel * shp, - char *shmaddr, int shmflg) + char __user *shmaddr, int shmflg) { return security_ops->shm_shmat(shp, shmaddr, shmflg); } @@ -2063,6 +2074,10 @@ return 0; } +static inline void security_inode_post_setxattr (struct dentry *dentry, char *name, + void *value, size_t size, int flags) +{ } + static inline int security_inode_getxattr (struct dentry *dentry, char *name) { return 0; @@ -2307,7 +2322,7 @@ } static inline int security_shm_shmat (struct shmid_kernel * shp, - char *shmaddr, int shmflg) + char __user *shmaddr, int shmflg) { return 0; } diff -Nru a/include/linux/sem.h b/include/linux/sem.h --- a/include/linux/sem.h Mon May 12 20:55:46 2003 +++ b/include/linux/sem.h Mon May 12 20:55:46 2003 @@ -138,10 +138,10 @@ }; asmlinkage long sys_semget (key_t key, int nsems, int semflg); -asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops); +asmlinkage long sys_semop (int semid, struct sembuf __user *sops, unsigned nsops); asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); -asmlinkage long sys_semtimedop(int semid, struct sembuf *sops, - unsigned nsops, const struct timespec *timeout); +asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, + unsigned nsops, const struct timespec __user *timeout); #endif /* __KERNEL__ */ diff -Nru a/include/linux/seq_file.h b/include/linux/seq_file.h --- a/include/linux/seq_file.h Mon May 12 20:55:49 2003 +++ b/include/linux/seq_file.h Mon May 12 20:55:49 2003 @@ -29,7 +29,7 @@ }; int seq_open(struct file *, struct seq_operations *); -ssize_t seq_read(struct file *, char *, size_t, loff_t *); +ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); loff_t seq_lseek(struct file *, loff_t, int); int seq_release(struct inode *, struct file *); int seq_escape(struct seq_file *, const char *, const char *); @@ -60,5 +60,6 @@ int single_open(struct file *, int (*)(struct seq_file *, void *), void *); int single_release(struct inode *, struct file *); +int seq_release_private(struct inode *, struct file *); #endif #endif diff -Nru a/include/linux/shm.h b/include/linux/shm.h --- a/include/linux/shm.h Mon May 12 20:55:48 2003 +++ b/include/linux/shm.h Mon May 12 20:55:48 2003 @@ -90,10 +90,10 @@ #define SHM_LOCKED 02000 /* segment will not be swapped */ #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ +long sys_shmat (int shmid, char __user *shmaddr, int shmflg, unsigned long *addr); asmlinkage long sys_shmget (key_t key, size_t size, int flag); -asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); -asmlinkage long sys_shmdt (char *shmaddr); -asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +asmlinkage long sys_shmdt (char __user *shmaddr); +asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf); #endif /* __KERNEL__ */ diff -Nru a/include/linux/signal.h b/include/linux/signal.h --- a/include/linux/signal.h Mon May 12 20:55:45 2003 +++ b/include/linux/signal.h Mon May 12 20:55:45 2003 @@ -201,7 +201,7 @@ sig->tail = &sig->head; } -extern long do_sigpending(void *, unsigned long); +extern long do_sigpending(void __user *, unsigned long); extern int sigprocmask(int, sigset_t *, sigset_t *); #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h --- a/include/linux/skbuff.h Mon May 12 20:55:47 2003 +++ b/include/linux/skbuff.h Mon May 12 20:55:47 2003 @@ -792,6 +792,15 @@ return len + skb_headlen(skb); } +static inline void skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) +{ + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + frag->page = page; + frag->page_offset = off; + frag->size = size; + skb_shinfo(skb)->nr_frags = i+1; +} + #define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \ BUG(); } while (0) #define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \ diff -Nru a/include/linux/slab.h b/include/linux/slab.h --- a/include/linux/slab.h Mon May 12 20:55:49 2003 +++ b/include/linux/slab.h Mon May 12 20:55:49 2003 @@ -49,7 +49,6 @@ /* prototypes */ extern void kmem_cache_init(void); -extern void kmem_cache_sizes_init(void); extern kmem_cache_t *kmem_find_general_cachep(size_t, int gfpflags); extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, diff -Nru a/include/linux/socket.h b/include/linux/socket.h --- a/include/linux/socket.h Mon May 12 20:55:48 2003 +++ b/include/linux/socket.h Mon May 12 20:55:48 2003 @@ -9,6 +9,7 @@ #include /* the SIOCxxx I/O controls */ #include /* iovec support */ #include /* pid_t */ +#include /* __user */ typedef unsigned short sa_family_t; @@ -242,8 +243,8 @@ #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ #endif -extern asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags); -extern asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned flags); +extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags); +extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags); @@ -285,8 +286,8 @@ extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode); extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len); extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len); -extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen); -extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr); +extern int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen); +extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr); extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); #endif diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h --- a/include/linux/sunrpc/svc.h Mon May 12 20:55:47 2003 +++ b/include/linux/sunrpc/svc.h Mon May 12 20:55:47 2003 @@ -176,8 +176,10 @@ { if (rqstp->rq_arghi <= rqstp->rq_argused) return -ENOMEM; - rqstp->rq_respages[rqstp->rq_resused++] = - rqstp->rq_argpages[--rqstp->rq_arghi]; + rqstp->rq_arghi--; + rqstp->rq_respages[rqstp->rq_resused] = + rqstp->rq_argpages[rqstp->rq_arghi]; + rqstp->rq_resused++; return 0; } diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h --- a/include/linux/sunrpc/xdr.h Mon May 12 20:55:49 2003 +++ b/include/linux/sunrpc/xdr.h Mon May 12 20:55:49 2003 @@ -157,6 +157,11 @@ extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, skb_reader_t *, skb_read_actor_t); +struct socket; +struct sockaddr; +extern int xdr_sendpages(struct socket *, struct sockaddr *, int, + struct xdr_buf *, unsigned int, int); + /* * Provide some simple tools for XDR buffer overflow-checking etc. */ diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h --- a/include/linux/sunrpc/xprt.h Mon May 12 20:55:48 2003 +++ b/include/linux/sunrpc/xprt.h Mon May 12 20:55:48 2003 @@ -198,7 +198,7 @@ #define XPRT_CONNECT 0 -#define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_connected(xp) (test_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) diff -Nru a/include/linux/swap.h b/include/linux/swap.h --- a/include/linux/swap.h Mon May 12 20:55:44 2003 +++ b/include/linux/swap.h Mon May 12 20:55:44 2003 @@ -66,6 +66,14 @@ unsigned long val; } swp_entry_t; +/* + * current->reclaim_state points to one of these when a task is running + * memory reclaim + */ +struct reclaim_state { + unsigned long reclaimed_slab; +}; + #ifdef __KERNEL__ struct address_space; diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Mon May 12 20:55:47 2003 +++ b/include/linux/sysctl.h Mon May 12 20:55:47 2003 @@ -36,11 +36,11 @@ member of a struct __sysctl_args to have? */ struct __sysctl_args { - int *name; + int __user *name; int nlen; - void *oldval; - size_t *oldlenp; - void *newval; + void __user *oldval; + size_t __user *oldlenp; + void __user *newval; size_t newlen; unsigned long __unused[4]; }; @@ -674,40 +674,40 @@ #ifdef __KERNEL__ -extern asmlinkage long sys_sysctl(struct __sysctl_args *); +extern asmlinkage long sys_sysctl(struct __sysctl_args __user *); extern void sysctl_init(void); typedef struct ctl_table ctl_table; -typedef int ctl_handler (ctl_table *table, int *name, int nlen, +typedef int ctl_handler (ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context); typedef int proc_handler (ctl_table *ctl, int write, struct file * filp, - void *buffer, size_t *lenp); + void __user *buffer, size_t *lenp); extern int proc_dostring(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_dointvec(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_dointvec_bset(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_dointvec_minmax(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_doulongvec_minmax(ctl_table *, int, struct file *, - void *, size_t *); + void __user *, size_t *); extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, - struct file *, void *, size_t *); + struct file *, void __user *, size_t *); -extern int do_sysctl (int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen); +extern int do_sysctl (int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen); extern int do_sysctl_strategy (ctl_table *table, - int *name, int nlen, + int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void ** context); diff -Nru a/include/linux/sysrq.h b/include/linux/sysrq.h --- a/include/linux/sysrq.h Mon May 12 20:55:44 2003 +++ b/include/linux/sysrq.h Mon May 12 20:55:44 2003 @@ -92,21 +92,3 @@ #define unregister_sysrq_key(ig,nore) __reterr() #endif - - -/* Deferred actions */ - -extern int emergency_sync_scheduled; - -#define EMERG_SYNC 1 -#define EMERG_REMOUNT 2 - -void do_emergency_sync(void); - -#ifdef CONFIG_MAGIC_SYSRQ -#define CHECK_EMERGENCY_SYNC \ - if (emergency_sync_scheduled) \ - do_emergency_sync(); -#else -#define CHECK_EMERGENCY_SYNC -#endif diff -Nru a/include/linux/time.h b/include/linux/time.h --- a/include/linux/time.h Mon May 12 20:55:47 2003 +++ b/include/linux/time.h Mon May 12 20:55:47 2003 @@ -204,7 +204,7 @@ extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); extern void clock_was_set(void); // call when ever the clock is set extern long do_nanosleep(struct timespec *t); -extern long do_utimes(char * filename, struct timeval * times); +extern long do_utimes(char __user * filename, struct timeval * times); #endif #define FD_SETSIZE __FD_SETSIZE diff -Nru a/include/linux/tty.h b/include/linux/tty.h --- a/include/linux/tty.h Mon May 12 20:55:46 2003 +++ b/include/linux/tty.h Mon May 12 20:55:46 2003 @@ -243,6 +243,7 @@ #define L_PENDIN(tty) _L_FLAG((tty),PENDIN) #define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) +struct device; /* * Where all of the state associated with a tty is kept while the tty * is open. Since the termios state should be kept even if the tty @@ -380,7 +381,7 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); -extern void tty_register_device(struct tty_driver *driver, unsigned index); +extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Mon May 12 20:55:46 2003 +++ b/include/linux/usb.h Mon May 12 20:55:46 2003 @@ -73,13 +73,22 @@ /** * struct usb_interface - what usb device drivers talk to * @altsetting: array of interface descriptors, one for each alternate - * setting that may be selected. each one includes a set of - * endpoint configurations. + * setting that may be selected. Each one includes a set of + * endpoint configurations and will be in numberic order, + * 0..num_altsetting. * @num_altsetting: number of altsettings defined. * @act_altsetting: index of current altsetting. this number is always * less than num_altsetting. after the device is configured, each * interface uses its default setting of zero. + * @max_altsetting: + * @minor: the minor number assigned to this interface, if this + * interface is bound to a driver that uses the USB major number. + * If this interface does not use the USB major, this field should + * be unused. The driver should set this value in the probe() + * function of the driver, after it has been assigned a minor + * number from the USB core by calling usb_register_dev(). * @dev: driver model's view of this device + * @class_dev: driver model's class view of this device. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -111,10 +120,12 @@ unsigned max_altsetting; /* total memory allocated */ struct usb_driver *driver; /* driver */ - kdev_t kdev; /* node this interface is bound to */ + int minor; /* minor number this interface is bound to */ struct device dev; /* interface specific device info */ + struct class_device class_dev; }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) +#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev) #define interface_to_usbdev(intf) \ container_of(intf->dev.parent, struct usb_device, dev) @@ -279,7 +290,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id); -extern struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev); +extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); @@ -433,6 +444,25 @@ extern struct bus_type usb_bus_type; +/** + * struct usb_class_driver - identifies a USB driver that wants to use the USB major number + * @name: devfs name for this driver. Will also be used by the driver + * class code to create a usb class device. + * @fops: pointer to the struct file_operations of this driver. + * @mode: the mode for the devfs file to be created for this driver. + * @minor_base: the start of the minor range for this driver. + * + * This structure is used for the usb_register_dev() and + * usb_unregister_dev() functions, to consolodate a number of the + * paramaters used for them. + */ +struct usb_class_driver { + char *name; + struct file_operations *fops; + mode_t mode; + int minor_base; +}; + /* * use these in module_init()/module_exit() * and don't forget MODULE_DEVICE_TABLE(usb, ...) @@ -440,8 +470,10 @@ extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); -extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor); -extern void usb_deregister_dev(int num_minors, int start_minor); +extern int usb_register_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver); +extern void usb_deregister_dev(struct usb_interface *intf, + struct usb_class_driver *class_driver); extern int usb_device_probe(struct device *dev); extern int usb_device_remove(struct device *dev); diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/usb_gadget.h Mon May 12 20:55:49 2003 @@ -0,0 +1,696 @@ +/* + * + * + * We call the USB code inside a Linux-based peripheral device a "gadget" + * driver, except for the hardware-specific bus glue. One USB host can + * master many USB gadgets, but the gadgets are only slaved to one host. + * + * + * (c) Copyright 2002-2003 by David Brownell + * All Rights Reserved. + * + * This software is licensed under the GNU GPL version 2. + * + * ALTERNATIVELY, the kernel API documentation which is included in this + * software may also be licenced under the "GNU Free Documentation + * License" (version 1.2 or, at your choice, any later version), when + * used as part of the "USB Gadget API for Linux" documentation. + */ + +#ifndef __LINUX_USB_GADGET_H +#define __LINUX_USB_GADGET_H + +#ifdef __KERNEL__ + +struct usb_ep; + +/** + * struct usb_request - describes one i/o request + * @buf: Buffer used for data. Always provide this; some controllers + * only use PIO, or don't use DMA for some endpoints. + * @dma: DMA address corresponding to 'buf'. If you don't set this + * field, and the usb controller needs one, it is responsible + * for mapping and unmapping the buffer. + * @length: Length of that data + * @no_interrupt: If true, hints that no completion irq is needed. + * Helpful sometimes with deep request queues. + * @zero: If true, when writing data, makes the last packet be "short" + * by adding a zero length packet as needed; + * @short_not_ok: When reading data, makes short packets be + * treated as errors (queue stops advancing till cleanup). + * @complete: Function called when request completes + * @context: For use by the completion callback + * @list: For use by the gadget driver. + * @status: Reports completion code, zero or a negative errno. + * Normally, faults block the transfer queue from advancing until + * the completion callback returns. + * Code "-ESHUTDOWN" indicates completion caused by device disconnect, + * or when the driver disabled the endpoint. + * @actual: Reports actual bytes transferred. For reads (OUT + * transfers) this may be less than the requested length. If the + * short_not_ok flag is set, short reads are treated as errors + * even when status otherwise indicates successful completion. + * Note that for writes (IN transfers) the data bytes may still + * reside in a device-side FIFO. + * + * These are allocated/freed through the endpoint they're used with. The + * hardware's driver can add extra per-request data to the memory it returns, + * which often avoids separate memory allocations (potential failures), + * later when the request is queued. + * + * Request flags affect request handling, such as whether a zero length + * packet is written (the "zero" flag), whether a short read should be + * treated as an error (blocking request queue advance, the "short_not_ok" + * flag), or hinting that an interrupt is not required (the "no_interrupt" + * flag, for use with deep request queues). + * + * Bulk endpoints can use any size buffers, and can also be used for interrupt + * transfers. interrupt-only endpoints can be much less functional. + */ + // NOTE this is analagous to 'struct urb' on the host side, + // except that it's thinner and promotes more pre-allocation. + // + // ISSUE should this be allocated through the device? + +struct usb_request { + void *buf; + unsigned length; + dma_addr_t dma; + + unsigned no_interrupt : 1, + zero : 1, + short_not_ok : 1; + + void (*complete)(struct usb_ep *ep, + struct usb_request *req); + void *context; + struct list_head list; + + int status; + unsigned actual; +}; + +/*-------------------------------------------------------------------------*/ + +/* endpoint-specific parts of the api to the usb controller hardware. + * unlike the urb model, (de)multiplexing layers are not required. + * (so this api could slash overhead if used on the host side...) + * + * note that device side usb controllers commonly differ in how many + * endpoints they support, as well as their capabilities. + */ +struct usb_ep_ops { + int (*enable) (struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc); + int (*disable) (struct usb_ep *ep); + + struct usb_request *(*alloc_request) (struct usb_ep *ep, + int gfp_flags); + void (*free_request) (struct usb_ep *ep, struct usb_request *req); + + void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes, + dma_addr_t *dma, int gfp_flags); + void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, + unsigned bytes); + // NOTE: on 2.5, drivers may also use dma_map() and + // dma_sync_single() to manage dma overhead. + + int (*queue) (struct usb_ep *ep, struct usb_request *req, + int gfp_flags); + int (*dequeue) (struct usb_ep *ep, struct usb_request *req); + + int (*set_halt) (struct usb_ep *ep, int value); + int (*fifo_status) (struct usb_ep *ep); + void (*fifo_flush) (struct usb_ep *ep); +}; + +/** + * struct usb_ep - device side representation of USB endpoint + * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk" + * @ep_list:the gadget's ep_list holds all of its endpoints + * @maxpacket:the maximum packet size used on this endpoint, as + * configured when the endpoint was enabled. + * @driver_data:for use by the gadget driver. all other fields are + * read-only to gadget drivers. + * + * the bus controller driver lists all the general purpose endpoints in + * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list, + * and is accessed only in response to a driver setup() callback. + */ +struct usb_ep { + void *driver_data; + + const char *name; + const struct usb_ep_ops *ops; + struct list_head ep_list; + unsigned maxpacket : 16; +}; + +/*-------------------------------------------------------------------------*/ + +/** + * usb_ep_enable - configure endpoint, making it usable + * @ep:the endpoint being configured. may not be the endpoint named "ep0". + * drivers discover endpoints through the ep_list of a usb_gadget. + * @desc:descriptor for desired behavior. caller guarantees this pointer + * remains valid until the endpoint is disabled; the data byte order + * is little-endian (usb-standard). + * + * when configurations are set, or when interface settings change, the driver + * will enable or disable the relevant endpoints. while it is enabled, an + * endpoint may be used for i/o until the driver receives a disconnect() from + * the host or until the endpoint is disabled. + * + * the ep0 implementation (which calls this routine) must ensure that the + * hardware capabilities of each endpoint match the descriptor provided + * for it. for example, an endpoint named "ep2in-bulk" would be usable + * for interrupt transfers as well as bulk, but it likely couldn't be used + * for iso transfers or for endpoint 14. some endpoints are fully + * configurable, with more generic names like "ep-a". (remember that for + * USB, "in" means "towards the USB master".) + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) +{ + return ep->ops->enable (ep, desc); +} + +/** + * usb_ep_disable - endpoint is no longer usable + * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0". + * + * no other task may be using this endpoint when this is called. + * any pending and uncompleted requests will complete with status + * indicating disconnect (-ESHUTDOWN) before this call returns. + * gadget drivers must call usb_ep_enable() again before queueing + * requests to the endpoint. + * + * returns zero, or a negative error code. + */ +static inline int +usb_ep_disable (struct usb_ep *ep) +{ + return ep->ops->disable (ep); +} + +/** + * usb_ep_alloc_request - allocate a request object to use with this endpoint + * @ep:the endpoint to be used with with the request + * @gfp_flags:GFP_* flags to use + * + * Request objects must be allocated with this call, since they normally + * need controller-specific setup and may even need endpoint-specific + * resources such as allocation of DMA descriptors. + * Requests may be submitted with usb_ep_queue(), and receive a single + * completion callback. Free requests with usb_ep_free_request(), when + * they are no longer needed. + * + * Returns the request, or null if one could not be allocated. + */ +static inline struct usb_request * +usb_ep_alloc_request (struct usb_ep *ep, int gfp_flags) +{ + return ep->ops->alloc_request (ep, gfp_flags); +} + +/** + * usb_ep_free_request - frees a request object + * @ep:the endpoint associated with the request + * @req:the request being freed + * + * Reverses the effect of usb_ep_alloc_request(). + * Caller guarantees the request is not queued, and that it will + * no longer be requeued (or otherwise used). + */ +static inline void +usb_ep_free_request (struct usb_ep *ep, struct usb_request *req) +{ + ep->ops->free_request (ep, req); +} + +/** + * usb_ep_alloc_buffer - allocate an I/O buffer + * @ep:the endpoint associated with the buffer + * @len:length of the desired buffer + * @dma:pointer to the buffer's DMA address; must be valid + * @gfp_flags:GFP_* flags to use + * + * Returns a new buffer, or null if one could not be allocated. + * The buffer is suitably aligned for dma, if that endpoint uses DMA, + * and the caller won't have to care about dma-inconsistency + * or any hidden "bounce buffer" mechanism. No additional per-request + * DMA mapping will be required for such buffers. + * Free it later with usb_ep_free_buffer(). + * + * You don't need to use this call to allocate I/O buffers unless you + * want to make sure drivers don't incur costs for such "bounce buffer" + * copies or per-request DMA mappings. + */ +static inline void * +usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma, + int gfp_flags) +{ + return ep->ops->alloc_buffer (ep, len, dma, gfp_flags); +} + +/** + * usb_ep_free_buffer - frees an i/o buffer + * @ep:the endpoint associated with the buffer + * @buf:CPU view address of the buffer + * @dma:the buffer's DMA address + * @len:length of the buffer + * + * reverses the effect of usb_ep_alloc_buffer(). + * caller guarantees the buffer will no longer be accessed + */ +static inline void +usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len) +{ + ep->ops->free_buffer (ep, buf, dma, len); +} + +/** + * usb_ep_queue - queues (submits) an I/O request to an endpoint. + * @ep:the endpoint associated with the request + * @req:the request being submitted + * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't + * pre-allocate all necessary memory with the request. + * + * This tells the device controller to perform the specified request through + * that endpoint (reading or writing a buffer). When the request completes, + * including being canceled by usb_ep_dequeue(), the request's completion + * routine is called to return the request to the driver. Any endpoint + * (except control endpoints like ep0) may have more than one transfer + * request queued; they complete in FIFO order. Once a gadget driver + * submits a request, that request may not be examined or modified until it + * is given back to that driver through the completion callback. + * + * Each request is turned into one or more packets. The controller driver + * never merges adjacent requests into the same packet. OUT transfers + * will sometimes use data that's already buffered in the hardware. + * + * Bulk endpoints can queue any amount of data; the transfer is packetized + * automatically. The last packet will be short if the request doesn't fill it + * out completely. Zero length packets (ZLPs) should be avoided in portable + * protocols since not all usb hardware can successfully handle zero length + * packets. (ZLPs may be explicitly written, and may be implicitly written if + * the request 'zero' flag is set.) Bulk endpoints may also be used + * for interrupt transfers; but the reverse is not true, and some endpoints + * won't support every interrupt transfer. (Such as 768 byte packets.) + * + * Interrupt-only endpoints are less functional than bulk endpoints, for + * example by not supporting queueing or not handling buffers that are + * larger than the endpoint's maxpacket size. They may also treat data + * toggle differently. + * + * Control endpoints ... after getting a setup() callback, the driver queues + * one response (optional if it would be zero length). That enables the + * status ack, after transfering data as specified in the response. Setup + * functions may return negative error codes to generate protocol stalls. + * + * For periodic endpoints, like interrupt or isochronous ones, the usb host + * arranges to poll once per interval, and the gadget driver usually will + * have queued some data to transfer at that time. + * + * Returns zero, or a negative error code. Endpoints that are not enabled, + * or which are enabled but halted, report errors; errors will also be + * reported when the usb peripheral is disconnected. + */ +static inline int +usb_ep_queue (struct usb_ep *ep, struct usb_request *req, int gfp_flags) +{ + return ep->ops->queue (ep, req, gfp_flags); +} + +/** + * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint + * @ep:the endpoint associated with the request + * @req:the request being canceled + * + * if the request is still active on the endpoint, it is dequeued and its + * completion routine is called (with status -ECONNRESET); else a negative + * error code is returned. + * + * note that some hardware can't clear out write fifos (to unlink the request + * at the head of the queue) except as part of disconnecting from usb. such + * restrictions prevent drivers from supporting configuration changes, + * even to configuration zero (a "chapter 9" requirement). + */ +static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req) +{ + return ep->ops->dequeue (ep, req); +} + +/** + * usb_ep_set_halt - sets the endpoint halt feature. + * @ep: the non-isochronous endpoint being stalled + * + * Use this to stall an endpoint, perhaps as an error report. + * Except for control endpoints, + * the endpoint stays halted (will not stream any data) until the host + * clears this feature; drivers may need to empty the endpoint's request + * queue first, to make sure no inappropriate transfers happen. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + */ +static inline int +usb_ep_set_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 1); +} + +/** + * usb_ep_clear_halt - clears endpoint halt, and resets toggle + * @ep:the bulk or interrupt endpoint being reset + * + * use this when responding to the standard usb "set interface" request, + * for endpoints that aren't reconfigured, after clearing any other state + * in the endpoint's i/o queue. + * + * returns zero, or a negative error code. on success, this call clears + * the underlying hardware state reflecting endpoint halt and data toggle. + */ +static inline int +usb_ep_clear_halt (struct usb_ep *ep) +{ + return ep->ops->set_halt (ep, 0); +} + +/** + * usb_ep_fifo_status - returns number of bytes in fifo, or error + * @ep: the endpoint whose fifo status is being checked. + * + * FIFO endpoints may have "unclaimed data" in them in certain cases, + * such as after aborted transfers. Hosts may not have collected all + * the IN data written by the gadget driver, as reported by a request + * completion. The gadget driver may not have collected all the data + * written OUT to it by the host. Drivers that need precise handling for + * fault reporting or recovery may need to use this call. + * + * This returns the number of such bytes in the fifo, or a negative + * errno if the endpoint doesn't use a FIFO or doesn't support such + * precise handling. + */ +static inline int +usb_ep_fifo_status (struct usb_ep *ep) +{ + if (ep->ops->fifo_status) + return ep->ops->fifo_status (ep); + else + return -EOPNOTSUPP; +} + +/** + * usb_ep_fifo_flush - flushes contents of a fifo + * @ep: the endpoint whose fifo is being flushed. + * + * This call may be used to flush the "unclaimed data" that may exist in + * an endpoint fifo after abnormal transaction terminations. The call + * must never be used except when endpoint is not being used for any + * protocol translation. + */ +static inline void +usb_ep_fifo_flush (struct usb_ep *ep) +{ + if (ep->ops->fifo_flush) + ep->ops->fifo_flush (ep); +} + + +/*-------------------------------------------------------------------------*/ + +struct usb_gadget; + +/* the rest of the api to the controller hardware: device operations, + * which don't involve endpoints (or i/o). + */ +struct usb_gadget_ops { + int (*get_frame)(struct usb_gadget *); + int (*wakeup)(struct usb_gadget *); + int (*set_selfpowered) (struct usb_gadget *, int value); + int (*ioctl)(struct usb_gadget *, + unsigned code, unsigned long param); +}; + +/** + * struct usb_gadget - represents a usb slave device + * @ep0: Endpoint zero, used when reading or writing responses to + * driver setup() requests + * @ep_list: List of other endpoints supported by the device. + * @speed: Speed of current connection to USB host. + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * + * Gadgets have a mostly-portable "gadget driver" implementing device + * functions, handling all usb configurations and interfaces. They + * also have a hardware-specific driver (accessed through ops vectors), + * which insulates the gadget driver from hardware details and packages + * the hardware endpoints through generic i/o queues. + * + * Except for the driver data, all fields in this structure are + * read-only to the gadget driver. That driver data is part of the + * "driver model" infrastructure in 2.5 (and later) kernels, and for + * earlier systems is grouped in a similar structure that's not known + * to the rest of the kernel. + */ +struct usb_gadget { + /* readonly to gadget driver */ + const struct usb_gadget_ops *ops; + struct usb_ep *ep0; + struct list_head ep_list; /* of usb_ep */ + enum usb_device_speed speed; + const char *name; + + /* use this to allocate dma-coherent buffers or set up + * dma mappings. or print diagnostics, etc. + */ + struct device dev; +}; + +static inline void set_gadget_data (struct usb_gadget *gadget, void *data) + { dev_set_drvdata (&gadget->dev, data); } +static inline void *get_gadget_data (struct usb_gadget *gadget) + { return dev_get_drvdata (&gadget->dev); } + +/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */ +#define gadget_for_each_ep(tmp,gadget) \ + list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) + + +/** + * usb_gadget_frame_number - returns the current frame number + * @gadget: controller that reports the frame number + * + * Returns the usb frame number, normally eleven bits from a SOF packet, + * or negative errno if this device doesn't support this capability. + */ +static inline int usb_gadget_frame_number (struct usb_gadget *gadget) +{ + return gadget->ops->get_frame (gadget); +} + +/** + * usb_gadget_wakeup - tries to wake up the host connected to this gadget + * @gadget: controller used to wake up the host + * + * Returns zero on success, else negative error code if the hardware + * doesn't support such attempts, or its support has not been enabled + * by the usb host. Drivers must return device descriptors that report + * their ability to support this, or hosts won't enable it. + */ +static inline int usb_gadget_wakeup (struct usb_gadget *gadget) +{ + if (!gadget->ops->wakeup) + return -EOPNOTSUPP; + return gadget->ops->wakeup (gadget); +} + +/** + * usb_gadget_set_selfpowered - sets the device selfpowered feature. + * @gadget:the device being declared as self-powered + * + * this affects the device status reported by the hardware driver + * to reflect that it now has a local power supply. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_set_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 1); +} + +/** + * usb_gadget_clear_selfpowered - clear the device selfpowered feature. + * @gadget:the device being declared as bus-powered + * + * this affects the device status reported by the hardware driver. + * some hardware may not support bus-powered operation, in which + * case this feature's value can never change. + * + * returns zero on success, else negative errno. + */ +static inline int +usb_gadget_clear_selfpowered (struct usb_gadget *gadget) +{ + if (!gadget->ops->set_selfpowered) + return -EOPNOTSUPP; + return gadget->ops->set_selfpowered (gadget, 0); +} + + +/*-------------------------------------------------------------------------*/ + +/** + * struct usb_gadget_driver - driver for usb 'slave' devices + * @function: String describing the gadget's function + * @speed: Highest speed the driver handles. + * @bind: Invoked when the driver is bound to a gadget, usually + * after registering the driver. + * At that point, ep0 is fully initialized, and ep_list holds + * the currently-available endpoints. + * Called in a context that permits sleeping. + * @setup: Invoked for ep0 control requests that aren't handled by + * the hardware level driver. Most calls must be handled by + * the gadget driver, including descriptor and configuration + * management. The 16 bit members of the setup data are in + * cpu order. Called in_interrupt; this may not sleep. Driver + * queues a response to ep0, or returns negative to stall. + * @disconnect: Invoked after all transfers have been stopped, + * when the host is disconnected. May be called in_interrupt; this + * may not sleep. + * @unbind: Invoked when the driver is unbound from a gadget, + * usually from rmmod (after a disconnect is reported). + * Called in a context that permits sleeping. + * @suspend: Invoked on USB suspend. May be called in_interrupt. + * @resume: Invoked on USB resume. May be called in_interrupt. + * + * Devices are disabled till a gadget driver successfully bind()s, which + * means the driver will handle setup() requests needed to enumerate (and + * meet "chapter 9" requirements) then do some useful work. + * + * Drivers use hardware-specific knowledge to configure the usb hardware. + * endpoint addressing is only one of several hardware characteristics that + * are in descriptors the ep0 implementation returns from setup() calls. + * + * Except for ep0 implementation, most driver code shouldn't need change to + * run on top of different usb controllers. It'll use endpoints set up by + * that ep0 implementation. + * + * The usb controller driver handles a few standard usb requests. Those + * include set_address, and feature flags for devices, interfaces, and + * endpoints (the get_status, set_feature, and clear_feature requests). + * + * Accordingly, the driver's setup() callback must always implement all + * get_descriptor requests, returning at least a device descriptor and + * a configuration descriptor. Drivers must make sure the endpoint + * descriptors match any hardware constraints. Some hardware also constrains + * other descriptors. (The pxa250 allows only configurations 1, 2, or 3). + * + * The driver's setup() callback must also implement set_configuration, + * and should also implement set_interface, get_configuration, and + * get_interface. Setting a configuration (or interface) is where + * endpoints should be activated or (config 0) shut down. + * + * (Note that only the default control endpoint is supported. Neither + * hosts nor devices generally support control traffic except to ep0.) + * + * Most devices will ignore USB suspend/resume operations, and so will + * not provide those callbacks. However, some may need to change modes + * when the host is not longer directing those activities. For example, + * local controls (buttons, dials, etc) may need to be re-enabled since + * the (remote) host can't do that any longer. + */ +struct usb_gadget_driver { + char *function; + enum usb_device_speed speed; + int (*bind)(struct usb_gadget *); + void (*unbind)(struct usb_gadget *); + int (*setup)(struct usb_gadget *, + const struct usb_ctrlrequest *); + void (*disconnect)(struct usb_gadget *); + void (*suspend)(struct usb_gadget *); + void (*resume)(struct usb_gadget *); + + // FIXME support safe rmmod + struct device_driver driver; +}; + + + +/*-------------------------------------------------------------------------*/ + +/* driver modules register and unregister, as usual. + * these calls must be made in a context that can sleep. + * + * these will usually be implemented directly by the hardware-dependent + * usb bus interface driver, which will only support a single driver. + */ + +/** + * usb_gadget_register_driver - register a gadget driver + * @driver:the driver being registered + * + * Call this in your gadget driver's module initialization function, + * to tell the underlying usb controller driver about your driver. + * The driver's bind() function will be called to bind it to a + * gadget. This function must be called in a context that can sleep. + */ +int usb_gadget_register_driver (struct usb_gadget_driver *driver); + +/** + * usb_gadget_unregister_driver - unregister a gadget driver + * @driver:the driver being unregistered + * + * Call this in your gadget driver's module cleanup function, + * to tell the underlying usb controller that your driver is + * going away. If the controller is connected to a USB host, + * it will first disconnect(). The driver is also requested + * to unbind() and clean up any device state, before this procedure + * finally returns. + * This function must be called in a context that can sleep. + */ +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify dealing with string descriptors */ + +/** + * struct usb_string - wraps a C string and its USB id + * @id:the (nonzero) ID for this string + * @s:the string, in ISO-8859/1 characters + * + * If you're using usb_gadget_get_string(), use this to wrap a string + * together with its ID. + */ +struct usb_string { + u8 id; + const char *s; +}; + +/** + * struct usb_gadget_strings - a set of USB strings in a given language + * @language:identifies the strings' language (0x0409 for en-us) + * @strings:array of strings with their ids + * + * If you're using usb_gadget_get_string(), use this to wrap all the + * strings for a given language. + */ +struct usb_gadget_strings { + u16 language; /* 0x0409 for en-us */ + struct usb_string *strings; +}; + +/* put descriptor for string with that id into buf (buflen >= 256) */ +int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); + + +#endif /* __KERNEL__ */ + +#endif /* __LINUX_USB_GADGET_H */ diff -Nru a/include/linux/wireless.h b/include/linux/wireless.h --- a/include/linux/wireless.h Mon May 12 20:55:47 2003 +++ b/include/linux/wireless.h Mon May 12 20:55:47 2003 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 15 12.7.02 + * Version : 16 2.4.03 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. @@ -69,6 +69,8 @@ /***************************** INCLUDES *****************************/ +/* To minimise problems in user space, I might remove those headers + * at some point. Jean II */ #include /* for "caddr_t" et al */ #include /* for "struct sockaddr" et al */ #include /* for IFNAMSIZ and co... */ @@ -80,7 +82,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 15 +#define WIRELESS_EXT 16 /* * Changes : @@ -163,6 +165,16 @@ * - Add IW_TXPOW_RANGE for range of Tx Powers * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points * - Add IW_MODE_MONITOR for passive monitor + * + * V15 to V16 + * ---------- + * - Increase the number of bitrates in iw_range to 32 (for 802.11g) + * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) + * - Reshuffle struct iw_range for increases, add filler + * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses + * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support + * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" + * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index */ /**************************** CONSTANTS ****************************/ @@ -196,9 +208,11 @@ /* SIOCGIWSTATS is strictly used between user space and the kernel, and * is never passed to the driver (i.e. the driver will never see it). */ -/* Mobile IP support (statistics per MAC address) */ +/* Spy support (statistics per MAC address - used for Mobile IP support) */ #define SIOCSIWSPY 0x8B10 /* set spy addresses */ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ +#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ +#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ /* Access Point manipulation */ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ @@ -306,13 +320,13 @@ /* ----------------------- OTHER CONSTANTS ----------------------- */ /* Maximum frequencies in the range struct */ -#define IW_MAX_FREQUENCIES 16 +#define IW_MAX_FREQUENCIES 32 /* Note : if you have something like 80 frequencies, * don't increase this constant and don't fill the frequency list. * The user will be able to set by channel anyway... */ /* Maximum bit rates in the range struct */ -#define IW_MAX_BITRATES 8 +#define IW_MAX_BITRATES 32 /* Maximum tx powers in the range struct */ #define IW_MAX_TXPOWER 8 @@ -320,12 +334,11 @@ * a few of them in the struct iw_range. */ /* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 /* set */ -#define IW_MAX_GET_SPY 64 /* get */ +#define IW_MAX_SPY 8 /* Maximum of address that you may get in the list of access points in range */ -#define IW_MAX_AP 8 +#define IW_MAX_AP 64 /* Maximum size of the ESSID and NICKN strings */ #define IW_ESSID_MAX_SIZE 32 @@ -354,7 +367,8 @@ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ /* Power management flags available (along with the value, if any) */ #define IW_POWER_ON 0x0000 /* No details... */ @@ -482,6 +496,17 @@ __u32 beacon; /* Missed beacons/superframe */ }; +/* + * Quality range (for spy threshold) + */ +struct iw_thrspy +{ + struct sockaddr addr; /* Source address (hw/mac) */ + struct iw_quality qual; /* Quality of the link */ + struct iw_quality low; /* Low threshold */ + struct iw_quality high; /* High threshold */ +}; + /* ------------------------ WIRELESS STATS ------------------------ */ /* * Wireless statistics (used for /proc/net/wireless) @@ -534,7 +559,7 @@ struct iw_quality qual; /* Quality part of statistics */ struct sockaddr ap_addr; /* Access point address */ - struct sockaddr addr; /* Destination address (hw) */ + struct sockaddr addr; /* Destination address (hw/mac) */ struct iw_param param; /* Other small parameters */ struct iw_point data; /* Other large parameters */ @@ -582,17 +607,31 @@ __u32 min_nwid; /* Minimal NWID we are able to set */ __u32 max_nwid; /* Maximal NWID we are able to set */ - /* Frequency */ - __u16 num_channels; /* Number of channels [0; num - 1] */ - __u8 num_frequency; /* Number of entry in the list */ - struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ - /* Note : this frequency list doesn't need to fit channel numbers */ + /* Old Frequency (backward compat - moved lower ) */ + __u16 old_num_channels; + __u8 old_num_frequency; + /* Filler to keep "version" at the same offset */ + __s32 old_freq[6]; /* signal level threshold range */ __s32 sensitivity; /* Quality of link & SNR stuff */ + /* Quality range (link, level, noise) + * If the quality is absolute, it will be in the range [0 ; max_qual], + * if the quality is dBm, it will be in the range [max_qual ; 0]. + * Don't forget that we use 8 bit arithmetics... */ struct iw_quality max_qual; /* Quality of the link */ + /* This should contain the average/typical values of the quality + * indicator. This should be the threshold between a "good" and + * a "bad" link (example : monitor going from green to orange). + * Currently, user space apps like quality monitors don't have any + * way to calibrate the measurement. With this, they can split + * the range between 0 and max_qual in different quality level + * (using a geometric subdivision centered on the average). + * I expect that people doing the user space apps will feedback + * us on which value we need to put in each driver... */ + struct iw_quality avg_qual; /* Quality of the link */ /* Rates */ __u8 num_bitrates; /* Number of entries in the list */ @@ -619,6 +658,8 @@ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ __u8 num_encoding_sizes; /* Number of entry in the list */ __u8 max_encoding_tokens; /* Max number of tokens */ + /* For drivers that need a "login/passwd" form */ + __u8 encoding_login_index; /* token index for login token */ /* Transmit power */ __u16 txpower_capa; /* What options are supported */ @@ -638,18 +679,12 @@ __s32 min_r_time; /* Minimal retry lifetime */ __s32 max_r_time; /* Maximal retry lifetime */ - /* Average quality of link & SNR */ - struct iw_quality avg_qual; /* Quality of the link */ - /* This should contain the average/typical values of the quality - * indicator. This should be the threshold between a "good" and - * a "bad" link (example : monitor going from green to orange). - * Currently, user space apps like quality monitors don't have any - * way to calibrate the measurement. With this, they can split - * the range between 0 and max_qual in different quality level - * (using a geometric subdivision centered on the average). - * I expect that people doing the user space apps will feedback - * us on which value we need to put in each driver... - */ + /* Frequency */ + __u16 num_channels; /* Number of channels [0; num - 1] */ + __u8 num_frequency; /* Number of entry in the list */ + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ + /* Note : this frequency list doesn't need to fit channel numbers, + * because each entry contain its channel index */ }; /* diff -Nru a/include/net/compat.h b/include/net/compat.h --- a/include/net/compat.h Mon May 12 20:55:45 2003 +++ b/include/net/compat.h Mon May 12 20:55:45 2003 @@ -27,7 +27,7 @@ #define compat_msghdr msghdr /* to avoid compiler warnings */ #endif /* defined(CONFIG_COMPAT) */ -extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr *); +extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *); extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int); extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned); extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned); diff -Nru a/include/net/dn_dev.h b/include/net/dn_dev.h --- a/include/net/dn_dev.h Mon May 12 20:55:44 2003 +++ b/include/net/dn_dev.h Mon May 12 20:55:44 2003 @@ -71,7 +71,6 @@ #define DN_DEV_MPOINT 4 int state; /* Initial state */ int forwarding; /* 0=EndNode, 1=L1Router, 2=L2Router */ - unsigned short blksize; /* Block Size */ unsigned long t2; /* Default value of t2 */ unsigned long t3; /* Default value of t3 */ int priority; /* Priority to be a router */ diff -Nru a/include/net/dn_fib.h b/include/net/dn_fib.h --- a/include/net/dn_fib.h Mon May 12 20:55:46 2003 +++ b/include/net/dn_fib.h Mon May 12 20:55:46 2003 @@ -1,6 +1,9 @@ #ifndef _NET_DN_FIB_H #define _NET_DN_FIB_H +/* WARNING: The ordering of these elements must match ordering + * of RTA_* rtnetlink attribute numbers. + */ struct dn_kern_rta { void *rta_dst; @@ -13,8 +16,10 @@ struct rtattr *rta_mx; struct rtattr *rta_mp; unsigned char *rta_protoinfo; - unsigned char *rta_flow; + u32 *rta_flow; struct rta_cacheinfo *rta_ci; + struct rta_session *rta_sess; + u8 *rta_hoplimit; }; struct dn_fib_res { @@ -101,10 +106,6 @@ int (*lookup)(struct dn_fib_table *t, const struct flowi *fl, struct dn_fib_res *res); int (*flush)(struct dn_fib_table *t); -#ifdef CONFIG_PROC_FS - int (*get_info)(struct dn_fib_table *table, char *buf, - int first, int count); -#endif /* CONFIG_PROC_FS */ int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb); unsigned char data[0]; @@ -183,6 +184,9 @@ extern struct dn_fib_table *dn_fib_tables[]; #else /* Endnode */ + +#define dn_fib_init() (0) +#define dn_fib_cleanup() (0) #define dn_fib_lookup(fl, res) (-ESRCH) #define dn_fib_info_put(fi) do { } while(0) diff -Nru a/include/net/dn_route.h b/include/net/dn_route.h --- a/include/net/dn_route.h Mon May 12 20:55:44 2003 +++ b/include/net/dn_route.h Mon May 12 20:55:44 2003 @@ -74,7 +74,7 @@ __u16 rt_saddr; __u16 rt_daddr; __u16 rt_gateway; - __u16 __padding; + __u16 rt_local_src; /* Source used for forwarding packets */ __u16 rt_src_map; __u16 rt_dst_map; diff -Nru a/include/net/ip6_fib.h b/include/net/ip6_fib.h --- a/include/net/ip6_fib.h Mon May 12 20:55:48 2003 +++ b/include/net/ip6_fib.h Mon May 12 20:55:48 2003 @@ -163,10 +163,12 @@ extern int fib6_add(struct fib6_node *root, struct rt6_info *rt, - struct nlmsghdr *nlh); + struct nlmsghdr *nlh, + void *rtattr); extern int fib6_del(struct rt6_info *rt, - struct nlmsghdr *nlh); + struct nlmsghdr *nlh, + void *rtattr); extern void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh); diff -Nru a/include/net/ip6_route.h b/include/net/ip6_route.h --- a/include/net/ip6_route.h Mon May 12 20:55:45 2003 +++ b/include/net/ip6_route.h Mon May 12 20:55:45 2003 @@ -38,9 +38,11 @@ extern int ipv6_route_ioctl(unsigned int cmd, void *arg); extern int ip6_route_add(struct in6_rtmsg *rtmsg, - struct nlmsghdr *); + struct nlmsghdr *, + void *rtattr); extern int ip6_del_rt(struct rt6_info *, - struct nlmsghdr *); + struct nlmsghdr *, + void *rtattr); extern int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev); diff -Nru a/include/net/ip_fib.h b/include/net/ip_fib.h --- a/include/net/ip_fib.h Mon May 12 20:55:48 2003 +++ b/include/net/ip_fib.h Mon May 12 20:55:48 2003 @@ -20,6 +20,9 @@ #include #include +/* WARNING: The ordering of these elements must match ordering + * of RTA_* rtnetlink attribute numbers. + */ struct kern_rta { void *rta_dst; @@ -32,8 +35,10 @@ struct rtattr *rta_mx; struct rtattr *rta_mp; unsigned char *rta_protoinfo; - unsigned char *rta_flow; + u32 *rta_flow; struct rta_cacheinfo *rta_ci; + struct rta_session *rta_sess; + u8 *rta_hoplimit; }; struct fib_nh diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h --- a/include/net/ipv6.h Mon May 12 20:55:48 2003 +++ b/include/net/ipv6.h Mon May 12 20:55:48 2003 @@ -316,6 +316,26 @@ struct ipv6_txoptions *opt, int hlimit, int flags); +extern int ip6_append_data(struct sock *sk, + int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), + void *from, + int length, + int transhdrlen, + int hlimit, + struct ipv6_txoptions *opt, + struct flowi *fl, + struct rt6_info *rt, + unsigned int flags); + +extern int ip6_push_pending_frames(struct sock *sk); + +extern void ip6_flush_pending_frames(struct sock *sk); + +extern int ip6_dst_lookup(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl, + struct in6_addr **saddr); + /* * skb processing functions */ diff -Nru a/include/net/ipx.h b/include/net/ipx.h --- a/include/net/ipx.h Mon May 12 20:55:44 2003 +++ b/include/net/ipx.h Mon May 12 20:55:44 2003 @@ -12,6 +12,7 @@ #include #include #include +#include struct ipx_address { __u32 net; @@ -25,11 +26,11 @@ #define IPX_MAX_PPROP_HOPS 8 struct ipxhdr { - __u16 ipx_checksum __attribute__ ((packed)); + __u16 ipx_checksum __attribute__ ((packed)); #define IPX_NO_CHECKSUM 0xFFFF - __u16 ipx_pktsize __attribute__ ((packed)); - __u8 ipx_tctrl; - __u8 ipx_type; + __u16 ipx_pktsize __attribute__ ((packed)); + __u8 ipx_tctrl; + __u8 ipx_type; #define IPX_TYPE_UNKNOWN 0x00 #define IPX_TYPE_RIP 0x01 /* may also be 0 */ #define IPX_TYPE_SAP 0x04 /* may also be 0 */ @@ -47,42 +48,42 @@ struct ipx_interface { /* IPX address */ - __u32 if_netnum; - unsigned char if_node[IPX_NODE_LEN]; - atomic_t refcnt; + __u32 if_netnum; + unsigned char if_node[IPX_NODE_LEN]; + atomic_t refcnt; /* physical device info */ struct net_device *if_dev; struct datalink_proto *if_dlink; - unsigned short if_dlink_type; + unsigned short if_dlink_type; /* socket support */ - unsigned short if_sknum; - struct sock *if_sklist; - spinlock_t if_sklist_lock; + unsigned short if_sknum; + struct sock *if_sklist; + spinlock_t if_sklist_lock; /* administrative overhead */ - int if_ipx_offset; - unsigned char if_internal; - unsigned char if_primary; + int if_ipx_offset; + unsigned char if_internal; + unsigned char if_primary; - struct ipx_interface *if_next; + struct list_head node; /* node in ipx_interfaces list */ }; struct ipx_route { - __u32 ir_net; + __u32 ir_net; struct ipx_interface *ir_intrfc; - unsigned char ir_routed; - unsigned char ir_router_node[IPX_NODE_LEN]; - struct ipx_route *ir_next; - atomic_t refcnt; + unsigned char ir_routed; + unsigned char ir_router_node[IPX_NODE_LEN]; + struct list_head node; /* node in ipx_routes list */ + atomic_t refcnt; }; #ifdef __KERNEL__ struct ipx_cb { - u8 ipx_tctrl; - u32 ipx_dest_net; - u32 ipx_source_net; + u8 ipx_tctrl; + u32 ipx_dest_net; + u32 ipx_source_net; struct { u32 netnum; int index; @@ -92,14 +93,16 @@ struct ipx_opt { struct ipx_address dest_addr; struct ipx_interface *intrfc; - unsigned short port; + unsigned short port; #ifdef CONFIG_IPX_INTERN - unsigned char node[IPX_NODE_LEN]; + unsigned char node[IPX_NODE_LEN]; #endif - unsigned short type; - /* To handle special ncp connection-handling sockets for mars_nwe, - * the connection number must be stored in the socket. */ - unsigned short ipx_ncp_conn; + unsigned short type; + /* + * To handle special ncp connection-handling sockets for mars_nwe, + * the connection number must be stored in the socket. + */ + unsigned short ipx_ncp_conn; }; #define ipx_sk(__sk) ((struct ipx_opt *)(__sk)->protinfo) @@ -108,10 +111,11 @@ #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 #define IPX_MAX_EPHEMERAL_SOCKET 0x7fff -extern struct ipx_route *ipx_routes; +extern struct list_head ipx_routes; extern rwlock_t ipx_routes_lock; -extern struct ipx_interface *ipx_interfaces; +extern struct list_head ipx_interfaces; +extern struct ipx_interface *ipx_interfaces_head(void); extern spinlock_t ipx_interfaces_lock; extern struct ipx_interface *ipx_primary_net; @@ -121,4 +125,4 @@ extern const char *ipx_frame_name(unsigned short); extern const char *ipx_device_name(struct ipx_interface *intrfc); -#endif /* def _NET_INET_IPX_H_ */ +#endif /* _NET_INET_IPX_H_ */ diff -Nru a/include/net/iw_handler.h b/include/net/iw_handler.h --- a/include/net/iw_handler.h Mon May 12 20:55:44 2003 +++ b/include/net/iw_handler.h Mon May 12 20:55:44 2003 @@ -1,7 +1,7 @@ /* * This file define the new driver API for Wireless Extensions * - * Version : 4 21.6.02 + * Version : 5 4.12.02 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. @@ -206,7 +206,7 @@ * will be needed... * I just plan to increment with each new version. */ -#define IW_HANDLER_VERSION 4 +#define IW_HANDLER_VERSION 5 /* * Changes : @@ -220,10 +220,18 @@ * V3 to V4 * -------- * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + * + * V4 to V5 + * -------- + * - Add new spy support : struct iw_spy_data & prototypes */ /**************************** CONSTANTS ****************************/ +/* Enable enhanced spy support. Disable to reduce footprint */ +#define IW_WIRELESS_SPY +#define IW_WIRELESS_THRSPY + /* Special error message for the driver to indicate that we * should do a commit after return from the iw_handler */ #define EIWCOMMIT EINPROGRESS @@ -315,6 +323,9 @@ * We will automatically export that to user space... */ struct iw_priv_args * private_args; + /* Driver enhanced spy support */ + long spy_offset; /* Spy data offset */ + /* In the long term, get_wireless_stats will move from * 'struct net_device' to here, to minimise bloat. */ }; @@ -350,6 +361,33 @@ /* Need to think of short header translation table. Later. */ +/* --------------------- ENHANCED SPY SUPPORT --------------------- */ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to include this struct in its private part and use the + * standard spy iw_handler. + */ + +/* + * Instance specific spy data, i.e. addresses spied and quality for them. + */ +struct iw_spy_data +{ +#ifdef IW_WIRELESS_SPY + /* --- Standard spy support --- */ + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#ifdef IW_WIRELESS_THRSPY + /* --- Enhanced spy support (event) */ + struct iw_quality spy_thr_low; /* Low threshold */ + struct iw_quality spy_thr_high; /* High threshold */ + u_char spy_thr_under[IW_MAX_SPY]; +#endif /* IW_WIRELESS_THRSPY */ +#endif /* IW_WIRELESS_SPY */ +}; + /**************************** PROTOTYPES ****************************/ /* * Functions part of the Wireless Extensions (defined in net/core/wireless.c). @@ -375,6 +413,31 @@ /* We may need a function to send a stream of events to user space. * More on that later... */ + +/* Standard handler for SIOCSIWSPY */ +extern int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWSPY */ +extern int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCSIWTHRSPY */ +extern int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWTHRSPY */ +extern int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Driver call to update spy records */ +extern void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats); /************************* INLINE FUNTIONS *************************/ /* diff -Nru a/include/net/protocol.h b/include/net/protocol.h --- a/include/net/protocol.h Mon May 12 20:55:46 2003 +++ b/include/net/protocol.h Mon May 12 20:55:46 2003 @@ -80,11 +80,9 @@ extern struct inet_protocol *inet_protocol_base; extern struct inet_protocol *inet_protos[MAX_INET_PROTOS]; -extern struct list_head inetsw[SOCK_MAX]; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; -extern struct list_head inetsw6[SOCK_MAX]; #endif extern int inet_add_protocol(struct inet_protocol *prot, unsigned char num); diff -Nru a/include/net/sctp/command.h b/include/net/sctp/command.h --- a/include/net/sctp/command.h Mon May 12 20:55:49 2003 +++ b/include/net/sctp/command.h Mon May 12 20:55:49 2003 @@ -182,7 +182,7 @@ /* Create a new sctp_command_sequence. * Return NULL if creating a new sequence fails. */ -sctp_cmd_seq_t *sctp_new_cmd_seq(int priority); +sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp); /* Initialize a block of memory as a command sequence. * Return 0 if the initialization fails. diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h --- a/include/net/sctp/constants.h Mon May 12 20:55:45 2003 +++ b/include/net/sctp/constants.h Mon May 12 20:55:45 2003 @@ -6,46 +6,42 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * - * The SCTP reference implementation is free software; + * The SCTP reference implementation 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. * - * the SCTP reference implementation is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * The SCTP reference implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Please send any bug reports or fixes you make to one of the following email - * addresses: - * - * La Monte H.P. Yarroll - * Karl Knutson - * Randall Stewart - * Ken Morneau - * Qiaobing Xie - * Xingang Guo - * Sridhar Samudrala - * Daisy Chang + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * Karl Knutson + * Randall Stewart + * Ken Morneau + * Qiaobing Xie + * Xingang Guo + * Sridhar Samudrala + * Daisy Chang * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. - * - * There are still LOTS of bugs in this code... I always run on the motto - * "it is a wonder any code ever works :)" - * - * */ #ifndef __sctp_constants_h__ @@ -220,7 +216,7 @@ * - A socket in SCTP_SS_LISTENING state indicates that it is willing to * accept new associations, but cannot initiate the creation of new ones. * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single - * association in ESTABLISHED state. + * association. */ typedef enum { SCTP_SS_CLOSED = TCP_CLOSE, @@ -336,9 +332,17 @@ #define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */ -#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash +#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash * functions simpler to write. */ + +#if defined (CONFIG_SCTP_HMAC_MD5) +#define SCTP_COOKIE_HMAC_ALG "md5" +#elif defined (CONFIG_SCTP_HMAC_SHA1) +#define SCTP_COOKIE_HMAC_ALG "sha1" +#else +#define SCTP_COOKIE_HMAC_ALG NULL +#endif /* These return values describe the success or failure of a number of * routines which form the lower interface to SCTP_outqueue. diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h --- a/include/net/sctp/sctp.h Mon May 12 20:55:45 2003 +++ b/include/net/sctp/sctp.h Mon May 12 20:55:45 2003 @@ -125,65 +125,61 @@ extern struct sock *sctp_get_ctl_sock(void); extern int sctp_copy_local_addr_list(struct sctp_protocol *, struct sctp_bind_addr *, - sctp_scope_t, int priority, int flags); + sctp_scope_t, int gfp, int flags); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern int sctp_register_pf(struct sctp_pf *, sa_family_t); /* * sctp/socket.c */ -extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); -extern int sctp_inet_listen(struct socket *sock, int backlog); -extern void sctp_write_space(struct sock *sk); -extern unsigned int sctp_poll(struct file *file, struct socket *sock, +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +int sctp_inet_listen(struct socket *sock, int backlog); +void sctp_write_space(struct sock *sk); +unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); /* * sctp/primitive.c */ -extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg); -extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg); -extern int sctp_primitive_ABORT(sctp_association_t *, void *arg); -extern int sctp_primitive_SEND(sctp_association_t *, void *arg); -extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg); +int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg); +int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); +int sctp_primitive_ABORT(struct sctp_association *, void *arg); +int sctp_primitive_SEND(struct sctp_association *, void *arg); +int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg); /* * sctp/crc32c.c */ -extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count); -extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); -extern __u32 sctp_end_cksum(__u32 cksum); +__u32 sctp_start_cksum(__u8 *ptr, __u16 count); +__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); +__u32 sctp_end_cksum(__u32 cksum); +__u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum); /* * sctp/input.c */ -extern int sctp_rcv(struct sk_buff *skb); -extern void sctp_v4_err(struct sk_buff *skb, u32 info); -extern void sctp_hash_established(sctp_association_t *); -extern void __sctp_hash_established(sctp_association_t *); -extern void sctp_unhash_established(sctp_association_t *); -extern void __sctp_unhash_established(sctp_association_t *); -extern void sctp_hash_endpoint(sctp_endpoint_t *); -extern void __sctp_hash_endpoint(sctp_endpoint_t *); -extern void sctp_unhash_endpoint(sctp_endpoint_t *); -extern void __sctp_unhash_endpoint(sctp_endpoint_t *); -extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *, - const union sctp_addr *, - struct sctp_transport **); -extern struct sock *sctp_err_lookup(int family, struct sk_buff *, - struct sctphdr *, struct sctp_endpoint **, - struct sctp_association **, - struct sctp_transport **); -extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, +int sctp_rcv(struct sk_buff *skb); +void sctp_v4_err(struct sk_buff *skb, u32 info); +void sctp_hash_established(struct sctp_association *); +void __sctp_hash_established(struct sctp_association *); +void sctp_unhash_established(struct sctp_association *); +void __sctp_unhash_established(struct sctp_association *); +void sctp_hash_endpoint(struct sctp_endpoint *); +void __sctp_hash_endpoint(struct sctp_endpoint *); +void sctp_unhash_endpoint(struct sctp_endpoint *); +void __sctp_unhash_endpoint(struct sctp_endpoint *); +struct sctp_association *__sctp_lookup_association( + const union sctp_addr *, + const union sctp_addr *, + struct sctp_transport **); +struct sock *sctp_err_lookup(int family, struct sk_buff *, + struct sctphdr *, struct sctp_endpoint **, + struct sctp_association **, + struct sctp_transport **); +void sctp_err_finish(struct sock *, struct sctp_endpoint *, struct sctp_association *); -extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, - struct sctp_transport *t, __u32 pmtu); -/* - * sctp/hashdriver.c - */ -extern void sctp_hash_digest(const char *secret, const int secret_len, - const char *text, const int text_len, - __u8 *digest); +void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, + struct sctp_transport *t, __u32 pmtu); /* * Section: Macros, externs, and inlines @@ -281,6 +277,7 @@ extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_ssnmap; +extern atomic_t sctp_dbg_objcnt_datamsg; /* Macros to atomically increment/decrement objcnt counters. */ #define SCTP_DBG_OBJCNT_INC(name) \ @@ -296,8 +293,8 @@ #define SCTP_DBG_OBJCNT_ENTRY(name) \ {.label= #name, .counter= &sctp_dbg_objcnt_## name} -extern void sctp_dbg_objcnt_init(void); -extern void sctp_dbg_objcnt_exit(void); +void sctp_dbg_objcnt_init(void); +void sctp_dbg_objcnt_exit(void); #else @@ -310,8 +307,8 @@ #endif /* CONFIG_SCTP_DBG_OBJCOUNT */ #if defined CONFIG_SYSCTL -extern void sctp_sysctl_register(void); -extern void sctp_sysctl_unregister(void); +void sctp_sysctl_register(void); +void sctp_sysctl_unregister(void); #else static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_unregister(void) { return; } @@ -322,9 +319,9 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -extern int sctp_v6_init(void); -extern void sctp_v6_exit(void); -extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +int sctp_v6_init(void); +void sctp_v6_exit(void); +void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); #else /* #ifdef defined(CONFIG_IPV6) */ @@ -334,15 +331,26 @@ #endif /* #if defined(CONFIG_IPV6) */ +/* Some wrappers, in case crypto not available. */ +#if defined (CONFIG_CRYPTO_HMAC) +#define sctp_crypto_alloc_tfm crypto_alloc_tfm +#define sctp_crypto_free_tfm crypto_free_tfm +#define sctp_crypto_hmac crypto_hmac +#else +#define sctp_crypto_alloc_tfm(x...) NULL +#define sctp_crypto_free_tfm(x...) +#define sctp_crypto_hmac(x...) +#endif + + /* Map an association to an assoc_id. */ -static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) +static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc) { return (sctp_assoc_t) asoc; } - /* Look up the association by its id. */ -sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); /* A macro to walk a list of skbs. */ @@ -422,12 +430,16 @@ } /* Break down data chunks at this point. */ -static inline int sctp_frag_point(int pmtu) +static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu) { - pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); - pmtu -= sizeof(struct sctp_sack_chunk); + int frag = pmtu; + frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); + frag -= sizeof(struct sctp_sack_chunk); - return pmtu; + if (sp->user_frag) + frag = min_t(int, frag, sp->user_frag); + + return frag; } /* Walk through a list of TLV parameters. Don't trust the @@ -475,7 +487,7 @@ extern struct proto sctp_prot; extern struct proc_dir_entry *proc_net_sctp; -extern void sctp_put_port(struct sock *sk); +void sctp_put_port(struct sock *sk); /* Static inline functions. */ @@ -501,10 +513,10 @@ /* Perform some sanity checks. */ static inline int sctp_sanity_check(void) { - SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= + SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= sizeof(((struct sk_buff *)0)->cb), "SCTP: ulpevent does not fit in skb!\n", return 0); - + return 1; } @@ -565,5 +577,27 @@ #endif /* CONFIG_IPV6 */ #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) + +/* Is a socket of this style? */ +#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) +int static inline __sctp_style(const struct sock *sk, sctp_socket_type_t style) +{ + return sctp_sk(sk)->type == style; +} + +/* Is the association in this state? */ +#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state)) +int static inline __sctp_state(const struct sctp_association *asoc, + sctp_state_t state) +{ + return asoc->state == state; +} + +/* Is the socket in this state? */ +#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) +int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) +{ + return sk->state == state; +} #endif /* __net_sctp_h__ */ diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h --- a/include/net/sctp/sm.h Mon May 12 20:55:46 2003 +++ b/include/net/sctp/sm.h Mon May 12 20:55:46 2003 @@ -6,10 +6,6 @@ * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * * These are definitions needed by the state machine. * * The SCTP reference implementation is free software; @@ -50,7 +46,6 @@ * be incorporated into the next SCTP release. */ - #include #include #include @@ -81,8 +76,8 @@ int action; } sctp_sm_command_t; -typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *, - const sctp_association_t *, +typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *, + const struct sctp_association *, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *); @@ -209,109 +204,104 @@ void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ -sctp_chunk_t *sctp_make_init(const sctp_association_t *, - const sctp_bind_addr_t *, - int priority, int vparam_len); -sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, - const sctp_chunk_t *, - const int priority, +struct sctp_chunk *sctp_make_init(const struct sctp_association *, + const struct sctp_bind_addr *, + int gfp, int vparam_len); +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *, + const struct sctp_chunk *, + const int gfp, const int unkparam_len); -sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cwr(const sctp_association_t *, +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *, const __u32 lowest_tsn, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_datafrag(sctp_association_t *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data, __u8 flags, __u16 ssn); -sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *, +struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 flags, __u16 ssn); -sctp_chunk_t *sctp_make_data(sctp_association_t *, +struct sctp_chunk *sctp_make_data(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data); -sctp_chunk_t *sctp_make_data_empty(sctp_association_t *, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *, const struct sctp_sndrcvinfo *, int len); -sctp_chunk_t *sctp_make_ecne(const sctp_association_t *, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, const __u32); -sctp_chunk_t *sctp_make_sack(const sctp_association_t *); -sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc); -sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *, - const sctp_chunk_t *); -void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); -sctp_chunk_t *sctp_make_abort(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_sack(const struct sctp_association *); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc); +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, + const struct sctp_chunk *); +void sctp_init_cause(struct sctp_chunk *, __u16 cause, const void *, size_t); +struct sctp_chunk *sctp_make_abort(const struct sctp_association *, + const struct sctp_chunk *, const size_t hint); -sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *, + const struct sctp_chunk *, __u32 tsn); -sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *, + const struct sctp_chunk *, const struct msghdr *); -sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, const struct sctp_transport *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *, + const struct sctp_chunk *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_op_error(const sctp_association_t *, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen); -void sctp_chunk_assign_tsn(sctp_chunk_t *); -void sctp_chunk_assign_ssn(sctp_chunk_t *); -int sctp_datachunks_from_user(sctp_association_t *, - const struct sctp_sndrcvinfo *, - struct msghdr *, int len, - struct sk_buff_head *); - +void sctp_chunk_assign_tsn(struct sctp_chunk *); +void sctp_chunk_assign_ssn(struct sctp_chunk *); /* Prototypes for statetable processing. */ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *, - sctp_association_t *asoc, + struct sctp_endpoint *, + struct sctp_association *asoc, void *event_arg, - int priority); + int gfp); int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *, - sctp_association_t *asoc, + struct sctp_endpoint *, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority); + int gfp); /* 2nd level prototypes */ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *retval, - int priority); + int gfp); -int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *); -void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap); +int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *); +void sctp_do_TSNdup(struct sctp_association *, struct sctp_chunk *, long gap); void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer); -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); +sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *); struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *, const struct sctp_association *, struct sctp_chunk *chunk, @@ -325,21 +315,21 @@ sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *, const struct sctp_chunk *, int *cookie_len, const __u8 *, int addrs_len); -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, - const sctp_association_t *, - sctp_chunk_t *, int priority, int *err, - sctp_chunk_t **err_chk_p); -int sctp_addip_addr_config(sctp_association_t *, sctp_param_t, +struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *, + const struct sctp_association *, + struct sctp_chunk *, int gfp, int *err, + struct sctp_chunk **err_chk_p); +int sctp_addip_addr_config(struct sctp_association *, sctp_param_t, struct sockaddr_storage*, int); -void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk); + struct sctp_chunk *err_chunk); /* 3rd level prototypes */ -__u32 sctp_generate_tag(const sctp_endpoint_t *); -__u32 sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); /* 4th level prototypes */ void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *, @@ -361,7 +351,7 @@ /* Get the size of a DATA chunk payload. */ -static inline __u16 sctp_data_size(sctp_chunk_t *chunk) +static inline __u16 sctp_data_size(struct sctp_chunk *chunk) { __u16 size; @@ -449,8 +439,8 @@ * tag and the T bit is set in the Chunk Flags. */ static inline int -sctp_vtag_verify_either(const sctp_chunk_t *chunk, - const sctp_association_t *asoc) +sctp_vtag_verify_either(const struct sctp_chunk *chunk, + const struct sctp_association *asoc) { /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2 * diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h --- a/include/net/sctp/structs.h Mon May 12 20:55:49 2003 +++ b/include/net/sctp/structs.h Mon May 12 20:55:49 2003 @@ -70,7 +70,6 @@ struct sockaddr sa; }; - /* Forward declarations for data structures. */ struct sctp_protocol; struct sctp_endpoint; @@ -83,14 +82,9 @@ struct sctp_bind_addr; struct sctp_ulpq; struct sctp_opt; -struct sctp_endpoint_common; +struct sctp_ep_common; struct sctp_ssnmap; -typedef struct sctp_endpoint sctp_endpoint_t; -typedef struct sctp_association sctp_association_t; -typedef struct sctp_chunk sctp_chunk_t; -typedef struct sctp_bind_addr sctp_bind_addr_t; -typedef struct sctp_endpoint_common sctp_endpoint_common_t; #include #include @@ -114,7 +108,7 @@ /* Used for hashing all associations. */ typedef struct sctp_hashbucket { rwlock_t lock; - sctp_endpoint_common_t *chain; + struct sctp_ep_common *chain; } sctp_hashbucket_t __attribute__((__aligned__(8))); @@ -235,7 +229,9 @@ int saddr); void (*from_sk) (union sctp_addr *, struct sock *sk); - void (*to_sk) (union sctp_addr *, + void (*to_sk_saddr) (union sctp_addr *, + struct sock *sk); + void (*to_sk_daddr) (union sctp_addr *, struct sock *sk); int (*addr_valid) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *); @@ -243,6 +239,7 @@ int (*is_any) (const union sctp_addr *); int (*available) (const union sctp_addr *); int (*skb_iif) (const struct sk_buff *sk); + int (*is_ce) (const struct sk_buff *sk); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; @@ -283,8 +280,11 @@ /* PF_ family specific functions. */ struct sctp_pf *pf; + /* Access to HMAC transform. */ + struct crypto_tfm *hmac; + /* What is our base endpointer? */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Various Socket Options. */ __u16 default_stream; @@ -293,10 +293,12 @@ struct sctp_rtoinfo rtoinfo; struct sctp_paddrparams paddrparam; struct sctp_event_subscribe subscribe; + int user_frag; __u32 autoclose; __u8 nodelay; __u8 disable_fragments; __u8 pd_mode; + __u8 v4mapped; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; @@ -448,6 +450,37 @@ return stream->ssn[id]++; } +/* Structure to track chunk fragments that have been acked, but peer + * fragments of the same message have not. + */ +struct sctp_datamsg { + /* Chunks waiting to be submitted to lower layer. */ + struct list_head chunks; + /* Chunks that have been transmitted. */ + struct list_head track; + /* Reference counting. */ + atomic_t refcnt; + /* When is this message no longer interesting to the peer? */ + unsigned long expires_at; + /* Did the messenge fail to send? */ + int send_error; + char send_failed; + /* Control whether fragments from this message can expire. */ + char can_expire; +}; + +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, + struct sctp_sndrcvinfo *, + struct msghdr *, int len); +struct sctp_datamsg *sctp_datamsg_new(int gfp); +void sctp_datamsg_put(struct sctp_datamsg *); +void sctp_datamsg_hold(struct sctp_datamsg *); +void sctp_datamsg_free(struct sctp_datamsg *); +void sctp_datamsg_track(struct sctp_chunk *); +void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *); +void sctp_datamsg_fail(struct sctp_chunk *, int error); +int sctp_datamsg_expires(struct sctp_chunk *); + /* RFC2960 1.4 Key Terms * @@ -462,9 +495,10 @@ * three elements of struct sk_buff. This allows us to reuse * all the skb_* queue management functions. */ - sctp_chunk_t *next; - sctp_chunk_t *prev; + struct sctp_chunk *next; + struct sctp_chunk *prev; struct sk_buff_head *list; + atomic_t refcnt; /* This is our link to the per-transport transmitted list. */ struct list_head transmitted_list; @@ -514,43 +548,52 @@ struct sctp_association *asoc; /* What endpoint received this chunk? */ - sctp_endpoint_common_t *rcvr; + struct sctp_ep_common *rcvr; /* We fill this in if we are calculating RTT. */ unsigned long sent_at; - __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ - __u8 num_times_sent; /* How man times did we send this? */ - __u8 has_tsn; /* Does this chunk have a TSN yet? */ - __u8 has_ssn; /* Does this chunk have a SSN yet? */ - __u8 singleton; /* Was this the only chunk in the packet? */ - __u8 end_of_packet; /* Was this the last chunk in the packet? */ - __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ - __u8 pdiscard; /* Discard the whole packet now? */ - __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ - __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ - __u8 tsn_missing_report; /* Data chunk missing counter. */ - /* What is the origin IP address for this chunk? */ union sctp_addr source; /* Destination address for this chunk. */ union sctp_addr dest; + /* For outbound message, track all fragments for SEND_FAILED. */ + struct sctp_datamsg *msg; + /* For an inbound chunk, this tells us where it came from. * For an outbound chunk, it tells us where we'd like it to * go. It is NULL if we have no preference. */ struct sctp_transport *transport; + + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ + __u8 resent; /* Has this chunk ever been retransmitted. */ + __u8 has_tsn; /* Does this chunk have a TSN yet? */ + __u8 has_ssn; /* Does this chunk have a SSN yet? */ + __u8 singleton; /* Was this the only chunk in the packet? */ + __u8 end_of_packet; /* Was this the last chunk in the packet? */ + __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ + __u8 pdiscard; /* Discard the whole packet now? */ + __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __u8 tsn_missing_report; /* Data chunk missing counter. */ }; -sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type, - __u8 flags, int size); -void sctp_free_chunk(sctp_chunk_t *); -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); -sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *, - struct sock *); -void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *); -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); +void sctp_chunk_hold(struct sctp_chunk *); +void sctp_chunk_put(struct sctp_chunk *); +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data); +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type, + __u8 flags, int size); +void sctp_chunk_free(struct sctp_chunk *); +void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); +struct sctp_chunk *sctp_chunkify(struct sk_buff *, + const struct sctp_association *, + struct sock *); +void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, + union sctp_addr *); +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ /* sin_family -- AF_INET or AF_INET6 @@ -562,7 +605,7 @@ union sctp_addr a; }; -typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *); +typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); /* This structure holds lists of chunks as we are assembling for * transmission. @@ -619,7 +662,7 @@ int ecn_capable, sctp_packet_phandler_t *get_prepend_chunk); typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, - sctp_chunk_t *); + struct sctp_chunk *); typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); sctp_outq_ohandler_init_t sctp_packet_init; @@ -697,7 +740,6 @@ */ int rto_pending; - /* * These are the congestion stats. */ @@ -771,9 +813,6 @@ */ int max_retrans; - /* We use this name for debugging output... */ - char *debug_name; - /* Per : A timer used by each destination. * Destination : * Timer : @@ -799,6 +838,35 @@ struct list_head send_ready; int malloced; /* Is this structure kfree()able? */ + + /* State information saved for SFR_CACC algorithm. The key + * idea in SFR_CACC is to maintain state at the sender on a + * per-destination basis when a changeover happens. + * char changeover_active; + * char cycling_changeover; + * __u32 next_tsn_at_change; + * char cacc_saw_newack; + */ + struct { + /* An unsigned integer, which stores the next TSN to be + * used by the sender, at the moment of changeover. + */ + __u32 next_tsn_at_change; + + /* A flag which indicates the occurrence of a changeover */ + char changeover_active; + + /* A glag which indicates whether the change of primary is + * the first switch to this destination address during an + * active switch. + */ + char cycling_changeover; + + /* A temporary flag, which is used during the processing of + * a SACK to estimate the causative TSN(s)'s group. + */ + char cacc_saw_newack; + } cacc; }; struct sctp_transport *sctp_transport_new(const union sctp_addr *, int); @@ -831,7 +899,7 @@ /* This is the packet which is currently off the in queue and is * being worked on through the inbound chunk processing. */ - sctp_chunk_t *in_progress; + struct sctp_chunk *in_progress; /* This is the delayed task to finish delivering inbound * messages. @@ -844,7 +912,7 @@ struct sctp_inq *sctp_inq_new(void); void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); -void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet); +void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); @@ -904,18 +972,21 @@ /* How many unackd bytes do we have in-flight? */ __u32 outstanding_bytes; + /* Corked? */ + char cork; + /* Is this structure empty? */ - int empty; + char empty; /* Are we kfree()able? */ - int malloced; + char malloced; }; struct sctp_outq *sctp_outq_new(struct sctp_association *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_free(struct sctp_outq*); -int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk); +int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); int sctp_outq_flush(struct sctp_outq *, int); int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *); int sctp_outq_is_empty(const struct sctp_outq *); @@ -926,10 +997,16 @@ sctp_outq_ohandler_t build, sctp_outq_ohandler_force_t force); void sctp_outq_restart(struct sctp_outq *); + void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, sctp_retransmit_reason_t); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); - +int sctp_outq_uncork(struct sctp_outq *); +/* Uncork and flush an outqueue. */ +static inline void sctp_outq_cork(struct sctp_outq *q) +{ + q->cork = 1; +} /* These bind address data fields common between endpoints and associations */ struct sctp_bind_addr { @@ -952,15 +1029,16 @@ int malloced; /* Are we kfree()able? */ }; -sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); -void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); -void sctp_bind_addr_free(sctp_bind_addr_t *); -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask); +void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); +void sctp_bind_addr_free(struct sctp_bind_addr *); +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp,int flags); -int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, +int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, int gfp); -int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); -int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *, +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); +int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_opt *); union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp); @@ -973,7 +1051,7 @@ int sctp_addr_is_valid(const union sctp_addr *addr); -/* What type of sctp_endpoint_common? */ +/* What type of endpoint? */ typedef enum { SCTP_EP_TYPE_SOCKET, SCTP_EP_TYPE_ASSOCIATION, @@ -995,10 +1073,10 @@ * */ -struct sctp_endpoint_common { +struct sctp_ep_common { /* Fields to help us manage our entries in the hash tables. */ - sctp_endpoint_common_t *next; - sctp_endpoint_common_t **pprev; + struct sctp_ep_common *next; + struct sctp_ep_common **pprev; int hashent; /* Runtime type information. What kind of endpoint is this? */ @@ -1024,7 +1102,7 @@ * bind_addr.port is our shared port number. * bind_addr.address_list is our set of local IP addresses. */ - sctp_bind_addr_t bind_addr; + struct sctp_bind_addr bind_addr; /* Protection during address list comparisons. */ rwlock_t addr_lock; @@ -1052,12 +1130,7 @@ struct sctp_endpoint { /* Common substructure for endpoint and association. */ - sctp_endpoint_common_t base; - - /* These are the system-wide defaults and other stuff which is - * endpoint-independent. - */ - struct sctp_protocol *proto; + struct sctp_ep_common base; /* Associations: A list of current associations and mappings * to the data consumers for each association. This @@ -1092,28 +1165,29 @@ }; /* Recover the outter endpoint structure. */ -static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) +static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; - ep = container_of(base, sctp_endpoint_t, base); + ep = container_of(base, struct sctp_endpoint, base); return ep; } /* These are function signatures for manipulating endpoints. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int); -sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *, - struct sctp_protocol *, - struct sock *, int gfp); -void sctp_endpoint_free(sctp_endpoint_t *); -void sctp_endpoint_put(sctp_endpoint_t *); -void sctp_endpoint_hold(sctp_endpoint_t *); -void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc); -struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, - const union sctp_addr *paddr, - struct sctp_transport **); -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, +struct sctp_endpoint *sctp_endpoint_new(struct sock *, int); +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *, + struct sock *, int gfp); +void sctp_endpoint_free(struct sctp_endpoint *); +void sctp_endpoint_put(struct sctp_endpoint *); +void sctp_endpoint_hold(struct sctp_endpoint *); +void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *); +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, + const union sctp_addr *paddr, + struct sctp_transport **); +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *, + const union sctp_addr *); +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *, const union sctp_addr *); int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr); @@ -1126,8 +1200,8 @@ sctp_init_chunk_t *init, int gfp); int sctp_process_param(struct sctp_association *, union sctp_params param, const union sctp_addr *from, int gfp); -__u32 sctp_generate_tag(const sctp_endpoint_t *); -__u32 sctp_generate_tsn(const sctp_endpoint_t *); +__u32 sctp_generate_tag(const struct sctp_endpoint *); +__u32 sctp_generate_tsn(const struct sctp_endpoint *); /* RFC2960 @@ -1150,7 +1224,7 @@ * In this context, it represents the associations's view * of the local endpoint of the association. */ - sctp_endpoint_common_t base; + struct sctp_ep_common base; /* Associations on the same socket. */ struct list_head asocs; @@ -1162,7 +1236,7 @@ __u32 eyecatcher; /* This is our parent endpoint. */ - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* These are those association elements needed in the cookie. */ sctp_cookie_t c; @@ -1337,7 +1411,6 @@ /* The largest timeout or RTO value to use in attempting an INIT */ __u16 max_init_timeo; - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; @@ -1438,9 +1511,6 @@ */ struct sctp_ulpq ulpq; - /* Need to send an ECNE Chunk? */ - int need_ecne; - /* Last TSN that caused an ECNE Chunk to be sent. */ __u32 last_ecne_tsn; @@ -1453,9 +1523,6 @@ /* Number of seconds of idle time before an association is closed. */ __u32 autoclose; - /* Name for debugging output... */ - char *debug_name; - /* These are to support * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses * and Enforcement of Flow and Message Limits" @@ -1463,8 +1530,7 @@ * or "ADDIP" for short. */ - /* Is the ADDIP extension enabled for this association? */ - int addip_enable; + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks * @@ -1480,7 +1546,7 @@ * [This is our one-and-only-one ASCONF in flight. If we do * not have an ASCONF in flight, this is NULL.] */ - sctp_chunk_t *addip_last_asconf; + struct sctp_chunk *addip_last_asconf; /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. * @@ -1495,7 +1561,7 @@ * [This is our saved ASCONF-ACK. We invalidate it when a new * ASCONF serial number arrives.] */ - sctp_chunk_t *addip_last_asconf_ack; + struct sctp_chunk *addip_last_asconf_ack; /* These ASCONF chunks are waiting to be sent. * @@ -1548,6 +1614,15 @@ * after reaching 4294967295. */ __u32 addip_serial; + + /* Is the ADDIP extension enabled for this association? */ + char addip_enable; + + /* Need to send an ECNE Chunk? */ + char need_ecne; + + /* Is it a temporary association? */ + char temp; }; @@ -1559,7 +1634,7 @@ }; /* Recover the outter association structure. */ -static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base) +static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base) { struct sctp_association *asoc; @@ -1571,10 +1646,10 @@ struct sctp_association * -sctp_association_new(const sctp_endpoint_t *, const struct sock *, +sctp_association_new(const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); struct sctp_association * -sctp_association_init(struct sctp_association *, const sctp_endpoint_t *, +sctp_association_init(struct sctp_association *, const struct sctp_endpoint *, const struct sock *, sctp_scope_t scope, int gfp); void sctp_association_free(struct sctp_association *); @@ -1614,8 +1689,8 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1, const union sctp_addr *ss2); -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc); -sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc); +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc); /* A convenience structure to parse out SCTP specific CMSGs. */ typedef struct sctp_cmsgs { diff -Nru a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h --- a/include/net/sctp/tsnmap.h Mon May 12 20:55:47 2003 +++ b/include/net/sctp/tsnmap.h Mon May 12 20:55:47 2003 @@ -114,7 +114,7 @@ }; /* Create a new tsnmap. */ -struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority); +struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp); /* Dispose of a tsnmap. */ void sctp_tsnmap_free(struct sctp_tsnmap *); diff -Nru a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h --- a/include/net/sctp/ulpevent.h Mon May 12 20:55:44 2003 +++ b/include/net/sctp/ulpevent.h Mon May 12 20:55:44 2003 @@ -10,13 +10,15 @@ * sctp_ulpevent type is used to carry information from the state machine * upwards to the ULP. * - * The SCTP reference implementation is free software; + * This file is part of the SCTP kernel reference Implementation + * + * The SCTP reference implementation 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. * - * the SCTP reference implementation is distributed in the hope that it + * The SCTP reference implementation 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. @@ -27,12 +29,17 @@ * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Please send any bug reports or fixes you make to one of the - * following email addresses: + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp * - * Jon Grimm - * La Monte H.P. Yarroll - * Karl Knutson + * Written or modified by: + * Jon Grimm + * La Monte H.P. Yarroll + * Karl Knutson * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -64,7 +71,7 @@ return (struct sctp_ulpevent *)skb->cb; } -struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority); +struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); @@ -76,7 +83,7 @@ __u16 error, __u16 outbound, __u16 inbound, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( const struct sctp_association *asoc, @@ -84,32 +91,32 @@ int flags, int state, int error, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_remote_error( const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_send_failed( const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, __u32 error, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( const struct sctp_association *asoc, __u16 flags, - int priority); + int gfp); struct sctp_ulpevent *sctp_ulpevent_make_pdapi( const struct sctp_association *asoc, - __u32 indication, int priority); + __u32 indication, int gfp); struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, struct sctp_chunk *chunk, - int priority); + int gfp); void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, struct msghdr *); diff -Nru a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h --- a/include/net/sctp/ulpqueue.h Mon May 12 20:55:45 2003 +++ b/include/net/sctp/ulpqueue.h Mon May 12 20:55:45 2003 @@ -50,14 +50,15 @@ struct sctp_ulpq { char malloced; char pd_mode; - sctp_association_t *asoc; + struct sctp_association *asoc; struct sk_buff_head reasm; struct sk_buff_head lobby; }; /* Prototypes. */ -struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority); -struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *); +struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp); +struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, + struct sctp_association *); void sctp_ulpq_free(struct sctp_ulpq *); /* Add a new DATA chunk for processing. */ diff -Nru a/include/net/sctp/user.h b/include/net/sctp/user.h --- a/include/net/sctp/user.h Mon May 12 20:55:44 2003 +++ b/include/net/sctp/user.h Mon May 12 20:55:44 2003 @@ -110,6 +110,10 @@ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS SCTP_NODELAY, /* Get/set nodelay option. */ #define SCTP_NODELAY SCTP_NODELAY + SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ +#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG, /* Get/set maximum fragment. */ +#define SCTP_MAXSEG SCTP_MAXSEG }; diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h --- a/include/net/xfrm.h Mon May 12 20:55:48 2003 +++ b/include/net/xfrm.h Mon May 12 20:55:48 2003 @@ -123,6 +123,12 @@ /* Data for encapsulator */ struct xfrm_encap_tmpl *encap; + /* IPComp needs an IPIP tunnel for handling uncompressed packets */ + struct xfrm_state *tunnel; + + /* If a tunnel, number of users + 1 */ + atomic_t tunnel_users; + /* State for replay detection */ struct xfrm_replay_state replay; @@ -196,6 +202,8 @@ extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); +extern void xfrm_state_delete_tunnel(struct xfrm_state *x); + struct xfrm_decap_state; struct xfrm_type { @@ -336,7 +344,7 @@ static inline void xfrm_pol_hold(struct xfrm_policy *policy) { - if (policy) + if (likely(policy != NULL)) atomic_inc(&policy->refcnt); } @@ -697,6 +705,11 @@ return __xfrm6_state_addr_check(x, daddr, saddr); } return 0; +} + +static inline int xfrm_state_kern(struct xfrm_state *x) +{ + return atomic_read(&x->tunnel_users); } /* diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Mon May 12 20:55:45 2003 +++ b/init/main.c Mon May 12 20:55:45 2003 @@ -417,7 +417,6 @@ */ console_init(); profile_init(); - kmem_cache_init(); local_irq_enable(); calibrate_delay(); #ifdef CONFIG_BLK_DEV_INITRD @@ -430,7 +429,7 @@ #endif page_address_init(); mem_init(); - kmem_cache_sizes_init(); + kmem_cache_init(); pidmap_init(); pgtable_cache_init(); pte_chain_init(); diff -Nru a/ipc/shm.c b/ipc/shm.c --- a/ipc/shm.c Mon May 12 20:55:46 2003 +++ b/ipc/shm.c Mon May 12 20:55:46 2003 @@ -149,7 +149,7 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma) { - UPDATE_ATIME(file->f_dentry->d_inode); + update_atime(file->f_dentry->d_inode); vma->vm_ops = &shm_vm_ops; shm_inc(file->f_dentry->d_inode->i_ino); return 0; @@ -270,7 +270,7 @@ return err; } -static inline unsigned long copy_shmid_to_user(void *buf, struct shmid64_ds *in, int version) +static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) { switch(version) { case IPC_64: @@ -301,7 +301,7 @@ mode_t mode; }; -static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void *buf, int version) +static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version) { switch(version) { case IPC_64: @@ -335,7 +335,7 @@ } } -static inline unsigned long copy_shminfo_to_user(void *buf, struct shminfo64 *in, int version) +static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version) { switch(version) { case IPC_64: @@ -393,7 +393,7 @@ } } -asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) +asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) { struct shm_setbuf setbuf; struct shmid_kernel *shp; @@ -580,7 +580,7 @@ case IPC_SET: { - if(copy_shmid_from_user (&setbuf, buf, version)) { + if (copy_shmid_from_user (&setbuf, buf, version)) { err = -EFAULT; goto out; } @@ -630,8 +630,12 @@ /* * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. + * + * NOTE! Despite the name, this is NOT a direct system call entrypoint. The + * "raddr" thing points to kernel space, and there has to be a wrapper around + * this. */ -asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) +long sys_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) { struct shmid_kernel *shp; unsigned long addr; @@ -745,7 +749,7 @@ * detach and kill segment if marked destroyed. * The work is done in shm_close. */ -asmlinkage long sys_shmdt(char *shmaddr) +asmlinkage long sys_shmdt(char __user *shmaddr) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *next; diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c --- a/kernel/cpufreq.c Mon May 12 20:55:45 2003 +++ b/kernel/cpufreq.c Mon May 12 20:55:45 2003 @@ -22,6 +22,7 @@ #include #include #include +#include /** * The "cpufreq driver" - the arch- or hardware-dependend low @@ -115,6 +116,7 @@ extern struct device_class cpu_devclass; static struct class_interface cpufreq_interface = { + .class = &cpu_class, .add = &cpufreq_add_dev, .remove = &cpufreq_remove_dev, }; diff -Nru a/kernel/exit.c b/kernel/exit.c --- a/kernel/exit.c Mon May 12 20:55:48 2003 +++ b/kernel/exit.c Mon May 12 20:55:48 2003 @@ -756,7 +756,7 @@ struct pid_link *link = p->pids + PIDTYPE_TGID; struct list_head *tmp, *head = &link->pidptr->task_list; -#if CONFIG_SMP +#ifdef CONFIG_SMP if (!p->sighand) BUG(); if (!spin_is_locked(&p->sighand->siglock) && diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Mon May 12 20:55:44 2003 +++ b/kernel/fork.c Mon May 12 20:55:44 2003 @@ -450,7 +450,7 @@ complete(vfork_done); } if (tsk->clear_child_tid && atomic_read(&mm->mm_users) > 1) { - u32 * tidptr = tsk->clear_child_tid; + u32 __user * tidptr = tsk->clear_child_tid; tsk->clear_child_tid = NULL; /* @@ -738,7 +738,7 @@ p->flags = new_flags; } -asmlinkage long sys_set_tid_address(int *tidptr) +asmlinkage long sys_set_tid_address(int __user *tidptr) { current->clear_child_tid = tidptr; @@ -757,8 +757,8 @@ unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, - int *parent_tidptr, - int *child_tidptr) + int __user *parent_tidptr, + int __user *child_tidptr) { int retval; struct task_struct *p = NULL; @@ -1073,8 +1073,8 @@ unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, - int *parent_tidptr, - int *child_tidptr) + int __user *parent_tidptr, + int __user *child_tidptr) { struct task_struct *p; int trace = 0; diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Mon May 12 20:55:44 2003 +++ b/kernel/ksyms.c Mon May 12 20:55:44 2003 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -429,17 +428,6 @@ #endif EXPORT_SYMBOL(mod_timer); -#ifdef CONFIG_SMP - -/* Big-Reader lock implementation */ -EXPORT_SYMBOL(__brlock_array); -#ifndef __BRLOCK_USE_ATOMICS -EXPORT_SYMBOL(__br_write_locks); -#endif -EXPORT_SYMBOL(__br_write_lock); -EXPORT_SYMBOL(__br_write_unlock); -#endif - #ifdef HAVE_DISABLE_HLT EXPORT_SYMBOL(disable_hlt); EXPORT_SYMBOL(enable_hlt); @@ -459,7 +447,7 @@ EXPORT_SYMBOL(complete_and_exit); EXPORT_SYMBOL(default_wake_function); EXPORT_SYMBOL(__wake_up); -#if CONFIG_SMP +#ifdef CONFIG_SMP EXPORT_SYMBOL_GPL(__wake_up_sync); /* internal use only */ #endif EXPORT_SYMBOL(wake_up_process); @@ -477,10 +465,10 @@ EXPORT_SYMBOL(set_user_nice); EXPORT_SYMBOL(task_nice); EXPORT_SYMBOL_GPL(idle_cpu); -#if CONFIG_SMP +#ifdef CONFIG_SMP EXPORT_SYMBOL_GPL(set_cpus_allowed); #endif -#if CONFIG_SMP || CONFIG_PREEMPT +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) EXPORT_SYMBOL(kernel_flag); #endif EXPORT_SYMBOL(jiffies); @@ -540,6 +528,7 @@ EXPORT_SYMBOL(seq_lseek); EXPORT_SYMBOL(single_open); EXPORT_SYMBOL(single_release); +EXPORT_SYMBOL(seq_release_private); /* Program loader interfaces */ #ifdef CONFIG_MMU @@ -578,8 +567,6 @@ /* all busmice */ EXPORT_SYMBOL(fasync_helper); EXPORT_SYMBOL(kill_fasync); - -EXPORT_SYMBOL(partition_name); /* binfmt_aout */ EXPORT_SYMBOL(get_write_access); diff -Nru a/kernel/panic.c b/kernel/panic.c --- a/kernel/panic.c Mon May 12 20:55:49 2003 +++ b/kernel/panic.c Mon May 12 20:55:49 2003 @@ -96,9 +96,8 @@ disabled_wait(caller); #endif local_irq_enable(); - for(;;) { - CHECK_EMERGENCY_SYNC - } + for (;;) + ; } /** @@ -111,7 +110,7 @@ * The string is overwritten by the next call to print_taint(). */ -const char *print_tainted() +const char *print_tainted(void) { static char buf[20]; if (tainted) { diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Mon May 12 20:55:48 2003 +++ b/kernel/sched.c Mon May 12 20:55:48 2003 @@ -863,7 +863,7 @@ #endif /* CONFIG_NUMA */ -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * double_lock_balance - lock the busiest runqueue @@ -1309,7 +1309,7 @@ } pick_next_task: if (unlikely(!rq->nr_running)) { -#if CONFIG_SMP +#ifdef CONFIG_SMP load_balance(rq, 1, cpu_to_node_mask(smp_processor_id())); if (rq->nr_running) goto pick_next_task; @@ -1440,7 +1440,7 @@ __wake_up_common(q, mode, 1, 0); } -#if CONFIG_SMP +#ifdef CONFIG_SMP /** * __wake_up - sync- wake up threads blocked on a waitqueue. @@ -2261,7 +2261,7 @@ #endif } -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * This is how migration works: * @@ -2443,7 +2443,7 @@ #endif -#if CONFIG_SMP || CONFIG_PREEMPT +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) /* * The 'big kernel lock' * diff -Nru a/kernel/signal.c b/kernel/signal.c --- a/kernel/signal.c Mon May 12 20:55:46 2003 +++ b/kernel/signal.c Mon May 12 20:55:46 2003 @@ -761,7 +761,7 @@ if (!irqs_disabled()) BUG(); -#if CONFIG_SMP +#ifdef CONFIG_SMP if (!spin_is_locked(&t->sighand->siglock)) BUG(); #endif @@ -846,7 +846,7 @@ unsigned int mask; int ret = 0; -#if CONFIG_SMP +#ifdef CONFIG_SMP if (!spin_is_locked(&p->sighand->siglock)) BUG(); #endif @@ -1146,6 +1146,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p) { int ret; + unsigned long flags; /* * We need the tasklist lock even for the specific @@ -1154,9 +1155,9 @@ * going away or changing from under us. */ read_lock(&tasklist_lock); - spin_lock_irq(&p->sighand->siglock); + spin_lock_irqsave(&p->sighand->siglock, flags); ret = specific_send_sig_info(sig, info, p); - spin_unlock_irq(&p->sighand->siglock); + spin_unlock_irqrestore(&p->sighand->siglock, flags); read_unlock(&tasklist_lock); return ret; } diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c --- a/kernel/sysctl.c Mon May 12 20:55:44 2003 +++ b/kernel/sysctl.c Mon May 12 20:55:44 2003 @@ -103,10 +103,10 @@ extern int acct_parm[]; #endif -static int parse_table(int *, int, void *, size_t *, void *, size_t, +static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t, ctl_table *, void **); static int proc_doutsstring(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp); + void __user *buffer, size_t *lenp); static ctl_table root_table[]; static struct ctl_table_header root_table_header = @@ -127,8 +127,8 @@ #ifdef CONFIG_PROC_FS -static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *); -static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *); +static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); +static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); static int proc_sys_permission(struct inode *, int); struct file_operations proc_sys_file_operations = { @@ -374,8 +374,8 @@ #endif } -int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, - void *newval, size_t newlen) +int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) { struct list_head *tmp; @@ -443,7 +443,7 @@ return test_perm(table->mode, op); } -static int parse_table(int *name, int nlen, +static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, ctl_table *table, void **context) @@ -484,7 +484,7 @@ /* Perform the actual read/write of a sysctl table entry. */ int do_sysctl_strategy (ctl_table *table, - int *name, int nlen, + int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { @@ -721,7 +721,7 @@ } } -static ssize_t do_rw_proc(int write, struct file * file, char * buf, +static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, size_t count, loff_t *ppos) { int op; @@ -752,16 +752,16 @@ return res; } -static ssize_t proc_readsys(struct file * file, char * buf, +static ssize_t proc_readsys(struct file * file, char __user * buf, size_t count, loff_t *ppos) { return do_rw_proc(0, file, buf, count, ppos); } -static ssize_t proc_writesys(struct file * file, const char * buf, +static ssize_t proc_writesys(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { - return do_rw_proc(1, file, (char *) buf, count, ppos); + return do_rw_proc(1, file, (char __user *) buf, count, ppos); } static int proc_sys_permission(struct inode *inode, int op) @@ -1345,7 +1345,7 @@ */ /* The generic string strategy routine: */ -int sysctl_string(ctl_table *table, int *name, int nlen, +int sysctl_string(ctl_table *table, int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, void **context) { @@ -1388,9 +1388,9 @@ * are between the minimum and maximum values given in the arrays * table->extra1 and table->extra2, respectively. */ -int sysctl_intvec(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) +int sysctl_intvec(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { int i, *vec, *min, *max; size_t length; @@ -1423,9 +1423,9 @@ } /* Strategy function to convert jiffies to seconds */ -int sysctl_jiffies(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) +int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { if (oldval) { size_t olen; @@ -1459,47 +1459,47 @@ return -ENOSYS; } -int sysctl_string(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) +int sysctl_string(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { return -ENOSYS; } -int sysctl_intvec(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) +int sysctl_intvec(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { return -ENOSYS; } -int sysctl_jiffies(ctl_table *table, int *name, int nlen, - void *oldval, size_t *oldlenp, - void *newval, size_t newlen, void **context) +int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) { return -ENOSYS; } int proc_dostring(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } @@ -1511,14 +1511,14 @@ } int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer, size_t *lenp) { return -ENOSYS; } diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Mon May 12 20:55:48 2003 +++ b/kernel/timer.c Mon May 12 20:55:48 2003 @@ -905,7 +905,7 @@ parent = me->group_leader->real_parent; for (;;) { pid = parent->tgid; -#if CONFIG_SMP +#ifdef CONFIG_SMP { struct task_struct *old = parent; diff -Nru a/lib/Makefile b/lib/Makefile --- a/lib/Makefile Mon May 12 20:55:44 2003 +++ b/lib/Makefile Mon May 12 20:55:44 2003 @@ -8,7 +8,7 @@ L_TARGET := lib.a -obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \ +obj-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ kobject.o idr.o diff -Nru a/lib/brlock.c b/lib/brlock.c --- a/lib/brlock.c Mon May 12 20:55:47 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,72 +0,0 @@ -/* - * - * linux/lib/brlock.c - * - * 'Big Reader' read-write spinlocks. See linux/brlock.h for details. - * - * Copyright 2000, Ingo Molnar - * Copyright 2000, David S. Miller - */ - -#include - -#ifdef CONFIG_SMP - -#include -#include - -#ifdef __BRLOCK_USE_ATOMICS - -brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] = - { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = RW_LOCK_UNLOCKED } }; - -void __br_write_lock (enum brlock_indices idx) -{ - int i; - - preempt_disable(); - for (i = 0; i < NR_CPUS; i++) - _raw_write_lock(&__brlock_array[i][idx]); -} - -void __br_write_unlock (enum brlock_indices idx) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) - _raw_write_unlock(&__brlock_array[i][idx]); - preempt_enable(); -} - -#else /* ! __BRLOCK_USE_ATOMICS */ - -brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] = - { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = 0 } }; - -struct br_wrlock __br_write_locks[__BR_IDX_MAX] = - { [0 ... __BR_IDX_MAX-1] = { SPIN_LOCK_UNLOCKED } }; - -void __br_write_lock (enum brlock_indices idx) -{ - int i; - - preempt_disable(); -again: - _raw_spin_lock(&__br_write_locks[idx].lock); - for (i = 0; i < NR_CPUS; i++) - if (__brlock_array[i][idx] != 0) { - _raw_spin_unlock(&__br_write_locks[idx].lock); - barrier(); - cpu_relax(); - goto again; - } -} - -void __br_write_unlock (enum brlock_indices idx) -{ - spin_unlock(&__br_write_locks[idx].lock); -} - -#endif /* __BRLOCK_USE_ATOMICS */ - -#endif /* CONFIG_SMP */ diff -Nru a/lib/inflate.c b/lib/inflate.c --- a/lib/inflate.c Mon May 12 20:55:46 2003 +++ b/lib/inflate.c Mon May 12 20:55:46 2003 @@ -271,14 +271,15 @@ STATIC unsigned hufts; /* track memory usage */ -STATIC int huft_build(b, n, s, d, e, t, m) -unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ -unsigned n; /* number of codes (assumed <= N_MAX) */ -unsigned s; /* number of simple-valued codes (0..s-1) */ -const ush *d; /* list of base values for non-simple codes */ -const ush *e; /* list of extra bits for non-simple codes */ -struct huft **t; /* result: starting table */ -int *m; /* maximum lookup bits, returns actual */ +STATIC int huft_build( + unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + const ush *d, /* list of base values for non-simple codes */ + const ush *e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m /* maximum lookup bits, returns actual */ + ) /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return zero on success, one if the given code set is incomplete (the tables are still built in this @@ -489,8 +490,9 @@ -STATIC int huft_free(t) -struct huft *t; /* table to free */ +STATIC int huft_free( + struct huft *t /* table to free */ + ) /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ @@ -510,9 +512,12 @@ } -STATIC int inflate_codes(tl, td, bl, bd) -struct huft *tl, *td; /* literal/length and distance decoder tables */ -int bl, bd; /* number of bits decoded by tl[] and td[] */ +STATIC int inflate_codes( + struct huft *tl, /* literal/length decoder tables */ + struct huft *td, /* distance decoder tables */ + int bl, /* number of bits decoded by tl[] */ + int bd /* number of bits decoded by td[] */ + ) /* inflate (decompress) the codes in a deflated (compressed) block. Return an error code or zero if it all goes ok. */ { @@ -619,7 +624,7 @@ -STATIC int inflate_stored() +STATIC int inflate_stored(void) /* "decompress" an inflated type 0 (stored) block. */ { unsigned n; /* number of bytes in block */ @@ -675,7 +680,7 @@ -STATIC int inflate_fixed() +STATIC int inflate_fixed(void) /* decompress an inflated type 1 (fixed Huffman codes) block. We should either replace this with a custom decoder, or at least precompute the Huffman tables. */ @@ -729,7 +734,7 @@ -STATIC int inflate_dynamic() +STATIC int inflate_dynamic(void) /* decompress an inflated type 2 (dynamic Huffman codes) block. */ { int i; /* temporary variables */ @@ -907,8 +912,9 @@ -STATIC int inflate_block(e) -int *e; /* last block flag */ +STATIC int inflate_block( + int *e /* last block flag */ + ) /* decompress an inflated block */ { unsigned t; /* block type */ @@ -954,7 +960,7 @@ -STATIC int inflate() +STATIC int inflate(void) /* decompress an inflated entry */ { int e; /* last block flag */ diff -Nru a/mm/bootmem.c b/mm/bootmem.c --- a/mm/bootmem.c Mon May 12 20:55:45 2003 +++ b/mm/bootmem.c Mon May 12 20:55:45 2003 @@ -311,7 +311,7 @@ void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size) { - return(free_bootmem_core(pgdat->bdata, physaddr, size)); + free_bootmem_core(pgdat->bdata, physaddr, size); } unsigned long __init free_all_bootmem_node (pg_data_t *pgdat) @@ -336,7 +336,7 @@ void __init free_bootmem (unsigned long addr, unsigned long size) { - return(free_bootmem_core(contig_page_data.bdata, addr, size)); + free_bootmem_core(contig_page_data.bdata, addr, size); } unsigned long __init free_all_bootmem (void) diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Mon May 12 20:55:45 2003 +++ b/mm/filemap.c Mon May 12 20:55:45 2003 @@ -681,7 +681,7 @@ *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; if (cached_page) page_cache_release(cached_page); - UPDATE_ATIME(inode); + update_atime(inode); } int file_read_actor(read_descriptor_t *desc, struct page *page, @@ -774,7 +774,7 @@ if (retval > 0) *ppos = pos + retval; } - UPDATE_ATIME(filp->f_dentry->d_inode); + update_atime(filp->f_dentry->d_inode); goto out; } @@ -802,7 +802,7 @@ } ssize_t -generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos) +generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos) { struct iovec local_iov = { .iov_base = buf, .iov_len = count }; @@ -812,7 +812,7 @@ EXPORT_SYMBOL(generic_file_aio_read); ssize_t -generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct iovec local_iov = { .iov_base = buf, .iov_len = count }; struct kiocb kiocb; @@ -846,7 +846,7 @@ } ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos, - size_t count, read_actor_t actor, void *target) + size_t count, read_actor_t actor, void __user *target) { read_descriptor_t desc; @@ -1259,7 +1259,7 @@ if (!mapping->a_ops->readpage) return -ENOEXEC; - UPDATE_ATIME(inode); + update_atime(inode); vma->vm_ops = &generic_file_vm_ops; return 0; } @@ -1412,7 +1412,7 @@ static inline int filemap_copy_from_user(struct page *page, unsigned long offset, - const char *buf, unsigned bytes) + const char __user *buf, unsigned bytes) { char *kaddr; int left; @@ -1437,7 +1437,7 @@ int left = 0; while (bytes) { - char *buf = iov->iov_base + base; + char __user *buf = iov->iov_base + base; int copy = min(bytes, iov->iov_len - base); base = 0; if ((left = __copy_from_user(vaddr, buf, copy))) @@ -1601,7 +1601,7 @@ const struct iovec *cur_iov = iov; /* current iovec */ size_t iov_base = 0; /* offset in the current iovec */ unsigned long seg; - char *buf; + char __user *buf; ocount = 0; for (seg = 0; seg < nr_segs; seg++) { @@ -1775,13 +1775,13 @@ return ret; } -ssize_t generic_file_aio_write(struct kiocb *iocb, const char *buf, +ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_dentry->d_inode->i_mapping->host; ssize_t err; - struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count }; + struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; BUG_ON(iocb->ki_pos != pos); @@ -1795,12 +1795,12 @@ EXPORT_SYMBOL(generic_file_aio_write); EXPORT_SYMBOL(generic_file_aio_write_nolock); -ssize_t generic_file_write(struct file *file, const char *buf, +ssize_t generic_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode->i_mapping->host; ssize_t err; - struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count }; + struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; down(&inode->i_sem); err = generic_file_write_nolock(file, &local_iov, 1, ppos); diff -Nru a/mm/mincore.c b/mm/mincore.c --- a/mm/mincore.c Mon May 12 20:55:49 2003 +++ b/mm/mincore.c Mon May 12 20:55:49 2003 @@ -39,7 +39,7 @@ } static long mincore_vma(struct vm_area_struct * vma, - unsigned long start, unsigned long end, unsigned char * vec) + unsigned long start, unsigned long end, unsigned char __user * vec) { long error, i, remaining; unsigned char * tmp; @@ -106,7 +106,7 @@ * -EAGAIN - A kernel resource was temporarily unavailable. */ asmlinkage long sys_mincore(unsigned long start, size_t len, - unsigned char * vec) + unsigned char __user * vec) { int index = 0; unsigned long end; diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c --- a/mm/page-writeback.c Mon May 12 20:55:47 2003 +++ b/mm/page-writeback.c Mon May 12 20:55:47 2003 @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -237,7 +236,6 @@ .nonblocking = 1, }; - CHECK_EMERGENCY_SYNC for ( ; ; ) { struct page_state ps; long background_thresh; @@ -272,7 +270,7 @@ struct page_state ps; get_page_state(&ps); - nr_pages = ps.nr_dirty; + nr_pages = ps.nr_dirty + ps.nr_unstable; } return pdflush_operation(background_writeout, nr_pages); } diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Mon May 12 20:55:44 2003 +++ b/mm/page_alloc.c Mon May 12 20:55:44 2003 @@ -537,6 +537,7 @@ int i; int cold; int do_retry; + struct reclaim_state reclaim_state; if (wait) might_sleep(); @@ -608,7 +609,12 @@ goto nopage; current->flags |= PF_MEMALLOC; + reclaim_state.reclaimed_slab = 0; + current->reclaim_state = &reclaim_state; + try_to_free_pages(classzone, gfp_mask, order); + + current->reclaim_state = NULL; current->flags &= ~PF_MEMALLOC; /* go through the zonelist yet one more time */ @@ -786,7 +792,7 @@ return nr_free_zone_pages(GFP_HIGHUSER & GFP_ZONEMASK); } -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM unsigned int nr_free_highpages (void) { pg_data_t *pgdat; diff -Nru a/mm/shmem.c b/mm/shmem.c --- a/mm/shmem.c Mon May 12 20:55:46 2003 +++ b/mm/shmem.c Mon May 12 20:55:46 2003 @@ -1013,7 +1013,7 @@ ops = &shmem_vm_ops; if (!inode->i_sb || !S_ISREG(inode->i_mode)) return -EACCES; - UPDATE_ATIME(inode); + update_atime(inode); vma->vm_ops = ops; return 0; } @@ -1114,7 +1114,7 @@ } static ssize_t -shmem_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; loff_t pos; @@ -1307,10 +1307,10 @@ } *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; - UPDATE_ATIME(inode); + update_atime(inode); } -static ssize_t shmem_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { read_descriptor_t desc; @@ -1333,7 +1333,7 @@ } static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos, - size_t count, read_actor_t actor, void *target) + size_t count, read_actor_t actor, void __user *target) { read_descriptor_t desc; @@ -1519,7 +1519,7 @@ return 0; } -static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen) +static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen) { return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode)); } @@ -1529,7 +1529,7 @@ return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode)); } -static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen) +static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct page *page = NULL; int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ); diff -Nru a/mm/slab.c b/mm/slab.c --- a/mm/slab.c Mon May 12 20:55:48 2003 +++ b/mm/slab.c Mon May 12 20:55:48 2003 @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -567,11 +568,40 @@ return cachep->array[smp_processor_id()]; } -/* Initialisation - setup the `cache' cache. */ +/* Initialisation. + * Called after the gfp() functions have been enabled, and before smp_init(). + */ void __init kmem_cache_init(void) { size_t left_over; + struct cache_sizes *sizes; + struct cache_names *names; + /* + * Fragmentation resistance on low memory - only use bigger + * page orders on machines with more than 32MB of memory. + */ + if (num_physpages > (32 << 20) >> PAGE_SHIFT) + slab_break_gfp_order = BREAK_GFP_ORDER_HI; + + + /* Bootstrap is tricky, because several objects are allocated + * from caches that do not exist yet: + * 1) initialize the cache_cache cache: it contains the kmem_cache_t + * structures of all caches, except cache_cache itself: cache_cache + * is statically allocated. + * Initially an __init data area is used for the head array, it's + * replaced with a kmalloc allocated array at the end of the bootstrap. + * 2) Create the first kmalloc cache. + * The kmem_cache_t for the new cache is allocated normally. An __init + * data area is used for the head array. + * 3) Create the remaining kmalloc caches, with minimally sized head arrays. + * 4) Replace the __init data head arrays for cache_cache and the first + * kmalloc cache with kmalloc allocated arrays. + * 5) Resize the head arrays of the kmalloc caches to their final sizes. + */ + + /* 1) create the cache_cache */ init_MUTEX(&cache_chain_sem); INIT_LIST_HEAD(&cache_chain); list_add(&cache_cache.next, &cache_chain); @@ -585,27 +615,10 @@ cache_cache.colour = left_over/cache_cache.colour_off; cache_cache.colour_next = 0; - /* Register a cpu startup notifier callback - * that initializes ac_data for all new cpus - */ - register_cpu_notifier(&cpucache_notifier); -} - -/* Initialisation - setup remaining internal and general caches. - * Called after the gfp() functions have been enabled, and before smp_init(). - */ -void __init kmem_cache_sizes_init(void) -{ - struct cache_sizes *sizes = malloc_sizes; - struct cache_names *names = cache_names; - - /* - * Fragmentation resistance on low memory - only use bigger - * page orders on machines with more than 32MB of memory. - */ - if (num_physpages > (32 << 20) >> PAGE_SHIFT) - slab_break_gfp_order = BREAK_GFP_ORDER_HI; + /* 2+3) create the kmalloc caches */ + sizes = malloc_sizes; + names = cache_names; while (sizes->cs_size) { /* For performance, all the general caches are L1 aligned. @@ -634,10 +647,7 @@ sizes++; names++; } - /* - * The generic caches are running - time to kick out the - * bootstrap cpucaches. - */ + /* 4) Replace the bootstrap head arrays */ { void * ptr; @@ -656,29 +666,42 @@ malloc_sizes[0].cs_cachep->array[smp_processor_id()] = ptr; local_irq_enable(); } + + /* 5) resize the head arrays to their final sizes */ + { + kmem_cache_t *cachep; + down(&cache_chain_sem); + list_for_each_entry(cachep, &cache_chain, next) + enable_cpucache(cachep); + up(&cache_chain_sem); + } + + /* Done! */ + g_cpucache_up = FULL; + + /* Register a cpu startup notifier callback + * that initializes ac_data for all new cpus + */ + register_cpu_notifier(&cpucache_notifier); + + + /* The reap timers are started later, with a module init call: + * That part of the kernel is not yet operational. + */ } int __init cpucache_init(void) { - kmem_cache_t *cachep; int cpu; - down(&cache_chain_sem); - g_cpucache_up = FULL; - - list_for_each_entry(cachep, &cache_chain, next) - enable_cpucache(cachep); - /* * Register the timers that return unneeded * pages to gfp. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) { if (cpu_online(cpu)) start_cpu_timer(cpu); } - up(&cache_chain_sem); return 0; } @@ -712,6 +735,7 @@ { unsigned long i = (1<gfporder); struct page *page = virt_to_page(addr); + const unsigned long nr_freed = i; /* free_pages() does not clear the type bit - we do that. * The pages have been unlinked from their cache-slab, @@ -720,9 +744,11 @@ */ while (i--) { ClearPageSlab(page); - dec_page_state(nr_slab); page++; } + sub_page_state(nr_slab, nr_freed); + if (current->reclaim_state) + current->reclaim_state->reclaimed_slab += nr_freed; free_pages((unsigned long)addr, cachep->gfporder); } @@ -914,12 +940,19 @@ } #if FORCED_DEBUG - if ((size < (PAGE_SIZE>>3)) && !(flags & SLAB_MUST_HWCACHE_ALIGN)) - /* - * do not red zone large object, causes severe - * fragmentation. - */ + /* + * Enable redzoning and last user accounting, except + * - for caches with forced alignment: redzoning would violate the + * alignment + * - for caches with large objects, if the increased size would + * increase the object size above the next power of two: caches + * with object sizes just above a power of two have a significant + * amount of internal fragmentation + */ + if ((size < (PAGE_SIZE>>3) || fls(size-1) == fls(size-1+3*BYTES_PER_WORD)) + && !(flags & SLAB_MUST_HWCACHE_ALIGN)) { flags |= SLAB_RED_ZONE|SLAB_STORE_USER; + } flags |= SLAB_POISON; #endif #endif @@ -1756,10 +1789,12 @@ slabp = GET_PAGE_SLAB(virt_to_page(objp)); list_del(&slabp->list); objnr = (objp - slabp->s_mem) / cachep->objsize; + check_slabp(cachep, slabp); slab_bufctl(slabp)[objnr] = slabp->free; slabp->free = objnr; STATS_DEC_ACTIVE(cachep); slabp->inuse--; + check_slabp(cachep, slabp); /* fixup slab chains */ if (slabp->inuse == 0) { @@ -2413,7 +2448,7 @@ * @count: data len * @data: unused */ -ssize_t slabinfo_write(struct file *file, const char *buffer, +ssize_t slabinfo_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { char kbuf[MAX_SLABINFO_WRITE+1], *tmp; diff -Nru a/mm/swapfile.c b/mm/swapfile.c --- a/mm/swapfile.c Mon May 12 20:55:45 2003 +++ b/mm/swapfile.c Mon May 12 20:55:45 2003 @@ -886,6 +886,10 @@ * requirements, they are simply tossed out - we will never use those blocks * for swapping. * + * For S_ISREG swapfiles we hold i_sem across the life of the swapon. This + * prevents root from shooting her foot off by ftruncating an in-use swapfile, + * which will scribble on the fs. + * * The amount of disk space which a single swap extent represents varies. * Typically it is in the 1-4 megabyte range. So we can have hundreds of * extents in the list. To avoid much list walking, we cache the previous @@ -1095,6 +1099,8 @@ bdev = swap_file->f_dentry->d_inode->i_bdev; set_blocksize(bdev, p->old_block_size); bd_release(bdev); + } else { + up(&swap_file->f_dentry->d_inode->i_mapping->host->i_sem); } filp_close(swap_file, NULL); err = 0; @@ -1228,6 +1234,8 @@ int swapfilesize; unsigned short *swap_map; struct page *page = NULL; + struct inode *inode; + struct inode *downed_inode = NULL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1274,39 +1282,42 @@ } p->swap_file = swap_file; + inode = swap_file->f_dentry->d_inode; + mapping = swap_file->f_dentry->d_inode->i_mapping; + + error = -EBUSY; + for (i = 0; i < nr_swapfiles; i++) { + struct swap_info_struct *q = &swap_info[i]; + + if (i == type || !q->swap_file) + continue; + if (mapping == q->swap_file->f_dentry->d_inode->i_mapping) + goto bad_swap; + } error = -EINVAL; - if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) { - bdev = swap_file->f_dentry->d_inode->i_bdev; + if (S_ISBLK(inode->i_mode)) { + bdev = inode->i_bdev; error = bd_claim(bdev, sys_swapon); if (error < 0) { bdev = NULL; goto bad_swap; } p->old_block_size = block_size(bdev); - error = set_blocksize(swap_file->f_dentry->d_inode->i_bdev, - PAGE_SIZE); + error = set_blocksize(inode->i_bdev, PAGE_SIZE); if (error < 0) goto bad_swap; p->bdev = bdev; - } else if (S_ISREG(swap_file->f_dentry->d_inode->i_mode)) { - p->bdev = swap_file->f_dentry->d_inode->i_sb->s_bdev; + } else if (S_ISREG(inode->i_mode)) { + p->bdev = inode->i_sb->s_bdev; + downed_inode = mapping->host; + down(&downed_inode->i_sem); } else { goto bad_swap; } - mapping = swap_file->f_dentry->d_inode->i_mapping; swapfilesize = mapping->host->i_size >> PAGE_SHIFT; - error = -EBUSY; - for (i = 0 ; i < nr_swapfiles ; i++) { - struct swap_info_struct *q = &swap_info[i]; - if (i == type || !q->swap_file) - continue; - if (mapping == q->swap_file->f_dentry->d_inode->i_mapping) - goto bad_swap; - } - /* * Read the swap header. */ @@ -1452,6 +1463,8 @@ } if (name) putname(name); + if (error && downed_inode) + up(&downed_inode->i_sem); return error; } diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c --- a/mm/vmalloc.c Mon May 12 20:55:47 2003 +++ b/mm/vmalloc.c Mon May 12 20:55:47 2003 @@ -97,8 +97,7 @@ do { struct page *page = **pages; - if (!pte_none(*pte)) - printk(KERN_ERR "alloc_area_pte: page already exists\n"); + WARN_ON(!pte_none(*pte)); if (!page) return -ENOMEM; diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Mon May 12 20:55:44 2003 +++ b/mm/vmscan.c Mon May 12 20:55:44 2003 @@ -817,12 +817,14 @@ * excessive rotation of the inactive list, which is _supposed_ to be an LRU, * yes? */ -int try_to_free_pages(struct zone *classzone, +int try_to_free_pages(struct zone *cz, unsigned int gfp_mask, unsigned int order) { int priority; + int ret = 0; const int nr_pages = SWAP_CLUSTER_MAX; int nr_reclaimed = 0; + struct reclaim_state *reclaim_state = current->reclaim_state; inc_page_state(allocstall); @@ -831,11 +833,12 @@ struct page_state ps; get_page_state(&ps); - nr_reclaimed += shrink_caches(classzone, priority, - &total_scanned, gfp_mask, - nr_pages, &ps); - if (nr_reclaimed >= nr_pages) - return 1; + nr_reclaimed += shrink_caches(cz, priority, &total_scanned, + gfp_mask, nr_pages, &ps); + if (nr_reclaimed >= nr_pages) { + ret = 1; + goto out; + } if (!(gfp_mask & __GFP_FS)) break; /* Let the caller handle it */ /* @@ -847,12 +850,18 @@ /* Take a nap, wait for some writeback to complete */ blk_congestion_wait(WRITE, HZ/10); - if (classzone - classzone->zone_pgdat->node_zones < ZONE_HIGHMEM) + if (cz - cz->zone_pgdat->node_zones < ZONE_HIGHMEM) { shrink_slab(total_scanned, gfp_mask); + if (reclaim_state) { + nr_reclaimed += reclaim_state->reclaimed_slab; + reclaim_state->reclaimed_slab = 0; + } + } } if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) out_of_memory(); - return 0; +out: + return ret; } /* @@ -878,6 +887,7 @@ int to_free = nr_pages; int priority; int i; + struct reclaim_state *reclaim_state = current->reclaim_state; inc_page_state(pageoutrun); @@ -908,8 +918,11 @@ max_scan = SWAP_CLUSTER_MAX; to_free -= shrink_zone(zone, max_scan, GFP_KERNEL, to_reclaim, &nr_mapped, ps, priority); - if (i < ZONE_HIGHMEM) + if (i < ZONE_HIGHMEM) { + reclaim_state->reclaimed_slab = 0; shrink_slab(max_scan + nr_mapped, GFP_KERNEL); + to_free += reclaim_state->reclaimed_slab; + } if (zone->all_unreclaimable) continue; if (zone->pages_scanned > zone->present_pages * 2) @@ -940,10 +953,14 @@ pg_data_t *pgdat = (pg_data_t*)p; struct task_struct *tsk = current; DEFINE_WAIT(wait); + struct reclaim_state reclaim_state = { + .reclaimed_slab = 0, + }; daemonize("kswapd%d", pgdat->node_id); set_cpus_allowed(tsk, node_to_cpumask(pgdat->node_id)); - + current->reclaim_state = &reclaim_state; + /* * Tell the memory management that we're a "memory allocator", * and that if we need more memory we should get access to it diff -Nru a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c --- a/net/8021q/vlanproc.c Mon May 12 20:55:45 2003 +++ b/net/8021q/vlanproc.c Mon May 12 20:55:45 2003 @@ -18,6 +18,7 @@ *****************************************************************************/ #include +#include #include /* offsetof(), etc. */ #include /* return codes */ #include @@ -75,6 +76,7 @@ */ static struct file_operations vlan_fops = { + .owner = THIS_MODULE, .read = vlan_proc_read, .ioctl = NULL, /* vlan_proc_ioctl */ }; @@ -84,6 +86,7 @@ */ static struct file_operations vlandev_fops = { + .owner = THIS_MODULE, .read = vlan_proc_read, .ioctl =NULL, /* vlan_proc_ioctl */ }; diff -Nru a/net/Kconfig b/net/Kconfig --- a/net/Kconfig Mon May 12 20:55:44 2003 +++ b/net/Kconfig Mon May 12 20:55:44 2003 @@ -266,6 +266,23 @@ subnetwork boundaries. These shortcut connections bypass routers enhancing overall network performance. +config ATM_BR2684 + tristate "RFC1483/2684 Bridged protocols" + depends on ATM && INET + help + ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483) + This device will act like an ethernet from the kernels point of view, + with the traffic being carried by ATM PVCs (currently 1 PVC/device). + This is sometimes used over DSL lines. If in doubt, say N. + +config ATM_BR2684_IPFILTER + bool "Per-VC IP filter kludge" + depends on ATM_BR2684 + help + This is an experimental mechanism for users who need to terminating a + large number of IP-only vcc's. Do not enable this unless you are sure + you know what you are doing. + config VLAN_8021Q tristate "802.1Q VLAN Support" diff -Nru a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c --- a/net/appletalk/atalk_proc.c Mon May 12 20:55:48 2003 +++ b/net/appletalk/atalk_proc.c Mon May 12 20:55:48 2003 @@ -241,6 +241,7 @@ } static struct file_operations atalk_seq_interface_fops = { + .owner = THIS_MODULE, .open = atalk_seq_interface_open, .read = seq_read, .llseek = seq_lseek, @@ -248,6 +249,7 @@ }; static struct file_operations atalk_seq_route_fops = { + .owner = THIS_MODULE, .open = atalk_seq_route_open, .read = seq_read, .llseek = seq_lseek, @@ -255,6 +257,7 @@ }; static struct file_operations atalk_seq_socket_fops = { + .owner = THIS_MODULE, .open = atalk_seq_socket_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/atm/Makefile b/net/atm/Makefile --- a/net/atm/Makefile Mon May 12 20:55:44 2003 +++ b/net/atm/Makefile Mon May 12 20:55:44 2003 @@ -7,6 +7,7 @@ obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o obj-$(CONFIG_ATM_CLIP) += clip.o ipcommon.o +obj-$(CONFIG_ATM_BR2684) += br2684.o ipcommon.o obj-$(CONFIG_NET_SCH_ATM) += ipcommon.o obj-$(CONFIG_PROC_FS) += proc.o diff -Nru a/net/atm/br2684.c b/net/atm/br2684.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/atm/br2684.c Mon May 12 20:55:49 2003 @@ -0,0 +1,804 @@ +/* +Experimental ethernet netdevice using ATM AAL5 as underlying carrier +(RFC1483 obsoleted by RFC2684) for Linux 2.4 +Author: Marcell GAL, 2000, XDSL Ltd, Hungary +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ipcommon.h" + +/* + * Define this to use a version of the code which interacts with the higher + * layers in a more intellegent way, by always reserving enough space for + * our header at the begining of the packet. However, there may still be + * some problems with programs like tcpdump. In 2.5 we'll sort out what + * we need to do to get this perfect. For now we just will copy the packet + * if we need space for the header + */ +/* #define FASTER_VERSION */ + +#ifdef DEBUG +#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args) +#else +#define DPRINTK(format, args...) +#endif + +#ifdef SKB_DEBUG +static void skb_debug(const struct sk_buff *skb) +{ +#define NUM2PRINT 50 + char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */ + int i = 0; + for (i = 0; i < skb->len && i < NUM2PRINT; i++) { + sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); + } + printk(KERN_DEBUG "br2684: skb: %s\n", buf); +} +#else +#define skb_debug(skb) do {} while (0) +#endif + +static unsigned char llc_oui_pid_pad[] = + { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 }; +#define PADLEN (2) + +enum br2684_encaps { + e_vc = BR2684_ENCAPS_VC, + e_llc = BR2684_ENCAPS_LLC, +}; + +struct br2684_vcc { + struct atm_vcc *atmvcc; + struct br2684_dev *brdev; + /* keep old push,pop functions for chaining */ + void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); + /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */ + enum br2684_encaps encaps; + struct list_head brvccs; +#ifdef CONFIG_ATM_BR2684_IPFILTER + struct br2684_filter filter; +#endif /* CONFIG_ATM_BR2684_IPFILTER */ +#ifndef FASTER_VERSION + unsigned copies_needed, copies_failed; +#endif /* FASTER_VERSION */ +}; + +struct br2684_dev { + struct net_device net_dev; + struct list_head br2684_devs; + int number; + struct list_head brvccs; /* one device <=> one vcc (before xmas) */ + struct net_device_stats stats; + int mac_was_set; +}; + +/* + * This lock should be held for writing any time the list of devices or + * their attached vcc's could be altered. It should be held for reading + * any time these are being queried. Note that we sometimes need to + * do read-locking under interrupt context, so write locking must block + * the current CPU's interrupts + */ +static rwlock_t devs_lock = RW_LOCK_UNLOCKED; + +static LIST_HEAD(br2684_devs); + +static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) +{ + return (struct br2684_dev *) ((char *) (net_dev) - + (unsigned long) (&((struct br2684_dev *) 0)->net_dev)); +} + +static inline struct br2684_dev *list_entry_brdev(const struct list_head *le) +{ + return list_entry(le, struct br2684_dev, br2684_devs); +} + +static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc) +{ + return (struct br2684_vcc *) (atmvcc->user_back); +} + +static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le) +{ + return list_entry(le, struct br2684_vcc, brvccs); +} + +/* Caller should hold read_lock(&devs_lock) */ +static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s) +{ + struct list_head *lh; + struct br2684_dev *brdev; + switch (s->method) { + case BR2684_FIND_BYNUM: + list_for_each(lh, &br2684_devs) { + brdev = list_entry_brdev(lh); + if (brdev->number == s->spec.devnum) + return brdev; + } + break; + case BR2684_FIND_BYIFNAME: + list_for_each(lh, &br2684_devs) { + brdev = list_entry_brdev(lh); + if (!strncmp(brdev->net_dev.name, s->spec.ifname, + sizeof brdev->net_dev.name)) + return brdev; + } + break; + } + return NULL; +} + +/* + * Send a packet out a particular vcc. Not to useful right now, but paves + * the way for multiple vcc's per itf. Returns true if we can send, + * otherwise false + */ +static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, + struct br2684_vcc *brvcc) +{ + struct atm_vcc *atmvcc; +#ifdef FASTER_VERSION + if (brvcc->encaps == e_llc) + memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8); + /* last 2 bytes of llc_oui_pid_pad are managed by header routines; + yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad) + */ +#else + int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; + if (skb_headroom(skb) < minheadroom) { + struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); + brvcc->copies_needed++; + dev_kfree_skb(skb); + if (skb2 == NULL) { + brvcc->copies_failed++; + return 0; + } + skb = skb2; + } + skb_push(skb, minheadroom); + if (brvcc->encaps == e_llc) + memcpy(skb->data, llc_oui_pid_pad, 10); + else + memset(skb->data, 0, 2); +#endif /* FASTER_VERSION */ + skb_debug(skb); + + ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; + DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); + if (!atm_may_send(atmvcc, skb->truesize)) { + /* we free this here for now, because we cannot know in a higher + layer whether the skb point it supplied wasn't freed yet. + now, it always is. + */ + dev_kfree_skb(skb); + return 0; + } + atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc); + ATM_SKB(skb)->atm_options = atmvcc->atm_options; + brdev->stats.tx_packets++; + brdev->stats.tx_bytes += skb->len; + atmvcc->send(atmvcc, skb); + return 1; +} + +static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb, + struct br2684_dev *brdev) +{ + return list_empty(&brdev->brvccs) ? NULL : + list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ +} + +static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct br2684_dev *brdev = BRPRIV(dev); + struct br2684_vcc *brvcc; + + DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst); + read_lock(&devs_lock); + brvcc = pick_outgoing_vcc(skb, brdev); + if (brvcc == NULL) { + DPRINTK("no vcc attached to dev %s\n", dev->name); + brdev->stats.tx_errors++; + brdev->stats.tx_carrier_errors++; + /* netif_stop_queue(dev); */ + dev_kfree_skb(skb); + read_unlock(&devs_lock); + return -EUNATCH; + } + if (!br2684_xmit_vcc(skb, brdev, brvcc)) { + /* + * We should probably use netif_*_queue() here, but that + * involves added complication. We need to walk before + * we can run + */ + /* don't free here! this pointer might be no longer valid! + dev_kfree_skb(skb); + */ + brdev->stats.tx_errors++; + brdev->stats.tx_fifo_errors++; + } + read_unlock(&devs_lock); + return 0; +} + +static struct net_device_stats *br2684_get_stats(struct net_device *dev) +{ + DPRINTK("br2684_get_stats\n"); + return &BRPRIV(dev)->stats; +} + +#ifdef FASTER_VERSION +/* + * These mirror eth_header and eth_header_cache. They are not usually + * exported for use in modules, so we grab them from net_device + * after ether_setup() is done with it. Bit of a hack. + */ +static int (*my_eth_header)(struct sk_buff *, struct net_device *, + unsigned short, void *, void *, unsigned); +static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *); + +static int +br2684_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + u16 *pad_before_eth; + int t = my_eth_header(skb, dev, type, daddr, saddr, len); + if (t > 0) { + pad_before_eth = (u16 *) skb_push(skb, 2); + *pad_before_eth = 0; + return dev->hard_header_len; /* or return 16; ? */ + } else + return t; +} + +static int +br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ +/* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so +xmit will add the additional header part in that case */ + u16 *pad_before_eth = (u16 *)(hh->hh_data); + int t = my_eth_header_cache(neigh, hh); + DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh); + if (t < 0) + return t; + else { + *pad_before_eth = 0; + hh->hh_len = PADLEN + ETH_HLEN; + } + return 0; +} + +/* + * This is similar to eth_type_trans, which cannot be used because of + * our dev->hard_header_len + */ +static inline unsigned short br_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + eth = skb->mac.ethernet; + + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + } + + else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *) rawp == 0xFFFF) + return htons(ETH_P_802_3); + + /* + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); +} +#endif /* FASTER_VERSION */ + +/* + * We remember when the MAC gets set, so we don't override it later with + * the ESI of the ATM card of the first VC + */ +static int (*my_eth_mac_addr)(struct net_device *, void *); +static int br2684_mac_addr(struct net_device *dev, void *p) +{ + int err = my_eth_mac_addr(dev, p); + if (!err) + BRPRIV(dev)->mac_was_set = 1; + return err; +} + +#ifdef CONFIG_ATM_BR2684_IPFILTER +/* this IOCTL is experimental. */ +static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg) +{ + struct br2684_vcc *brvcc; + struct br2684_filter_set fs; + + if (copy_from_user(&fs, (void *) arg, sizeof fs)) + return -EFAULT; + if (fs.ifspec.method != BR2684_FIND_BYNOTHING) { + /* + * This is really a per-vcc thing, but we can also search + * by device + */ + struct br2684_dev *brdev; + read_lock(&devs_lock); + brdev = br2684_find_dev(&fs.ifspec); + if (brdev == NULL || list_empty(&brdev->brvccs) || + brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ + brvcc = NULL; + else + brvcc = list_entry_brvcc(brdev->brvccs.next); + read_unlock(&devs_lock); + if (brvcc == NULL) + return -ESRCH; + } else + brvcc = BR2684_VCC(atmvcc); + memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter)); + return 0; +} + +/* Returns 1 if packet should be dropped */ +static inline int +packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) +{ + if (brvcc->filter.netmask == 0) + return 0; /* no filter in place */ + if (type == __constant_htons(ETH_P_IP) && + (((struct iphdr *) (skb->data))->daddr & brvcc->filter. + netmask) == brvcc->filter.prefix) + return 0; + if (type == __constant_htons(ETH_P_ARP)) + return 0; + /* TODO: we should probably filter ARPs too.. don't want to have + * them returning values that don't make sense, or is that ok? + */ + return 1; /* drop */ +} +#endif /* CONFIG_ATM_BR2684_IPFILTER */ + +static void br2684_close_vcc(struct br2684_vcc *brvcc) +{ + DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev); + write_lock_irq(&devs_lock); + list_del(&brvcc->brvccs); + write_unlock_irq(&devs_lock); + brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ + brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ + kfree(brvcc); + MOD_DEC_USE_COUNT; +} + +/* when AAL5 PDU comes in: */ +static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) +{ + struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); + struct br2684_dev *brdev = brvcc->brdev; + int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN; + + DPRINTK("br2684_push\n"); + + if (skb == NULL) { /* skb==NULL means VCC is being destroyed */ + br2684_close_vcc(brvcc); + if (list_empty(&brdev->brvccs)) { + read_lock(&devs_lock); + list_del(&brdev->br2684_devs); + read_unlock(&devs_lock); + unregister_netdev(&brdev->net_dev); + kfree(brdev); + } + return; + } + + skb_debug(skb); + atm_return(atmvcc, skb->truesize); + DPRINTK("skb from brdev %p\n", brdev); + if (brvcc->encaps == e_llc) { + /* let us waste some time for checking the encapsulation. + Note, that only 7 char is checked so frames with a valid FCS + are also accepted (but FCS is not checked of course) */ + if (memcmp(skb->data, llc_oui_pid_pad, 7)) { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); + return; + } + } else { + plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */ + /* first 2 chars should be 0 */ + if (*((u16 *) (skb->data)) != 0) { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); + return; + } + } + if (skb->len < plen) { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); /* dev_ not needed? */ + return; + } + +#ifdef FASTER_VERSION + /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier, + than should be. What else should I set? */ + skb_pull(skb, plen); + skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN; + skb->pkt_type = PACKET_HOST; +#ifdef CONFIG_BR2684_FAST_TRANS + skb->protocol = ((u16 *) skb->data)[-1]; +#else /* some protocols might require this: */ + skb->protocol = br_type_trans(skb, &brdev->net_dev); +#endif /* CONFIG_BR2684_FAST_TRANS */ +#else + skb_pull(skb, plen - ETH_HLEN); + skb->protocol = eth_type_trans(skb, &brdev->net_dev); +#endif /* FASTER_VERSION */ +#ifdef CONFIG_ATM_BR2684_IPFILTER + if (packet_fails_filter(skb->protocol, brvcc, skb)) { + brdev->stats.rx_dropped++; + dev_kfree_skb(skb); + return; + } +#endif /* CONFIG_ATM_BR2684_IPFILTER */ + skb->dev = &brdev->net_dev; + ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ + DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol)); + skb_debug(skb); + if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */ + brdev->stats.rx_dropped++; + dev_kfree_skb(skb); + return; + } + brdev->stats.rx_packets++; + brdev->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); + netif_rx(skb); +} + +static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg) +{ +/* assign a vcc to a dev +Note: we do not have explicit unassign, but look at _push() +*/ + int err; + struct br2684_vcc *brvcc; + struct sk_buff_head copy; + struct sk_buff *skb; + struct br2684_dev *brdev; + struct atm_backend_br2684 be; + + MOD_INC_USE_COUNT; + if (copy_from_user(&be, (void *) arg, sizeof be)) { + MOD_DEC_USE_COUNT; + return -EFAULT; + } + write_lock_irq(&devs_lock); + brdev = br2684_find_dev(&be.ifspec); + if (brdev == NULL) { + printk(KERN_ERR + "br2684: tried to attach to non-existant device\n"); + err = -ENXIO; + goto error; + } + if (atmvcc->push == NULL) { + err = -EBADFD; + goto error; + } + if (!list_empty(&brdev->brvccs)) { /* Only 1 VCC/dev right now */ + err = -EEXIST; + goto error; + } + if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || + be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != + BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) || + be.min_size != 0) { + err = -EINVAL; + goto error; + } + brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL); + if (!brvcc) { + err = -ENOMEM; + goto error; + } + memset(brvcc, 0, sizeof(struct br2684_vcc)); + DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, + brvcc); + if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { + unsigned char *esi = atmvcc->dev->esi; + if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) + memcpy(brdev->net_dev.dev_addr, esi, + brdev->net_dev.addr_len); + else + brdev->net_dev.dev_addr[2] = 1; + } + list_add(&brvcc->brvccs, &brdev->brvccs); + write_unlock_irq(&devs_lock); + brvcc->brdev = brdev; + brvcc->atmvcc = atmvcc; + atmvcc->user_back = brvcc; + brvcc->encaps = (enum br2684_encaps) be.encaps; + brvcc->old_push = atmvcc->push; + barrier(); + atmvcc->push = br2684_push; + skb_queue_head_init(©); + skb_migrate(&atmvcc->sk->receive_queue, ©); + while ((skb = skb_dequeue(©))) { + BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; + BRPRIV(skb->dev)->stats.rx_packets--; + br2684_push(atmvcc, skb); + } + return 0; + error: + write_unlock_irq(&devs_lock); + MOD_DEC_USE_COUNT; + return err; +} + +static int br2684_create(unsigned long arg) +{ + int err; + struct br2684_dev *brdev; + struct atm_newif_br2684 ni; + + DPRINTK("br2684_create\n"); + /* + * We track module use by vcc's NOT the devices they're on. We're + * protected here against module death by the kernel_lock, but if + * we need to sleep we should make sure that the module doesn't + * disappear under us. + */ + MOD_INC_USE_COUNT; + if (copy_from_user(&ni, (void *) arg, sizeof ni)) { + MOD_DEC_USE_COUNT; + return -EFAULT; + } + if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { + MOD_DEC_USE_COUNT; + return -EINVAL; + } + if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + memset(brdev, 0, sizeof(struct br2684_dev)); + INIT_LIST_HEAD(&brdev->brvccs); + + write_lock_irq(&devs_lock); + brdev->number = list_empty(&br2684_devs) ? 1 : + list_entry_brdev(br2684_devs.prev)->number + 1; + list_add_tail(&brdev->br2684_devs, &br2684_devs); + write_unlock_irq(&devs_lock); + + if (ni.ifname[0] != '\0') { + memcpy(brdev->net_dev.name, ni.ifname, + sizeof(brdev->net_dev.name)); + brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0'; + } else + sprintf(brdev->net_dev.name, "nas%d", brdev->number); + DPRINTK("registered netdev %s\n", brdev->net_dev.name); + ether_setup(&brdev->net_dev); + brdev->mac_was_set = 0; +#ifdef FASTER_VERSION + my_eth_header = brdev->net_dev.hard_header; + brdev->net_dev.hard_header = br2684_header; + my_eth_header_cache = brdev->net_dev.hard_header_cache; + brdev->net_dev.hard_header_cache = br2684_header_cache; + brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */ +#endif + my_eth_mac_addr = brdev->net_dev.set_mac_address; + brdev->net_dev.set_mac_address = br2684_mac_addr; + brdev->net_dev.hard_start_xmit = br2684_start_xmit; + brdev->net_dev.get_stats = br2684_get_stats; + + /* open, stop, do_ioctl ? */ + err = register_netdev(&brdev->net_dev); + MOD_DEC_USE_COUNT; + if (err < 0) { + printk(KERN_ERR "br2684_create: register_netdev failed\n"); + write_lock_irq(&devs_lock); + list_del(&brdev->br2684_devs); + write_unlock_irq(&devs_lock); + kfree(brdev); + return err; + } + return 0; +} + +/* + * This handles ioctls actually performed on our vcc - we must return + * -ENOIOCTLCMD for any unrecognized ioctl + */ +static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd, + unsigned long arg) +{ + int err; + switch(cmd) { + case ATM_SETBACKEND: + case ATM_NEWBACKENDIF: { + atm_backend_t b; + MOD_INC_USE_COUNT; + err = get_user(b, (atm_backend_t *) arg); + MOD_DEC_USE_COUNT; + if (err) + return -EFAULT; + if (b != ATM_BACKEND_BR2684) + return -ENOIOCTLCMD; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (cmd == ATM_SETBACKEND) + return br2684_regvcc(atmvcc, arg); + else + return br2684_create(arg); + } +#ifdef CONFIG_ATM_BR2684_IPFILTER + case BR2684_SETFILT: + if (atmvcc->push != br2684_push) + return -ENOIOCTLCMD; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + MOD_INC_USE_COUNT; + err = br2684_setfilt(atmvcc, arg); + MOD_DEC_USE_COUNT; + return err; +#endif /* CONFIG_ATM_BR2684_IPFILTER */ + } + return -ENOIOCTLCMD; +} + +/* Never put more than 256 bytes in at once */ +static int br2684_proc_engine(loff_t pos, char *buf) +{ + struct list_head *lhd, *lhc; + struct br2684_dev *brdev; + struct br2684_vcc *brvcc; + list_for_each(lhd, &br2684_devs) { + brdev = list_entry_brdev(lhd); + if (pos-- == 0) + return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:" + "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name, + brdev->number, + brdev->net_dev.dev_addr[0], + brdev->net_dev.dev_addr[1], + brdev->net_dev.dev_addr[2], + brdev->net_dev.dev_addr[3], + brdev->net_dev.dev_addr[4], + brdev->net_dev.dev_addr[5], + brdev->mac_was_set ? "set" : "auto"); + list_for_each(lhc, &brdev->brvccs) { + brvcc = list_entry_brvcc(lhc); + if (pos-- == 0) + return sprintf(buf, " vcc %d.%d.%d: encaps=%s" +#ifndef FASTER_VERSION + ", failed copies %u/%u" +#endif /* FASTER_VERSION */ + "\n", brvcc->atmvcc->dev->number, + brvcc->atmvcc->vpi, brvcc->atmvcc->vci, + (brvcc->encaps == e_llc) ? "LLC" : "VC" +#ifndef FASTER_VERSION + , brvcc->copies_failed + , brvcc->copies_needed +#endif /* FASTER_VERSION */ + ); +#ifdef CONFIG_ATM_BR2684_IPFILTER +#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] +#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3) + if (brvcc->filter.netmask != 0 && pos-- == 0) + return sprintf(buf, " filter=%d.%d.%d.%d/" + "%d.%d.%d.%d\n", bs(prefix), bs(netmask)); +#undef bs +#undef b1 +#endif /* CONFIG_ATM_BR2684_IPFILTER */ + } + } + return 0; +} + +static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count, + loff_t *pos) +{ + unsigned long page; + int len = 0, x, left; + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + left = PAGE_SIZE - 256; + if (count < left) + left = count; + read_lock(&devs_lock); + for (;;) { + x = br2684_proc_engine(*pos, &((char *) page)[len]); + if (x == 0) + break; + if (x > left) + /* + * This should only happen if the user passed in + * a "count" too small for even one line + */ + x = -EINVAL; + if (x < 0) { + len = x; + break; + } + len += x; + left -= x; + (*pos)++; + if (left < 256) + break; + } + read_unlock(&devs_lock); + if (len > 0 && copy_to_user(buf, (char *) page, len)) + len = -EFAULT; + free_page(page); + return len; +} + +static struct file_operations br2684_proc_operations = { + read: br2684_proc_read, +}; + +extern struct proc_dir_entry *atm_proc_root; /* from proc.c */ + +extern int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); + +/* the following avoids some spurious warnings from the compiler */ +#define UNUSED __attribute__((unused)) + +static int __init UNUSED br2684_init(void) +{ + struct proc_dir_entry *p; + if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL) + return -ENOMEM; + p->proc_fops = &br2684_proc_operations; + br2684_ioctl_hook = br2684_ioctl; + return 0; +} + +static void __exit UNUSED br2684_exit(void) +{ + struct br2684_dev *brdev; + br2684_ioctl_hook = NULL; + remove_proc_entry("br2684", atm_proc_root); + while (!list_empty(&br2684_devs)) { + brdev = list_entry_brdev(br2684_devs.next); + unregister_netdev(&brdev->net_dev); + list_del(&brdev->br2684_devs); + kfree(brdev); + } +} + +module_init(br2684_init); +module_exit(br2684_exit); + +MODULE_AUTHOR("Marcell GAL"); +MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5"); +MODULE_LICENSE("GPL"); diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c Mon May 12 20:55:49 2003 +++ b/net/atm/clip.c Mon May 12 20:55:49 2003 @@ -127,6 +127,8 @@ struct atmarp_entry *entry = NEIGH2ENTRY(n); struct clip_vcc *clip_vcc; + write_lock(&n->lock); + for (clip_vcc = entry->vccs; clip_vcc; clip_vcc = clip_vcc->next) if (clip_vcc->idle_timeout && @@ -141,6 +143,7 @@ if (entry->vccs || time_before(jiffies, entry->expires)) { np = &n->next; + write_unlock(&n->lock); continue; } if (atomic_read(&n->refcnt) > 1) { @@ -152,11 +155,13 @@ NULL) dev_kfree_skb(skb); np = &n->next; + write_unlock(&n->lock); continue; } *np = n->next; DPRINTK("expired neigh %p\n",n); n->dead = 1; + write_unlock(&n->lock); neigh_release(n); } } @@ -218,6 +223,7 @@ clip_vcc->last_use = jiffies; PRIV(skb->dev)->stats.rx_packets++; PRIV(skb->dev)->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } @@ -427,7 +433,6 @@ ((u16 *) here)[3] = skb->protocol; } atomic_add(skb->truesize,&vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); diff -Nru a/net/atm/common.c b/net/atm/common.c --- a/net/atm/common.c Mon May 12 20:55:49 2003 +++ b/net/atm/common.c Mon May 12 20:55:49 2003 @@ -62,6 +62,13 @@ EXPORT_SYMBOL(pppoatm_ioctl_hook); #endif +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) +int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); +#ifdef CONFIG_ATM_BR2684_MODULE +EXPORT_SYMBOL(br2684_ioctl_hook); +#endif +#endif + #include "resources.h" /* atm_find_dev */ #include "common.h" /* prototypes */ #include "protocols.h" /* atm_init_ */ @@ -91,7 +98,7 @@ } while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize); - atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &vcc->sk->wmem_alloc); return skb; } @@ -107,7 +114,6 @@ vcc = atm_sk(sk); memset(&vcc->flags,0,sizeof(vcc->flags)); vcc->dev = NULL; - vcc->alloc_tx = alloc_tx; vcc->callback = NULL; memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); @@ -120,7 +126,6 @@ vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ vcc->atm_options = vcc->aal_options = 0; init_waitqueue_head(&vcc->sleep); - skb_queue_head_init(&vcc->listenq); sk->sleep = &vcc->sleep; sock->sk = sk; return 0; @@ -138,9 +143,7 @@ if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { atm_return(vcc,skb->truesize); - if (vcc->dev->ops->free_rx_skb) - vcc->dev->ops->free_rx_skb(vcc,skb); - else kfree_skb(skb); + kfree_skb(skb); } spin_lock (&atm_dev_lock); fops_put (vcc->dev->ops); @@ -388,31 +391,8 @@ (unsigned long) buff,eff_len); DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize); atm_return(vcc,skb->truesize); - if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */ - /* iovcnt set, use scatter-gather for receive */ - int el, cnt; - struct iovec *iov = (struct iovec *)skb->data; - unsigned char *p = (unsigned char *)buff; - - el = eff_len; - error = 0; - for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) { -/*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/ - error = copy_to_user(p,iov->iov_base, - (iov->iov_len > el) ? el : iov->iov_len) ? - -EFAULT : 0; - if (error) break; - p += iov->iov_len; - el -= (iov->iov_len > el)?el:iov->iov_len; - iov++; - } - if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); - else vcc->dev->ops->free_rx_skb(vcc, skb); - return error ? error : eff_len; - } error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; - if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb); - else vcc->dev->ops->free_rx_skb(vcc, skb); + kfree_skb(skb); return error ? error : eff_len; } @@ -444,7 +424,7 @@ add_wait_queue(&vcc->sleep,&wait); set_current_state(TASK_INTERRUPTIBLE); error = 0; - while (!(skb = vcc->alloc_tx(vcc,eff))) { + while (!(skb = alloc_tx(vcc,eff))) { if (m->msg_flags & MSG_DONTWAIT) { error = -EAGAIN; break; @@ -469,7 +449,6 @@ remove_wait_queue(&vcc->sleep,&wait); if (error) return error; skb->dev = NULL; /* for paths shared with net_device interfaces */ - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; if (copy_from_user(skb_put(skb,size),buff,size)) { kfree_skb(skb); @@ -489,15 +468,14 @@ vcc = ATM_SD(sock); poll_wait(file,&vcc->sleep,wait); mask = 0; - if (skb_peek(&vcc->sk->receive_queue) || skb_peek(&vcc->listenq)) + if (skb_peek(&vcc->sk->receive_queue)) mask |= POLLIN | POLLRDNORM; if (test_bit(ATM_VF_RELEASED,&vcc->flags) || test_bit(ATM_VF_CLOSE,&vcc->flags)) mask |= POLLHUP; if (sock->state != SS_CONNECTING) { if (vcc->qos.txtp.traffic_class != ATM_NONE && - vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc)+ - ATM_PDU_OVHD <= vcc->sk->sndbuf) + vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc) <= vcc->sk->sndbuf) mask |= POLLOUT | POLLWRNORM; } else if (vcc->reply != WAITING) { @@ -564,7 +542,7 @@ goto done; } ret_val = put_user(vcc->sk->sndbuf- - atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD, + atomic_read(&vcc->sk->wmem_alloc), (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: @@ -781,6 +759,13 @@ #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) if (pppoatm_ioctl_hook) { ret_val = pppoatm_ioctl_hook(vcc, cmd, arg); + if (ret_val != -ENOIOCTLCMD) + goto done; + } +#endif +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) + if (br2684_ioctl_hook) { + ret_val = br2684_ioctl_hook(vcc, cmd, arg); if (ret_val != -ENOIOCTLCMD) goto done; } diff -Nru a/net/atm/lec.c b/net/atm/lec.c --- a/net/atm/lec.c Mon May 12 20:55:47 2003 +++ b/net/atm/lec.c Mon May 12 20:55:47 2003 @@ -204,7 +204,6 @@ if (atm_may_send(vcc, skb->len)) { atomic_add(skb->truesize, &vcc->sk->wmem_alloc); ATM_SKB(skb)->vcc = vcc; - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = vcc->atm_options; priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; @@ -302,7 +301,7 @@ #endif min_frame_size = LEC_MINIMUM_8023_SIZE; if (skb->len < min_frame_size) { - if (skb->truesize < min_frame_size) { + if ((skb->len + skb_tailroom(skb)) < min_frame_size) { skb2 = skb_copy_expand(skb, 0, min_frame_size - skb->truesize, GFP_ATOMIC); dev_kfree_skb(skb); @@ -399,7 +398,7 @@ int i; char *tmp; /* FIXME */ - atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); mesg = (struct atmlec_msg *)skb->data; tmp = skb->data; tmp += sizeof(struct atmlec_msg); @@ -715,6 +714,7 @@ skb->protocol = eth_type_trans(skb, dev); priv->stats.rx_packets++; priv->stats.rx_bytes += skb->len; + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } } diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c --- a/net/atm/mpc.c Mon May 12 20:55:48 2003 +++ b/net/atm/mpc.c Mon May 12 20:55:48 2003 @@ -324,7 +324,9 @@ return; } -static const char * __attribute__ ((unused)) mpoa_device_type_string(char type) +static const char *mpoa_device_type_string(char type) __attribute__ ((unused)); + +static const char *mpoa_device_type_string(char type) { switch(type) { case NON_MPOA: @@ -429,7 +431,7 @@ if (tlvs == NULL) return; } if (end_of_tlvs - tlvs != 0) - printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n", + printk("mpoa: (%s) lane2_assoc_ind: ignoring %Zd bytes of trailing TLV carbage\n", dev->name, end_of_tlvs - tlvs); return; } @@ -521,7 +523,6 @@ } atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */ ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; @@ -730,6 +731,7 @@ eg->packets_rcvd++; mpc->eg_ops->put(eg); + memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(new_skb); return; @@ -861,7 +863,7 @@ struct mpoa_client *mpc = find_mpc_by_vcc(vcc); struct k_message *mesg = (struct k_message*)skb->data; - atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); if (mpc == NULL) { printk("mpoa: msg_from_mpoad: no mpc found\n"); diff -Nru a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c --- a/net/atm/mpoa_proc.c Mon May 12 20:55:48 2003 +++ b/net/atm/mpoa_proc.c Mon May 12 20:55:48 2003 @@ -42,6 +42,7 @@ * Define allowed FILE OPERATIONS */ static struct file_operations mpc_file_operations = { + .owner = THIS_MODULE, .read = proc_mpc_read, .write = proc_mpc_write, }; diff -Nru a/net/atm/pppoatm.c b/net/atm/pppoatm.c --- a/net/atm/pppoatm.c Mon May 12 20:55:47 2003 +++ b/net/atm/pppoatm.c Mon May 12 20:55:47 2003 @@ -232,7 +232,6 @@ return 1; } atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n", pvcc->chan.unit, skb, ATM_SKB(skb)->vcc, diff -Nru a/net/atm/proc.c b/net/atm/proc.c --- a/net/atm/proc.c Mon May 12 20:55:45 2003 +++ b/net/atm/proc.c Mon May 12 20:55:45 2003 @@ -57,10 +57,12 @@ loff_t *pos); static struct file_operations proc_dev_atm_operations = { + .owner = THIS_MODULE, .read = proc_dev_atm_read, }; static struct file_operations proc_spec_atm_operations = { + .owner = THIS_MODULE, .read = proc_spec_atm_read, }; diff -Nru a/net/atm/raw.c b/net/atm/raw.c --- a/net/atm/raw.c Mon May 12 20:55:48 2003 +++ b/net/atm/raw.c Mon May 12 20:55:48 2003 @@ -37,7 +37,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize); - atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); dev_kfree_skb_any(skb); wake_up(&vcc->sleep); } diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c --- a/net/atm/signaling.c Mon May 12 20:55:48 2003 +++ b/net/atm/signaling.c Mon May 12 20:55:48 2003 @@ -98,7 +98,7 @@ struct atm_vcc *session_vcc; msg = (struct atmsvc_msg *) skb->data; - atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type, (unsigned long) msg->vcc); vcc = *(struct atm_vcc **) &msg->vcc; @@ -129,12 +129,12 @@ case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; DPRINTK("as_indicate!!!\n"); - if (!vcc->backlog_quota) { + if (vcc->sk->ack_backlog == vcc->sk->max_ack_backlog) { sigd_enq(0,as_reject,vcc,NULL,NULL); return 0; } - vcc->backlog_quota--; - skb_queue_tail(&vcc->listenq,skb); + vcc->sk->ack_backlog++; + skb_queue_tail(&vcc->sk->receive_queue,skb); if (vcc->callback) { DPRINTK("waking vcc->sleep 0x%p\n", &vcc->sleep); diff -Nru a/net/atm/svc.c b/net/atm/svc.c --- a/net/atm/svc.c Mon May 12 20:55:47 2003 +++ b/net/atm/svc.c Mon May 12 20:55:47 2003 @@ -64,8 +64,8 @@ DPRINTK("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { - sigd_enq(vcc,as_close,NULL,NULL,NULL); add_wait_queue(&vcc->sleep,&wait); + sigd_enq(vcc,as_close,NULL,NULL,NULL); while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { set_current_state(TASK_UNINTERRUPTIBLE); schedule(); @@ -74,7 +74,7 @@ } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ - while ((skb = skb_dequeue(&vcc->listenq))) { + while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { DPRINTK("LISTEN REL\n"); sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); dev_kfree_skb(skb); @@ -124,8 +124,8 @@ if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; vcc->local = *addr; vcc->reply = WAITING; - sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); add_wait_queue(&vcc->sleep,&wait); + sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { set_current_state(TASK_UNINTERRUPTIBLE); schedule(); @@ -169,12 +169,13 @@ !vcc->qos.rxtp.traffic_class) return -EINVAL; vcc->remote = *addr; vcc->reply = WAITING; + add_wait_queue(&vcc->sleep,&wait); sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); if (flags & O_NONBLOCK) { + remove_wait_queue(&vcc->sleep,&wait); sock->state = SS_CONNECTING; return -EINPROGRESS; } - add_wait_queue(&vcc->sleep,&wait); error = 0; while (vcc->reply == WAITING && sigd) { set_current_state(TASK_INTERRUPTIBLE); @@ -243,8 +244,8 @@ /* let server handle listen on unbound sockets */ if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; vcc->reply = WAITING; - sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); add_wait_queue(&vcc->sleep,&wait); + sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { set_current_state(TASK_UNINTERRUPTIBLE); schedule(); @@ -252,7 +253,7 @@ remove_wait_queue(&vcc->sleep,&wait); if (!sigd) return -EUNATCH; set_bit(ATM_VF_LISTEN,&vcc->flags); - vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; + vcc->sk->max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; return vcc->reply; } @@ -276,7 +277,7 @@ DECLARE_WAITQUEUE(wait,current); add_wait_queue(&old_vcc->sleep,&wait); - while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) { + while (!(skb = skb_dequeue(&old_vcc->sk->receive_queue)) && sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { error = old_vcc->reply; @@ -305,7 +306,7 @@ error = atm_connect(newsock,msg->pvc.sap_addr.itf, msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); dev_kfree_skb(skb); - old_vcc->backlog_quota++; + old_vcc->sk->ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); @@ -313,8 +314,8 @@ } /* wait should be short, so we ignore the non-blocking flag */ new_vcc->reply = WAITING; - sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); add_wait_queue(&new_vcc->sleep,&wait); + sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); while (new_vcc->reply == WAITING && sigd) { set_current_state(TASK_UNINTERRUPTIBLE); schedule(); @@ -347,8 +348,8 @@ DECLARE_WAITQUEUE(wait,current); vcc->reply = WAITING; - sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); add_wait_queue(&vcc->sleep,&wait); + sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { set_current_state(TASK_UNINTERRUPTIBLE); diff -Nru a/net/bluetooth/hci_proc.c b/net/bluetooth/hci_proc.c --- a/net/bluetooth/hci_proc.c Mon May 12 20:55:45 2003 +++ b/net/bluetooth/hci_proc.c Mon May 12 20:55:45 2003 @@ -115,6 +115,7 @@ } static struct file_operations inq_seq_fops = { + .owner = THIS_MODULE, .open = inq_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c --- a/net/bluetooth/l2cap.c Mon May 12 20:55:47 2003 +++ b/net/bluetooth/l2cap.c Mon May 12 20:55:47 2003 @@ -2048,6 +2048,7 @@ } static struct file_operations l2cap_seq_fops = { + .owner = THIS_MODULE, .open = l2cap_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c --- a/net/bluetooth/rfcomm/core.c Mon May 12 20:55:44 2003 +++ b/net/bluetooth/rfcomm/core.c Mon May 12 20:55:44 2003 @@ -1824,6 +1824,7 @@ } static struct file_operations rfcomm_seq_fops = { + .owner = THIS_MODULE, .open = rfcomm_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c --- a/net/bluetooth/rfcomm/sock.c Mon May 12 20:55:47 2003 +++ b/net/bluetooth/rfcomm/sock.c Mon May 12 20:55:47 2003 @@ -821,6 +821,7 @@ } static struct file_operations rfcomm_seq_fops = { + .owner = THIS_MODULE, .open = rfcomm_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c --- a/net/bluetooth/sco.c Mon May 12 20:55:45 2003 +++ b/net/bluetooth/sco.c Mon May 12 20:55:45 2003 @@ -933,6 +933,7 @@ } static struct file_operations sco_seq_fops = { + .owner = THIS_MODULE, .open = sco_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c --- a/net/bridge/br_fdb.c Mon May 12 20:55:44 2003 +++ b/net/bridge/br_fdb.c Mon May 12 20:55:44 2003 @@ -20,25 +20,19 @@ #include #include "br_private.h" -static __inline__ unsigned long __timeout(struct net_bridge *br) +/* if topology_changing then use forward_delay (default 15 sec) + * otherwise keep longer (default 5 minutes) + */ +static __inline__ unsigned long hold_time(const struct net_bridge *br) { - unsigned long timeout; - - timeout = jiffies - br->ageing_time; - if (br->topology_change) - timeout = jiffies - br->forward_delay; - - return timeout; + return br->topology_change ? br->forward_delay : br->ageing_time; } -static __inline__ int has_expired(struct net_bridge *br, - struct net_bridge_fdb_entry *fdb) +static __inline__ int has_expired(const struct net_bridge *br, + const struct net_bridge_fdb_entry *fdb) { - if (!fdb->is_static && - time_before_eq(fdb->ageing_timer, __timeout(br))) - return 1; - - return 0; + return !fdb->is_static + && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); } static __inline__ void copy_fdb(struct __fdb_entry *ent, @@ -52,7 +46,7 @@ : ((jiffies - f->ageing_timer) * USER_HZ) / HZ; } -static __inline__ int br_mac_hash(unsigned char *mac) +static __inline__ int br_mac_hash(const unsigned char *mac) { unsigned long x; @@ -68,7 +62,14 @@ return x & (BR_HASH_SIZE - 1); } -void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr) +static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f) +{ + hlist_del(&f->hlist); + list_del(&f->age_list); + br_fdb_put(f); +} + +void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) { struct net_bridge *br; int i; @@ -98,25 +99,29 @@ write_unlock_bh(&br->hash_lock); } -void br_fdb_cleanup(struct net_bridge *br) +void br_fdb_cleanup(unsigned long _data) { - int i; - unsigned long timeout; - - timeout = __timeout(br); + struct net_bridge *br = (struct net_bridge *)_data; + struct list_head *l, *n; + unsigned long delay; write_lock_bh(&br->hash_lock); - for (i=0;ihash[i]) { - struct net_bridge_fdb_entry *f - = hlist_entry(h, struct net_bridge_fdb_entry, hlist); - if (!f->is_static && - time_before_eq(f->ageing_timer, timeout)) { - hlist_del(&f->hlist); - br_fdb_put(f); + delay = hold_time(br); + + list_for_each_safe(l, n, &br->age_list) { + struct net_bridge_fdb_entry *f + = list_entry(l, struct net_bridge_fdb_entry, age_list); + unsigned long expires = f->ageing_timer + delay; + + if (time_before_eq(expires, jiffies)) { + if (!f->is_static) { + pr_debug("expire age %lu jiffies %lu\n", + f->ageing_timer, jiffies); + fdb_delete(f); } + } else { + mod_timer(&br->gc_timer, expires); + break; } } write_unlock_bh(&br->hash_lock); @@ -134,8 +139,7 @@ struct net_bridge_fdb_entry *f = hlist_entry(h, struct net_bridge_fdb_entry, hlist); if (f->dst == p) { - hlist_del(&f->hlist); - br_fdb_put(f); + fdb_delete(f); } } } @@ -237,55 +241,46 @@ return num; } -static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb, - struct net_bridge_port *source, - int is_local) -{ - if (!fdb->is_static || is_local) { - fdb->dst = source; - fdb->is_local = is_local; - fdb->is_static = is_local; - fdb->ageing_timer = jiffies; - } -} - -void br_fdb_insert(struct net_bridge *br, - struct net_bridge_port *source, - unsigned char *addr, - int is_local) +void br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, + const unsigned char *addr, int is_local) { struct hlist_node *h; struct net_bridge_fdb_entry *fdb; - int hash; - - hash = br_mac_hash(addr); + int hash = br_mac_hash(addr); write_lock_bh(&br->hash_lock); hlist_for_each(h, &br->hash[hash]) { fdb = hlist_entry(h, struct net_bridge_fdb_entry, hlist); if (!fdb->is_local && !memcmp(fdb->addr.addr, addr, ETH_ALEN)) { - __fdb_possibly_replace(fdb, source, is_local); - write_unlock_bh(&br->hash_lock); - return; + if (likely(!fdb->is_static || is_local)) { + /* move to end of age list */ + list_del(&fdb->age_list); + goto update; + } + goto out; } - } fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC); - if (fdb == NULL) { - write_unlock_bh(&br->hash_lock); - return; - } + if (fdb == NULL) + goto out; memcpy(fdb->addr.addr, addr, ETH_ALEN); atomic_set(&fdb->use_count, 1); + hlist_add_head(&fdb->hlist, &br->hash[hash]); + + if (!timer_pending(&br->gc_timer)) { + br->gc_timer.expires = jiffies + hold_time(br); + add_timer(&br->gc_timer); + } + + update: fdb->dst = source; fdb->is_local = is_local; fdb->is_static = is_local; fdb->ageing_timer = jiffies; - - hlist_add_head(&fdb->hlist, &br->hash[hash]); - + list_add_tail(&fdb->age_list, &br->age_list); + out: write_unlock_bh(&br->hash_lock); } diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c --- a/net/bridge/br_if.c Mon May 12 20:55:49 2003 +++ b/net/bridge/br_if.c Mon May 12 20:55:49 2003 @@ -84,8 +84,6 @@ memset(br, 0, sizeof(*br)); dev = &br->dev; - init_timer(&br->tick); - strncpy(dev->name, name, IFNAMSIZ); dev->priv = br; dev->priv_flags = IFF_EBRIDGE; @@ -109,12 +107,10 @@ br->bridge_forward_delay = br->forward_delay = 15 * HZ; br->topology_change = 0; br->topology_change_detected = 0; - br_timer_clear(&br->hello_timer); - br_timer_clear(&br->tcn_timer); - br_timer_clear(&br->topology_change_timer); - br->ageing_time = 300 * HZ; - br->gc_interval = 4 * HZ; + INIT_LIST_HEAD(&br->age_list); + + br_stp_timer_init(br); return br; } diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c --- a/net/bridge/br_input.c Mon May 12 20:55:45 2003 +++ b/net/bridge/br_input.c Mon May 12 20:55:45 2003 @@ -143,6 +143,9 @@ return -1; } + if (!memcmp(p->br->dev.dev_addr, dest, ETH_ALEN)) + skb->pkt_type = PACKET_HOST; + NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, br_handle_frame_finish); rcu_read_unlock(); diff -Nru a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c --- a/net/bridge/br_ioctl.c Mon May 12 20:55:44 2003 +++ b/net/bridge/br_ioctl.c Mon May 12 20:55:44 2003 @@ -32,9 +32,10 @@ } /* Report time remaining in user HZ */ -static unsigned long timer_residue(const struct br_timer *timer) +static unsigned long timer_residue(const struct timer_list *timer) { - return ticks_to_user(timer->running ? (jiffies - timer->expires) : 0); + return ticks_to_user(timer_pending(timer) + ? (timer->expires - jiffies) : 0); } static int br_ioctl_device(struct net_bridge *br, @@ -87,7 +88,6 @@ b.root_port = br->root_port; b.stp_enabled = br->stp_enabled; b.ageing_time = ticks_to_user(br->ageing_time); - b.gc_interval = ticks_to_user(br->gc_interval); b.hello_timer_value = timer_residue(&br->hello_timer); b.tcn_timer_value = timer_residue(&br->tcn_timer); b.topology_change_timer_value = timer_residue(&br->topology_change_timer); @@ -146,8 +146,7 @@ br->ageing_time = user_to_ticks(arg0); return 0; - case BRCTL_SET_GC_INTERVAL: - br->gc_interval = user_to_ticks(arg0); + case BRCTL_SET_GC_INTERVAL: /* no longer used */ return 0; case BRCTL_GET_PORT_INFO: diff -Nru a/net/bridge/br_private.h b/net/bridge/br_private.h --- a/net/bridge/br_private.h Mon May 12 20:55:45 2003 +++ b/net/bridge/br_private.h Mon May 12 20:55:45 2003 @@ -18,7 +18,6 @@ #include #include #include -#include "br_private_timer.h" #define BR_HASH_BITS 8 #define BR_HASH_SIZE (1 << BR_HASH_BITS) @@ -44,10 +43,11 @@ struct net_bridge_fdb_entry { struct hlist_node hlist; - atomic_t use_count; - mac_addr addr; struct net_bridge_port *dst; + struct list_head age_list; + atomic_t use_count; unsigned long ageing_timer; + mac_addr addr; unsigned is_local:1; unsigned is_static:1; }; @@ -71,10 +71,9 @@ unsigned config_pending:1; int priority; - struct br_timer forward_delay_timer; - struct br_timer hold_timer; - struct br_timer message_age_timer; - + struct timer_list forward_delay_timer; + struct timer_list hold_timer; + struct timer_list message_age_timer; struct rcu_head rcu; }; @@ -86,7 +85,7 @@ struct net_device_stats statistics; rwlock_t hash_lock; struct hlist_head hash[BR_HASH_SIZE]; - struct timer_list tick; + struct list_head age_list; /* STP */ bridge_id designated_root; @@ -103,13 +102,12 @@ unsigned topology_change:1; unsigned topology_change_detected:1; - struct br_timer hello_timer; - struct br_timer tcn_timer; - struct br_timer topology_change_timer; - struct br_timer gc_timer; + struct timer_list hello_timer; + struct timer_list tcn_timer; + struct timer_list topology_change_timer; + struct timer_list gc_timer; int ageing_time; - int gc_interval; }; extern struct notifier_block br_device_notifier; @@ -128,8 +126,8 @@ /* br_fdb.c */ extern void br_fdb_changeaddr(struct net_bridge_port *p, - unsigned char *newaddr); -extern void br_fdb_cleanup(struct net_bridge *br); + const unsigned char *newaddr); +extern void br_fdb_cleanup(unsigned long arg); extern void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p); extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, @@ -140,9 +138,9 @@ int maxnum, int offset); extern void br_fdb_insert(struct net_bridge *br, - struct net_bridge_port *source, - unsigned char *addr, - int is_local); + struct net_bridge_port *source, + const unsigned char *addr, + int is_local); /* br_forward.c */ extern void br_deliver(const struct net_bridge_port *to, @@ -188,10 +186,10 @@ extern void br_netfilter_fini(void); /* br_stp.c */ +extern void br_log_state(const struct net_bridge_port *p); extern struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no); extern void br_init_port(struct net_bridge_port *p); -extern port_id br_make_port_id(struct net_bridge_port *p); extern void br_become_designated_port(struct net_bridge_port *p); /* br_stp_if.c */ @@ -209,5 +207,9 @@ /* br_stp_bpdu.c */ extern void br_stp_handle_bpdu(struct sk_buff *skb); + +/* br_stp_timer.c */ +extern void br_stp_timer_init(struct net_bridge *br); +extern void br_stp_port_timer_init(struct net_bridge_port *p); #endif diff -Nru a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h --- a/net/bridge/br_private_stp.h Mon May 12 20:55:47 2003 +++ b/net/bridge/br_private_stp.h Mon May 12 20:55:47 2003 @@ -47,7 +47,6 @@ extern void br_port_state_selection(struct net_bridge *); extern void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu); extern void br_received_tcn_bpdu(struct net_bridge_port *p); -extern void br_tick(unsigned long __data); extern void br_transmit_config(struct net_bridge_port *p); extern void br_transmit_tcn(struct net_bridge *br); extern void br_topology_change_detection(struct net_bridge *br); diff -Nru a/net/bridge/br_private_timer.h b/net/bridge/br_private_timer.h --- a/net/bridge/br_private_timer.h Mon May 12 20:55:45 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ -/* - * Linux ethernet bridge - * - * Authors: - * Lennert Buytenhek - * - * $Id: br_private_timer.h,v 1.1 2000/02/18 16:47:13 davem Exp $ - * - * 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. - */ - -#ifndef _BR_PRIVATE_TIMER_H -#define _BR_PRIVATE_TIMER_H - -struct br_timer -{ - int running; - unsigned long expires; -}; - -extern __inline__ void br_timer_clear(struct br_timer *t) -{ - t->running = 0; -} - -extern __inline__ unsigned long br_timer_get_residue(struct br_timer *t) -{ - if (t->running) - return jiffies - t->expires; - - return 0; -} - -extern __inline__ void br_timer_set(struct br_timer *t, unsigned long x) -{ - t->expires = x; - t->running = 1; -} - -extern __inline__ int br_timer_is_running(struct br_timer *t) -{ - return t->running; -} - -extern __inline__ int br_timer_has_expired(struct br_timer *t, unsigned long to) -{ - return t->running && time_after_eq(jiffies, t->expires + to); -} - - -#endif diff -Nru a/net/bridge/br_stp.c b/net/bridge/br_stp.c --- a/net/bridge/br_stp.c Mon May 12 20:55:45 2003 +++ b/net/bridge/br_stp.c Mon May 12 20:55:45 2003 @@ -12,7 +12,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - #include #include #include @@ -20,6 +19,18 @@ #include "br_private.h" #include "br_private_stp.h" +static const char *br_port_state_names[] = { + "disabled", "learning", "forwarding", "blocking", +}; + +void br_log_state(const struct net_bridge_port *p) +{ + pr_info("%s: port %d(%s) entering %s state\n", + p->br->dev.name, p->port_no, p->dev->name, + br_port_state_names[p->state]); + +} + /* called under bridge lock */ struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no) { @@ -34,7 +45,8 @@ } /* called under bridge lock */ -static int br_should_become_root_port(struct net_bridge_port *p, int root_port) +static int br_should_become_root_port(const struct net_bridge_port *p, + int root_port) { struct net_bridge *br; struct net_bridge_port *rp; @@ -116,9 +128,12 @@ br->hello_time = br->bridge_hello_time; br->forward_delay = br->bridge_forward_delay; br_topology_change_detection(br); - br_timer_clear(&br->tcn_timer); - br_config_bpdu_generation(br); - br_timer_set(&br->hello_timer, jiffies); + del_timer(&br->tcn_timer); + + if (br->dev.flags & IFF_UP) { + br_config_bpdu_generation(br); + mod_timer(&br->hello_timer, jiffies + br->hello_time); + } } /* called under bridge lock */ @@ -127,7 +142,8 @@ struct br_config_bpdu bpdu; struct net_bridge *br; - if (br_timer_is_running(&p->hold_timer)) { + + if (timer_pending(&p->hold_timer)) { p->config_pending = 1; return; } @@ -142,12 +158,11 @@ bpdu.port_id = p->port_id; bpdu.message_age = 0; if (!br_is_root_bridge(br)) { - struct net_bridge_port *root; - unsigned long age; + struct net_bridge_port *root + = br_get_port(br, br->root_port); + bpdu.max_age = root->message_age_timer.expires - jiffies; - root = br_get_port(br, br->root_port); - age = br_timer_get_residue(&root->message_age_timer) + 1; - bpdu.message_age = age; + if (bpdu.max_age <= 0) bpdu.max_age = 1; } bpdu.max_age = br->max_age; bpdu.hello_time = br->hello_time; @@ -157,22 +172,26 @@ p->topology_change_ack = 0; p->config_pending = 0; - br_timer_set(&p->hold_timer, jiffies); + + mod_timer(&p->hold_timer, jiffies + BR_HOLD_TIME); } /* called under bridge lock */ -static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu) +static inline void br_record_config_information(struct net_bridge_port *p, + const struct br_config_bpdu *bpdu) { p->designated_root = bpdu->root; p->designated_cost = bpdu->root_path_cost; p->designated_bridge = bpdu->bridge_id; p->designated_port = bpdu->port_id; - br_timer_set(&p->message_age_timer, jiffies - bpdu->message_age); + mod_timer(&p->message_age_timer, jiffies + + (p->br->max_age - bpdu->message_age)); } /* called under bridge lock */ -static void br_record_config_timeout_values(struct net_bridge *br, struct br_config_bpdu *bpdu) +static inline void br_record_config_timeout_values(struct net_bridge *br, + const struct br_config_bpdu *bpdu) { br->max_age = bpdu->max_age; br->hello_time = bpdu->hello_time; @@ -187,7 +206,7 @@ } /* called under bridge lock */ -static int br_should_become_designated_port(struct net_bridge_port *p) +static int br_should_become_designated_port(const struct net_bridge_port *p) { struct net_bridge *br; int t; @@ -261,25 +280,28 @@ } /* called under bridge lock */ -static void br_topology_change_acknowledged(struct net_bridge *br) +static inline void br_topology_change_acknowledged(struct net_bridge *br) { br->topology_change_detected = 0; - br_timer_clear(&br->tcn_timer); + del_timer(&br->tcn_timer); } /* called under bridge lock */ void br_topology_change_detection(struct net_bridge *br) { - printk(KERN_INFO "%s: topology change detected", br->dev.name); + if (!(br->dev.flags & IFF_UP)) + return; + pr_info("%s: topology change detected", br->dev.name); if (br_is_root_bridge(br)) { printk(", propagating"); br->topology_change = 1; - br_timer_set(&br->topology_change_timer, jiffies); + mod_timer(&br->topology_change_timer, jiffies + + br->bridge_forward_delay + br->bridge_max_age); } else if (!br->topology_change_detected) { printk(", sending tcn bpdu"); br_transmit_tcn(br); - br_timer_set(&br->tcn_timer, jiffies); + mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); } printk("\n"); @@ -299,7 +321,7 @@ } /* called under bridge lock */ -static void br_reply(struct net_bridge_port *p) +static inline void br_reply(struct net_bridge_port *p) { br_transmit_config(p); } @@ -323,6 +345,7 @@ p->designated_port = p->port_id; } + /* called under bridge lock */ static void br_make_blocking(struct net_bridge_port *p) { @@ -332,11 +355,9 @@ p->state == BR_STATE_LEARNING) br_topology_change_detection(p->br); - printk(KERN_INFO "%s: port %i(%s) entering %s state\n", - p->br->dev.name, p->port_no, p->dev->name, "blocking"); - p->state = BR_STATE_BLOCKING; - br_timer_clear(&p->forward_delay_timer); + br_log_state(p); + del_timer(&p->forward_delay_timer); } } @@ -345,20 +366,12 @@ { if (p->state == BR_STATE_BLOCKING) { if (p->br->stp_enabled) { - printk(KERN_INFO "%s: port %i(%s) entering %s state\n", - p->br->dev.name, p->port_no, p->dev->name, - "listening"); - p->state = BR_STATE_LISTENING; } else { - printk(KERN_INFO "%s: port %i(%s) entering %s state\n", - p->br->dev.name, p->port_no, p->dev->name, - "learning"); - p->state = BR_STATE_LEARNING; } - br_timer_set(&p->forward_delay_timer, jiffies); - } + br_log_state(p); + mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); } } /* called under bridge lock */ @@ -373,7 +386,7 @@ p->topology_change_ack = 0; br_make_forwarding(p); } else if (br_is_designated_port(p)) { - br_timer_clear(&p->message_age_timer); + del_timer(&p->message_age_timer); br_make_forwarding(p); } else { p->config_pending = 0; @@ -381,11 +394,12 @@ br_make_blocking(p); } } + } } /* called under bridge lock */ -static void br_topology_change_acknowledge(struct net_bridge_port *p) +static inline void br_topology_change_acknowledge(struct net_bridge_port *p) { p->topology_change_ack = 1; br_transmit_config(p); @@ -396,20 +410,23 @@ { struct net_bridge *br; int was_root; - + br = p->br; was_root = br_is_root_bridge(br); + if (br_supersedes_port_info(p, bpdu)) { br_record_config_information(p, bpdu); br_configuration_update(br); br_port_state_selection(br); if (!br_is_root_bridge(br) && was_root) { - br_timer_clear(&br->hello_timer); + del_timer(&br->hello_timer); if (br->topology_change_detected) { - br_timer_clear(&br->topology_change_timer); + del_timer(&br->topology_change_timer); br_transmit_tcn(br); - br_timer_set(&br->tcn_timer, jiffies); + + mod_timer(&br->tcn_timer, + jiffies + br->bridge_hello_time); } } @@ -428,7 +445,7 @@ void br_received_tcn_bpdu(struct net_bridge_port *p) { if (br_is_designated_port(p)) { - printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n", + pr_info("%s: received tcn bpdu on port %i(%s)\n", p->br->dev.name, p->port_no, p->dev->name); br_topology_change_detection(p->br); diff -Nru a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c --- a/net/bridge/br_stp_if.c Mon May 12 20:55:48 2003 +++ b/net/bridge/br_stp_if.c Mon May 12 20:55:48 2003 @@ -20,7 +20,7 @@ #include "br_private.h" #include "br_private_stp.h" -__u16 br_make_port_id(struct net_bridge_port *p) +static inline __u16 br_make_port_id(const struct net_bridge_port *p) { return (p->priority << 8) | p->port_no; } @@ -33,33 +33,25 @@ p->state = BR_STATE_BLOCKING; p->topology_change_ack = 0; p->config_pending = 0; - br_timer_clear(&p->message_age_timer); - br_timer_clear(&p->forward_delay_timer); - br_timer_clear(&p->hold_timer); + + br_stp_port_timer_init(p); } /* called under bridge lock */ void br_stp_enable_bridge(struct net_bridge *br) { struct net_bridge_port *p; - struct timer_list *timer = &br->tick; spin_lock_bh(&br->lock); - init_timer(timer); - timer->data = (unsigned long) br; - timer->function = br_tick; - timer->expires = jiffies + 1; - add_timer(timer); - - br_timer_set(&br->hello_timer, jiffies); + br->hello_timer.expires = jiffies + br->hello_time; + add_timer(&br->hello_timer); br_config_bpdu_generation(br); list_for_each_entry(p, &br->port_list, list) { if (p->dev->flags & IFF_UP) br_stp_enable_port(p); - } - br_timer_set(&br->gc_timer, jiffies); + } spin_unlock_bh(&br->lock); } @@ -68,22 +60,22 @@ { struct net_bridge_port *p; - spin_lock_bh(&br->lock); - br->topology_change = 0; - br->topology_change_detected = 0; - br_timer_clear(&br->hello_timer); - br_timer_clear(&br->topology_change_timer); - br_timer_clear(&br->tcn_timer); - br_timer_clear(&br->gc_timer); - br_fdb_cleanup(br); - + spin_lock(&br->lock); list_for_each_entry(p, &br->port_list, list) { if (p->state != BR_STATE_DISABLED) br_stp_disable_port(p); + } - spin_unlock_bh(&br->lock); - del_timer_sync(&br->tick); + br->topology_change = 0; + br->topology_change_detected = 0; + spin_unlock(&br->lock); + + del_timer_sync(&br->hello_timer); + del_timer_sync(&br->topology_change_timer); + del_timer_sync(&br->tcn_timer); + del_timer_sync(&br->gc_timer); + } /* called under bridge lock */ @@ -108,10 +100,13 @@ p->state = BR_STATE_DISABLED; p->topology_change_ack = 0; p->config_pending = 0; - br_timer_clear(&p->message_age_timer); - br_timer_clear(&p->forward_delay_timer); - br_timer_clear(&p->hold_timer); + + del_timer(&p->message_age_timer); + del_timer(&p->forward_delay_timer); + del_timer(&p->hold_timer); + br_configuration_update(br); + br_port_state_selection(br); if (br_is_root_bridge(br) && !wasroot) diff -Nru a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c --- a/net/bridge/br_stp_timer.c Mon May 12 20:55:46 2003 +++ b/net/bridge/br_stp_timer.c Mon May 12 20:55:46 2003 @@ -20,51 +20,59 @@ #include "br_private.h" #include "br_private_stp.h" -static void dump_bridge_id(bridge_id *id) -{ - printk("%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", id->prio[0], - id->prio[1], id->addr[0], id->addr[1], id->addr[2], id->addr[3], - id->addr[4], id->addr[5]); -} - /* called under bridge lock */ -static int br_is_designated_for_some_port(struct net_bridge *br) +static int br_is_designated_for_some_port(const struct net_bridge *br) { struct net_bridge_port *p; list_for_each_entry(p, &br->port_list, list) { if (p->state != BR_STATE_DISABLED && - !memcmp(&p->designated_bridge, &br->bridge_id, 8)) + !memcmp(&p->designated_bridge, &br->bridge_id, 8)) return 1; } return 0; } -/* called under bridge lock */ -static void br_hello_timer_expired(struct net_bridge *br) +static void br_hello_timer_expired(unsigned long arg) { - br_config_bpdu_generation(br); - br_timer_set(&br->hello_timer, jiffies); + struct net_bridge *br = (struct net_bridge *)arg; + + pr_debug("%s: hello timer expired\n", br->dev.name); + spin_lock_bh(&br->lock); + if (br->dev.flags & IFF_UP) { + br_config_bpdu_generation(br); + + br->hello_timer.expires = jiffies + br->hello_time; + add_timer(&br->hello_timer); + } + spin_unlock_bh(&br->lock); } -/* called under bridge lock */ -static void br_message_age_timer_expired(struct net_bridge_port *p) +static void br_message_age_timer_expired(unsigned long arg) { - struct net_bridge *br; + struct net_bridge_port *p = (struct net_bridge_port *) arg; + struct net_bridge *br = p->br; + const bridge_id *id = &p->designated_bridge; int was_root; - br = p->br; - printk(KERN_INFO "%s: ", br->dev.name); - printk("neighbour "); - dump_bridge_id(&p->designated_bridge); - printk(" lost on port %i(%s)\n", p->port_no, p->dev->name); + if (p->state == BR_STATE_DISABLED) + return; + + + pr_info("%s: neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s)\n", + br->dev.name, + id->prio[0], id->prio[1], + id->addr[0], id->addr[1], id->addr[2], + id->addr[3], id->addr[4], id->addr[5], + p->port_no, p->dev->name); /* * According to the spec, the message age timer cannot be * running when we are the root bridge. So.. this was_root * check is redundant. I'm leaving it in for now, though. */ + spin_lock_bh(&br->lock); was_root = br_is_root_bridge(br); br_become_designated_port(p); @@ -72,107 +80,101 @@ br_port_state_selection(br); if (br_is_root_bridge(br) && !was_root) br_become_root_bridge(br); + spin_unlock_bh(&br->lock); } -/* called under bridge lock */ -static void br_forward_delay_timer_expired(struct net_bridge_port *p) +static void br_forward_delay_timer_expired(unsigned long arg) { - if (p->state == BR_STATE_LISTENING) { - printk(KERN_INFO "%s: port %i(%s) entering %s state\n", - p->br->dev.name, p->port_no, p->dev->name, "learning"); + struct net_bridge_port *p = (struct net_bridge_port *) arg; + struct net_bridge *br = p->br; + pr_debug("%s: %d(%s) forward delay timer\n", + br->dev.name, p->port_no, p->dev->name); + spin_lock_bh(&br->lock); + if (p->state == BR_STATE_LISTENING) { p->state = BR_STATE_LEARNING; - br_timer_set(&p->forward_delay_timer, jiffies); + p->forward_delay_timer.expires = jiffies + br->forward_delay; + add_timer(&p->forward_delay_timer); } else if (p->state == BR_STATE_LEARNING) { - printk(KERN_INFO "%s: port %i(%s) entering %s state\n", - p->br->dev.name, p->port_no, p->dev->name, "forwarding"); - p->state = BR_STATE_FORWARDING; - if (br_is_designated_for_some_port(p->br)) - br_topology_change_detection(p->br); + if (br_is_designated_for_some_port(br)) + br_topology_change_detection(br); } + br_log_state(p); + spin_unlock_bh(&br->lock); } -/* called under bridge lock */ -static void br_tcn_timer_expired(struct net_bridge *br) +static void br_tcn_timer_expired(unsigned long arg) { - printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->dev.name); - br_transmit_tcn(br); - br_timer_set(&br->tcn_timer, jiffies); + struct net_bridge *br = (struct net_bridge *) arg; + + pr_debug("%s: tcn timer expired\n", br->dev.name); + spin_lock_bh(&br->lock); + if (br->dev.flags & IFF_UP) { + br_transmit_tcn(br); + + br->tcn_timer.expires = jiffies + br->bridge_hello_time; + add_timer(&br->tcn_timer); + } + spin_unlock_bh(&br->lock); } -/* called under bridge lock */ -static void br_topology_change_timer_expired(struct net_bridge *br) +static void br_topology_change_timer_expired(unsigned long arg) { + struct net_bridge *br = (struct net_bridge *) arg; + + pr_debug("%s: topo change timer expired\n", br->dev.name); + spin_lock_bh(&br->lock); br->topology_change_detected = 0; br->topology_change = 0; + spin_unlock_bh(&br->lock); } -/* called under bridge lock */ -static void br_hold_timer_expired(struct net_bridge_port *p) +static void br_hold_timer_expired(unsigned long arg) { + struct net_bridge_port *p = (struct net_bridge_port *) arg; + + pr_debug("%s: %d(%s) hold timer expired\n", + p->br->dev.name, p->port_no, p->dev->name); + + spin_lock_bh(&p->br->lock); if (p->config_pending) br_transmit_config(p); + spin_unlock_bh(&p->br->lock); } -/* called under bridge lock */ -static void br_check_port_timers(struct net_bridge_port *p) +static inline void br_timer_init(struct timer_list *timer, + void (*_function)(unsigned long), + unsigned long _data) { - if (br_timer_has_expired(&p->message_age_timer, p->br->max_age)) { - br_timer_clear(&p->message_age_timer); - br_message_age_timer_expired(p); - } - - if (br_timer_has_expired(&p->forward_delay_timer, p->br->forward_delay)) { - br_timer_clear(&p->forward_delay_timer); - br_forward_delay_timer_expired(p); - } - - if (br_timer_has_expired(&p->hold_timer, BR_HOLD_TIME)) { - br_timer_clear(&p->hold_timer); - br_hold_timer_expired(p); - } + init_timer(timer); + timer->function = _function; + timer->data = _data; } -/* called under bridge lock */ -static void br_check_timers(struct net_bridge *br) +void br_stp_timer_init(struct net_bridge *br) { - struct net_bridge_port *p; + br_timer_init(&br->hello_timer, br_hello_timer_expired, + (unsigned long) br); - if (br_timer_has_expired(&br->gc_timer, br->gc_interval)) { - br_timer_set(&br->gc_timer, jiffies); - br_fdb_cleanup(br); - } + br_timer_init(&br->tcn_timer, br_tcn_timer_expired, + (unsigned long) br); - if (br_timer_has_expired(&br->hello_timer, br->hello_time)) { - br_timer_clear(&br->hello_timer); - br_hello_timer_expired(br); - } - - if (br_timer_has_expired(&br->tcn_timer, br->bridge_hello_time)) { - br_timer_clear(&br->tcn_timer); - br_tcn_timer_expired(br); - } - - if (br_timer_has_expired(&br->topology_change_timer, br->bridge_forward_delay + br->bridge_max_age)) { - br_timer_clear(&br->topology_change_timer); - br_topology_change_timer_expired(br); - } + br_timer_init(&br->topology_change_timer, + br_topology_change_timer_expired, + (unsigned long) br); - list_for_each_entry(p, &br->port_list, list) { - if (p->state != BR_STATE_DISABLED) - br_check_port_timers(p); - } + br_timer_init(&br->gc_timer, br_fdb_cleanup, (unsigned long) br); } -void br_tick(unsigned long __data) +void br_stp_port_timer_init(struct net_bridge_port *p) { - struct net_bridge *br = (struct net_bridge *)__data; + br_timer_init(&p->message_age_timer, br_message_age_timer_expired, + (unsigned long) p); - if (spin_trylock_bh(&br->lock)) { - br_check_timers(br); - spin_unlock_bh(&br->lock); - } - br->tick.expires = jiffies + 1; - add_timer(&br->tick); -} + br_timer_init(&p->forward_delay_timer, br_forward_delay_timer_expired, + (unsigned long) p); + + br_timer_init(&p->hold_timer, br_hold_timer_expired, + (unsigned long) p); +} diff -Nru a/net/compat.c b/net/compat.c --- a/net/compat.c Mon May 12 20:55:47 2003 +++ b/net/compat.c Mon May 12 20:55:47 2003 @@ -27,8 +27,6 @@ #include #include -#define AA(__x) ((unsigned long)(__x)) - static inline int iov_from_user_compat_to_kern(struct iovec *kiov, struct compat_iovec *uiov32, int niov) @@ -393,31 +391,27 @@ struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval; struct sock_fprog kfprog; mm_segment_t old_fs; - compat_uptr_t uptr; - unsigned int fsize; int ret; + compat_uptr_t ptr; if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) || __get_user(kfprog.len, &fprog32->len) || - __get_user(uptr, &fprog32->filter)) + __get_user(ptr, &fprog32->filter)) return -EFAULT; + kfprog.filter = compat_ptr(ptr); - fsize = kfprog.len * sizeof(struct sock_filter); - kfprog.filter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); - if (kfprog.filter == NULL) - return -ENOMEM; - if (copy_from_user(kfprog.filter, compat_ptr(uptr), fsize)) { - kfree(kfprog.filter); + if (kfprog.len * sizeof(struct sock_filter) < kfprog.len) + return -EINVAL; + + if (verify_area(VERIFY_READ, kfprog.filter, + kfprog.len * sizeof(struct sock_filter))) return -EFAULT; - } old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *)&kfprog, sizeof(kfprog)); set_fs(old_fs); - - kfree(kfprog.filter); return ret; } diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Mon May 12 20:55:46 2003 +++ b/net/core/dev.c Mon May 12 20:55:46 2003 @@ -90,7 +90,6 @@ #include #include #include -#include #include #include #include @@ -170,8 +169,9 @@ * 86DD IPv6 */ -static struct packet_type *ptype_base[16]; /* 16 way hashed list */ -static struct packet_type *ptype_all; /* Taps */ +static spinlock_t ptype_lock = SPIN_LOCK_UNLOCKED; +static struct list_head ptype_base[16]; /* 16 way hashed list */ +static struct list_head ptype_all; /* Taps */ #ifdef OFFLINE_SAMPLE static void sample_queue(unsigned long dummy); @@ -239,14 +239,17 @@ * Add a protocol handler to the networking stack. The passed &packet_type * is linked into kernel lists and may not be freed until it has been * removed from the kernel lists. + * + * This call does not sleep therefore it can not + * guarantee all CPU's that are in middle of receiving packets + * will see the new packet type (until the next received packet). */ void dev_add_pack(struct packet_type *pt) { int hash; - br_write_lock_bh(BR_NETPROTO_LOCK); - + spin_lock_bh(&ptype_lock); #ifdef CONFIG_NET_FASTROUTE /* Hack to detect packet socket */ if (pt->data && (long)(pt->data) != 1) { @@ -256,52 +259,76 @@ #endif if (pt->type == htons(ETH_P_ALL)) { netdev_nit++; - pt->next = ptype_all; - ptype_all = pt; + list_add_rcu(&pt->list, &ptype_all); } else { hash = ntohs(pt->type) & 15; - pt->next = ptype_base[hash]; - ptype_base[hash] = pt; + list_add_rcu(&pt->list, &ptype_base[hash]); } - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&ptype_lock); } extern void linkwatch_run_queue(void); + + /** - * dev_remove_pack - remove packet handler + * __dev_remove_pack - remove packet handler * @pt: packet type declaration * * Remove a protocol handler that was previously added to the kernel * protocol handlers by dev_add_pack(). The passed &packet_type is removed * from the kernel lists and can be freed or reused once this function - * returns. + * returns. + * + * The packet type might still be in use by receivers + * and must not be freed until after all the CPU's have gone + * through a quiescent state. */ -void dev_remove_pack(struct packet_type *pt) +void __dev_remove_pack(struct packet_type *pt) { - struct packet_type **pt1; + struct list_head *head; + struct packet_type *pt1; - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&ptype_lock); if (pt->type == htons(ETH_P_ALL)) { netdev_nit--; - pt1 = &ptype_all; + head = &ptype_all; } else - pt1 = &ptype_base[ntohs(pt->type) & 15]; + head = &ptype_base[ntohs(pt->type) & 15]; - for (; *pt1; pt1 = &((*pt1)->next)) { - if (pt == *pt1) { - *pt1 = pt->next; + list_for_each_entry(pt1, head, list) { + if (pt == pt1) { #ifdef CONFIG_NET_FASTROUTE if (pt->data) netdev_fastroute_obstacles--; #endif + list_del_rcu(&pt->list); goto out; } } + printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt); out: - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&ptype_lock); +} +/** + * dev_remove_pack - remove packet handler + * @pt: packet type declaration + * + * Remove a protocol handler that was previously added to the kernel + * protocol handlers by dev_add_pack(). The passed &packet_type is removed + * from the kernel lists and can be freed or reused once this function + * returns. + * + * This call sleeps to guarantee that no CPU is looking at the packet + * type after return. + */ +void dev_remove_pack(struct packet_type *pt) +{ + __dev_remove_pack(pt); + + synchronize_net(); } /****************************************************************************** @@ -943,8 +970,8 @@ struct packet_type *ptype; do_gettimeofday(&skb->stamp); - br_read_lock(BR_NETPROTO_LOCK); - for (ptype = ptype_all; ptype; ptype = ptype->next) { + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_all, list) { /* Never send packets back to the socket * they originated from - MvS (miquels@drinkel.ow.org) */ @@ -974,7 +1001,7 @@ ptype->func(skb2, skb->dev, ptype); } } - br_read_unlock(BR_NETPROTO_LOCK); + rcu_read_unlock(); } /* Calculate csum in the case, when packet is misrouted. @@ -1365,7 +1392,7 @@ if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC)) goto out_kfree; -#if CONFIG_SMP +#ifdef CONFIG_SMP /* Old protocols did not depened on BHs different of NET_BH and TIMER_BH - they need to be fixed for the new assumptions. */ @@ -1488,7 +1515,8 @@ skb->h.raw = skb->nh.raw = skb->data; pt_prev = NULL; - for (ptype = ptype_all; ptype; ptype = ptype->next) { + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &ptype_all, list) { if (!ptype->dev || ptype->dev == skb->dev) { if (pt_prev) { if (!pt_prev->data) { @@ -1511,17 +1539,15 @@ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) if (skb->dev->br_port) { - int ret; - ret = handle_bridge(skb, pt_prev); if (br_handle_frame_hook(skb) == 0) - return ret; + goto out; pt_prev = NULL; } #endif - for (ptype = ptype_base[ntohs(type) & 15]; ptype; ptype = ptype->next) { + list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { if (pt_prev) { @@ -1552,6 +1578,8 @@ ret = NET_RX_DROP; } + out: + rcu_read_unlock(); return ret; } @@ -1625,7 +1653,8 @@ unsigned long start_time = jiffies; int budget = netdev_max_backlog; - br_read_lock(BR_NETPROTO_LOCK); + + preempt_disable(); local_irq_disable(); while (!list_empty(&queue->poll_list)) { @@ -1654,7 +1683,7 @@ } out: local_irq_enable(); - br_read_unlock(BR_NETPROTO_LOCK); + preempt_enable(); return; softnet_break: @@ -1912,6 +1941,7 @@ } static struct file_operations dev_seq_fops = { + .owner = THIS_MODULE, .open = dev_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -1931,6 +1961,7 @@ } static struct file_operations softnet_seq_fops = { + .owner = THIS_MODULE, .open = softnet_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -1995,9 +2026,9 @@ dev_hold(master); } - br_write_lock_bh(BR_NETPROTO_LOCK); slave->master = master; - br_write_unlock_bh(BR_NETPROTO_LOCK); + + synchronize_net(); if (old) dev_put(old); @@ -2661,8 +2692,8 @@ /* Synchronize with packet receive processing. */ void synchronize_net(void) { - br_write_lock_bh(BR_NETPROTO_LOCK); - br_write_unlock_bh(BR_NETPROTO_LOCK); + might_sleep(); + synchronize_kernel(); } /** @@ -2845,6 +2876,10 @@ goto out; subsystem_register(&net_subsys); + + INIT_LIST_HEAD(&ptype_all); + for (i = 0; i < 16; i++) + INIT_LIST_HEAD(&ptype_base[i]); #ifdef CONFIG_NET_DIVERT dv_init(); diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c --- a/net/core/neighbour.c Mon May 12 20:55:44 2003 +++ b/net/core/neighbour.c Mon May 12 20:55:44 2003 @@ -440,8 +440,8 @@ if (!neigh->dead) { printk(KERN_WARNING - "Destroying alive neighbour %p from %08lx\n", neigh, - *(((unsigned long *)&neigh) - 1)); + "Destroying alive neighbour %p\n", neigh); + dump_stack(); return; } diff -Nru a/net/core/pktgen.c b/net/core/pktgen.c --- a/net/core/pktgen.c Mon May 12 20:55:47 2003 +++ b/net/core/pktgen.c Mon May 12 20:55:47 2003 @@ -226,21 +226,20 @@ { struct net_device *odev; - rtnl_lock(); - odev = __dev_get_by_name(info->outdev); + odev = dev_get_by_name(info->outdev); if (!odev) { sprintf(info->result, "No such netdevice: \"%s\"", info->outdev); - goto out_unlock; + goto out; } if (odev->type != ARPHRD_ETHER) { sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev); - goto out_unlock; + goto out_put; } if (!netif_running(odev)) { sprintf(info->result, "Device is down: \"%s\"", info->outdev); - goto out_unlock; + goto out_put; } /* Default to the interface's mac if not explicitly set. */ @@ -257,13 +256,13 @@ info->saddr_min = 0; info->saddr_max = 0; if (strlen(info->src_min) == 0) { - if (odev->ip_ptr) { - struct in_device *in_dev = odev->ip_ptr; - + struct in_device *in_dev = in_dev_get(odev); + if (in_dev) { if (in_dev->ifa_list) { info->saddr_min = in_dev->ifa_list->ifa_address; info->saddr_max = info->saddr_min; } + in_dev_put(in_dev); } } else { @@ -282,13 +281,11 @@ info->cur_udp_dst = info->udp_dst_min; info->cur_udp_src = info->udp_src_min; - atomic_inc(&odev->refcnt); - rtnl_unlock(); - return odev; -out_unlock: - rtnl_unlock(); +out_put: + dev_put(odev); +out: return NULL; } @@ -1258,7 +1255,6 @@ } if (!strcmp(name, "inject") || !strcmp(name, "start")) { - MOD_INC_USE_COUNT; if (info->busy) { strcpy(info->result, "Already running...\n"); } @@ -1268,7 +1264,6 @@ inject(info); info->busy = 0; } - MOD_DEC_USE_COUNT; return count; } @@ -1337,6 +1332,7 @@ pginfos[i].proc_ent->read_proc = proc_read; pginfos[i].proc_ent->write_proc = proc_write; pginfos[i].proc_ent->data = (void*)(long)(i); + pginfos[i].proc_ent->owner = THIS_MODULE; sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i", PG_PROC_DIR, i); pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0); diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c --- a/net/core/skbuff.c Mon May 12 20:55:48 2003 +++ b/net/core/skbuff.c Mon May 12 20:55:48 2003 @@ -126,9 +126,6 @@ struct sk_buff *skb; u8 *data; - if (gfp_mask & __GFP_WAIT) - might_sleep(); - /* Get the HEAD */ skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask & ~__GFP_DMA); diff -Nru a/net/core/wireless.c b/net/core/wireless.c --- a/net/core/wireless.c Mon May 12 20:55:48 2003 +++ b/net/core/wireless.c Mon May 12 20:55:48 2003 @@ -2,7 +2,7 @@ * This file implement the Wireless Extensions APIs. * * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved. * * (As all part of the Linux kernel, this file is GPL) */ @@ -43,19 +43,26 @@ * o Turn on WE_STRICT_WRITE by default + kernel warning * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + * + * v6 - 9.01.03 - Jean II + * o Add common spy support : iw_handler_set_spy(), wireless_spy_update() + * o Add enhanced spy support : iw_handler_set_thrspy() and event. + * o Add WIRELESS_EXT version display in /proc/net/wireless */ /***************************** INCLUDES *****************************/ #include /* Not needed ??? */ +#include #include /* off_t */ #include /* struct ifreq, dev_get_by_name() */ #include #include /* rtnetlink stuff */ #include -#include /* Pretty obvious */ #include /* for __init */ +#include /* ARPHRD_ETHER */ +#include /* Pretty obvious */ #include /* New driver API */ #include /* copy_to_user() */ @@ -69,6 +76,7 @@ /* Debugging stuff */ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ +#undef WE_SPY_DEBUG /* Debug enhanced spy support */ /* Options */ #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ @@ -76,7 +84,7 @@ /************************* GLOBAL VARIABLES *************************/ /* - * You should not use global variables, because or re-entrancy. + * You should not use global variables, because of re-entrancy. * On our case, it's only const, so it's OK... */ /* @@ -152,7 +160,19 @@ .header_type = IW_HEADER_TYPE_POINT, .token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality), - .max_tokens = IW_MAX_GET_SPY, + .max_tokens = IW_MAX_SPY, + }, + [SIOCSIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, + }, + [SIOCGIWTHRSPY - SIOCIWFIRST] = { + .header_type = IW_HEADER_TYPE_POINT, + .token_size = sizeof(struct iw_thrspy), + .min_tokens = 1, + .max_tokens = 1, }, [SIOCSIWAP - SIOCIWFIRST] = { .header_type = IW_HEADER_TYPE_ADDR, @@ -440,9 +460,10 @@ { if (v == (void *)1) seq_printf(seq, "Inter-| sta-| Quality | Discarded " - "packets | Missed\n" + "packets | Missed | WE\n" " face | tus | link level noise | nwid " - "crypt frag retry misc | beacon\n"); + "crypt frag retry misc | beacon | %d\n", + WIRELESS_EXT); else wireless_seq_printf_stats(seq, v); return 0; @@ -465,6 +486,7 @@ } static struct file_operations wireless_seq_fops = { + .owner = THIS_MODULE, .open = wireless_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -1098,4 +1120,253 @@ kfree(event); return; /* Always success, I guess ;-) */ +} + +/********************** ENHANCED IWSPY SUPPORT **********************/ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to use those standard spy iw_handler in struct iw_handler_def, + * push data to us via wireless_spy_update() and include struct iw_spy_data + * in its private part (and advertise it in iw_handler_def->spy_offset). + * One of the main advantage of centralising spy support here is that + * it becomes much easier to improve and extend it without having to touch + * the drivers. One example is the addition of the Spy-Threshold events. + * Note : IW_WIRELESS_SPY is defined in iw_handler.h + */ + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set Spy List + */ +int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Disable spy collection while we copy the addresses. + * As we don't disable interrupts, we need to do this to avoid races. + * As we are the only writer, this is good enough. */ + spydata->spy_number = 0; + + /* Are there are addresses to copy? */ + if(wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for(i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length); + for (i = 0; i < wrqu->data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + spydata->spy_address[i][0], + spydata->spy_address[i][1], + spydata->spy_address[i][2], + spydata->spy_address[i][3], + spydata->spy_address[i][4], + spydata->spy_address[i][5]); +#endif /* WE_SPY_DEBUG */ + } + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +#else /* IW_WIRELESS_SPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_SPY */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get Spy List + */ +int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for(i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if(spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for(i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated = 0; + return 0; +#else /* IW_WIRELESS_SPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_SPY */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_THRSPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Just do it */ + memcpy(&(spydata->spy_thr_low), &(threshold->low), + 2 * sizeof(struct iw_quality)); + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level); +#endif /* WE_SPY_DEBUG */ + + return 0; +#else /* IW_WIRELESS_THRSPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_THRSPY */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_THRSPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Just do it */ + memcpy(&(threshold->low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + + return 0; +#else /* IW_WIRELESS_THRSPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_THRSPY */ +} + +#ifdef IW_WIRELESS_THRSPY +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); + /* Copy also thresholds */ + memcpy(&(threshold.low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n", + threshold.addr.sa_data[0], + threshold.addr.sa_data[1], + threshold.addr.sa_data[2], + threshold.addr.sa_data[3], + threshold.addr.sa_data[4], + threshold.addr.sa_data[5], threshold.qual.level); +#endif /* WE_SPY_DEBUG */ + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} +#endif /* IW_WIRELESS_THRSPY */ + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + int i; + int match = -1; + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); +#endif /* WE_SPY_DEBUG */ + + /* Update all records that match */ + for(i = 0; i < spydata->spy_number; i++) + if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } +#ifdef IW_WIRELESS_THRSPY + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if(match >= 0) { + if(spydata->spy_thr_under[match]) { + if(wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if(wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +#endif /* IW_WIRELESS_THRSPY */ +#endif /* IW_WIRELESS_SPY */ } diff -Nru a/net/decnet/Kconfig b/net/decnet/Kconfig --- a/net/decnet/Kconfig Mon May 12 20:55:49 2003 +++ b/net/decnet/Kconfig Mon May 12 20:55:49 2003 @@ -17,11 +17,11 @@ depends on DECNET && EXPERIMENTAL ---help--- Add support for turning your DECnet Endnode into a level 1 or 2 - router. This is an unfinished option for developers only. If you + router. This is an experimental, but functional option. If you do say Y here, then make sure that you also say Y to "Kernel/User network link driver", "Routing messages" and "Network packet filtering". The first two are required to allow configuration via - rtnetlink (currently you need Alexey Kuznetsov's iproute2 package + rtnetlink (you will need Alexey Kuznetsov's iproute2 package from ). The "Network packet filtering" option will be required for the forthcoming routing daemon to work. @@ -34,4 +34,6 @@ If you say Y here, you will be able to specify different routes for packets with different FWMARK ("firewalling mark") values (see ipchains(8), "-m" argument). + +source "net/decnet/netfilter/Kconfig" diff -Nru a/net/decnet/Makefile b/net/decnet/Makefile --- a/net/decnet/Makefile Mon May 12 20:55:45 2003 +++ b/net/decnet/Makefile Mon May 12 20:55:45 2003 @@ -1,7 +1,10 @@ obj-$(CONFIG_DECNET) += decnet.o -decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o dn_route.o dn_dev.o dn_neigh.o dn_timer.o +decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o \ + dn_route.o dn_dev.o dn_neigh.o dn_timer.o decnet-$(CONFIG_DECNET_ROUTER) += dn_fib.o dn_rules.o dn_table.o -decnet-$(CONFIG_DECNET_FW) += dn_fw.o decnet-y += sysctl_net_decnet.o + +obj-$(CONFIG_NETFILTER) += netfilter/ + diff -Nru a/net/decnet/TODO b/net/decnet/TODO --- a/net/decnet/TODO Mon May 12 20:55:47 2003 +++ b/net/decnet/TODO Mon May 12 20:55:47 2003 @@ -23,15 +23,9 @@ o check MSG_CTRUNC is set where it should be. - o Start to hack together user level software and add more DECnet support - in ifconfig for example. - o Find all the commonality between DECnet and IPv4 routing code and extract it into a small library of routines. [probably a project for 2.7.xx] - o Add the routing message grabbing netfilter module [written, tested, - awaiting merge] - o Add perfect socket hashing - an idea suggested by Paul Koning. Currently we have a half-way house scheme which seems to work reasonably well, but the full scheme is still worth implementing, its not not top of my list @@ -44,6 +38,4 @@ o DECnet sendpages() function o AIO for DECnet - - o Eliminate dn_db->parms.blksize diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c --- a/net/decnet/af_decnet.c Mon May 12 20:55:46 2003 +++ b/net/decnet/af_decnet.c Mon May 12 20:55:47 2003 @@ -116,6 +116,7 @@ #include #include #include +#include #include #include #include @@ -676,45 +677,6 @@ } -static char *dn_state2asc(unsigned char state) -{ - switch(state) { - case DN_O: - return "OPEN"; - case DN_CR: - return " CR"; - case DN_DR: - return " DR"; - case DN_DRC: - return " DRC"; - case DN_CC: - return " CC"; - case DN_CI: - return " CI"; - case DN_NR: - return " NR"; - case DN_NC: - return " NC"; - case DN_CD: - return " CD"; - case DN_RJ: - return " RJ"; - case DN_RUN: - return " RUN"; - case DN_DI: - return " DI"; - case DN_DIC: - return " DIC"; - case DN_DN: - return " DN"; - case DN_CL: - return " CL"; - case DN_CN: - return " CN"; - } - - return "????"; -} static int dn_create(struct socket *sock, int protocol) { @@ -1001,6 +963,7 @@ fl.fld_dst = dn_saddr2dn(&scp->peer); fl.fld_src = dn_saddr2dn(&scp->addr); dn_sk_ports_copy(&fl, scp); + fl.proto = DNPROTO_NSP; if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0) goto out; sk->route_caps = sk->dst_cache->dev->features; @@ -1964,7 +1927,7 @@ unsigned char fctype; long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL)) + if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE)) return -EOPNOTSUPP; if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) @@ -2143,6 +2106,95 @@ .data = (void*)1, }; +#ifdef CONFIG_PROC_FS +struct dn_iter_state { + int bucket; +}; + +static struct sock *dn_socket_get_first(struct seq_file *seq) +{ + struct dn_iter_state *state = seq->private; + struct sock *n = NULL; + + for(state->bucket = 0; + state->bucket < DN_SK_HASH_SIZE; + ++state->bucket) { + n = dn_sk_hash[state->bucket]; + if (n) + break; + } + + return n; +} + +static struct sock *dn_socket_get_next(struct seq_file *seq, + struct sock *n) +{ + struct dn_iter_state *state = seq->private; + + n = n->next; +try_again: + if (n) + goto out; + if (++state->bucket >= DN_SK_HASH_SIZE) + goto out; + n = dn_sk_hash[state->bucket]; + goto try_again; +out: + return n; +} + +static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos) +{ + struct sock *sk = dn_socket_get_first(seq); + + if (sk) { + while(*pos && (sk = dn_socket_get_next(seq, sk))) + --*pos; + } + return *pos ? NULL : sk; +} + +static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos) +{ + void *rc; + read_lock_bh(&dn_hash_lock); + rc = socket_get_idx(seq, &pos); + if (!rc) { + read_unlock_bh(&dn_hash_lock); + } + return rc; +} + +static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? dn_socket_get_idx(seq, *pos - 1) : (void*)1; +} + +static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + void *rc; + + if (v == (void*)1) { + rc = dn_socket_get_idx(seq, 0); + goto out; + } + + rc = dn_socket_get_next(seq, v); + if (rc) + goto out; + read_unlock_bh(&dn_hash_lock); +out: + ++*pos; + return rc; +} + +static void dn_socket_seq_stop(struct seq_file *seq, void *v) +{ + if (v && v != (void*)1) + read_unlock_bh(&dn_hash_lock); +} + #define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126) static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf) @@ -2163,70 +2215,127 @@ } } -static int dn_get_info(char *buffer, char **start, off_t offset, int length) +static char *dn_state2asc(unsigned char state) { - struct sock *sk; - struct dn_scp *scp; - int len = 0; - off_t pos = 0; - off_t begin = 0; + switch(state) { + case DN_O: + return "OPEN"; + case DN_CR: + return " CR"; + case DN_DR: + return " DR"; + case DN_DRC: + return " DRC"; + case DN_CC: + return " CC"; + case DN_CI: + return " CI"; + case DN_NR: + return " NR"; + case DN_NC: + return " NC"; + case DN_CD: + return " CD"; + case DN_RJ: + return " RJ"; + case DN_RUN: + return " RUN"; + case DN_DI: + return " DI"; + case DN_DIC: + return " DIC"; + case DN_DN: + return " DN"; + case DN_CL: + return " CL"; + case DN_CN: + return " CN"; + } + + return "????"; +} + +static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk) +{ + struct dn_scp *scp = DN_SK(sk); char buf1[DN_ASCBUF_LEN]; char buf2[DN_ASCBUF_LEN]; char local_object[DN_MAXOBJL+3]; char remote_object[DN_MAXOBJL+3]; - int i; - len += sprintf(buffer + len, "Local Remote\n"); + dn_printable_object(&scp->addr, local_object); + dn_printable_object(&scp->peer, remote_object); - read_lock(&dn_hash_lock); - for(i = 0; i < DN_SK_HASH_SIZE; i++) { - for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) { - scp = DN_SK(sk); - - dn_printable_object(&scp->addr, local_object); - dn_printable_object(&scp->peer, remote_object); - - len += sprintf(buffer + len, - "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), - scp->addrloc, - scp->numdat, - scp->numoth, - scp->ackxmt_dat, - scp->ackxmt_oth, - scp->flowloc_sw, - local_object, - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), - scp->addrrem, - scp->numdat_rcv, - scp->numoth_rcv, - scp->ackrcv_dat, - scp->ackrcv_oth, - scp->flowrem_sw, - remote_object, - dn_state2asc(scp->state), - ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > (offset + length)) - break; - } + seq_printf(seq, + "%6s/%04X %04d:%04d %04d:%04d %01d %-16s " + "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), + scp->addrloc, + scp->numdat, + scp->numoth, + scp->ackxmt_dat, + scp->ackxmt_oth, + scp->flowloc_sw, + local_object, + dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), + scp->addrrem, + scp->numdat_rcv, + scp->numoth_rcv, + scp->ackrcv_dat, + scp->ackrcv_oth, + scp->flowrem_sw, + remote_object, + dn_state2asc(scp->state), + ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER")); +} + +static int dn_socket_seq_show(struct seq_file *seq, void *v) +{ + if (v == (void*)1) { + seq_puts(seq, "Local Remote\n"); + } else { + dn_socket_format_entry(seq, v); } - read_unlock(&dn_hash_lock); + return 0; +} - *start = buffer + (offset - begin); - len -= (offset - begin); +static struct seq_operations dn_socket_seq_ops = { + .start = dn_socket_seq_start, + .next = dn_socket_seq_next, + .stop = dn_socket_seq_stop, + .show = dn_socket_seq_show, +}; - if (len > length) - len = length; +static int dn_socket_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); - return len; + if (!s) + goto out; + + rc = seq_open(file, &dn_socket_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); +out: + return rc; +out_kfree: + kfree(s); + goto out; } +static struct file_operations dn_socket_seq_fops = { + .open = dn_socket_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; +#endif static struct net_proto_family dn_family_ops = { .family = AF_DECnet, @@ -2258,13 +2367,11 @@ void dn_register_sysctl(void); void dn_unregister_sysctl(void); - MODULE_DESCRIPTION("The Linux DECnet Network Protocol"); MODULE_AUTHOR("Linux DECnet Project Team"); MODULE_LICENSE("GPL"); - -static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n"; +static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n"; static int __init decnet_init(void) { @@ -2281,15 +2388,12 @@ dev_add_pack(&dn_dix_packet_type); register_netdevice_notifier(&dn_dev_notifier); - proc_net_create("decnet", 0, dn_get_info); + proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops); dn_neigh_init(); dn_dev_init(); dn_route_init(); - -#ifdef CONFIG_DECNET_ROUTER dn_fib_init(); -#endif /* CONFIG_DECNET_ROUTER */ dn_register_sysctl(); @@ -2316,10 +2420,7 @@ dn_route_cleanup(); dn_dev_cleanup(); dn_neigh_cleanup(); - -#ifdef CONFIG_DECNET_ROUTER dn_fib_cleanup(); -#endif /* CONFIG_DECNET_ROUTER */ proc_net_remove("decnet"); diff -Nru a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c --- a/net/decnet/dn_dev.c Mon May 12 20:55:45 2003 +++ b/net/decnet/dn_dev.c Mon May 12 20:55:45 2003 @@ -20,6 +20,8 @@ * Steve Whitehouse : /proc/sys/net/decnet/conf//forwarding * Steve Whitehouse : Removed timer1 - it's a user space issue now * Patrick Caulfield : Fixed router hello message format + * Steve Whitehouse : Got rid of constant sizes for blksize for + * devices. All mtu based now. */ #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -72,16 +75,13 @@ static int dn_eth_up(struct net_device *); static void dn_eth_down(struct net_device *); static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa); -#if 0 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa); -#endif static struct dn_dev_parms dn_dev_list[] = { { .type = ARPHRD_ETHER, /* Ethernet */ .mode = DN_DEV_BCAST, .state = DN_DEV_S_RU, - .blksize = 1498, .t2 = 1, .t3 = 10, .name = "ethernet", @@ -94,7 +94,6 @@ .type = ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */ .mode = DN_DEV_BCAST, .state = DN_DEV_S_RU, - .blksize = 1400, .t2 = 1, .t3 = 10, .name = "ipgre", @@ -106,7 +105,6 @@ .type = ARPHRD_X25, /* Bog standard X.25 */ .mode = DN_DEV_UCAST, .state = DN_DEV_S_DS, - .blksize = 230, .t2 = 1, .t3 = 120, .name = "x25", @@ -119,7 +117,6 @@ .type = ARPHRD_PPP, /* DECnet over PPP */ .mode = DN_DEV_BCAST, .state = DN_DEV_S_RU, - .blksize = 230, .t2 = 1, .t3 = 10, .name = "ppp", @@ -127,24 +124,20 @@ .timer3 = dn_send_brd_hello, }, #endif -#if 0 { .type = ARPHRD_DDCMP, /* DECnet over DDCMP */ .mode = DN_DEV_UCAST, .state = DN_DEV_S_DS, - .blksize = 230, .t2 = 1, .t3 = 120, .name = "ddcmp", .ctl_name = NET_DECNET_CONF_DDCMP, .timer3 = dn_send_ptp_hello, }, -#endif { .type = ARPHRD_LOOPBACK, /* Loopback interface - always last */ .mode = DN_DEV_BCAST, .state = DN_DEV_S_RU, - .blksize = 1498, .t2 = 1, .t3 = 10, .name = "loopback", @@ -254,6 +247,21 @@ }, {0}} }; +static inline __u16 mtu2blksize(struct net_device *dev) +{ + u32 blksize = dev->mtu; + if (blksize > 0xffff) + blksize = 0xffff; + + if (dev->type == ARPHRD_ETHER || + dev->type == ARPHRD_PPP || + dev->type == ARPHRD_IPGRE || + dev->type == ARPHRD_LOOPBACK) + blksize -= 2; + + return (__u16)blksize; +} + static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms) { struct dn_dev_sysctl_table *t; @@ -553,7 +561,6 @@ struct dn_dev *dn_db; struct net_device *dev; struct dn_ifaddr *ifa = NULL, **ifap = NULL; - int exclusive = 0; int ret = 0; if (copy_from_user(ifr, arg, DN_IFREQ_SIZE)) @@ -572,13 +579,13 @@ return -EACCES; if (sdn->sdn_family != AF_DECnet) return -EINVAL; - rtnl_lock(); - exclusive = 1; break; default: return -EINVAL; } + rtnl_lock(); + if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) { ret = -ENODEV; goto done; @@ -618,15 +625,13 @@ ret = dn_dev_set_ifa(dev, ifa); } done: - if (exclusive) - rtnl_unlock(); + rtnl_unlock(); return ret; rarok: if (copy_to_user(arg, ifr, DN_IFREQ_SIZE)) - return -EFAULT; - - return 0; + ret = -EFAULT; + goto done; } static struct dn_dev *dn_dev_by_index(int ifindex) @@ -858,7 +863,7 @@ memcpy(msg->tiver, dn_eco_version, 3); dn_dn2eth(msg->id, ifa->ifa_local); msg->iinfo = DN_RT_INFO_ENDN; - msg->blksize = dn_htons(dn_db->parms.blksize); + msg->blksize = dn_htons(mtu2blksize(dev)); msg->area = 0x00; memset(msg->seed, 0, 8); memcpy(msg->neighbor, dn_hiord, ETH_ALEN); @@ -920,10 +925,10 @@ unsigned short *pktlen; char *src; - if (dn_db->parms.blksize < (26 + 7)) + if (mtu2blksize(dev) < (26 + 7)) return; - n = dn_db->parms.blksize - 26; + n = mtu2blksize(dev) - 26; n /= 7; if (n > 32) @@ -946,7 +951,7 @@ ptr += ETH_ALEN; *ptr++ = dn_db->parms.forwarding == 1 ? DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; - *((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize); + *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev)); ptr += 2; *ptr++ = dn_db->parms.priority; /* Priority */ *ptr++ = 0; /* Area: Reserved */ @@ -990,16 +995,13 @@ dn_send_router_hello(dev, ifa); } -#if 0 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) { int tdlen = 16; int size = dev->hard_header_len + 2 + 4 + tdlen; struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC); - struct dn_dev *dn_db = dev->dn_ptr; int i; unsigned char *ptr; - struct dn_neigh *dn = (struct dn_neigh *)dn_db->router; char src[ETH_ALEN]; if (skb == NULL) @@ -1020,7 +1022,6 @@ dn_dn2eth(src, ifa->ifa_local); dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src); } -#endif static int dn_eth_up(struct net_device *dev) { @@ -1332,6 +1333,63 @@ #ifdef CONFIG_PROC_FS +static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev) +{ + do { + dev = dev->next; + } while(dev && !dev->dn_ptr); + + return dev; +} + +static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos) +{ + struct net_device *dev; + + dev = dev_base; + if (dev && !dev->dn_ptr) + dev = dn_dev_get_next(seq, dev); + if (pos) { + while(dev && (dev = dn_dev_get_next(seq, dev))) + --pos; + } + return dev; +} + +static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos) { + struct net_device *dev; + read_lock(&dev_base_lock); + dev = dn_dev_get_idx(seq, *pos - 1); + if (dev == NULL) + read_unlock(&dev_base_lock); + return dev; + } + return (void*)1; +} + +static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct net_device *dev = v; + loff_t one = 1; + + if (v == (void*)1) { + dev = dn_dev_seq_start(seq, &one); + } else { + dev = dn_dev_get_next(seq, dev); + if (dev == NULL) + read_unlock(&dev_base_lock); + } + ++*pos; + return dev; +} + +static void dn_dev_seq_stop(struct seq_file *seq, void *v) +{ + if (v && v != (void*)1) + read_unlock(&dev_base_lock); +} static char *dn_type2asc(char type) { @@ -1347,56 +1405,50 @@ return "?"; } -static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int length) +static int dn_dev_seq_show(struct seq_file *seq, void *v) { - struct dn_dev *dn_db; - struct net_device *dev; - int len = 0; - off_t pos = 0; - off_t begin = 0; - char peer_buf[DN_ASCBUF_LEN]; - char router_buf[DN_ASCBUF_LEN]; - - - len += sprintf(buffer, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n"); - - read_lock(&dev_base_lock); - for (dev = dev_base; dev; dev = dev->next) { - if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL) - continue; + if (v == (void*)1) + seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n"); + else { + struct net_device *dev = v; + char peer_buf[DN_ASCBUF_LEN]; + char router_buf[DN_ASCBUF_LEN]; + struct dn_dev *dn_db = dev->dn_ptr; - len += sprintf(buffer + len, "%-8s %1s %04u %04u %04lu %04lu %04hu %03d %02x %-10s %-7s %-7s\n", + seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" + " %04hu %03d %02x %-10s %-7s %-7s\n", dev->name ? dev->name : "???", dn_type2asc(dn_db->parms.mode), 0, 0, dn_db->t3, dn_db->parms.t3, - dn_db->parms.blksize, + mtu2blksize(dev), dn_db->parms.priority, dn_db->parms.state, dn_db->parms.name, dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "", dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : ""); + } + return 0; +} +static struct seq_operations dn_dev_seq_ops = { + .start = dn_dev_seq_start, + .next = dn_dev_seq_next, + .stop = dn_dev_seq_stop, + .show = dn_dev_seq_show, +}; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } - - read_unlock(&dev_base_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) len = length; - - return(len); +static int dn_dev_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &dn_dev_seq_ops); } +static struct file_operations dn_dev_seq_fops = { + .open = dn_dev_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif /* CONFIG_PROC_FS */ static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = @@ -1448,9 +1500,7 @@ rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table; -#ifdef CONFIG_PROC_FS - proc_net_create("decnet_dev", 0, decnet_dev_get_info); -#endif /* CONFIG_PROC_FS */ + proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops); #ifdef CONFIG_SYSCTL { diff -Nru a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c --- a/net/decnet/dn_fib.c Mon May 12 20:55:49 2003 +++ b/net/decnet/dn_fib.c Mon May 12 20:55:49 2003 @@ -67,18 +67,18 @@ int error; u8 scope; } dn_fib_props[RTA_MAX+1] = { - { .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_UNSPEC */ - { .error = 0, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNICAST */ - { .error = 0, .scope = RT_SCOPE_HOST }, /* RTN_LOCAL */ - { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_BROADCAST */ - { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_ANYCAST */ - { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, /* RTN_MULTICAST */ - { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */ - { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, /* RTN_UNREACHABLE */ - { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */ - { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, /* RTN_THROW */ - { .error = 0, .scope = RT_SCOPE_NOWHERE }, /* RTN_NAT */ - { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE } /* RTN_XRESOLVE */ + [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, + [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE }, + [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST }, + [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, + [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, + [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, + [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, + [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE }, + [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, + [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, + [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, + [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }, }; void dn_fib_free_info(struct dn_fib_info *fi) @@ -218,7 +218,7 @@ if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; - atomic_inc(&dev->refcnt); + dev_hold(dev); nh->nh_scope = RT_SCOPE_LINK; return 0; } @@ -242,7 +242,7 @@ nh->nh_dev = DN_FIB_RES_DEV(res); if (nh->nh_dev == NULL) goto out; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); err = -ENETDOWN; if (!(nh->nh_dev->flags & IFF_UP)) goto out; @@ -262,7 +262,7 @@ if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); nh->nh_scope = RT_SCOPE_HOST; } @@ -792,53 +792,12 @@ dn_rt_cache_flush(-1); } -#ifdef CONFIG_PROC_FS - -static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - int first = offset / 128; - char *ptr = buffer; - int count = (length + 127) / 128; - int len; - int i; - struct dn_fib_table *tb; - - *start = buffer + (offset % 128); - - if (--first < 0) { - sprintf(buffer, "%-127s\n", "Iface\tDest\tGW \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT"); - --count; - ptr += 128; - first = 0; - } - - - for(i = RT_MIN_TABLE; (i <= RT_TABLE_MAX) && (count > 0); i++) { - if ((tb = dn_fib_get_table(i, 0)) != NULL) { - int n = tb->get_info(tb, ptr, first, count); - count -= n; - ptr += n * 128; - } - } - - len = ptr - *start; - if (len >= length) - return length; - if (len >= 0) - return len; - - return 0; -} -#endif /* CONFIG_PROC_FS */ - static struct notifier_block dn_fib_dnaddr_notifier = { .notifier_call = dn_fib_dnaddr_event, }; void __exit dn_fib_cleanup(void) { - proc_net_remove("decnet_route"); - dn_fib_table_cleanup(); dn_fib_rules_cleanup(); @@ -848,10 +807,6 @@ void __init dn_fib_init(void) { - -#ifdef CONFIG_PROC_FS - proc_net_create("decnet_route", 0, decnet_rt_get_info); -#endif dn_fib_table_init(); dn_fib_rules_init(); diff -Nru a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c --- a/net/decnet/dn_neigh.c Mon May 12 20:55:47 2003 +++ b/net/decnet/dn_neigh.c Mon May 12 20:55:47 2003 @@ -202,7 +202,7 @@ struct net_device *dev = neigh->dev; char mac_addr[ETH_ALEN]; - dn_dn2eth(mac_addr, rt->rt_saddr); + dn_dn2eth(mac_addr, rt->rt_local_src); if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0) return neigh->ops->queue_xmit(skb); @@ -692,48 +692,24 @@ goto out; } -static int dn_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = (struct seq_file *)file->private_data; - - kfree(seq->private); - seq->private = NULL; - return seq_release(inode, file); -} - static struct file_operations dn_neigh_seq_fops = { + .owner = THIS_MODULE, .open = dn_neigh_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = dn_seq_release, + .release = seq_release_private, }; -static int __init dn_neigh_proc_init(void) -{ - int rc = 0; - struct proc_dir_entry *p = create_proc_entry("decnet_neigh", S_IRUGO, proc_net); - if (p) - p->proc_fops = &dn_neigh_seq_fops; - else - rc = -ENOMEM; - return rc; -} - -#else -static int __init dn_neigh_proc_init(void) -{ - return 0; -} #endif void __init dn_neigh_init(void) { neigh_table_init(&dn_neigh_table); - - dn_neigh_proc_init(); + proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops); } void __exit dn_neigh_cleanup(void) { + proc_net_remove("decnet_neigh"); neigh_table_clear(&dn_neigh_table); } diff -Nru a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c --- a/net/decnet/dn_nsp_in.c Mon May 12 20:55:45 2003 +++ b/net/decnet/dn_nsp_in.c Mon May 12 20:55:45 2003 @@ -28,6 +28,7 @@ * Steve Whitehouse: Added backlog congestion level return codes. * Patrick Caulfield: * Steve Whitehouse: Added flow control support (outbound) + * Steve Whitehouse: Prepare for nonlinear skbs */ /****************************************************************************** @@ -240,7 +241,7 @@ cb->info = msg->info; cb->segsize = dn_ntohs(msg->segsize); - if (skb->len < sizeof(*msg)) + if (!pskb_may_pull(skb, sizeof(*msg))) goto err_out; skb_pull(skb, sizeof(*msg)); @@ -721,34 +722,19 @@ unsigned char *ptr = (unsigned char *)skb->data; unsigned short reason = NSP_REASON_NL; + if (!pskb_may_pull(skb, 2)) + goto free_out; + skb->h.raw = skb->data; cb->nsp_flags = *ptr++; if (decnet_debug_level & 2) printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags); - if (skb->len < 2) - goto free_out; - if (cb->nsp_flags & 0x83) goto free_out; /* - * Returned packets... - * Swap src & dst and look up in the normal way. - */ - if (cb->rt_flags & DN_RT_F_RTS) { - unsigned short tmp = cb->dst_port; - cb->dst_port = cb->src_port; - cb->src_port = tmp; - tmp = cb->dst; - cb->dst = cb->src; - cb->src = tmp; - sk = dn_find_by_skb(skb); - goto got_it; - } - - /* * Filter out conninits and useless packet types */ if ((cb->nsp_flags & 0x0c) == 0x08) { @@ -759,12 +745,14 @@ goto free_out; case 0x10: case 0x60: + if (unlikely(cb->rt_flags & DN_RT_F_RTS)) + goto free_out; sk = dn_find_listener(skb, &reason); goto got_it; } } - if (skb->len < 3) + if (!pskb_may_pull(skb, 3)) goto free_out; /* @@ -777,13 +765,26 @@ /* * If not a connack, grab the source address too. */ - if (skb->len >= 5) { + if (pskb_may_pull(skb, 5)) { cb->src_port = *(unsigned short *)ptr; ptr += 2; skb_pull(skb, 5); } /* + * Returned packets... + * Swap src & dst and look up in the normal way. + */ + if (unlikely(cb->rt_flags & DN_RT_F_RTS)) { + unsigned short tmp = cb->dst_port; + cb->dst_port = cb->src_port; + cb->src_port = tmp; + tmp = cb->dst; + cb->dst = cb->src; + cb->src = tmp; + } + + /* * Find the socket to which this skb is destined. */ sk = dn_find_by_skb(skb); @@ -795,6 +796,15 @@ /* Reset backoff */ scp->nsp_rxtshift = 0; + /* + * We linearize everything except data segments here. + */ + if (cb->nsp_flags & ~0x60) { + if (unlikely(skb_is_nonlinear(skb)) && + skb_linearize(skb, GFP_ATOMIC) != 0) + goto free_out; + } + bh_lock_sock(sk); ret = NET_RX_SUCCESS; if (decnet_debug_level & 8) @@ -835,7 +845,10 @@ struct dn_skb_cb *cb = DN_SKB_CB(skb); if (cb->rt_flags & DN_RT_F_RTS) { - dn_returned_conn_init(sk, skb); + if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68) + dn_returned_conn_init(sk, skb); + else + kfree_skb(skb); return NET_RX_SUCCESS; } diff -Nru a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c --- a/net/decnet/dn_nsp_out.c Mon May 12 20:55:49 2003 +++ b/net/decnet/dn_nsp_out.c Mon May 12 20:55:49 2003 @@ -96,6 +96,7 @@ fl.fld_src = dn_saddr2dn(&scp->addr); fl.fld_dst = dn_saddr2dn(&scp->peer); dn_sk_ports_copy(&fl, scp); + fl.proto = DNPROTO_NSP; if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) { dst = sk_dst_get(sk); sk->route_caps = dst->dev->features; @@ -349,8 +350,7 @@ { unsigned char *ptr = skb_push(skb, len); - if (len < 5) - BUG(); + BUG_ON(len < 5); *ptr++ = msgflag; *((unsigned short *)ptr) = scp->addrrem; @@ -367,8 +367,7 @@ unsigned short ackcrs = scp->numoth_rcv & 0x0FFF; unsigned short *ptr; - if (hlen < 9) - BUG(); + BUG_ON(hlen < 9); scp->ackxmt_dat = acknum; scp->ackxmt_oth = ackcrs; @@ -485,8 +484,8 @@ * We don't expect to see acknowledgements for packets we * haven't sent yet. */ - if (xmit_count == 0) - BUG(); + WARN_ON(xmit_count == 0); + /* * If the packet has only been sent once, we can use it * to calculate the RTT and also open the window a little diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c --- a/net/decnet/dn_route.c Mon May 12 20:55:49 2003 +++ b/net/decnet/dn_route.c Mon May 12 20:55:49 2003 @@ -39,6 +39,7 @@ * no ref count on net devices. * Steve Whitehouse : RCU for the route cache * Steve Whitehouse : Preparations for the flow cache + * Steve Whitehouse : Prepare for nonlinear skbs */ /****************************************************************************** @@ -70,6 +71,7 @@ #include #include #include +#include #include #include #include @@ -97,14 +99,17 @@ static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; -int dn_rt_min_delay = 2*HZ; -int dn_rt_max_delay = 10*HZ; -static unsigned long dn_rt_deadline = 0; +int dn_rt_min_delay = 2 * HZ; +int dn_rt_max_delay = 10 * HZ; +int dn_rt_mtu_expires = 10 * 60 * HZ; + +static unsigned long dn_rt_deadline; static int dn_dst_gc(void); static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); static void dn_dst_link_failure(struct sk_buff *); +static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); static int dn_route_input(struct sk_buff *); static void dn_run_flush(unsigned long dummy); @@ -124,6 +129,7 @@ .check = dn_dst_check, .negative_advice = dn_dst_negative_advice, .link_failure = dn_dst_link_failure, + .update_pmtu = dn_dst_update_pmtu, .entry_size = sizeof(struct dn_route), .entries = ATOMIC_INIT(0), }; @@ -210,16 +216,49 @@ return 0; } +/* + * The decnet standards don't impose a particular minimum mtu, what they + * do insist on is that the routing layer accepts a datagram of at least + * 230 bytes long. Here we have to subtract the routing header length from + * 230 to get the minimum acceptable mtu. If there is no neighbour, then we + * assume the worst and use a long header size. + * + * We update both the mtu and the advertised mss (i.e. the segment size we + * advertise to the other end). + */ +static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) +{ + u32 min_mtu = 230; + struct dn_dev *dn = dst->neighbour ? + (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL; + + if (dn && dn->use_long == 0) + min_mtu -= 6; + else + min_mtu -= 21; + + if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) { + if (!(dst_metric_locked(dst, RTAX_MTU))) { + dst->metrics[RTAX_MTU-1] = mtu; + dst_set_expires(dst, dn_rt_mtu_expires); + } + if (!(dst_metric_locked(dst, RTAX_ADVMSS))) { + u32 mss = mtu - DN_MAX_NSP_DATA_HEADER; + if (dst->metrics[RTAX_ADVMSS-1] > mss) + dst->metrics[RTAX_ADVMSS-1] = mss; + } + } +} + +/* + * When a route has been marked obsolete. (e.g. routing cache flush) + */ static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie) { dst_release(dst); return NULL; } -/* - * This is called through sendmsg() when you specify MSG_TRYHARD - * and there is already a route in cache. - */ static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst) { dst_release(dst); @@ -467,7 +506,7 @@ struct dn_skb_cb *cb = DN_SKB_CB(skb); unsigned char *ptr = skb->data; - if (skb->len < 21) /* 20 for long header, 1 for shortest nsp */ + if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */ goto drop_it; skb_pull(skb, 20); @@ -505,7 +544,7 @@ struct dn_skb_cb *cb = DN_SKB_CB(skb); unsigned char *ptr = skb->data; - if (skb->len < 6) /* 5 for short header + 1 for shortest nsp */ + if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */ goto drop_it; skb_pull(skb, 5); @@ -555,6 +594,9 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out; + if (!pskb_may_pull(skb, 3)) + goto dump_it; + skb_pull(skb, 2); if (len > skb->len) @@ -573,6 +615,8 @@ */ if (flags & DN_RT_F_PF) { padlen = flags & ~DN_RT_F_PF; + if (!pskb_may_pull(skb, padlen + 1)) + goto dump_it; skb_pull(skb, padlen); flags = *skb->data; } @@ -594,6 +638,10 @@ padlen); if (flags & DN_RT_PKT_CNTL) { + if (unlikely(skb_is_nonlinear(skb)) && + skb_linearize(skb, GFP_ATOMIC) != 0) + goto dump_it; + switch(flags & DN_RT_CNTL_MSK) { case DN_RT_PKT_INIT: dn_dev_init_pkt(skb); @@ -712,7 +760,7 @@ * packets, so we don't need to test for them here. */ cb->rt_flags &= ~DN_RT_F_IE; - if (rt->rt_flags | RTCF_DOREDIRECT) + if (rt->rt_flags & RTCF_DOREDIRECT) cb->rt_flags |= DN_RT_F_IE; return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output); @@ -788,8 +836,10 @@ { __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); int match = 16; - while(tmp) - tmp >>= 1, match--; + while(tmp) { + tmp >>= 1; + match--; + } return match; } @@ -899,17 +949,19 @@ /* No destination? Assume its local */ if (!fl.fld_dst) { fl.fld_dst = fl.fld_src; -#if 0 - if (!fl.fld_dst) - /* grab an address from loopback? */ -#endif + err = -EADDRNOTAVAIL; if (dev_out) dev_put(dev_out); - if (!fl.fld_dst) - goto out; dev_out = &loopback_dev; dev_hold(dev_out); + if (!fl.fld_dst) { + fl.fld_dst = + fl.fld_src = dnet_select_source(dev_out, 0, + RT_SCOPE_HOST); + if (!fl.fld_dst) + goto out; + } fl.oif = loopback_dev.ifindex; res.type = RTN_LOCAL; goto make_route; @@ -1061,6 +1113,7 @@ rt->rt_saddr = fl.fld_src; rt->rt_daddr = fl.fld_dst; rt->rt_gateway = gateway ? gateway : fl.fld_dst; + rt->rt_local_src = fl.fld_src; rt->rt_dst_map = fl.fld_dst; rt->rt_src_map = fl.fld_src; @@ -1075,14 +1128,14 @@ rt->u.dst.input = dn_rt_bug; rt->rt_flags = flags; if (flags & RTCF_LOCAL) - rt->u.dst.output = dn_nsp_rx; + rt->u.dst.input = dn_nsp_rx; - if (dn_rt_set_next_hop(rt, &res)) + err = dn_rt_set_next_hop(rt, &res); + if (err) goto e_neighbour; hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); dn_insert_route(rt, hash, (struct dn_route **)pprt); - err = 0; done: if (neigh) @@ -1175,6 +1228,7 @@ unsigned hash; int flags = 0; __u16 gateway = 0; + __u16 local_src = 0; struct flowi fl = { .nl_u = { .dn_u = { .daddr = cb->dst, .saddr = cb->src, @@ -1275,6 +1329,8 @@ if (out_dev == in_dev && !(flags & RTCF_NAT)) flags |= RTCF_DOREDIRECT; + local_src = DN_FIB_RES_PREFSRC(res); + case RTN_BLACKHOLE: case RTN_UNREACHABLE: break; @@ -1319,6 +1375,8 @@ rt->rt_gateway = fl.fld_dst; if (gateway) rt->rt_gateway = gateway; + rt->rt_local_src = local_src ? local_src : rt->rt_saddr; + rt->rt_dst_map = fl.fld_dst; rt->rt_src_map = fl.fld_src; @@ -1352,12 +1410,12 @@ if (rt->u.dst.dev) dev_hold(rt->u.dst.dev); - if (dn_rt_set_next_hop(rt, &res)) + err = dn_rt_set_next_hop(rt, &res); + if (err) goto e_neighbour; hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst); dn_insert_route(rt, hash, (struct dn_route **)&skb->dst); - err = 0; done: if (neigh) @@ -1449,7 +1507,7 @@ * they deal only with inputs and not with replies like they do * currently. */ - RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_saddr); + RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src); if (rt->rt_daddr != rt->rt_gateway) RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) @@ -1490,6 +1548,7 @@ struct flowi fl; memset(&fl, 0, sizeof(fl)); + fl.proto = DNPROTO_NSP; skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) @@ -1609,54 +1668,114 @@ } #ifdef CONFIG_PROC_FS +struct dn_rt_cache_iter_state { + int bucket; +}; -static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int length) +static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq) { - int len = 0; - off_t pos = 0; - off_t begin = 0; - struct dn_route *rt; - int i; - char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN]; + struct dn_route *rt = NULL; + struct dn_rt_cache_iter_state *s = seq->private; - for(i = 0; i <= dn_rt_hash_mask; i++) { + for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) { rcu_read_lock(); - rt = dn_rt_hash_table[i].chain; - for(; rt != NULL; rt = rt->u.rt_next) { - read_barrier_depends(); - len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n", - rt->u.dst.dev ? rt->u.dst.dev->name : "*", - dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), - dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), - atomic_read(&rt->u.dst.__refcnt), - rt->u.dst.__use, - (int) dst_metric(&rt->u.dst, RTAX_RTT) - ); - + rt = dn_rt_hash_table[s->bucket].chain; + if (rt) + break; + rcu_read_unlock(); + } + return rt; +} +static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt) +{ + struct dn_rt_cache_iter_state *s = seq->private; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } + smp_read_barrier_depends(); + rt = rt->u.rt_next; + while(!rt) { rcu_read_unlock(); - if (pos > offset + length) + if (--s->bucket < 0) break; + rcu_read_lock(); + rt = dn_rt_hash_table[s->bucket].chain; } + return rt; +} + +static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct dn_route *rt = dn_rt_cache_get_first(seq); + + if (rt) { + while(*pos && (rt = dn_rt_cache_get_next(seq, rt))) + --*pos; + } + return *pos ? NULL : rt; +} + +static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct dn_route *rt = dn_rt_cache_get_next(seq, v); + ++*pos; + return rt; +} - *start = buffer + (offset - begin); - len -= (offset - begin); +static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v) +{ + rcu_read_unlock(); +} - if (len > length) len = length; +static int dn_rt_cache_seq_show(struct seq_file *seq, void *v) +{ + struct dn_route *rt = v; + char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN]; - return(len); + seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n", + rt->u.dst.dev ? rt->u.dst.dev->name : "*", + dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), + dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), + atomic_read(&rt->u.dst.__refcnt), + rt->u.dst.__use, + (int) dst_metric(&rt->u.dst, RTAX_RTT)); + return 0; } +static struct seq_operations dn_rt_cache_seq_ops = { + .start = dn_rt_cache_seq_start, + .next = dn_rt_cache_seq_next, + .stop = dn_rt_cache_seq_stop, + .show = dn_rt_cache_seq_show, +}; + +static int dn_rt_cache_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (!s) + goto out; + rc = seq_open(file, &dn_rt_cache_seq_ops); + if (rc) + goto out_kfree; + seq = file->private_data; + seq->private = s; + memset(s, 0, sizeof(*s)); +out: + return rc; +out_kfree: + kfree(s); + goto out; +} + +static struct file_operations dn_rt_cache_seq_fops = { + .open = dn_rt_cache_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + #endif /* CONFIG_PROC_FS */ void __init dn_route_init(void) @@ -1714,9 +1833,7 @@ dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1); -#ifdef CONFIG_PROC_FS - proc_net_create("decnet_cache",0,decnet_cache_get_info); -#endif /* CONFIG_PROC_FS */ + proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops); } void __exit dn_route_cleanup(void) diff -Nru a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c --- a/net/decnet/dn_rules.c Mon May 12 20:55:48 2003 +++ b/net/decnet/dn_rules.c Mon May 12 20:55:48 2003 @@ -173,9 +173,11 @@ memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ); new_r->r_ifname[IFNAMSIZ-1] = 0; new_r->r_ifindex = -1; - dev = __dev_get_by_name(new_r->r_ifname); - if (dev) + dev = dev_get_by_name(new_r->r_ifname); + if (dev) { new_r->r_ifindex = dev->ifindex; + dev_put(dev); + } } rp = &dn_fib_rules; diff -Nru a/net/decnet/dn_table.c b/net/decnet/dn_table.c --- a/net/decnet/dn_table.c Mon May 12 20:55:45 2003 +++ b/net/decnet/dn_table.c Mon May 12 20:55:45 2003 @@ -744,86 +744,6 @@ return err; } -#ifdef CONFIG_PROC_FS - -static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi) -{ - static unsigned type2flags[RTN_MAX+1] = { - 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0 - }; - unsigned flags = type2flags[type]; - - if (fi && fi->fib_nh->nh_gw) - flags |= RTF_GATEWAY; - if (mask == 0xFFFF) - flags |= RTF_HOST; - if (dead) - flags |= RTF_UP; - return flags; -} - -static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer) -{ - int len; - unsigned flags = dn_fib_flag_trans(type, dead, mask, fi); - - if (fi) { - len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", - fi->dn_fib_dev ? fi->dn_fib_dev->name : "*", prefix, - fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, - mask, 0, 0, 0); - } else { - len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u", - prefix, 0, - flags, 0, 0, 0, - mask, 0, 0, 0); - } - memset(buffer+len, ' ', 127-len); - buffer[127] = '\n'; -} - -static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count) -{ - struct dn_hash *table = (struct dn_hash *)tb->data; - struct dn_zone *dz; - int pos = 0; - int n = 0; - - read_lock(&dn_fib_tables_lock); - for(dz = table->dh_zone_list; dz; dz = dz->dz_next) { - int i; - struct dn_fib_node *f; - int maxslot = dz->dz_divisor; - struct dn_fib_node **fp = dz->dz_hash; - - if (dz->dz_nent == 0) - continue; - - if (pos + dz->dz_nent < first) { - pos += dz->dz_nent; - continue; - } - - for(i = 0; i < maxslot; i++, fp++) { - for(f = *fp; f ; f = f->fn_next) { - if (++pos <= first) - continue; - dn_fib_node_get_info(f->fn_type, - f->fn_state & DN_S_ZOMBIE, - DN_FIB_INFO(f), - dz_prefix(f->fn_key, dz), - DZ_MASK(dz), buffer); - buffer += 128; - if (++n >= count) - goto out; - } - } - } -out: - read_unlock(&dn_fib_tables_lock); - return n; -} -#endif /* CONFIG_PROC_FS */ struct dn_fib_table *dn_fib_get_table(int n, int create) { @@ -855,9 +775,6 @@ t->delete = dn_fib_table_delete; t->lookup = dn_fib_table_lookup; t->flush = dn_fib_table_flush; -#ifdef CONFIG_PROC_FS - t->get_info = dn_fib_table_get_info; -#endif t->dump = dn_fib_table_dump; memset(t->data, 0, sizeof(struct dn_hash)); dn_fib_tables[n] = t; diff -Nru a/net/decnet/netfilter/Kconfig b/net/decnet/netfilter/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/decnet/netfilter/Kconfig Mon May 12 20:55:49 2003 @@ -0,0 +1,15 @@ +# +# DECnet netfilter configuration +# + +menu "DECnet: Netfilter Configuration" + depends on DECNET && NETFILTER && EXPERIMENTAL + +config DECNET_NF_GRABULATOR + tristate "Routing message grabulator (for userland routing daemon)" + help + Enable this module if you want to use the userland DECnet routing + daemon. You will also need to enable routing support for DECnet + unless you just want to monitor routing messages from other nodes. + +endmenu diff -Nru a/net/decnet/netfilter/Makefile b/net/decnet/netfilter/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/decnet/netfilter/Makefile Mon May 12 20:55:49 2003 @@ -0,0 +1,6 @@ +# +# Makefile for DECnet netfilter modules +# + +obj-$(CONFIG_DECNET_NF_GRABULATOR) += dn_rtmsg.o + diff -Nru a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/decnet/netfilter/dn_rtmsg.c Mon May 12 20:55:49 2003 @@ -0,0 +1,167 @@ +/* + * DECnet An implementation of the DECnet protocol suite for the LINUX + * operating system. DECnet is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * DECnet Routing Message Grabulator + * + * (C) 2000 ChyGwyn Limited - http://www.chygwyn.com/ + * This code may be copied under the GPL v.2 or at your option + * any later version. + * + * Author: Steven Whitehouse + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static struct sock *dnrmg = NULL; + + +static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp) +{ + struct sk_buff *skb = NULL; + size_t size; + unsigned char *old_tail; + struct nlmsghdr *nlh; + unsigned char *ptr; + struct nf_dn_rtmsg *rtm; + + size = NLMSG_SPACE(rt_skb->len); + size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)); + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) + goto nlmsg_failure; + old_tail = skb->tail; + nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh)); + rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh); + rtm->nfdn_ifindex = rt_skb->dev->ifindex; + ptr = NFDN_RTMSG(rtm); + memcpy(ptr, rt_skb->data, rt_skb->len); + nlh->nlmsg_len = skb->tail - old_tail; + return skb; + +nlmsg_failure: + if (skb) + kfree(skb); + *errp = -ENOMEM; + if (net_ratelimit()) + printk(KERN_ERR "dn_rtmsg: error creating netlink message\n"); + return NULL; +} + +static void dnrmg_send_peer(struct sk_buff *skb) +{ + struct sk_buff *skb2; + int status = 0; + int group = 0; + unsigned char flags = *skb->data; + + switch(flags & DN_RT_CNTL_MSK) { + case DN_RT_PKT_L1RT: + group = DNRMG_L1_GROUP; + break; + case DN_RT_PKT_L2RT: + group = DNRMG_L2_GROUP; + break; + default: + return; + } + + skb2 = dnrmg_build_message(skb, &status); + if (skb2 == NULL) + return; + NETLINK_CB(skb2).dst_groups = group; + netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC); +} + + +static unsigned int dnrmg_hook(unsigned int hook, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + dnrmg_send_peer(*pskb); + return NF_ACCEPT; +} + + +#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) + +static inline void dnrmg_receive_user_skb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; + + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) + return; + + if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) + RCV_SKB_FAIL(-EPERM); + + /* Eventually we might send routing messages too */ + + RCV_SKB_FAIL(-EINVAL); +} + +static void dnrmg_receive_user_sk(struct sock *sk, int len) +{ + struct sk_buff *skb; + + while((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + dnrmg_receive_user_skb(skb); + kfree_skb(skb); + } +} + +static struct nf_hook_ops dnrmg_ops = { + .hook = dnrmg_hook, + .pf = PF_DECnet, + .hooknum = NF_DN_ROUTE, + .priority = NF_DN_PRI_DNRTMSG, +}; + +static int __init init(void) +{ + int rv = 0; + + dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk); + if (dnrmg == NULL) { + printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket"); + return -ENOMEM; + } + + rv = nf_register_hook(&dnrmg_ops); + if (rv) { + sock_release(dnrmg->socket); + } + + return rv; +} + +static void __exit fini(void) +{ + nf_unregister_hook(&dnrmg_ops); + sock_release(dnrmg->socket); +} + + +MODULE_DESCRIPTION("DECnet Routing Message Grabulator"); +MODULE_AUTHOR("Steven Whitehouse "); +MODULE_LICENSE("GPL"); + +module_init(init); +module_exit(fini); + diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c --- a/net/econet/af_econet.c Mon May 12 20:55:46 2003 +++ b/net/econet/af_econet.c Mon May 12 20:55:46 2003 @@ -325,7 +325,7 @@ { /* Real hardware Econet. We're not worthy etc. */ #ifdef CONFIG_ECONET_NATIVE - atomic_inc(&dev->refcnt); + dev_hold(dev); skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, msg->msg_flags & MSG_DONTWAIT, &err); diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/af_inet.c Mon May 12 20:55:44 2003 @@ -94,7 +94,6 @@ #include #include #include -#include #include #include #include @@ -129,7 +128,8 @@ /* The inetsw table contains everything that inet_create needs to * build a new socket. */ -struct list_head inetsw[SOCK_MAX]; +static struct list_head inetsw[SOCK_MAX]; +static spinlock_t inetsw_lock = SPIN_LOCK_UNLOCKED; /* New destruction routine */ @@ -337,8 +337,8 @@ /* Look for the requested type/protocol pair. */ answer = NULL; - br_read_lock_bh(BR_NETPROTO_LOCK); - list_for_each(p, &inetsw[sock->type]) { + rcu_read_lock(); + list_for_each_rcu(p, &inetsw[sock->type]) { answer = list_entry(p, struct inet_protosw, list); /* Check the non-wild match. */ @@ -356,7 +356,6 @@ } answer = NULL; } - br_read_unlock_bh(BR_NETPROTO_LOCK); err = -ESOCKTNOSUPPORT; if (!answer) @@ -373,6 +372,7 @@ sk->no_check = answer->no_check; if (INET_PROTOSW_REUSE & answer->flags) sk->reuse = 1; + rcu_read_unlock(); inet = inet_sk(sk); @@ -427,6 +427,7 @@ out: return err; out_sk_free: + rcu_read_unlock(); sk_free(sk); goto out; } @@ -926,6 +927,7 @@ struct net_proto_family inet_family_ops = { .family = PF_INET, .create = inet_create, + .owner = THIS_MODULE, }; @@ -978,7 +980,7 @@ int protocol = p->protocol; struct list_head *last_perm; - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&inetsw_lock); if (p->type > SOCK_MAX) goto out_illegal; @@ -1007,9 +1009,12 @@ * non-permanent entry. This means that when we remove this entry, the * system automatically returns to the old behavior. */ - list_add(&p->list, last_perm); + list_add_rcu(&p->list, last_perm); out: - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&inetsw_lock); + + synchronize_net(); + return; out_permanent: @@ -1031,9 +1036,11 @@ "Attempt to unregister permanent protocol %d.\n", p->protocol); } else { - br_write_lock_bh(BR_NETPROTO_LOCK); - list_del(&p->list); - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&inetsw_lock); + list_del_rcu(&p->list); + spin_unlock_bh(&inetsw_lock); + + synchronize_net(); } } diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c --- a/net/ipv4/arp.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/arp.c Mon May 12 20:55:48 2003 @@ -1384,6 +1384,7 @@ } static struct file_operations arp_seq_fops = { + .owner = THIS_MODULE, .open = arp_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c --- a/net/ipv4/fib_frontend.c Mon May 12 20:55:49 2003 +++ b/net/ipv4/fib_frontend.c Mon May 12 20:55:49 2003 @@ -115,9 +115,9 @@ if (res.type != RTN_LOCAL) goto out; dev = FIB_RES_DEV(res); - if (dev) - atomic_inc(&dev->refcnt); + if (dev) + dev_hold(dev); out: fib_res_put(&res); return dev; diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c --- a/net/ipv4/fib_hash.c Mon May 12 20:55:46 2003 +++ b/net/ipv4/fib_hash.c Mon May 12 20:55:46 2003 @@ -1065,6 +1065,7 @@ } static struct file_operations fib_seq_fops = { + .owner = THIS_MODULE, .open = fib_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c --- a/net/ipv4/fib_semantics.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/fib_semantics.c Mon May 12 20:55:45 2003 @@ -406,7 +406,7 @@ if (!(dev->flags&IFF_UP)) return -ENETDOWN; nh->nh_dev = dev; - atomic_inc(&dev->refcnt); + dev_hold(dev); nh->nh_scope = RT_SCOPE_LINK; return 0; } @@ -429,7 +429,7 @@ nh->nh_oif = FIB_RES_OIF(res); if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL) goto out; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); err = -ENETDOWN; if (!(nh->nh_dev->flags & IFF_UP)) goto out; @@ -451,7 +451,7 @@ return -ENETDOWN; } nh->nh_dev = in_dev->dev; - atomic_inc(&nh->nh_dev->refcnt); + dev_hold(nh->nh_dev); nh->nh_scope = RT_SCOPE_HOST; in_dev_put(in_dev); } diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c --- a/net/ipv4/icmp.c Mon May 12 20:55:49 2003 +++ b/net/ipv4/icmp.c Mon May 12 20:55:49 2003 @@ -695,15 +695,12 @@ } read_unlock(&raw_v4_lock); - /* - * This can't change while we are doing it. - * Callers have obtained BR_NETPROTO_LOCK so - * we are OK. - */ - + rcu_read_lock(); ipprot = inet_protos[hash]; + smp_read_barrier_depends(); if (ipprot && ipprot->err_handler) ipprot->err_handler(skb, info); + rcu_read_unlock(); out: return; diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c --- a/net/ipv4/ip_input.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/ip_input.c Mon May 12 20:55:44 2003 @@ -215,6 +215,7 @@ /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data; + rcu_read_lock(); { /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */ int protocol = skb->nh.iph->protocol; @@ -235,10 +236,11 @@ if ((ipprot = inet_protos[hash]) != NULL) { int ret; + smp_read_barrier_depends(); if (!ipprot->no_policy && !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { kfree_skb(skb); - return 0; + goto out; } ret = ipprot->handler(skb); if (ret < 0) { @@ -258,6 +260,8 @@ kfree_skb(skb); } } + out: + rcu_read_unlock(); return 0; } diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c --- a/net/ipv4/ip_output.c Mon May 12 20:55:49 2003 +++ b/net/ipv4/ip_output.c Mon May 12 20:55:49 2003 @@ -685,16 +685,6 @@ return 0; } -static void -skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) -{ - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - frag->page = page; - frag->page_offset = off; - frag->size = size; - skb_shinfo(skb)->nr_frags = i+1; -} - static inline unsigned int csum_page(struct page *page, int offset, int copy) { diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c --- a/net/ipv4/ipcomp.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/ipcomp.c Mon May 12 20:55:48 2003 @@ -94,7 +94,9 @@ memcpy(&tmp_iph, iph, iph->ihl * 4); nexthdr = *(u8 *)skb->data; skb_pull(skb, sizeof(struct ipcomp_hdr)); + skb->nh.raw += sizeof(struct ipcomp_hdr); memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4); + iph = skb->nh.iph; iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ipcomp_hdr)); iph->protocol = nexthdr; skb->h.raw = skb->data; @@ -267,6 +269,67 @@ xfrm_state_put(x); } +/* We always hold one tunnel user reference to indicate a tunnel */ +static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) +{ + struct xfrm_state *t; + + t = xfrm_state_alloc(); + if (t == NULL) + goto out; + + t->id.proto = IPPROTO_IPIP; + t->id.spi = x->props.saddr.a4; + t->id.daddr.a4 = x->id.daddr.a4; + memcpy(&t->sel, &x->sel, sizeof(t->sel)); + t->props.family = AF_INET; + t->props.mode = 1; + t->props.saddr.a4 = x->props.saddr.a4; + + t->type = xfrm_get_type(IPPROTO_IPIP, t->props.family); + if (t->type == NULL) + goto error; + + if (t->type->init_state(t, NULL)) + goto error; + + t->km.state = XFRM_STATE_VALID; + atomic_set(&t->tunnel_users, 1); +out: + return t; + +error: + xfrm_state_put(t); + t = NULL; + goto out; +} + +/* + * Must be protected by xfrm_cfg_sem. State and tunnel user references are + * always incremented on success. + */ +static int ipcomp_tunnel_attach(struct xfrm_state *x) +{ + int err = 0; + struct xfrm_state *t; + + t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4, + x->props.saddr.a4, IPPROTO_IPIP, AF_INET); + if (!t) { + t = ipcomp_tunnel_create(x); + if (!t) { + err = -EINVAL; + goto out; + } + xfrm_state_insert(t); + xfrm_state_hold(t); + } + x->tunnel = t; + atomic_inc(&t->tunnel_users); +out: + return err; +} + static void ipcomp_free_data(struct ipcomp_data *ipcd) { if (ipcd->tfm) @@ -305,6 +368,12 @@ ipcd->tfm = crypto_alloc_tfm(x->calg->alg_name, 0); if (!ipcd->tfm) goto error; + + if (x->props.mode) { + err = ipcomp_tunnel_attach(x); + if (err) + goto error; + } calg_desc = xfrm_calg_get_byname(x->calg->alg_name); BUG_ON(!calg_desc); diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c --- a/net/ipv4/netfilter/ip_conntrack_core.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/netfilter/ip_conntrack_core.c Mon May 12 20:55:44 2003 @@ -1188,12 +1188,9 @@ local_bh_enable(); if (!skb) { - if (sk) sock_put(sk); + if (sk) + sock_put(sk); return skb; - } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { - kfree_skb(skb); - if (sk) sock_put(sk); - return NULL; } if (sk) { diff -Nru a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c --- a/net/ipv4/netfilter/ip_fw_compat.c Mon May 12 20:55:46 2003 +++ b/net/ipv4/netfilter/ip_fw_compat.c Mon May 12 20:55:46 2003 @@ -15,34 +15,10 @@ #include #include #include +#include "ip_fw_compat.h" static struct firewall_ops *fwops; -/* From ip_fw_compat_redir.c */ -extern unsigned int -do_redirect(struct sk_buff *skb, - const struct net_device *dev, - u_int16_t redirpt); - -extern void -check_for_redirect(struct sk_buff *skb); - -extern void -check_for_unredirect(struct sk_buff *skb); - -/* From ip_fw_compat_masq.c */ -extern unsigned int -do_masquerade(struct sk_buff **pskb, const struct net_device *dev); - -extern unsigned int -check_for_masq_error(struct sk_buff *pskb); - -extern unsigned int -check_for_demasq(struct sk_buff **pskb); - -extern int __init masq_init(void); -extern void masq_cleanup(void); - /* They call these; we do what they want. */ int register_firewall(int pf, struct firewall_ops *fw) { @@ -167,7 +143,7 @@ /* Handle ICMP errors from client here */ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP && (*pskb)->nfct) - check_for_masq_error(*pskb); + check_for_masq_error(pskb); } return NF_ACCEPT; diff -Nru a/net/ipv4/netfilter/ip_fw_compat.h b/net/ipv4/netfilter/ip_fw_compat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/netfilter/ip_fw_compat.h Mon May 12 20:55:49 2003 @@ -0,0 +1,28 @@ +#ifndef _LINUX_IP_FW_COMPAT_H +#define _LINUX_IP_FW_COMPAT_H + +/* From ip_fw_compat_redir.c */ +extern unsigned int +do_redirect(struct sk_buff *skb, + const struct net_device *dev, + u_int16_t redirpt); + +extern void +check_for_redirect(struct sk_buff *skb); + +extern void +check_for_unredirect(struct sk_buff *skb); + +/* From ip_fw_compat_masq.c */ +extern unsigned int +do_masquerade(struct sk_buff **pskb, const struct net_device *dev); + +extern void check_for_masq_error(struct sk_buff **pskb); + +extern unsigned int +check_for_demasq(struct sk_buff **pskb); + +extern int __init masq_init(void); +extern void masq_cleanup(void); + +#endif /* _LINUX_IP_FW_COMPAT_H */ diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c --- a/net/ipv4/netfilter/ip_fw_compat_masq.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/netfilter/ip_fw_compat_masq.c Mon May 12 20:55:48 2003 @@ -25,6 +25,7 @@ #include #include #include +#include "ip_fw_compat.h" #if 0 #define DEBUGP printk @@ -35,16 +36,15 @@ unsigned int do_masquerade(struct sk_buff **pskb, const struct net_device *dev) { - struct iphdr *iph = (*pskb)->nh.iph; struct ip_nat_info *info; enum ip_conntrack_info ctinfo; struct ip_conntrack *ct; unsigned int ret; /* Sorry, only ICMP, TCP and UDP. */ - if (iph->protocol != IPPROTO_ICMP - && iph->protocol != IPPROTO_TCP - && iph->protocol != IPPROTO_UDP) + if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP + && (*pskb)->nh.iph->protocol != IPPROTO_TCP + && (*pskb)->nh.iph->protocol != IPPROTO_UDP) return NF_DROP; /* Feed it to connection tracking; in fact we're in NF_IP_FORWARD, @@ -68,7 +68,7 @@ /* Setup the masquerade, if not already */ if (!info->initialized) { u_int32_t newsrc; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->daddr } } }; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } }; struct rtable *rt; struct ip_nat_multi_range range; @@ -103,19 +103,19 @@ } void -check_for_masq_error(struct sk_buff *skb) +check_for_masq_error(struct sk_buff **pskb) { enum ip_conntrack_info ctinfo; struct ip_conntrack *ct; - ct = ip_conntrack_get(skb, &ctinfo); + ct = ip_conntrack_get(*pskb, &ctinfo); /* Wouldn't be here if not tracked already => masq'ed ICMP ping or error related to masq'd connection */ IP_NF_ASSERT(ct); if (ctinfo == IP_CT_RELATED) { - icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING, + icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING, CTINFO2DIR(ctinfo)); - icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING, + icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING, CTINFO2DIR(ctinfo)); } } @@ -124,19 +124,18 @@ check_for_demasq(struct sk_buff **pskb) { struct ip_conntrack_tuple tuple; - struct iphdr *iph = (*pskb)->nh.iph; struct ip_conntrack_protocol *protocol; struct ip_conntrack_tuple_hash *h; enum ip_conntrack_info ctinfo; struct ip_conntrack *ct; int ret; - protocol = ip_ct_find_proto(iph->protocol); + protocol = ip_ct_find_proto((*pskb)->nh.iph->protocol); /* We don't feed packets to conntrack system unless we know they're part of an connection already established by an explicit masq command. */ - switch (iph->protocol) { + switch ((*pskb)->nh.iph->protocol) { case IPPROTO_ICMP: /* ICMP errors. */ ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING); @@ -146,16 +145,10 @@ server here (== DNAT). Do SNAT icmp manips in POST_ROUTING handling. */ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - /* FIXME: Remove once NAT handled non-linear. - */ - if (skb_is_nonlinear(*pskb) - && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - - icmp_reply_translation(*pskb, ct, + icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING, CTINFO2DIR(ctinfo)); - icmp_reply_translation(*pskb, ct, + icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING, CTINFO2DIR(ctinfo)); } @@ -166,7 +159,7 @@ case IPPROTO_UDP: IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0); - if (!get_tuple(iph, *pskb, iph->ihl*4, &tuple, protocol)) { + if (!get_tuple((*pskb)->nh.iph, *pskb, (*pskb)->nh.iph->ihl*4, &tuple, protocol)) { if (net_ratelimit()) printk("ip_fw_compat_masq: Can't get tuple\n"); return NF_ACCEPT; diff -Nru a/net/ipv4/netfilter/ip_fw_compat_redir.c b/net/ipv4/netfilter/ip_fw_compat_redir.c --- a/net/ipv4/netfilter/ip_fw_compat_redir.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/netfilter/ip_fw_compat_redir.c Mon May 12 20:55:48 2003 @@ -28,6 +28,7 @@ #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock) #include +#include "ip_fw_compat.h" #if 0 #define DEBUGP printk diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c --- a/net/ipv4/netfilter/ip_nat_core.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/netfilter/ip_nat_core.c Mon May 12 20:55:45 2003 @@ -13,6 +13,8 @@ #include #include #include /* For tcp_prot in getorigdst */ +#include +#include #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock) #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock) @@ -698,14 +700,29 @@ list_prepend(&byipsproto[ipsprotohash], &info->byipsproto); } -static void -manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len, +/* Returns true if succeeded. */ +static int +manip_pkt(u_int16_t proto, + struct sk_buff **pskb, + unsigned int iphdroff, const struct ip_conntrack_manip *manip, - enum ip_nat_manip_type maniptype, - __u32 *nfcache) + enum ip_nat_manip_type maniptype) { - *nfcache |= NFC_ALTERED; - find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype); + struct iphdr *iph; + + (*pskb)->nfcache |= NFC_ALTERED; + if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph))) + return 0; + + iph = (void *)(*pskb)->data + iphdroff; + + /* Manipulate protcol part. */ + if (!find_nat_proto(proto)->manip_pkt(pskb, + iphdroff + iph->ihl*4, + manip, maniptype)) + return 0; + + iph = (void *)(*pskb)->data + iphdroff; if (maniptype == IP_NAT_MANIP_SRC) { iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip, @@ -716,17 +733,7 @@ iph->check); iph->daddr = manip->ip; } -#if 0 - if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) - DEBUGP("IP: checksum on packet bad.\n"); - - if (proto == IPPROTO_TCP) { - void *th = (u_int32_t *)iph + iph->ihl; - if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr, - csum_partial((char *)th, len-4*iph->ihl, 0))) - DEBUGP("TCP: checksum on packet bad\n"); - } -#endif + return 1; } static inline int exp_for_packet(struct ip_conntrack_expect *exp, @@ -754,25 +761,13 @@ unsigned int i; struct ip_nat_helper *helper; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP; + int proto = (*pskb)->nh.iph->protocol; /* Need nat lock to protect against modification, but neither conntrack (referenced) and helper (deleted with synchronize_bh()) can vanish. */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->num_manips; i++) { - /* raw socket (tcpdump) may have clone of incoming - skb: don't disturb it --RR */ - if (skb_cloned(*pskb) && !(*pskb)->sk) { - struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) { - READ_UNLOCK(&ip_nat_lock); - return NF_DROP; - } - kfree_skb(*pskb); - *pskb = nskb; - } - if (info->manips[i].direction == dir && info->manips[i].hooknum == hooknum) { DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n", @@ -781,12 +776,12 @@ ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip), htons(info->manips[i].manip.u.all)); - manip_pkt((*pskb)->nh.iph->protocol, - (*pskb)->nh.iph, - (*pskb)->len, - &info->manips[i].manip, - info->manips[i].maniptype, - &(*pskb)->nfcache); + if (!manip_pkt(proto, pskb, 0, + &info->manips[i].manip, + info->manips[i].maniptype)) { + READ_UNLOCK(&ip_nat_lock); + return NF_DROP; + } } } helper = info->helper; @@ -839,12 +834,14 @@ /* Adjust sequence number only once per packet * (helper is called at all hooks) */ - if (is_tcp && (hooknum == NF_IP_POST_ROUTING - || hooknum == NF_IP_LOCAL_IN)) { + if (proto == IPPROTO_TCP + && (hooknum == NF_IP_POST_ROUTING + || hooknum == NF_IP_LOCAL_IN)) { DEBUGP("ip_nat_core: adjusting sequence number\n"); /* future: put this in a l4-proto specific function, * and call this function here. */ - ip_nat_seq_adjust(*pskb, ct, ctinfo); + if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) + ret = NF_DROP; } return ret; @@ -855,39 +852,54 @@ /* not reached */ } -unsigned int -icmp_reply_translation(struct sk_buff *skb, +int +icmp_reply_translation(struct sk_buff **pskb, struct ip_conntrack *conntrack, unsigned int hooknum, int dir) { - struct iphdr *iph = skb->nh.iph; - struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl); - struct iphdr *inner = (struct iphdr *)(hdr + 1); - size_t datalen = skb->len - ((void *)inner - (void *)iph); + struct { + struct icmphdr icmp; + struct iphdr ip; + } *inside; unsigned int i; struct ip_nat_info *info = &conntrack->nat.info; + int hdrlen; + + if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside))) + return 0; + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + + /* We're actually going to mangle it beyond trivial checksum + adjustment, so make sure the current checksum is correct. */ + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) { + hdrlen = (*pskb)->nh.iph->ihl * 4; + if ((u16)csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, 0))) + return 0; + } - IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr)); /* Must be RELATED */ - IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master + IP_NF_ASSERT((*pskb)->nfct + - (struct ip_conntrack *)(*pskb)->nfct->master == IP_CT_RELATED - || skb->nfct - (struct ip_conntrack *)skb->nfct->master + || (*pskb)->nfct + - (struct ip_conntrack *)(*pskb)->nfct->master == IP_CT_RELATED+IP_CT_IS_REPLY); /* Redirects on non-null nats must be dropped, else they'll start talking to each other without our translation, and be confused... --RR */ - if (hdr->type == ICMP_REDIRECT) { + if (inside->icmp.type == ICMP_REDIRECT) { /* Don't care about races here. */ if (info->initialized != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST)) || info->num_manips != 0) - return NF_DROP; + return 0; } DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n", - skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); + *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); /* Note: May not be from a NAT'd host, but probably safest to do translation always as if it came from the host itself (even though a "host unreachable" coming from the host @@ -918,11 +930,13 @@ ? "DST" : "SRC", NIPQUAD(info->manips[i].manip.ip), ntohs(info->manips[i].manip.u.udp.port)); - manip_pkt(inner->protocol, inner, - skb->len - ((void *)inner - (void *)iph), - &info->manips[i].manip, - !info->manips[i].maniptype, - &skb->nfcache); + if (!manip_pkt(inside->ip.protocol, pskb, + (*pskb)->nh.iph->ihl*4 + + sizeof(inside->icmp), + &info->manips[i].manip, + !info->manips[i].maniptype)) + goto unlock_fail; + /* Outer packet needs to have IP header NATed like it's a reply. */ @@ -932,22 +946,86 @@ info->manips[i].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", NIPQUAD(info->manips[i].manip.ip)); - manip_pkt(0, iph, skb->len, - &info->manips[i].manip, - info->manips[i].maniptype, - &skb->nfcache); + if (!manip_pkt(0, pskb, 0, + &info->manips[i].manip, + info->manips[i].maniptype)) + goto unlock_fail; } } READ_UNLOCK(&ip_nat_lock); - /* Since we mangled inside ICMP packet, recalculate its - checksum from scratch. (Hence the handling of incorrect - checksums in conntrack, so we don't accidentally fix one.) */ - hdr->checksum = 0; - hdr->checksum = ip_compute_csum((unsigned char *)hdr, - sizeof(*hdr) + datalen); + hdrlen = (*pskb)->nh.iph->ihl * 4; - return NF_ACCEPT; + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; + + inside->icmp.checksum = 0; + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, + (*pskb)->len - hdrlen, + 0)); + return 1; + + unlock_fail: + READ_UNLOCK(&ip_nat_lock); + return 0; +} + +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) +{ + struct sk_buff *nskb; + unsigned int iplen; + + if (writable_len > (*pskb)->len) + return 0; + + /* Not exclusive use of packet? Must copy. */ + if (skb_shared(*pskb) || skb_cloned(*pskb)) + goto copy_skb; + + /* Alexey says IP hdr is always modifiable and linear, so ok. */ + if (writable_len <= (*pskb)->nh.iph->ihl*4) + return 1; + + iplen = writable_len - (*pskb)->nh.iph->ihl*4; + + /* DaveM says protocol headers are also modifiable. */ + switch ((*pskb)->nh.iph->protocol) { + case IPPROTO_TCP: { + struct tcphdr hdr; + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, + &hdr, sizeof(hdr)) != 0) + goto copy_skb; + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4) + goto pull_skb; + goto copy_skb; + } + case IPPROTO_UDP: + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr)) + goto pull_skb; + goto copy_skb; + case IPPROTO_ICMP: + if (writable_len + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr)) + goto pull_skb; + goto copy_skb; + /* Insert other cases here as desired */ + } + +copy_skb: + nskb = skb_copy(*pskb, GFP_ATOMIC); + if (!nskb) + return 0; + BUG_ON(skb_is_nonlinear(nskb)); + + /* Rest of kernel will get very unhappy if we pass it a + suddenly-orphaned skbuff */ + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + return 1; + +pull_skb: + return pskb_may_pull(*pskb, writable_len); } int __init ip_nat_init(void) diff -Nru a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c --- a/net/ipv4/netfilter/ip_nat_helper.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/netfilter/ip_nat_helper.c Mon May 12 20:55:45 2003 @@ -46,14 +46,14 @@ #endif DECLARE_LOCK(ip_nat_seqofs_lock); - -static inline int -ip_nat_resize_packet(struct sk_buff **skb, - struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo, - int new_size) + +/* Setup TCP sequence correction given this change at this sequence */ +static inline void +adjust_tcp_sequence(u32 seq, + int sizediff, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) { - struct iphdr *iph; int dir; struct ip_nat_seq *this_way, *other_way; @@ -65,52 +65,89 @@ this_way = &ct->nat.info.seq[dir]; other_way = &ct->nat.info.seq[!dir]; - if (new_size > (*skb)->len + skb_tailroom(*skb)) { - struct sk_buff *newskb; - newskb = skb_copy_expand(*skb, skb_headroom(*skb), - new_size - (*skb)->len, - GFP_ATOMIC); - - if (!newskb) { - printk("ip_nat_resize_packet: oom\n"); - return 0; - } else { - kfree_skb(*skb); - *skb = newskb; - } + DEBUGP("ip_nat_resize_packet: Seq_offset before: "); + DUMP_OFFSET(this_way); + + LOCK_BH(&ip_nat_seqofs_lock); + + /* SYN adjust. If it's uninitialized, of this is after last + * correction, record it: we don't handle more than one + * adjustment in the window, but do deal with common case of a + * retransmit */ + if (this_way->offset_before == this_way->offset_after + || before(this_way->correction_pos, seq)) { + this_way->correction_pos = seq; + this_way->offset_before = this_way->offset_after; + this_way->offset_after += sizediff; } + UNLOCK_BH(&ip_nat_seqofs_lock); - iph = (*skb)->nh.iph; - if (iph->protocol == IPPROTO_TCP) { - struct tcphdr *tcph = (void *)iph + iph->ihl*4; - - DEBUGP("ip_nat_resize_packet: Seq_offset before: "); - DUMP_OFFSET(this_way); - - LOCK_BH(&ip_nat_seqofs_lock); - - /* SYN adjust. If it's uninitialized, of this is after last - * correction, record it: we don't handle more than one - * adjustment in the window, but do deal with common case of a - * retransmit */ - if (this_way->offset_before == this_way->offset_after - || before(this_way->correction_pos, ntohl(tcph->seq))) { - this_way->correction_pos = ntohl(tcph->seq); - this_way->offset_before = this_way->offset_after; - this_way->offset_after = (int32_t) - this_way->offset_before + new_size - - (*skb)->len; - } + DEBUGP("ip_nat_resize_packet: Seq_offset after: "); + DUMP_OFFSET(this_way); +} + +/* Frobs data inside this packet, which is linear. */ +static void mangle_contents(struct sk_buff *skb, + unsigned int dataoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + unsigned char *data; + + BUG_ON(skb_is_nonlinear(skb)); + data = (unsigned char *)skb->nh.iph + dataoff; - UNLOCK_BH(&ip_nat_seqofs_lock); + /* move post-replacement */ + memmove(data + match_offset + rep_len, + data + match_offset + match_len, + skb->tail - (data + match_offset + match_len)); - DEBUGP("ip_nat_resize_packet: Seq_offset after: "); - DUMP_OFFSET(this_way); + /* insert data from buffer */ + memcpy(data + match_offset, rep_buffer, rep_len); + + /* update skb info */ + if (rep_len > match_len) { + DEBUGP("ip_nat_mangle_packet: Extending packet by " + "%u from %u bytes\n", rep_len - match_len, + skb->len); + skb_put(skb, rep_len - match_len); + } else { + DEBUGP("ip_nat_mangle_packet: Shrinking packet from " + "%u from %u bytes\n", match_len - rep_len, + skb->len); + __skb_trim(skb, skb->len + rep_len - match_len); } - - return 1; + + /* fix IP hdr checksum information */ + skb->nh.iph->tot_len = htons(skb->len); + ip_send_check(skb->nh.iph); + skb->csum = csum_partial(data, skb->len - dataoff, 0); } +/* Unusual, but possible case. */ +static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) +{ + struct sk_buff *nskb; + + if ((*pskb)->len + extra > 65535) + return 0; + + nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); + if (!nskb) + return 0; + + /* Transfer socket to new skb. */ + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); +#ifdef CONFIG_NETFILTER_DEBUG + nskb->nf_debug = (*pskb)->nf_debug; +#endif + kfree_skb(*pskb); + *pskb = nskb; + return 1; +} /* Generic function for mangling variable-length address changes inside * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX @@ -121,91 +158,41 @@ * * */ int -ip_nat_mangle_tcp_packet(struct sk_buff **skb, +ip_nat_mangle_tcp_packet(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, - char *rep_buffer, + const char *rep_buffer, unsigned int rep_len) { - struct iphdr *iph = (*skb)->nh.iph; + struct iphdr *iph; struct tcphdr *tcph; - unsigned char *data; - u_int32_t tcplen, newlen, newtcplen; - tcplen = (*skb)->len - iph->ihl*4; - newtcplen = tcplen - match_len + rep_len; - newlen = iph->ihl*4 + newtcplen; - - if (newlen > 65535) { - if (net_ratelimit()) - printk("ip_nat_mangle_tcp_packet: nat'ed packet " - "exceeds maximum packet size\n"); + if (!skb_ip_make_writable(pskb, (*pskb)->len)) return 0; - } - if ((*skb)->len != newlen) { - if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) { - printk("resize_packet failed!!\n"); - return 0; - } - } + if (rep_len > match_len + && rep_len - match_len > skb_tailroom(*pskb) + && !enlarge_skb(pskb, rep_len - match_len)) + return 0; - /* Alexey says: if a hook changes _data_ ... it can break - original packet sitting in tcp queue and this is fatal */ - if (skb_cloned(*skb)) { - struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); - if (!nskb) { - if (net_ratelimit()) - printk("Out of memory cloning TCP packet\n"); - return 0; - } - /* Rest of kernel will get very unhappy if we pass it - a suddenly-orphaned skbuff */ - if ((*skb)->sk) - skb_set_owner_w(nskb, (*skb)->sk); - kfree_skb(*skb); - *skb = nskb; - } + SKB_LINEAR_ASSERT(*pskb); - /* skb may be copied !! */ - iph = (*skb)->nh.iph; + iph = (*pskb)->nh.iph; tcph = (void *)iph + iph->ihl*4; - data = (void *)tcph + tcph->doff*4; - - if (rep_len != match_len) - /* move post-replacement */ - memmove(data + match_offset + rep_len, - data + match_offset + match_len, - (*skb)->tail - (data + match_offset + match_len)); - - /* insert data from buffer */ - memcpy(data + match_offset, rep_buffer, rep_len); - - /* update skb info */ - if (newlen > (*skb)->len) { - DEBUGP("ip_nat_mangle_tcp_packet: Extending packet by " - "%u to %u bytes\n", newlen - (*skb)->len, newlen); - skb_put(*skb, newlen - (*skb)->len); - } else { - DEBUGP("ip_nat_mangle_tcp_packet: Shrinking packet from " - "%u to %u bytes\n", (*skb)->len, newlen); - skb_trim(*skb, newlen); - } - - /* fix checksum information */ - iph->tot_len = htons(newlen); - (*skb)->csum = csum_partial((char *)tcph + tcph->doff*4, - newtcplen - tcph->doff*4, 0); + mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, + match_offset, match_len, rep_buffer, rep_len); tcph->check = 0; - tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr, + tcph->check = tcp_v4_check(tcph, (*pskb)->len - iph->ihl*4, + iph->saddr, iph->daddr, csum_partial((char *)tcph, tcph->doff*4, - (*skb)->csum)); - ip_send_check(iph); - + (*pskb)->csum)); + adjust_tcp_sequence(ntohl(tcph->seq), + (int)match_len - (int)rep_len, + ct, ctinfo); return 1; } @@ -220,219 +207,164 @@ * should be fairly easy to do. */ int -ip_nat_mangle_udp_packet(struct sk_buff **skb, +ip_nat_mangle_udp_packet(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned int match_offset, unsigned int match_len, - char *rep_buffer, + const char *rep_buffer, unsigned int rep_len) { - struct iphdr *iph = (*skb)->nh.iph; - struct udphdr *udph = (void *)iph + iph->ihl * 4; - unsigned char *data; - u_int32_t udplen, newlen, newudplen; + struct iphdr *iph; + struct udphdr *udph; + int need_csum = ((*pskb)->csum != 0); - udplen = (*skb)->len - iph->ihl*4; - newudplen = udplen - match_len + rep_len; - newlen = iph->ihl*4 + newudplen; - - if (newlen > 65535) { - if (net_ratelimit()) - printk("ip_nat_mangle_udp_packet: nat'ed packet " - "exceeds maximum packet size\n"); + if (!skb_ip_make_writable(pskb, (*pskb)->len)) return 0; - } - if ((*skb)->len != newlen) { - if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) { - printk("resize_packet failed!!\n"); - return 0; - } - } - - /* Alexey says: if a hook changes _data_ ... it can break - original packet sitting in tcp queue and this is fatal */ - if (skb_cloned(*skb)) { - struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC); - if (!nskb) { - if (net_ratelimit()) - printk("Out of memory cloning TCP packet\n"); - return 0; - } - /* Rest of kernel will get very unhappy if we pass it - a suddenly-orphaned skbuff */ - if ((*skb)->sk) - skb_set_owner_w(nskb, (*skb)->sk); - kfree_skb(*skb); - *skb = nskb; - } + if (rep_len > match_len + && rep_len - match_len > skb_tailroom(*pskb) + && !enlarge_skb(pskb, rep_len - match_len)) + return 0; - /* skb may be copied !! */ - iph = (*skb)->nh.iph; + iph = (*pskb)->nh.iph; udph = (void *)iph + iph->ihl*4; - data = (void *)udph + sizeof(struct udphdr); - - if (rep_len != match_len) - /* move post-replacement */ - memmove(data + match_offset + rep_len, - data + match_offset + match_len, - (*skb)->tail - (data + match_offset + match_len)); - - /* insert data from buffer */ - memcpy(data + match_offset, rep_buffer, rep_len); + mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), + match_offset, match_len, rep_buffer, rep_len); - /* update skb info */ - if (newlen > (*skb)->len) { - DEBUGP("ip_nat_mangle_udp_packet: Extending packet by " - "%u to %u bytes\n", newlen - (*skb)->len, newlen); - skb_put(*skb, newlen - (*skb)->len); - } else { - DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from " - "%u to %u bytes\n", (*skb)->len, newlen); - skb_trim(*skb, newlen); - } - - /* update the length of the UDP and IP packets to the new values*/ - udph->len = htons((*skb)->len - iph->ihl*4); - iph->tot_len = htons(newlen); + /* update the length of the UDP packet */ + udph->len = htons((*pskb)->len - iph->ihl*4); /* fix udp checksum if udp checksum was previously calculated */ - if ((*skb)->csum != 0) { - (*skb)->csum = csum_partial((char *)udph + - sizeof(struct udphdr), - newudplen - sizeof(struct udphdr), - 0); - + if (need_csum) { udph->check = 0; - udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, - newudplen, IPPROTO_UDP, - csum_partial((char *)udph, + udph->check + = csum_tcpudp_magic(iph->saddr, iph->daddr, + (*pskb)->len - iph->ihl*4, + IPPROTO_UDP, + csum_partial((char *)udph, sizeof(struct udphdr), - (*skb)->csum)); - } - - ip_send_check(iph); - + (*pskb)->csum)); + } else + (*pskb)->csum = 0; return 1; } /* Adjust one found SACK option including checksum correction */ static void -sack_adjust(struct tcphdr *tcph, - unsigned char *ptr, +sack_adjust(struct sk_buff *skb, + struct tcphdr *tcph, + unsigned int sackoff, + unsigned int sackend, struct ip_nat_seq *natseq) { - struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2); - int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; - int i; - - for (i = 0; i < num_sacks; i++, sp++) { + while (sackoff < sackend) { + struct tcp_sack_block *sack; u_int32_t new_start_seq, new_end_seq; - if (after(ntohl(sp->start_seq) - natseq->offset_before, + sack = (void *)skb->data + sackoff; + if (after(ntohl(sack->start_seq) - natseq->offset_before, natseq->correction_pos)) - new_start_seq = ntohl(sp->start_seq) + new_start_seq = ntohl(sack->start_seq) - natseq->offset_after; else - new_start_seq = ntohl(sp->start_seq) + new_start_seq = ntohl(sack->start_seq) - natseq->offset_before; new_start_seq = htonl(new_start_seq); - if (after(ntohl(sp->end_seq) - natseq->offset_before, + if (after(ntohl(sack->end_seq) - natseq->offset_before, natseq->correction_pos)) - new_end_seq = ntohl(sp->end_seq) + new_end_seq = ntohl(sack->end_seq) - natseq->offset_after; else - new_end_seq = ntohl(sp->end_seq) + new_end_seq = ntohl(sack->end_seq) - natseq->offset_before; new_end_seq = htonl(new_end_seq); DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", - ntohl(sp->start_seq), new_start_seq, - ntohl(sp->end_seq), new_end_seq); + ntohl(sack->start_seq), new_start_seq, + ntohl(sack->end_seq), new_end_seq); tcph->check = - ip_nat_cheat_check(~sp->start_seq, new_start_seq, - ip_nat_cheat_check(~sp->end_seq, + ip_nat_cheat_check(~sack->start_seq, new_start_seq, + ip_nat_cheat_check(~sack->end_seq, new_end_seq, tcph->check)); - - sp->start_seq = new_start_seq; - sp->end_seq = new_end_seq; + sack->start_seq = new_start_seq; + sack->end_seq = new_end_seq; + sackoff += sizeof(*sack); } } - -/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */ -static inline int -ip_nat_sack_adjust(struct sk_buff *skb, - struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo) +/* TCP SACK sequence number adjustment */ +static inline unsigned int +ip_nat_sack_adjust(struct sk_buff **pskb, + struct tcphdr *tcph, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) { - struct iphdr *iph; - struct tcphdr *tcph; - unsigned char *ptr; - int length, dir, sack_adjusted = 0; + unsigned int dir, optoff, optend; - iph = skb->nh.iph; - tcph = (void *)iph + iph->ihl*4; - length = (tcph->doff*4)-sizeof(struct tcphdr); - ptr = (unsigned char *)(tcph+1); + optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); + optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; + + if (!skb_ip_make_writable(pskb, optend)) + return 0; dir = CTINFO2DIR(ctinfo); - while (length > 0) { - int opcode = *ptr++; - int opsize; + while (optoff < optend) { + /* Usually: option, length. */ + unsigned char *op = (*pskb)->data + optoff; - switch (opcode) { + switch (op[0]) { case TCPOPT_EOL: - return !sack_adjusted; + return 1; case TCPOPT_NOP: - length--; + optoff++; continue; default: - opsize = *ptr++; - if (opsize > length) /* no partial opts */ - return !sack_adjusted; - if (opcode == TCPOPT_SACK) { - /* found SACK */ - if((opsize >= (TCPOLEN_SACK_BASE - +TCPOLEN_SACK_PERBLOCK)) && - !((opsize - TCPOLEN_SACK_BASE) - % TCPOLEN_SACK_PERBLOCK)) - sack_adjust(tcph, ptr-2, - &ct->nat.info.seq[!dir]); - - sack_adjusted = 1; - } - ptr += opsize-2; - length -= opsize; + /* no partial options */ + if (optoff + 1 == optend + || optoff + op[1] > optend + || op[1] < 2) + return 0; + if (op[0] == TCPOPT_SACK + && op[1] >= 2+TCPOLEN_SACK_PERBLOCK + && ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) + sack_adjust(*pskb, tcph, optoff+2, + optoff+op[1], + &ct->nat.info.seq[!dir]); + optoff += op[1]; } } - return !sack_adjusted; + return 1; } -/* TCP sequence number adjustment */ -int -ip_nat_seq_adjust(struct sk_buff *skb, +/* TCP sequence number adjustment. Returns true or false. */ +int +ip_nat_seq_adjust(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { - struct iphdr *iph; struct tcphdr *tcph; int dir, newseq, newack; struct ip_nat_seq *this_way, *other_way; - - iph = skb->nh.iph; - tcph = (void *)iph + iph->ihl*4; dir = CTINFO2DIR(ctinfo); this_way = &ct->nat.info.seq[dir]; other_way = &ct->nat.info.seq[!dir]; - + + /* No adjustments to make? Very common case. */ + if (!this_way->offset_before && !this_way->offset_after + && !other_way->offset_before && !other_way->offset_after) + return 1; + + if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) + return 0; + + tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; if (after(ntohl(tcph->seq), this_way->correction_pos)) newseq = ntohl(tcph->seq) + this_way->offset_after; else @@ -458,9 +390,7 @@ tcph->seq = newseq; tcph->ack_seq = newack; - ip_nat_sack_adjust(skb, ct, ctinfo); - - return 0; + return ip_nat_sack_adjust(pskb, tcph, ct, ctinfo); } static inline int diff -Nru a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c Mon May 12 20:55:45 2003 @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -42,17 +43,24 @@ return 0; } -static void -icmp_manip_pkt(struct iphdr *iph, size_t len, +static int +icmp_manip_pkt(struct sk_buff **pskb, + unsigned int hdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { - struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl); + struct icmphdr *hdr; + + if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr))) + return 0; + + hdr = (void *)(*pskb)->data + hdroff; hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF, - manip->u.icmp.id, - hdr->checksum); + manip->u.icmp.id, + hdr->checksum); hdr->un.echo.id = manip->u.icmp.id; + return 1; } static unsigned int diff -Nru a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c Mon May 12 20:55:44 2003 @@ -7,6 +7,7 @@ #include #include #include +#include static int tcp_in_range(const struct ip_conntrack_tuple *tuple, @@ -73,36 +74,49 @@ return 0; } -static void -tcp_manip_pkt(struct iphdr *iph, size_t len, +static int +tcp_manip_pkt(struct sk_buff **pskb, + unsigned int hdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { - struct tcphdr *hdr = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + struct tcphdr *hdr; u_int32_t oldip; - u_int16_t *portptr; + u_int16_t *portptr, oldport; + int hdrsize = 8; /* TCP connection tracking guarantees this much */ + + /* this could be a inner header returned in icmp packet; in such + cases we cannot update the checksum field since it is outside of + the 8 bytes of transport layer headers we are guaranteed */ + if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) + hdrsize = sizeof(struct tcphdr); + + if (!skb_ip_make_writable(pskb, hdroff + hdrsize)) + return 0; + + hdr = (void *)(*pskb)->data + hdroff; if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ - oldip = iph->saddr; + oldip = (*pskb)->nh.iph->saddr; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ - oldip = iph->daddr; + oldip = (*pskb)->nh.iph->daddr; portptr = &hdr->dest; } - /* this could be a inner header returned in icmp packet; in such - cases we cannot update the checksum field since it is outside of - the 8 bytes of transport layer headers we are guaranteed */ - if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) <= len) { - hdr->check = ip_nat_cheat_check(~oldip, manip->ip, - ip_nat_cheat_check(*portptr ^ 0xFFFF, + oldport = *portptr; + *portptr = manip->u.tcp.port; + + if (hdrsize < sizeof(*hdr)) + return 1; + + hdr->check = ip_nat_cheat_check(~oldip, manip->ip, + ip_nat_cheat_check(oldport ^ 0xFFFF, manip->u.tcp.port, hdr->check)); - } - - *portptr = manip->u.tcp.port; + return 1; } static unsigned int diff -Nru a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c --- a/net/ipv4/netfilter/ip_nat_proto_udp.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c Mon May 12 20:55:45 2003 @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -72,22 +73,27 @@ return 0; } -static void -udp_manip_pkt(struct iphdr *iph, size_t len, +static int +udp_manip_pkt(struct sk_buff **pskb, + unsigned int hdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { - struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl); + struct udphdr *hdr; u_int32_t oldip; u_int16_t *portptr; + if (!skb_ip_make_writable(pskb, hdroff + sizeof(hdr))) + return 0; + + hdr = (void *)(*pskb)->data + hdroff; if (maniptype == IP_NAT_MANIP_SRC) { /* Get rid of src ip and src pt */ - oldip = iph->saddr; + oldip = (*pskb)->nh.iph->saddr; portptr = &hdr->source; } else { /* Get rid of dst ip and dst pt */ - oldip = iph->daddr; + oldip = (*pskb)->nh.iph->daddr; portptr = &hdr->dest; } if (hdr->check) /* 0 is a special case meaning no checksum */ @@ -96,6 +102,7 @@ manip->u.udp.port, hdr->check)); *portptr = manip->u.udp.port; + return 1; } static unsigned int diff -Nru a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c --- a/net/ipv4/netfilter/ip_nat_proto_unknown.c Mon May 12 20:55:46 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c Mon May 12 20:55:46 2003 @@ -29,12 +29,13 @@ return 0; } -static void -unknown_manip_pkt(struct iphdr *iph, size_t len, +static int +unknown_manip_pkt(struct sk_buff **pskb, + unsigned int hdroff, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype) { - return; + return 1; } static unsigned int diff -Nru a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c --- a/net/ipv4/netfilter/ip_nat_standalone.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/netfilter/ip_nat_standalone.c Mon May 12 20:55:48 2003 @@ -71,10 +71,6 @@ /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off @@ -95,12 +91,14 @@ /* Exception: ICMP redirect to new connection (not in hash table yet). We must not let this through, in case we're doing NAT to the same network. */ - struct iphdr *iph = (*pskb)->nh.iph; - struct icmphdr *hdr = (struct icmphdr *) - ((u_int32_t *)iph + iph->ihl); - if (iph->protocol == IPPROTO_ICMP - && hdr->type == ICMP_REDIRECT) - return NF_DROP; + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { + struct icmphdr hdr; + + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, + &hdr, sizeof(hdr)) == 0 + && hdr.type == ICMP_REDIRECT) + return NF_DROP; + } return NF_ACCEPT; } @@ -108,8 +106,11 @@ case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { - return icmp_reply_translation(*pskb, ct, hooknum, - CTINFO2DIR(ctinfo)); + if (!icmp_reply_translation(pskb, ct, hooknum, + CTINFO2DIR(ctinfo))) + return NF_DROP; + else + return NF_ACCEPT; } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: @@ -174,10 +175,6 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)) { - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) @@ -213,10 +210,6 @@ u_int32_t saddr, daddr; unsigned int ret; - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) @@ -387,4 +380,5 @@ EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); EXPORT_SYMBOL(ip_nat_mangle_udp_packet); EXPORT_SYMBOL(ip_nat_used_tuple); +EXPORT_SYMBOL(skb_ip_make_writable); MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c --- a/net/ipv4/netfilter/ip_nat_tftp.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/netfilter/ip_nat_tftp.c Mon May 12 20:55:45 2003 @@ -57,9 +57,7 @@ struct sk_buff **pskb) { int dir = CTINFO2DIR(ctinfo); - struct iphdr *iph = (*pskb)->nh.iph; - struct udphdr *udph = (void *)iph + iph->ihl * 4; - struct tftphdr *tftph = (void *)udph + 8; + struct tftphdr tftph; struct ip_conntrack_tuple repl; if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) @@ -71,7 +69,11 @@ return NF_ACCEPT; } - switch (ntohs(tftph->opcode)) { + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), + &tftph, sizeof(tftph)) != 0) + return NF_DROP; + + switch (ntohs(tftph.opcode)) { /* RRQ and WRQ works the same way */ case TFTP_OPCODE_READ: case TFTP_OPCODE_WRITE: @@ -104,8 +106,10 @@ #if 0 const struct ip_conntrack_tuple *repl = &master->tuplehash[IP_CT_DIR_REPLY].tuple; - struct iphdr *iph = (*pskb)->nh.iph; - struct udphdr *udph = (void *)iph + iph->ihl*4; + struct udphdr udph; + + if (skb_copy_bits(*pskb,(*pskb)->nh.iph->ihl*4,&udph,sizeof(udph))!=0) + return NF_DROP; #endif IP_NF_ASSERT(info); @@ -119,8 +123,8 @@ mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " "newsrc: %u.%u.%u.%u\n", - NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), - NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), + NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source), + NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest), NIPQUAD(orig->dst.ip)); } else { mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip; @@ -130,8 +134,8 @@ DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " "newdst: %u.%u.%u.%u:%u\n", - NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), - NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), + NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source), + NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest), NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port)); } diff -Nru a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c --- a/net/ipv4/netfilter/ipchains_core.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/netfilter/ipchains_core.c Mon May 12 20:55:48 2003 @@ -839,7 +839,9 @@ i->branch->refcount--; kfree(i); i = tmp; - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); } return 0; } @@ -870,6 +872,11 @@ struct ip_fwkernel *i; FWC_HAVE_LOCK(fwc_wlocks); + + /* Are we unloading now? We will block on nf_unregister_sockopt */ + if (!try_module_get(THIS_MODULE)) + return ENOPROTOOPT; + /* Special case if no rules already present */ if (chainptr->chain == NULL) { @@ -886,7 +893,6 @@ if (rule->branch) rule->branch->refcount++; append_successful: - MOD_INC_USE_COUNT; return 0; } @@ -900,6 +906,11 @@ struct ip_fwkernel *f = chainptr->chain; FWC_HAVE_LOCK(fwc_wlocks); + + /* Are we unloading now? We will block on nf_unregister_sockopt */ + if (!try_module_get(THIS_MODULE)) + return ENOPROTOOPT; + /* special case if the position is number 1 */ if (position == 1) { frwl->next = chainptr->chain; @@ -917,7 +928,6 @@ f->next = frwl; insert_successful: - MOD_INC_USE_COUNT; return 0; } @@ -952,7 +962,9 @@ kfree(tmp); } - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); return 0; } @@ -1059,7 +1071,9 @@ else chainptr->chain = ftmp->next; kfree(ftmp); - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); break; } @@ -1101,7 +1115,9 @@ tmp->next = tmp2->next; kfree(tmp2); - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); return 0; } @@ -1149,12 +1165,15 @@ if (strcmp(tmp->label,label) == 0) return EEXIST; + /* Are we unloading now? We will block on nf_unregister_sockopt */ + if (!try_module_get(THIS_MODULE)) + return ENOPROTOOPT; + tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is * zero since this is a * user defined chain * * and therefore can be * deleted */ - MOD_INC_USE_COUNT; return 0; } diff -Nru a/net/ipv4/netfilter/ipfwadm_core.c b/net/ipv4/netfilter/ipfwadm_core.c --- a/net/ipv4/netfilter/ipfwadm_core.c Mon May 12 20:55:46 2003 +++ b/net/ipv4/netfilter/ipfwadm_core.c Mon May 12 20:55:46 2003 @@ -707,7 +707,9 @@ ftmp = *chainptr; *chainptr = ftmp->fw_next; kfree(ftmp); - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); } WRITE_UNLOCK(&ip_fw_lock); } @@ -718,6 +720,10 @@ { struct ip_fw *ftmp; + /* Are we unloading now? We will block on nf_unregister_sockopt */ + if (!try_module_get(THIS_MODULE)) + return ENOPROTOOPT; + ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL ); if ( ftmp == NULL ) { @@ -748,7 +754,6 @@ ftmp->fw_next = *chainptr; *chainptr=ftmp; WRITE_UNLOCK(&ip_fw_lock); - MOD_INC_USE_COUNT; return(0); } @@ -758,6 +763,10 @@ struct ip_fw *chtmp=NULL; struct ip_fw *volatile chtmp_prev=NULL; + /* Are we unloading now? We will block on nf_unregister_sockopt */ + if (!try_module_get(THIS_MODULE)) + return ENOPROTOOPT; + ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL ); if ( ftmp == NULL ) { @@ -796,7 +805,6 @@ else *chainptr=ftmp; WRITE_UNLOCK(&ip_fw_lock); - MOD_INC_USE_COUNT; return(0); } @@ -869,7 +877,9 @@ } WRITE_UNLOCK(&ip_fw_lock); if (was_found) { - MOD_DEC_USE_COUNT; + /* We will block in cleanup's unregister sockopt if unloaded, + so this is safe. */ + module_put(THIS_MODULE); return 0; } else return(EINVAL); diff -Nru a/net/ipv4/proc.c b/net/ipv4/proc.c --- a/net/ipv4/proc.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/proc.c Mon May 12 20:55:44 2003 @@ -80,6 +80,7 @@ } static struct file_operations sockstat_seq_fops = { + .owner = THIS_MODULE, .open = sockstat_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -171,6 +172,7 @@ } static struct file_operations snmp_seq_fops = { + .owner = THIS_MODULE, .open = snmp_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -227,6 +229,7 @@ } static struct file_operations netstat_seq_fops = { + .owner = THIS_MODULE, .open = netstat_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/protocol.c b/net/ipv4/protocol.c --- a/net/ipv4/protocol.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/protocol.c Mon May 12 20:55:44 2003 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -49,6 +48,7 @@ #include struct inet_protocol *inet_protos[MAX_INET_PROTOS]; +static spinlock_t inet_proto_lock = SPIN_LOCK_UNLOCKED; /* * Add a protocol handler to the hash tables @@ -60,16 +60,14 @@ hash = protocol & (MAX_INET_PROTOS - 1); - br_write_lock_bh(BR_NETPROTO_LOCK); - + spin_lock_bh(&inet_proto_lock); if (inet_protos[hash]) { ret = -1; } else { inet_protos[hash] = prot; ret = 0; } - - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&inet_proto_lock); return ret; } @@ -84,16 +82,16 @@ hash = protocol & (MAX_INET_PROTOS - 1); - br_write_lock_bh(BR_NETPROTO_LOCK); - + spin_lock_bh(&inet_proto_lock); if (inet_protos[hash] == prot) { inet_protos[hash] = NULL; ret = 0; } else { ret = -1; } + spin_unlock_bh(&inet_proto_lock); - br_write_unlock_bh(BR_NETPROTO_LOCK); + synchronize_net(); return ret; } diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c --- a/net/ipv4/raw.c Mon May 12 20:55:47 2003 +++ b/net/ipv4/raw.c Mon May 12 20:55:47 2003 @@ -807,6 +807,7 @@ } static struct file_operations raw_seq_fops = { + .owner = THIS_MODULE, .open = raw_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Mon May 12 20:55:49 2003 +++ b/net/ipv4/route.c Mon May 12 20:55:49 2003 @@ -382,6 +382,7 @@ } static struct file_operations rt_cache_seq_fops = { + .owner = THIS_MODULE, .open = rt_cache_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -431,16 +432,17 @@ rth->u.dst.expires; } -static int rt_may_expire(struct rtable *rth, int tmo1, int tmo2) +static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2) { - int age; + unsigned long age; int ret = 0; if (atomic_read(&rth->u.dst.__refcnt)) goto out; ret = 1; - if (rth->u.dst.expires && (long)(rth->u.dst.expires - jiffies) <= 0) + if (rth->u.dst.expires && + time_after_eq(jiffies, rth->u.dst.expires)) goto out; age = jiffies - rth->u.dst.lastuse; @@ -462,7 +464,7 @@ for (t = ip_rt_gc_interval << rt_hash_log; t >= 0; t -= ip_rt_gc_timeout) { - unsigned tmo = ip_rt_gc_timeout; + unsigned long tmo = ip_rt_gc_timeout; i = (i + 1) & rt_hash_mask; rthp = &rt_hash_table[i].chain; @@ -471,7 +473,7 @@ while ((rth = *rthp) != NULL) { if (rth->u.dst.expires) { /* Entry is expired even if it is in use */ - if ((long)(now - rth->u.dst.expires) <= 0) { + if (time_before_eq(now, rth->u.dst.expires)) { tmo >>= 1; rthp = &rth->u.rt_next; continue; @@ -489,7 +491,7 @@ spin_unlock(&rt_hash_table[i].lock); /* Fallback loop breaker. */ - if ((jiffies - now) > 0) + if (time_after(jiffies, now)) break; } rover = i; @@ -591,7 +593,7 @@ static int rt_garbage_collect(void) { - static unsigned expire = RT_GC_TIMEOUT; + static unsigned long expire = RT_GC_TIMEOUT; static unsigned long last_gc; static int rover; static int equilibrium; @@ -643,7 +645,7 @@ int i, k; for (i = rt_hash_mask, k = rover; i >= 0; i--) { - unsigned tmo = expire; + unsigned long tmo = expire; k = (k + 1) & rt_hash_mask; rthp = &rt_hash_table[k].chain; @@ -689,7 +691,7 @@ if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) goto out; - } while (!in_softirq() && jiffies - now < 1); + } while (!in_softirq() && time_before_eq(jiffies, now)); if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) goto out; @@ -1067,7 +1069,7 @@ /* No redirected packets during ip_rt_redirect_silence; * reset the algorithm. */ - if (jiffies - rt->u.dst.rate_last > ip_rt_redirect_silence) + if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence)) rt->u.dst.rate_tokens = 0; /* Too many ignored redirects; do not send anything @@ -1081,8 +1083,9 @@ /* Check for load limit; set rate_last to the latest sent * redirect. */ - if (jiffies - rt->u.dst.rate_last > - (ip_rt_redirect_load << rt->u.dst.rate_tokens)) { + if (time_after(jiffies, + (rt->u.dst.rate_last + + (ip_rt_redirect_load << rt->u.dst.rate_tokens)))) { icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway); rt->u.dst.rate_last = jiffies; ++rt->u.dst.rate_tokens; diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/tcp_ipv4.c Mon May 12 20:55:45 2003 @@ -2569,6 +2569,7 @@ } static struct file_operations tcp_seq_fops = { + .owner = THIS_MODULE, .open = tcp_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Mon May 12 20:55:48 2003 +++ b/net/ipv4/tcp_minisocks.c Mon May 12 20:55:48 2003 @@ -444,6 +444,8 @@ while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) { tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death; + if (tw->next_death) + tw->next_death->pprev_death = tw->pprev_death; tw->pprev_death = NULL; spin_unlock(&tw_death_lock); @@ -758,6 +760,7 @@ tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp)); newsk->socket = NULL; newsk->sleep = NULL; + newsk->owner = NULL; newtp->tstamp_ok = req->tstamp_ok; if((newtp->sack_ok = req->sack_ok) != 0) { diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c --- a/net/ipv4/udp.c Mon May 12 20:55:45 2003 +++ b/net/ipv4/udp.c Mon May 12 20:55:45 2003 @@ -1483,6 +1483,7 @@ } static struct file_operations udp_seq_fops = { + .owner = THIS_MODULE, .open = udp_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c --- a/net/ipv4/xfrm4_state.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/xfrm4_state.c Mon May 12 20:55:44 2003 @@ -50,7 +50,7 @@ spi == x->id.spi && daddr->a4 == x->id.daddr.a4 && proto == x->id.proto) { - atomic_inc(&x->refcnt); + xfrm_state_hold(x); return x; } } @@ -84,7 +84,7 @@ } } if (x0) { - atomic_inc(&x0->refcnt); + xfrm_state_hold(x0); } else if (create && (x0 = xfrm_state_alloc()) != NULL) { x0->sel.daddr.a4 = daddr->a4; x0->sel.saddr.a4 = saddr->a4; @@ -99,9 +99,9 @@ x0->props.reqid = reqid; x0->props.family = AF_INET; x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; - atomic_inc(&x0->refcnt); + xfrm_state_hold(x0); mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ); - atomic_inc(&x0->refcnt); + xfrm_state_hold(0); list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h); wake_up(&km_waitq); } diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c --- a/net/ipv4/xfrm4_tunnel.c Mon May 12 20:55:44 2003 +++ b/net/ipv4/xfrm4_tunnel.c Mon May 12 20:55:44 2003 @@ -163,36 +163,32 @@ skb->nh.iph->saddr, IPPROTO_IPIP, AF_INET); - if (x) { - spin_lock(&x->lock); + if (!x) + goto drop; - if (unlikely(x->km.state != XFRM_STATE_VALID)) - goto drop_unlock; - } + spin_lock(&x->lock); + + if (unlikely(x->km.state != XFRM_STATE_VALID)) + goto drop_unlock; err = ipip_xfrm_rcv(x, NULL, skb); if (err) goto drop_unlock; - if (x) { - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock(&x->lock); - - xfrm_state_put(x); - } - - return 0; + x->curlft.bytes += skb->len; + x->curlft.packets++; + spin_unlock(&x->lock); + xfrm_state_put(x); +out: + return err; drop_unlock: - if (x) { - spin_unlock(&x->lock); - xfrm_state_put(x); - } + spin_unlock(&x->lock); + xfrm_state_put(x); +drop: + err = NET_RX_DROP; kfree_skb(skb); -out: - return 0; + goto out; } static void ipip_err(struct sk_buff *skb, u32 info) diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c --- a/net/ipv6/addrconf.c Mon May 12 20:55:48 2003 +++ b/net/ipv6/addrconf.c Mon May 12 20:55:48 2003 @@ -1210,7 +1210,7 @@ if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) rtmsg.rtmsg_flags |= RTF_NONEXTHOP; - ip6_route_add(&rtmsg, NULL); + ip6_route_add(&rtmsg, NULL, NULL); } /* Create "default" multicast route to the interface */ @@ -1227,7 +1227,7 @@ rtmsg.rtmsg_ifindex = dev->ifindex; rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF; rtmsg.rtmsg_type = RTMSG_NEWROUTE; - ip6_route_add(&rtmsg, NULL); + ip6_route_add(&rtmsg, NULL, NULL); } static void sit_route_add(struct net_device *dev) @@ -1244,7 +1244,7 @@ rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL); + ip6_route_add(&rtmsg, NULL, NULL); } static void addrconf_add_lroute(struct net_device *dev) @@ -1336,7 +1336,7 @@ if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { if (pinfo->onlink == 0 || valid_lft == 0) { - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); rt = NULL; } else { rt->rt6i_expires = rt_expires; @@ -1960,7 +1960,7 @@ rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex; - ip6_route_add(&rtmsg, NULL); + ip6_route_add(&rtmsg, NULL, NULL); } out: diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c Mon May 12 20:55:47 2003 +++ b/net/ipv6/af_inet6.c Mon May 12 20:55:47 2003 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include @@ -75,8 +74,10 @@ /* IPv6 procfs goodies... */ #ifdef CONFIG_PROC_FS +extern int raw6_proc_init(void); +extern int raw6_proc_exit(void); + extern int anycast6_get_info(char *, char **, off_t, int); -extern int raw6_get_info(char *, char **, off_t, int); extern int tcp6_get_info(char *, char **, off_t, int); extern int udp6_get_info(char *, char **, off_t, int); extern int afinet6_get_info(char *, char **, off_t, int); @@ -102,7 +103,8 @@ /* The inetsw table contains everything that inet_create needs to * build a new socket. */ -struct list_head inetsw6[SOCK_MAX]; +static struct list_head inetsw6[SOCK_MAX]; +static spinlock_t inetsw6_lock = SPIN_LOCK_UNLOCKED; static void inet6_sock_destruct(struct sock *sk) { @@ -111,7 +113,6 @@ #ifdef INET_REFCNT_DEBUG atomic_dec(&inet6_sock_nr); #endif - module_put(THIS_MODULE); } static __inline__ kmem_cache_t *inet6_sk_slab(int protocol) @@ -163,8 +164,8 @@ /* Look for the requested type/protocol pair. */ answer = NULL; - br_read_lock_bh(BR_NETPROTO_LOCK); - list_for_each(p, &inetsw6[sock->type]) { + rcu_read_lock(); + list_for_each_rcu(p, &inetsw6[sock->type]) { answer = list_entry(p, struct inet_protosw, list); /* Check the non-wild match. */ @@ -182,7 +183,6 @@ } answer = NULL; } - br_read_unlock_bh(BR_NETPROTO_LOCK); if (!answer) goto free_and_badtype; @@ -199,6 +199,7 @@ sk->no_check = answer->no_check; if (INET_PROTOSW_REUSE & answer->flags) sk->reuse = 1; + rcu_read_unlock(); inet = inet_sk(sk); @@ -243,11 +244,6 @@ atomic_inc(&inet6_sock_nr); atomic_inc(&inet_sock_nr); #endif - if (!try_module_get(THIS_MODULE)) { - inet_sock_release(sk); - return -EBUSY; - } - if (inet->num) { /* It assumes that any protocol which allows * the user to assign a number at socket @@ -259,7 +255,6 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - module_put(THIS_MODULE); inet_sock_release(sk); return err; } @@ -267,12 +262,15 @@ return 0; free_and_badtype: + rcu_read_unlock(); sk_free(sk); return -ESOCKTNOSUPPORT; free_and_badperm: + rcu_read_unlock(); sk_free(sk); return -EPERM; free_and_noproto: + rcu_read_unlock(); sk_free(sk); return -EPROTONOSUPPORT; do_oom: @@ -542,6 +540,7 @@ struct net_proto_family inet6_family_ops = { .family = PF_INET6, .create = inet6_create, + .owner = THIS_MODULE, }; #ifdef MODULE @@ -580,7 +579,7 @@ int protocol = p->protocol; struct list_head *last_perm; - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&inetsw6_lock); if (p->type > SOCK_MAX) goto out_illegal; @@ -609,9 +608,9 @@ * non-permanent entry. This means that when we remove this entry, the * system automatically returns to the old behavior. */ - list_add(&p->list, last_perm); + list_add_rcu(&p->list, last_perm); out: - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&inetsw6_lock); return; out_permanent: @@ -629,7 +628,17 @@ void inet6_unregister_protosw(struct inet_protosw *p) { - inet_unregister_protosw(p); + if (INET_PROTOSW_PERMANENT & p->flags) { + printk(KERN_ERR + "Attempt to unregister permanent protocol %d.\n", + p->protocol); + } else { + spin_lock_bh(&inetsw6_lock); + list_del_rcu(&p->list); + spin_unlock_bh(&inetsw6_lock); + + synchronize_net(); + } } int @@ -779,7 +788,7 @@ /* Create /proc/foo6 entries. */ #ifdef CONFIG_PROC_FS err = -ENOMEM; - if (!proc_net_create("raw6", 0, raw6_get_info)) + if (raw6_proc_init()) goto proc_raw6_fail; if (!proc_net_create("tcp6", 0, tcp6_get_info)) goto proc_tcp6_fail; @@ -820,7 +829,7 @@ proc_udp6_fail: proc_net_remove("tcp6"); proc_tcp6_fail: - proc_net_remove("raw6"); + raw6_proc_exit(); proc_raw6_fail: igmp6_cleanup(); #endif @@ -845,7 +854,7 @@ /* First of all disallow new sockets creation. */ sock_unregister(PF_INET6); #ifdef CONFIG_PROC_FS - proc_net_remove("raw6"); + raw6_proc_exit(); proc_net_remove("tcp6"); proc_net_remove("udp6"); proc_net_remove("sockstat6"); diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c --- a/net/ipv6/exthdrs.c Mon May 12 20:55:44 2003 +++ b/net/ipv6/exthdrs.c Mon May 12 20:55:44 2003 @@ -252,8 +252,13 @@ return 1; } - if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) { - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1); + if (hdr->type != IPV6_SRCRT_TYPE_0) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); + return -1; + } + + if (hdr->hdrlen & 0x01) { + icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); return -1; } diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c --- a/net/ipv6/icmp.c Mon May 12 20:55:45 2003 +++ b/net/ipv6/icmp.c Mon May 12 20:55:45 2003 @@ -28,6 +28,7 @@ * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit. * Randy Dunlap and * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support + * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data */ #include @@ -104,42 +105,6 @@ spin_unlock_bh(&icmpv6_socket->sk->lock.slock); } - - -/* - * getfrag callback - */ - -static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, - char *buff, unsigned int offset, unsigned int len) -{ - struct icmpv6_msg *msg = (struct icmpv6_msg *) data; - struct icmp6hdr *icmph; - __u32 csum; - - if (offset) { - csum = skb_copy_and_csum_bits(msg->skb, msg->offset + - (offset - sizeof(struct icmp6hdr)), - buff, len, msg->csum); - msg->csum = csum; - return 0; - } - - csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff, - sizeof(struct icmp6hdr), msg->csum); - - csum = skb_copy_and_csum_bits(msg->skb, msg->offset, - buff + sizeof(struct icmp6hdr), - len - sizeof(struct icmp6hdr), csum); - - icmph = (struct icmp6hdr *) buff; - - icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len, - IPPROTO_ICMPV6, csum); - return 0; -} - - /* * Slightly more convenient version of icmpv6_send. */ @@ -242,22 +207,74 @@ return (optval&0xC0) == 0x80; } +int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6hdr *thdr, int len) +{ + struct sk_buff *skb; + struct icmp6hdr *icmp6h; + int err = 0; + + if ((skb = skb_peek(&sk->write_queue)) == NULL) + goto out; + + icmp6h = (struct icmp6hdr*) skb->h.raw; + memcpy(icmp6h, thdr, sizeof(struct icmp6hdr)); + icmp6h->icmp6_cksum = 0; + + if (skb_queue_len(&sk->write_queue) == 1) { + skb->csum = csum_partial((char *)icmp6h, + sizeof(struct icmp6hdr), skb->csum); + icmp6h->icmp6_cksum = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + len, fl->proto, skb->csum); + } else { + u32 tmp_csum = 0; + + skb_queue_walk(&sk->write_queue, skb) { + tmp_csum = csum_add(tmp_csum, skb->csum); + } + + tmp_csum = csum_partial((char *)icmp6h, + sizeof(struct icmp6hdr), tmp_csum); + tmp_csum = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + len, fl->proto, tmp_csum); + icmp6h->icmp6_cksum = tmp_csum; + } + if (icmp6h->icmp6_cksum == 0) + icmp6h->icmp6_cksum = -1; + ip6_push_pending_frames(sk); +out: + return err; +} + +static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) +{ + struct sk_buff *org_skb = (struct sk_buff *)from; + __u32 csum = 0; + csum = skb_copy_and_csum_bits(org_skb, offset, to, len, csum); + skb->csum = csum_block_add(skb->csum, csum, odd); + return 0; +} + /* * Send an ICMP message in response to a packet in error */ - void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, struct net_device *dev) { struct inet6_dev *idev; struct ipv6hdr *hdr = skb->nh.ipv6h; struct sock *sk = icmpv6_socket->sk; - struct in6_addr *saddr = NULL; - int iif = 0; - struct icmpv6_msg msg; + struct ipv6_pinfo *np = inet6_sk(sk); + struct in6_addr *saddr = NULL, *tmp_saddr = NULL; + struct dst_entry *dst; + struct icmp6hdr tmp_hdr; struct flowi fl; + int iif = 0; int addr_type = 0; - int len; + int len, plen; + int hlimit = -1; + int err = 0; if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail) return; @@ -328,36 +345,48 @@ if (!icmpv6_xrlim_allow(sk, type, &fl)) goto out; - /* - * ok. kick it. checksum will be provided by the - * getfrag_t callback. - */ - - msg.icmph.icmp6_type = type; - msg.icmph.icmp6_code = code; - msg.icmph.icmp6_cksum = 0; - msg.icmph.icmp6_pointer = htonl(info); - - msg.skb = skb; - msg.offset = skb->nh.raw - skb->data; - msg.csum = 0; - msg.daddr = &hdr->saddr; - - len = skb->len - msg.offset + sizeof(struct icmp6hdr); - len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr)); + tmp_hdr.icmp6_type = type; + tmp_hdr.icmp6_code = code; + tmp_hdr.icmp6_cksum = 0; + tmp_hdr.icmp6_pointer = htonl(info); + + if (!fl.oif && ipv6_addr_is_multicast(fl.fl6_dst)) + fl.oif = np->mcast_oif; + + err = ip6_dst_lookup(sk, &dst, &fl, &tmp_saddr); + if (err) goto out; + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit; + } + plen = skb->nh.raw - skb->data; + __skb_pull(skb, plen); + len = skb->len; + len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr)); if (len < 0) { if (net_ratelimit()) printk(KERN_DEBUG "icmp: len problem\n"); + __skb_push(skb, plen); goto out; } - msg.len = len; - idev = in6_dev_get(skb->dev); - - ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1, - MSG_DONTWAIT); + + err = ip6_append_data(sk, icmpv6_getfrag, skb, len + sizeof(struct icmp6hdr), sizeof(struct icmp6hdr), + hlimit, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); + if (err) { + ip6_flush_pending_frames(sk); + goto out; + } + err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); + __skb_push(skb, plen); + if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB) ICMP6_INC_STATS_OFFSET_BH(idev, Icmp6OutDestUnreachs, type - ICMPV6_DEST_UNREACH); ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs); @@ -365,6 +394,7 @@ if (likely(idev != NULL)) in6_dev_put(idev); out: + if (tmp_saddr) kfree(tmp_saddr); icmpv6_xmit_unlock(); } @@ -372,10 +402,14 @@ { struct sock *sk = icmpv6_socket->sk; struct inet6_dev *idev; + struct ipv6_pinfo *np = inet6_sk(sk); + struct in6_addr *saddr = NULL, *tmp_saddr = NULL; struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw; - struct in6_addr *saddr; - struct icmpv6_msg msg; + struct icmp6hdr tmp_hdr; struct flowi fl; + struct dst_entry *dst; + int err = 0; + int hlimit = -1; saddr = &skb->nh.ipv6h->daddr; @@ -383,39 +417,55 @@ ipv6_chk_acast_addr(0, saddr)) saddr = NULL; - msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY; - msg.icmph.icmp6_code = 0; - msg.icmph.icmp6_cksum = 0; - msg.icmph.icmp6_identifier = icmph->icmp6_identifier; - msg.icmph.icmp6_sequence = icmph->icmp6_sequence; - - msg.skb = skb; - msg.offset = 0; - msg.csum = 0; - msg.len = skb->len + sizeof(struct icmp6hdr); - msg.daddr = &skb->nh.ipv6h->saddr; + memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); + tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY; fl.proto = IPPROTO_ICMPV6; - fl.fl6_dst = msg.daddr; + fl.fl6_dst = &skb->nh.ipv6h->saddr; fl.fl6_src = saddr; fl.oif = skb->dev->ifindex; fl.fl6_flowlabel = 0; fl.fl_icmp_type = ICMPV6_ECHO_REPLY; fl.fl_icmp_code = 0; + icmpv6_xmit_lock(); + + if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr)) + fl.oif = np->mcast_oif; + + err = ip6_dst_lookup(sk, &dst, &fl, &tmp_saddr); + + if (err) goto out; + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit; + } + idev = in6_dev_get(skb->dev); - icmpv6_xmit_lock(); + err = ip6_append_data(sk, icmpv6_getfrag, skb, skb->len + sizeof(struct icmp6hdr), + sizeof(struct icmp6hdr), hlimit, NULL, &fl, + (struct rt6_info*)dst, MSG_DONTWAIT); - ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, - MSG_DONTWAIT); - ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies); - ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs); + if (err) { + ip6_flush_pending_frames(sk); + goto out; + } + err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr)); - icmpv6_xmit_unlock(); + ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies); + ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs); if (likely(idev != NULL)) in6_dev_put(idev); +out: + if (tmp_saddr) kfree(tmp_saddr); + icmpv6_xmit_unlock(); } static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) @@ -456,9 +506,12 @@ hash = nexthdr & (MAX_INET_PROTOS - 1); + rcu_read_lock(); ipprot = inet6_protos[hash]; + smp_read_barrier_depends(); if (ipprot && ipprot->err_handler) ipprot->err_handler(skb, NULL, type, code, inner_offset, info); + rcu_read_unlock(); read_lock(&raw_v6_lock); if ((sk = raw_v6_htable[hash]) != NULL) { diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c --- a/net/ipv6/ip6_fib.c Mon May 12 20:55:48 2003 +++ b/net/ipv6/ip6_fib.c Mon May 12 20:55:48 2003 @@ -434,9 +434,6 @@ if (fn->fn_flags&RTN_TL_ROOT && fn->leaf == &ip6_null_entry && !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){ - /* - * The top fib of ip6 routing table includes ip6_null_entry. - */ fn->leaf = rt; rt->u.next = NULL; goto out; @@ -505,7 +502,7 @@ * with source addr info in sub-trees */ -int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh) +int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) { struct fib6_node *fn; int err = -ENOMEM; @@ -593,7 +590,7 @@ #ifdef CONFIG_IPV6_SUBTREES /* Subtree creation failed, probably main tree node - is orphan. If it is, shot it. + is orphan. If it is, shoot it. */ st_failure: if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT)) @@ -887,7 +884,7 @@ } static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, void *_rtattr) { struct fib6_walker_t *w; struct rt6_info *rt = *rtp; @@ -946,14 +943,14 @@ rt6_release(rt); } -int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh) +int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) { struct fib6_node *fn = rt->rt6i_node; struct rt6_info **rtp; #if RT6_DEBUG >= 2 if (rt->u.dst.obsolete>0) { - BUG_TRAP(fn==NULL || rt->u.dst.obsolete<=0); + BUG_TRAP(fn==NULL); return -ENOENT; } #endif @@ -971,7 +968,7 @@ for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) { if (*rtp == rt) { - fib6_del_route(fn, rtp, nlh); + fib6_del_route(fn, rtp, nlh, _rtattr); return 0; } } @@ -979,7 +976,7 @@ } /* - * Tree transversal function. + * Tree traversal function. * * Certainly, it is not interrupt safe. * However, it is internally reenterable wrt itself and fib6_add/fib6_del. @@ -1100,7 +1097,7 @@ res = c->func(rt, c->arg); if (res < 0) { w->leaf = rt; - res = fib6_del(rt, NULL); + res = fib6_del(rt, NULL, NULL); if (res) { #if RT6_DEBUG >= 2 printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res); @@ -1179,14 +1176,14 @@ */ if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { - if ((long)(now - rt->rt6i_expires) > 0) { + if (time_after(now, rt->rt6i_expires)) { RT6_TRACE("expiring %p\n", rt); return -1; } gc_args.more++; } else if (rt->rt6i_flags & RTF_CACHE) { if (atomic_read(&rt->u.dst.__refcnt) == 0 && - (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) { + time_after_eq(now, rt->u.dst.lastuse + gc_args.timeout)) { RT6_TRACE("aging clone %p\n", rt); return -1; } diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c --- a/net/ipv6/ip6_input.c Mon May 12 20:55:48 2003 +++ b/net/ipv6/ip6_input.c Mon May 12 20:55:48 2003 @@ -152,6 +152,7 @@ skb->h.raw += (skb->h.raw[1]+1)<<3; } + rcu_read_lock(); resubmit: if (!pskb_pull(skb, skb->h.raw - skb->data)) goto discard; @@ -165,6 +166,7 @@ if ((ipprot = inet6_protos[hash]) != NULL) { int ret; + smp_read_barrier_depends(); if (ipprot->flags & INET6_PROTO_FINAL) { if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) { skb->csum = csum_sub(skb->csum, @@ -173,10 +175,8 @@ } } if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && - !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - return 0; - } + !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard; ret = ipprot->handler(&skb, &nhoff); if (ret > 0) @@ -194,10 +194,11 @@ kfree_skb(skb); } } - + rcu_read_unlock(); return 0; discard: + rcu_read_unlock(); kfree_skb(skb); return 0; } diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c Mon May 12 20:55:44 2003 +++ b/net/ipv6/ip6_output.c Mon May 12 20:55:44 2003 @@ -23,6 +23,9 @@ * * H. von Brand : Added missing #include * Imran Patel : frag id should be in NBO + * Kazunori MIYAZAWA @USAGI + * : add ip6_append_data and related functions + * for datagram xmit */ #include @@ -52,6 +55,8 @@ #include #include +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)); + static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr) { static u32 ipv6_fragmentation_id = 1; @@ -98,7 +103,7 @@ } -int ip6_output(struct sk_buff *skb) +int ip6_output2(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct net_device *dev = dst->dev; @@ -134,6 +139,13 @@ return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); } +int ip6_output(struct sk_buff *skb) +{ + if ((skb->len > skb->dst->dev->mtu || skb_shinfo(skb)->frag_list)) + return ip6_fragment(skb, ip6_output2); + else + return ip6_output2(skb); +} #ifdef CONFIG_NETFILTER int ip6_route_me_harder(struct sk_buff *skb) @@ -846,4 +858,659 @@ drop: kfree_skb(skb); return -EINVAL; +} + +static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) +{ + to->pkt_type = from->pkt_type; + to->priority = from->priority; + to->protocol = from->protocol; + to->security = from->security; + to->dst = dst_clone(from->dst); + to->dev = from->dev; + +#ifdef CONFIG_NET_SCHED + to->tc_index = from->tc_index; +#endif +#ifdef CONFIG_NETFILTER + to->nfmark = from->nfmark; + /* Connection association is same as pre-frag packet */ + to->nfct = from->nfct; + nf_conntrack_get(to->nfct); +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + to->nf_bridge = from->nf_bridge; + nf_bridge_get(to->nf_bridge); +#endif +#ifdef CONFIG_NETFILTER_DEBUG + to->nf_debug = from->nf_debug; +#endif +#endif +} + +static int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr) +{ + u16 offset = sizeof(struct ipv6hdr); + struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); + unsigned int packet_len = skb->tail - skb->nh.raw; + int found_rhdr = 0; + *nexthdr = &skb->nh.ipv6h->nexthdr; + + while (offset + 1 <= packet_len) { + + switch (**nexthdr) { + + case NEXTHDR_HOP: + case NEXTHDR_ROUTING: + case NEXTHDR_DEST: + if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1; + if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset; + offset += ipv6_optlen(exthdr); + *nexthdr = &exthdr->nexthdr; + exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset); + break; + default : + return offset; + } + } + + return offset; +} + +static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) +{ + struct net_device *dev; + struct rt6_info *rt = (struct rt6_info*)skb->dst; + struct sk_buff *frag; + struct ipv6hdr *tmp_hdr; + struct frag_hdr *fh; + unsigned int mtu, hlen, left, len; + u32 frag_id = 0; + int ptr, offset = 0, err=0; + u8 *prevhdr, nexthdr = 0; + + dev = rt->u.dst.dev; + hlen = ip6_found_nexthdr(skb, &prevhdr); + nexthdr = *prevhdr; + + mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); + + if (skb_shinfo(skb)->frag_list) { + int first_len = 0; + + if (first_len - hlen > mtu || + ((first_len - hlen) & 7) || + skb_cloned(skb)) + goto slow_path; + + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + /* Correct geometry. */ + if (frag->len > mtu || + ((frag->len & 7) && frag->next) || + skb_headroom(frag) < hlen) + goto slow_path; + + /* Correct socket ownership. */ + if (frag->sk == NULL) + goto slow_path; + + /* Partially cloned skb? */ + if (skb_shared(frag)) + goto slow_path; + } + + err = 0; + offset = 0; + frag = skb_shinfo(skb)->frag_list; + skb_shinfo(skb)->frag_list = 0; + /* BUILD HEADER */ + + tmp_hdr = kmalloc(hlen, GFP_ATOMIC); + if (!tmp_hdr) { + IP6_INC_STATS(Ip6FragFails); + return -ENOMEM; + } + + *prevhdr = NEXTHDR_FRAGMENT; + memcpy(tmp_hdr, skb->nh.raw, hlen); + __skb_pull(skb, hlen); + fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr)); + skb->nh.raw = __skb_push(skb, hlen); + memcpy(skb->nh.raw, tmp_hdr, hlen); + + ipv6_select_ident(skb, fh); + fh->nexthdr = nexthdr; + fh->reserved = 0; + fh->frag_off = htons(0x0001); + frag_id = fh->identification; + + first_len = skb_pagelen(skb); + skb->data_len = first_len - skb_headlen(skb); + skb->len = first_len; + skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); + + + for (;;) { + /* Prepare header of the next frame, + * before previous one went down. */ + if (frag) { + frag->h.raw = frag->data; + fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr)); + frag->nh.raw = __skb_push(frag, hlen); + memcpy(frag->nh.raw, tmp_hdr, hlen); + offset += skb->len - hlen - sizeof(struct frag_hdr); + fh->nexthdr = nexthdr; + fh->reserved = 0; + if (frag->next != NULL) + offset |= 0x0001; + fh->frag_off = htons(offset); + fh->identification = frag_id; + frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); + ip6_copy_metadata(frag, skb); + } + err = output(skb); + + if (err || !frag) + break; + + skb = frag; + frag = skb->next; + skb->next = NULL; + } + + if (tmp_hdr) + kfree(tmp_hdr); + + if (err == 0) { + IP6_INC_STATS(Ip6FragOKs); + return 0; + } + + while (frag) { + skb = frag->next; + kfree_skb(frag); + frag = skb; + } + + IP6_INC_STATS(Ip6FragFails); + return err; + } + +slow_path: + left = skb->len - hlen; /* Space per frame */ + ptr = hlen; /* Where to start from */ + + /* + * Fragment the datagram. + */ + + *prevhdr = NEXTHDR_FRAGMENT; + + /* + * Keep copying data until we run out. + */ + while(left > 0) { + len = left; + /* IF: it doesn't fit, use 'mtu' - the data space left */ + if (len > mtu) + len = mtu; + /* IF: we are not sending upto and including the packet end + then align the next start on an eight byte boundary */ + if (len < left) { + len &= ~7; + } + /* + * Allocate buffer. + */ + + if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { + NETDEBUG(printk(KERN_INFO "IPv6: frag: no memory for new fragment!\n")); + err = -ENOMEM; + goto fail; + } + + /* + * Set up data on packet + */ + + ip6_copy_metadata(frag, skb); + skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev)); + skb_put(frag, len + hlen + sizeof(struct frag_hdr)); + frag->nh.raw = frag->data; + fh = (struct frag_hdr*)(frag->data + hlen); + frag->h.raw = frag->data + hlen + sizeof(struct frag_hdr); + + /* + * Charge the memory for the fragment to any owner + * it might possess + */ + if (skb->sk) + skb_set_owner_w(frag, skb->sk); + + /* + * Copy the packet header into the new buffer. + */ + memcpy(frag->nh.raw, skb->data, hlen); + + /* + * Build fragment header. + */ + fh->nexthdr = nexthdr; + fh->reserved = 0; + if (frag_id) { + ipv6_select_ident(skb, fh); + frag_id = fh->identification; + } else + fh->identification = frag_id; + + /* + * Copy a block of the IP datagram. + */ + if (skb_copy_bits(skb, ptr, frag->h.raw, len)) + BUG(); + left -= len; + + fh->frag_off = htons( left > 0 ? (offset | 0x0001) : offset); + frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr)); + + ptr += len; + offset += len; + + /* + * Put this fragment into the sending queue. + */ + + IP6_INC_STATS(Ip6FragCreates); + + err = output(frag); + if (err) + goto fail; + } + kfree_skb(skb); + IP6_INC_STATS(Ip6FragOKs); + return err; + +fail: + kfree_skb(skb); + IP6_INC_STATS(Ip6FragFails); + return err; +} + +int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl, struct in6_addr **saddr) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + int err = 0; + + *dst = __sk_dst_check(sk, np->dst_cookie); + if (*dst) { + struct rt6_info *rt = (struct rt6_info*)*dst; + + /* Yes, checking route validity in not connected + case is not very simple. Take into account, + that we do not support routing by source, TOS, + and MSG_DONTROUTE --ANK (980726) + + 1. If route was host route, check that + cached destination is current. + If it is network route, we still may + check its validity using saved pointer + to the last used address: daddr_cache. + We do not want to save whole address now, + (because main consumer of this service + is tcp, which has not this problem), + so that the last trick works only on connected + sockets. + 2. oif also should be the same. + */ + + if (((rt->rt6i_dst.plen != 128 || + ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr)) + && (np->daddr_cache == NULL || + ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache))) + || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { + *dst = NULL; + } else + dst_hold(*dst); + } + + if (*dst == NULL) + *dst = ip6_route_output(sk, fl); + + if ((*dst)->error) { + IP6_INC_STATS(Ip6OutNoRoutes); + dst_release(*dst); + return -ENETUNREACH; + } + + if (fl->fl6_src == NULL) { + *saddr = kmalloc(sizeof(struct in6_addr), GFP_ATOMIC); + err = ipv6_get_saddr(*dst, fl->fl6_dst, *saddr); + + if (err) { +#if IP6_DEBUG >= 2 + printk(KERN_DEBUG "ip6_build_xmit: " + "no availiable source address\n"); +#endif + return err; + } + fl->fl6_src = *saddr; + } + + if (*dst) { + if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) { + dst_release(*dst); + return -ENETUNREACH; + } + } + + return 0; +} + +int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), + void *from, int length, int transhdrlen, + int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt, + unsigned int flags) +{ + struct inet_opt *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct sk_buff *skb; + unsigned int maxfraglen, fragheaderlen; + int exthdrlen; + int hh_len; + int mtu; + int copy = 0; + int err; + int offset = 0; + int csummode = CHECKSUM_NONE; + + if (flags&MSG_PROBE) + return 0; + if (skb_queue_empty(&sk->write_queue)) { + /* + * setup for corking + */ + if (opt) { + if (np->cork.opt == NULL) + np->cork.opt = kmalloc(opt->tot_len, sk->allocation); + memcpy(np->cork.opt, opt, opt->tot_len); + inet->cork.flags |= IPCORK_OPT; + /* need source address above miyazawa*/ + exthdrlen += opt->opt_flen ? opt->opt_flen : 0; + } + dst_hold(&rt->u.dst); + np->cork.rt = rt; + np->cork.fl = fl; + inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst); + inet->cork.length = 0; + inet->sndmsg_page = NULL; + inet->sndmsg_off = 0; + if ((exthdrlen = rt->u.dst.header_len) != 0) { + length += exthdrlen; + transhdrlen += exthdrlen; + } + } else { + rt = np->cork.rt; + if (inet->cork.flags & IPCORK_OPT) + opt = np->cork.opt; + transhdrlen = 0; + exthdrlen = 0; + mtu = inet->cork.fragsize; + } + + hh_len = (rt->u.dst.dev->hard_header_len&~15) + 16; + + fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0); + maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); + + if (mtu < 65576) { + if (inet->cork.length + length > 0xFFFF - fragheaderlen) { + ipv6_local_error(sk, EMSGSIZE, fl, mtu-exthdrlen); + return -EMSGSIZE; + } + } + + inet->cork.length += length; + + if ((skb = skb_peek_tail(&sk->write_queue)) == NULL) + goto alloc_new_skb; + + while (length > 0) { + if ((copy = maxfraglen - skb->len) <= 0) { + char *data; + unsigned int datalen; + unsigned int fraglen; + unsigned int alloclen; + BUG_TRAP(copy == 0); +alloc_new_skb: + datalen = maxfraglen - fragheaderlen; + if (datalen > length) + datalen = length; + fraglen = datalen + fragheaderlen; + if ((flags & MSG_MORE) && + !(rt->u.dst.dev->features&NETIF_F_SG)) + alloclen = maxfraglen; + else + alloclen = fraglen; + alloclen += sizeof(struct frag_hdr); + if (transhdrlen) { + skb = sock_alloc_send_skb(sk, + alloclen + hh_len + 15, + (flags & MSG_DONTWAIT), &err); + } else { + skb = NULL; + if (atomic_read(&sk->wmem_alloc) <= 2*sk->sndbuf) + skb = sock_wmalloc(sk, + alloclen + hh_len + 15, 1, + sk->allocation); + if (unlikely(skb == NULL)) + err = -ENOBUFS; + } + if (skb == NULL) + goto error; + /* + * Fill in the control structures + */ + skb->ip_summed = csummode; + skb->csum = 0; + /* reserve 8 byte for fragmentation */ + skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); + + /* + * Find where to start putting bytes + */ + data = skb_put(skb, fraglen); + skb->nh.raw = data + exthdrlen; + data += fragheaderlen; + skb->h.raw = data + exthdrlen; + copy = datalen - transhdrlen; + if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, 0, skb) < 0) { + err = -EFAULT; + kfree_skb(skb); + goto error; + } + + offset += copy; + length -= datalen; + transhdrlen = 0; + exthdrlen = 0; + csummode = CHECKSUM_NONE; + + /* + * Put the packet on the pending queue + */ + __skb_queue_tail(&sk->write_queue, skb); + continue; + } + + if (copy > length) + copy = length; + + if (!(rt->u.dst.dev->features&NETIF_F_SG)) { + unsigned int off; + + off = skb->len; + if (getfrag(from, skb_put(skb, copy), + offset, copy, off, skb) < 0) { + __skb_trim(skb, off); + err = -EFAULT; + goto error; + } + } else { + int i = skb_shinfo(skb)->nr_frags; + skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; + struct page *page = inet->sndmsg_page; + int off = inet->sndmsg_off; + unsigned int left; + + if (page && (left = PAGE_SIZE - off) > 0) { + if (copy >= left) + copy = left; + if (page != frag->page) { + if (i == MAX_SKB_FRAGS) { + err = -EMSGSIZE; + goto error; + } + get_page(page); + skb_fill_page_desc(skb, i, page, inet->sndmsg_off, 0); + frag = &skb_shinfo(skb)->frags[i]; + } + } else if(i < MAX_SKB_FRAGS) { + if (copy > PAGE_SIZE) + copy = PAGE_SIZE; + page = alloc_pages(sk->allocation, 0); + if (page == NULL) { + err = -ENOMEM; + goto error; + } + inet->sndmsg_page = page; + inet->sndmsg_off = 0; + + skb_fill_page_desc(skb, i, page, 0, 0); + frag = &skb_shinfo(skb)->frags[i]; + skb->truesize += PAGE_SIZE; + atomic_add(PAGE_SIZE, &sk->wmem_alloc); + } else { + err = -EMSGSIZE; + goto error; + } + if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) { + err = -EFAULT; + goto error; + } + inet->sndmsg_off += copy; + frag->size += copy; + skb->len += copy; + skb->data_len += copy; + } + offset += copy; + length -= copy; + } + return 0; +error: + inet->cork.length -= length; + IP6_INC_STATS(Ip6OutDiscards); + return err; +} + +int ip6_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb, *tmp_skb; + struct sk_buff **tail_skb; + struct in6_addr *final_dst = NULL; + struct inet_opt *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct ipv6hdr *hdr; + struct ipv6_txoptions *opt = np->cork.opt; + struct rt6_info *rt = np->cork.rt; + struct flowi *fl = np->cork.fl; + unsigned char proto = fl->proto; + int err = 0; + + if ((skb = __skb_dequeue(&sk->write_queue)) == NULL) + goto out; + tail_skb = &(skb_shinfo(skb)->frag_list); + + /* move skb->data to ip header from ext header */ + if (skb->data < skb->nh.raw) + __skb_pull(skb, skb->nh.raw - skb->data); + while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) { + __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw); + *tail_skb = tmp_skb; + tail_skb = &(tmp_skb->next); + skb->len += tmp_skb->len; + skb->data_len += tmp_skb->len; +#if 0 /* Logically correct, but useless work, ip_fragment() will have to undo */ + skb->truesize += tmp_skb->truesize; + __sock_put(tmp_skb->sk); + tmp_skb->destructor = NULL; + tmp_skb->sk = NULL; +#endif + } + + final_dst = fl->fl6_dst; + __skb_pull(skb, skb->h.raw - skb->nh.raw); + if (opt && opt->opt_flen) + ipv6_push_frag_opts(skb, opt, &proto); + if (opt && opt->opt_nflen) + ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst); + + skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); + + *(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000); + + if (skb->len < 65536) + hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + else + hdr->payload_len = 0; + hdr->hop_limit = np->hop_limit; + hdr->nexthdr = proto; + memcpy(&hdr->saddr, fl->fl6_src, sizeof(struct in6_addr)); + memcpy(&hdr->daddr, final_dst, sizeof(struct in6_addr)); + + skb->dst = dst_clone(&rt->u.dst); + err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); + if (err) { + if (err > 0) + err = inet->recverr ? net_xmit_errno(err) : 0; + if (err) + goto error; + } + +out: + inet->cork.flags &= ~IPCORK_OPT; + if (np->cork.opt) { + kfree(np->cork.opt); + np->cork.opt = NULL; + } + if (np->cork.rt) { + np->cork.rt = NULL; + } + if (np->cork.fl) { + np->cork.fl = NULL; + } + return err; +error: + goto out; +} + +void ip6_flush_pending_frames(struct sock *sk) +{ + struct inet_opt *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct sk_buff *skb; + + while ((skb = __skb_dequeue_tail(&sk->write_queue)) != NULL) + kfree_skb(skb); + + inet->cork.flags &= ~IPCORK_OPT; + + if (np->cork.opt) { + kfree(np->cork.opt); + np->cork.opt = NULL; + } + if (np->cork.rt) { + np->cork.rt = NULL; + } + if (np->cork.fl) { + np->cork.fl = NULL; + } } diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c Mon May 12 20:55:47 2003 +++ b/net/ipv6/ndisc.c Mon May 12 20:55:47 2003 @@ -976,7 +976,7 @@ struct rt6_info *rt; rt = rt6_get_dflt_router(saddr, dev); if (rt) - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); } } else { if (msg->icmph.icmp6_router) @@ -1050,7 +1050,7 @@ rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); if (rt && lifetime == 0) { - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); rt = NULL; } diff -Nru a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c --- a/net/ipv6/netfilter/ip6t_ah.c Mon May 12 20:55:44 2003 +++ b/net/ipv6/netfilter/ip6t_ah.c Mon May 12 20:55:44 2003 @@ -19,13 +19,6 @@ #define DEBUGP(format, args...) #endif -struct ahhdr { - __u8 nexthdr; - __u8 hdrlen; - __u16 reserved; - __u32 spi; -}; - /* Returns 1 if the spi is matched by the range, 0 otherwise */ static inline int spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) @@ -48,7 +41,7 @@ u_int16_t datalen, int *hotdrop) { - struct ahhdr *ah = NULL; + struct ip_auth_hdr *ah = NULL; const struct ip6t_ah *ahinfo = matchinfo; unsigned int temp; int len; @@ -128,12 +121,12 @@ /* AH header not found */ if ( temp != MASK_AH ) return 0; - if (len < (int)sizeof(struct ahhdr)){ + if (len < (int)sizeof(struct ip_auth_hdr)){ *hotdrop = 1; return 0; } - ah=skb->data+ptr; + ah = (struct ip_auth_hdr *) (skb->data + ptr); DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); DEBUGP("RES %04X ", ah->reserved); diff -Nru a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c --- a/net/ipv6/netfilter/ip6t_esp.c Mon May 12 20:55:47 2003 +++ b/net/ipv6/netfilter/ip6t_esp.c Mon May 12 20:55:47 2003 @@ -19,10 +19,6 @@ #define DEBUGP(format, args...) #endif -struct esphdr { - __u32 spi; -}; - /* Returns 1 if the spi is matched by the range, 0 otherwise */ static inline int spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) @@ -45,7 +41,7 @@ u_int16_t datalen, int *hotdrop) { - struct esphdr *esp = NULL; + struct ip_esp_hdr *esp = NULL; const struct ip6t_esp *espinfo = matchinfo; unsigned int temp; int len; @@ -118,12 +114,12 @@ /* ESP header not found */ if ( temp != MASK_ESP ) return 0; - if (len < (int)sizeof(struct esphdr)){ + if (len < (int)sizeof(struct ip_esp_hdr)){ *hotdrop = 1; return 0; } - esp=skb->data+ptr; + esp = (struct ip_esp_hdr *) (skb->data + ptr); DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi)); diff -Nru a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c --- a/net/ipv6/netfilter/ip6t_frag.c Mon May 12 20:55:45 2003 +++ b/net/ipv6/netfilter/ip6t_frag.c Mon May 12 20:55:45 2003 @@ -147,7 +147,7 @@ return 0; } - frag=skb->data+ptr; + frag = (struct fraghdr *) (skb->data + ptr); DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen); DEBUGP("INFO %04X ", frag->info); diff -Nru a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c --- a/net/ipv6/netfilter/ip6t_ipv6header.c Mon May 12 20:55:49 2003 +++ b/net/ipv6/netfilter/ip6t_ipv6header.c Mon May 12 20:55:49 2003 @@ -18,12 +18,6 @@ MODULE_DESCRIPTION("IPv6 headers match"); MODULE_AUTHOR("Andras Kis-Szabo "); -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(format, args...) -#endif - static int ipv6header_match(const struct sk_buff *skb, const struct net_device *in, @@ -39,10 +33,8 @@ int len; u8 nexthdr; unsigned int ptr; - struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; /* Make sure this isn't an evil packet */ - DEBUGP("ipv6_header entered \n"); /* type of the 1st exthdr */ nexthdr = skb->nh.ipv6h->nexthdr; @@ -52,44 +44,10 @@ len = skb->len - ptr; temp = 0; - DEBUGP("ipv6_header nexthdr %02X \n",nexthdr); - DEBUGP("ipv6_header ptr %08X \n",ptr); - DEBUGP("ipv6_header skblen %04X \n",skb->len); - DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len); - DEBUGP("ipv6_header len %04X \n",len); -#if 0 - for (temp=0;templen;temp++){ - if (!(temp % 16 )) DEBUGP("\nipv6_header data "); - DEBUGP("%02X ",skb->data[temp]); - } -#endif - DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n", - skb->h.raw[0], - skb->h.raw[1], - skb->h.raw[2], - skb->h.raw[3]); - DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n", - skb->nh.raw[0], - skb->nh.raw[1], - skb->nh.raw[2], - skb->nh.raw[3]); - DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n", - opt->iif, - opt->ra, - opt->hop, - opt->auth, - opt->dst0, - opt->srcrt, - opt->dst1); - - temp = 0; - while (ip6t_ext_hdr(nexthdr)) { struct ipv6_opt_hdr *hdr; int hdrlen; - DEBUGP("ipv6_header header iteration \n"); - /* Is there enough space for the next ext header? */ if (len < (int)sizeof(struct ipv6_opt_hdr)) return 0; @@ -114,8 +72,6 @@ else hdrlen = ipv6_optlen(hdr); - DEBUGP("ipv6_header hdrlen %04X \n",hdrlen); - /* set the flag */ switch (nexthdr){ case NEXTHDR_HOP: @@ -134,7 +90,6 @@ temp |= MASK_DSTOPTS; break; default: - DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr); return 0; break; } @@ -142,17 +97,13 @@ nexthdr = hdr->nexthdr; len -= hdrlen; ptr += hdrlen; - if ( ptr > skb->len ) { - DEBUGP("ipv6_header new ptr %04X \n",ptr); + if (ptr > skb->len) break; - } } if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) ) temp |= MASK_PROTO; - DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags); - if (info->modeflag) return (!( (temp & info->matchflags) ^ info->matchflags) ^ info->invflags); @@ -169,11 +120,8 @@ { /* Check for obvious errors */ /* This match is valid in all hooks! */ - if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) { - DEBUGP("ip6t_ipv6header: matchsize != %u\n", - IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))); + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) return 0; - } return 1; } diff -Nru a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c --- a/net/ipv6/netfilter/ip6t_rt.c Mon May 12 20:55:45 2003 +++ b/net/ipv6/netfilter/ip6t_rt.c Mon May 12 20:55:45 2003 @@ -130,7 +130,7 @@ return 0; } - route=skb->data+ptr; + route = (struct ipv6_rt_hdr *) (skb->data + ptr); DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen); DEBUGP("TYPE %04X ", route->type); diff -Nru a/net/ipv6/proc.c b/net/ipv6/proc.c --- a/net/ipv6/proc.c Mon May 12 20:55:46 2003 +++ b/net/ipv6/proc.c Mon May 12 20:55:46 2003 @@ -198,6 +198,7 @@ } static struct file_operations sockstat6_seq_fops = { + .owner = THIS_MODULE, .open = sockstat6_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -210,6 +211,7 @@ } static struct file_operations snmp6_seq_fops = { + .owner = THIS_MODULE, .open = snmp6_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/ipv6/protocol.c b/net/ipv6/protocol.c --- a/net/ipv6/protocol.c Mon May 12 20:55:45 2003 +++ b/net/ipv6/protocol.c Mon May 12 20:55:45 2003 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -41,12 +40,14 @@ #include struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; +static spinlock_t inet6_proto_lock = SPIN_LOCK_UNLOCKED; + int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol) { int ret, hash = protocol & (MAX_INET_PROTOS - 1); - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&inet6_proto_lock); if (inet6_protos[hash]) { ret = -1; @@ -55,7 +56,7 @@ ret = 0; } - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&inet6_proto_lock); return ret; } @@ -68,7 +69,7 @@ { int ret, hash = protocol & (MAX_INET_PROTOS - 1); - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&inet6_proto_lock); if (inet6_protos[hash] != prot) { ret = -1; @@ -77,7 +78,9 @@ ret = 0; } - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&inet6_proto_lock); + + synchronize_net(); return ret; } diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c --- a/net/ipv6/raw.c Mon May 12 20:55:46 2003 +++ b/net/ipv6/raw.c Mon May 12 20:55:46 2003 @@ -12,6 +12,7 @@ * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) + * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -47,6 +50,9 @@ #include #include +#include +#include + struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE]; rwlock_t raw_v6_lock = RW_LOCK_UNLOCKED; @@ -435,87 +441,115 @@ goto out_free; } -/* - * Sending... - */ +static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct raw6_opt *opt, int len) +{ + struct sk_buff *skb; + int err = 0; + u16 *csum; -struct rawv6_fakehdr { - struct iovec *iov; - struct sock *sk; - __u32 len; - __u32 cksum; - __u32 proto; - struct in6_addr *daddr; -}; + if ((skb = skb_peek(&sk->write_queue)) == NULL) + goto out; -static int rawv6_getfrag(const void *data, struct in6_addr *saddr, - char *buff, unsigned int offset, unsigned int len) -{ - struct iovec *iov = (struct iovec *) data; + if (opt->offset + 1 < len) + csum = (u16 *)(skb->h.raw + opt->offset); + else { + err = -EINVAL; + goto out; + } + + if (skb_queue_len(&sk->write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + /* should be check HW csum miyazawa */ + *csum = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + len, fl->proto, skb->csum); + } else { + u32 tmp_csum = 0; - return memcpy_fromiovecend(buff, iov, offset, len); + skb_queue_walk(&sk->write_queue, skb) { + tmp_csum = csum_add(tmp_csum, skb->csum); + } + + tmp_csum = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + len, fl->proto, tmp_csum); + *csum = tmp_csum; + } + if (*csum == 0) + *csum = -1; + ip6_push_pending_frames(sk); +out: + return err; } -static int rawv6_frag_cksum(const void *data, struct in6_addr *addr, - char *buff, unsigned int offset, - unsigned int len) +static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, + struct flowi *fl, struct rt6_info *rt, + unsigned int flags) { - struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data; - - if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset, - len, &hdr->cksum)) - return -EFAULT; - - if (offset == 0) { - struct sock *sk; - struct raw6_opt *opt; - struct in6_addr *daddr; - - sk = hdr->sk; - opt = raw6_sk(sk); + struct inet_opt *inet = inet_sk(sk); + struct ipv6hdr *iph; + struct sk_buff *skb; + unsigned int hh_len; + int err; - if (hdr->daddr) - daddr = hdr->daddr; - else - daddr = addr + 1; - - hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len, - hdr->proto, hdr->cksum); - - if (opt->offset + 1 < len) { - __u16 *csum; + if (length > rt->u.dst.dev->mtu) { + ipv6_local_error(sk, EMSGSIZE, fl, rt->u.dst.dev->mtu); + return -EMSGSIZE; + } + if (flags&MSG_PROBE) + goto out; - csum = (__u16 *) (buff + opt->offset); - if (*csum) { - /* in case cksum was not initialized */ - __u32 sum = hdr->cksum; - sum += *csum; - *csum = hdr->cksum = (sum + (sum>>16)); - } else { - *csum = hdr->cksum; - } - } else { - if (net_ratelimit()) - printk(KERN_DEBUG "icmp: cksum offset too big\n"); - return -EINVAL; - } - } - return 0; -} + hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); + + skb = sock_alloc_send_skb(sk, length+hh_len+15, + flags&MSG_DONTWAIT, &err); + if (skb == NULL) + goto error; + skb_reserve(skb, hh_len); + + skb->priority = sk->priority; + skb->dst = dst_clone(&rt->u.dst); + skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length); + skb->ip_summed = CHECKSUM_NONE; + + skb->h.raw = skb->nh.raw; + err = memcpy_fromiovecend((void *)iph, from, 0, length); + if (err) + goto error_fault; + + err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, + dst_output); + if (err > 0) + err = inet->recverr ? net_xmit_errno(err) : 0; + if (err) + goto error; +out: + return 0; + +error_fault: + err = -EFAULT; + kfree_skb(skb); +error: + IP6_INC_STATS(Ip6OutDiscards); + return err; +} static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len) { struct ipv6_txoptions opt_space; struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *saddr = NULL; struct inet_opt *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); + struct raw6_opt *raw_opt = raw6_sk(sk); struct ipv6_txoptions *opt = NULL; struct ip6_flowlabel *flowlabel = NULL; + struct dst_entry *dst = NULL; struct flowi fl; int addr_len = msg->msg_namelen; - struct in6_addr *daddr; - struct raw6_opt *raw_opt; int hlimit = -1; u16 proto; int err; @@ -549,6 +583,8 @@ if (!proto) proto = inet->num; + else if (proto != inet->num) + return(-EINVAL); if (proto > 255) return(-EINVAL); @@ -587,6 +623,7 @@ * unspecfied destination address * treated as error... is this correct ? */ + fl6_sock_release(flowlabel); return(-EINVAL); } @@ -616,39 +653,71 @@ if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); - raw_opt = raw6_sk(sk); - fl.proto = proto; fl.fl6_dst = daddr; if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr)) fl.fl6_src = &np->saddr; fl.fl_icmp_type = 0; fl.fl_icmp_code = 0; - - if (raw_opt->checksum) { - struct rawv6_fakehdr hdr; - - hdr.iov = msg->msg_iov; - hdr.sk = sk; - hdr.len = len; - hdr.cksum = 0; - hdr.proto = proto; - if (opt && opt->srcrt) - hdr.daddr = daddr; + /* merge ip6_build_xmit from ip6_output */ + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + fl.fl6_dst = rt0->addr; + } + + if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr)) + fl.oif = np->mcast_oif; + + err = ip6_dst_lookup(sk, &dst, &fl, &saddr); + if (err) goto out; + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(fl.fl6_dst)) + hlimit = np->mcast_hops; else - hdr.daddr = NULL; + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit; + } - err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len, - opt, hlimit, msg->msg_flags); + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; + +back_from_confirm: + if (inet->hdrincl) { + err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags); } else { - err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len, - opt, hlimit, msg->msg_flags); + lock_sock(sk); + err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, + hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags); + + if (err) + ip6_flush_pending_frames(sk); + else if (!(msg->msg_flags & MSG_MORE)) { + if (raw_opt->checksum) { + err = rawv6_push_pending_frames(sk, &fl, raw_opt, len); + } else { + err = ip6_push_pending_frames(sk); + } + } } +done: + ip6_dst_store(sk, dst, fl.nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL); + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); +out: fl6_sock_release(flowlabel); - + if (saddr) kfree(saddr); return err<0?err:len; +do_confirm: + dst_confirm(dst); + if (!(msg->msg_flags & MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto done; } static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, @@ -831,80 +900,6 @@ return(0); } -#define LINE_LEN 190 -#define LINE_FMT "%-190s\n" - -static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i) -{ - struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; - __u16 destp, srcp; - - dest = &np->daddr; - src = &np->rcv_saddr; - destp = 0; - srcp = inet_sk(sp)->num; - sprintf(tmpbuf, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - i, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->state, - atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), - 0, 0L, 0, - sock_i_uid(sp), 0, - sock_i_ino(sp), - atomic_read(&sp->refcnt), sp); -} - -int raw6_get_info(char *buffer, char **start, off_t offset, int length) -{ - int len = 0, num = 0, i; - off_t pos = 0; - off_t begin; - char tmpbuf[LINE_LEN+2]; - - if (offset < LINE_LEN+1) - len += sprintf(buffer, LINE_FMT, - " sl " /* 6 */ - "local_address " /* 38 */ - "remote_address " /* 38 */ - "st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */ - " uid timeout inode"); /* 21 */ - /*----*/ - /*144 */ - pos = LINE_LEN+1; - read_lock(&raw_v6_lock); - for (i = 0; i < RAWV6_HTABLE_SIZE; i++) { - struct sock *sk; - - for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) { - if (sk->family != PF_INET6) - continue; - pos += LINE_LEN+1; - if (pos <= offset) - continue; - get_raw6_sock(sk, tmpbuf, i); - len += sprintf(buffer+len, LINE_FMT, tmpbuf); - if(len >= length) - goto out; - } - } -out: - read_unlock(&raw_v6_lock); - begin = len - (pos - offset); - *start = buffer + begin; - len -= begin; - if(len > length) - len = length; - if (len < 0) - len = 0; - return len; -} - struct proto rawv6_prot = { .name = "RAW", .close = rawv6_close, @@ -922,3 +917,151 @@ .hash = raw_v6_hash, .unhash = raw_v6_unhash, }; + +#ifdef CONFIG_PROC_FS +struct raw6_iter_state { + int bucket; +}; + +#define raw6_seq_private(seq) ((struct raw6_iter_state *)&seq->private) + +static struct sock *raw6_get_first(struct seq_file *seq) +{ + struct sock *sk = NULL; + struct raw6_iter_state* state = raw6_seq_private(seq); + + for (state->bucket = 0; state->bucket < RAWV6_HTABLE_SIZE; ++state->bucket) { + sk = raw_v6_htable[state->bucket]; + while (sk && sk->family != PF_INET6) + sk = sk->next; + if (sk) + break; + } + return sk; +} + +static struct sock *raw6_get_next(struct seq_file *seq, struct sock *sk) +{ + struct raw6_iter_state* state = raw6_seq_private(seq); + + do { + sk = sk->next; +try_again: + ; + } while (sk && sk->family != PF_INET6); + + if (!sk && ++state->bucket < RAWV6_HTABLE_SIZE) { + sk = raw_v6_htable[state->bucket]; + goto try_again; + } + return sk; +} + +static struct sock *raw6_get_idx(struct seq_file *seq, loff_t pos) +{ + struct sock *sk = raw6_get_first(seq); + if (sk) + while (pos && (sk = raw6_get_next(seq, sk)) != NULL) + --pos; + return pos ? NULL : sk; +} + +static void *raw6_seq_start(struct seq_file *seq, loff_t *pos) +{ + read_lock(&raw_v6_lock); + return *pos ? raw6_get_idx(seq, *pos) : (void *)1; +} + +static void *raw6_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *sk; + + if (v == (void *)1) + sk = raw6_get_first(seq); + else + sk = raw6_get_next(seq, v); + ++*pos; + return sk; +} + +static void raw6_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock(&raw_v6_lock); +} + +static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) +{ + struct ipv6_pinfo *np = inet6_sk(sp); + struct in6_addr *dest, *src; + __u16 destp, srcp; + + dest = &np->daddr; + src = &np->rcv_saddr; + destp = 0; + srcp = inet_sk(sp)->num; + seq_printf(seq, + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", + i, + src->s6_addr32[0], src->s6_addr32[1], + src->s6_addr32[2], src->s6_addr32[3], srcp, + dest->s6_addr32[0], dest->s6_addr32[1], + dest->s6_addr32[2], dest->s6_addr32[3], destp, + sp->state, + atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), + 0, 0L, 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), + atomic_read(&sp->refcnt), sp); +} + +static int raw6_seq_show(struct seq_file *seq, void *v) +{ + if (v == (void *)1) + seq_printf(seq, + " sl " + "local_address " + "remote_address " + "st tx_queue rx_queue tr tm->when retrnsmt" + " uid timeout inode\n"); + else + raw6_sock_seq_show(seq, v, raw6_seq_private(seq)->bucket); + return 0; +} + +static struct seq_operations raw6_seq_ops = { + .start = raw6_seq_start, + .next = raw6_seq_next, + .stop = raw6_seq_stop, + .show = raw6_seq_show, +}; + +static int raw6_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &raw6_seq_ops); +} + +static struct file_operations raw6_seq_fops = { + .owner = THIS_MODULE, + .open = raw6_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init raw6_proc_init(void) +{ + struct proc_dir_entry *p = create_proc_entry("raw6", S_IRUGO, proc_net); + + if (!p) + return -ENOMEM; + p->proc_fops = &raw6_seq_fops; + + return 0; +} + +void raw6_proc_exit(void) +{ + remove_proc_entry("raw6", proc_net); +} +#endif /* CONFIG_PROC_FS */ diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c Mon May 12 20:55:48 2003 +++ b/net/ipv6/route.c Mon May 12 20:55:48 2003 @@ -39,6 +39,7 @@ #ifdef CONFIG_PROC_FS #include +#include #endif #include @@ -323,12 +324,12 @@ be destroyed. */ -static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh) +static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) { int err; write_lock_bh(&rt6_lock); - err = fib6_add(&ip6_routing_table, rt, nlh); + err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr); write_unlock_bh(&rt6_lock); return err; @@ -371,7 +372,7 @@ dst_hold(&rt->u.dst); - err = rt6_ins(rt, NULL); + err = rt6_ins(rt, NULL, NULL); if (err == 0) return rt; @@ -525,7 +526,7 @@ if (rt) { if (rt->rt6i_flags & RTF_CACHE) - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); else dst_release(dst); } @@ -564,7 +565,7 @@ static unsigned long last_gc; unsigned long now = jiffies; - if ((long)(now - last_gc) < ip6_rt_gc_min_interval && + if (time_after(last_gc + ip6_rt_gc_min_interval, now) && atomic_read(&ip6_dst_ops.entries) <= ip6_rt_max_size) goto out; @@ -628,14 +629,17 @@ * */ -int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh) +int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) { int err; struct rtmsg *r; + struct rtattr **rta; struct rt6_info *rt; struct net_device *dev = NULL; int addr_type; + rta = (struct rtattr **) _rtattr; + if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128) return -EINVAL; #ifndef CONFIG_IPV6_SUBTREES @@ -767,13 +771,38 @@ if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS; + else if (rta && rta[RTA_HOPLIMIT-1]) + memcpy(&rt->rt6i_hoplimit, RTA_DATA(rta[RTA_HOPLIMIT-1]), 1); else rt->rt6i_hoplimit = ipv6_get_hoplimit(dev); + rt->rt6i_flags = rtmsg->rtmsg_flags; install_route: - rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); - rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss); + if (rta && rta[RTA_METRICS-1]) { + int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]); + struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]); + + while (RTA_OK(attr, attrlen)) { + unsigned flavor = attr->rta_type; + if (flavor) { + if (flavor > RTAX_MAX) { + err = -EINVAL; + goto out; + } + rt->u.dst.metrics[flavor-1] = + *(u32 *)RTA_DATA(attr); + } + attr = RTA_NEXT(attr, attrlen); + } + } + if (!rt->u.dst.metrics[RTAX_MTU-1]) + rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); + if (!rt->u.dst.metrics[RTAX_ADVMSS-1]) + rt->u.dst.metrics[RTAX_ADVMSS-1] = + max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, + ip6_rt_min_advmss); + /* Maximal non-jumbo IPv6 payload is 65535 and corresponding MSS is 65535 - tcp_header_size. 65535 is also valid and means: "any MSS, rely only on pmtu discovery" @@ -781,7 +810,7 @@ if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535-20) rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535; rt->u.dst.dev = dev; - return rt6_ins(rt, nlh); + return rt6_ins(rt, nlh, _rtattr); out: if (dev) @@ -790,7 +819,7 @@ return err; } -int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh) +int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr) { int err; @@ -802,13 +831,13 @@ dst_release(&rt->u.dst); - err = fib6_del(rt, nlh); + err = fib6_del(rt, nlh, _rtattr); write_unlock_bh(&rt6_lock); return err; } -static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh) +static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) { struct fib6_node *fn; struct rt6_info *rt; @@ -835,7 +864,7 @@ dst_hold(&rt->u.dst); read_unlock_bh(&rt6_lock); - return ip6_del_rt(rt, nlh); + return ip6_del_rt(rt, nlh, _rtattr); } } read_unlock_bh(&rt6_lock); @@ -937,11 +966,11 @@ nrt->u.dst.metrics[RTAX_ADVMSS-1] = 65535; nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev); - if (rt6_ins(nrt, NULL)) + if (rt6_ins(nrt, NULL, NULL)) goto out; if (rt->rt6i_flags&RTF_CACHE) { - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); return; } @@ -1027,7 +1056,7 @@ dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; - rt6_ins(nrt, NULL); + rt6_ins(nrt, NULL, NULL); } out: @@ -1098,7 +1127,7 @@ rtmsg.rtmsg_ifindex = dev->ifindex; - ip6_route_add(&rtmsg, NULL); + ip6_route_add(&rtmsg, NULL, NULL); return rt6_get_dflt_router(gwaddr, dev); } @@ -1124,7 +1153,7 @@ read_unlock_bh(&rt6_lock); - ip6_del_rt(rt, NULL); + ip6_del_rt(rt, NULL, NULL); goto restart; } @@ -1150,10 +1179,10 @@ rtnl_lock(); switch (cmd) { case SIOCADDRT: - err = ip6_route_add(&rtmsg, NULL); + err = ip6_route_add(&rtmsg, NULL, NULL); break; case SIOCDELRT: - err = ip6_route_del(&rtmsg, NULL); + err = ip6_route_del(&rtmsg, NULL, NULL); break; default: err = -EINVAL; @@ -1173,7 +1202,7 @@ int ip6_pkt_discard(struct sk_buff *skb) { IP6_INC_STATS(Ip6OutNoRoutes); - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); kfree_skb(skb); return 0; } @@ -1209,7 +1238,7 @@ ipv6_addr_copy(&rt->rt6i_dst.addr, addr); rt->rt6i_dst.plen = 128; - rt6_ins(rt, NULL); + rt6_ins(rt, NULL, NULL); return 0; } @@ -1226,7 +1255,7 @@ rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1); if (rt) { if (rt->rt6i_dst.plen == 128) - err = ip6_del_rt(rt, NULL); + err = ip6_del_rt(rt, NULL, NULL); else dst_release(&rt->u.dst); } @@ -1356,7 +1385,7 @@ if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_del(&rtmsg, nlh); + return ip6_route_del(&rtmsg, nlh, arg); } int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) @@ -1366,7 +1395,7 @@ if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) return -EINVAL; - return ip6_route_add(&rtmsg, nlh); + return ip6_route_add(&rtmsg, nlh, arg); } struct rt6_rtnl_dump_arg @@ -1751,27 +1780,29 @@ extern struct rt6_statistics rt6_stats; -static int rt6_proc_stats(char *buffer, char **start, off_t offset, int length) +static int rt6_stats_seq_show(struct seq_file *seq, void *v) { - int len; - - len = sprintf(buffer, "%04x %04x %04x %04x %04x %04x\n", + seq_printf(seq, "%04x %04x %04x %04x %04x %04x\n", rt6_stats.fib_nodes, rt6_stats.fib_route_nodes, rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries, rt6_stats.fib_rt_cache, atomic_read(&ip6_dst_ops.entries)); - len -= offset; - - if (len > length) - len = length; - if(len < 0) - len = 0; - - *start = buffer + offset; + return 0; +} - return len; +static int rt6_stats_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, rt6_stats_seq_show, NULL); } + +static struct file_operations rt6_stats_seq_fops = { + .owner = THIS_MODULE, + .open = rt6_stats_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_SYSCTL @@ -1877,6 +1908,8 @@ void __init ip6_route_init(void) { + struct proc_dir_entry *p; + ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, @@ -1884,7 +1917,9 @@ fib6_init(); #ifdef CONFIG_PROC_FS proc_net_create("ipv6_route", 0, rt6_proc_info); - proc_net_create("rt6_stats", 0, rt6_proc_stats); + p = create_proc_entry("rt6_stats", S_IRUGO, proc_net); + if (p) + p->proc_fops = &rt6_stats_seq_fops; #endif xfrm6_init(); } @@ -1894,7 +1929,7 @@ { #ifdef CONFIG_PROC_FS proc_net_remove("ipv6_route"); - proc_net_remove("rt6_stats"); + remove_proc_entry("rt6_stats", proc_net); #endif xfrm6_fini(); rt6_ifdown(NULL); diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c --- a/net/ipv6/udp.c Mon May 12 20:55:48 2003 +++ b/net/ipv6/udp.c Mon May 12 20:55:48 2003 @@ -14,6 +14,7 @@ * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind * a single port at the same time. + * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -575,7 +576,7 @@ for(; s; s = s->next) { struct inet_opt *inet = inet_sk(s); - if (inet->num == num) { + if (inet->num == num && sk->family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); if (inet->dport) { if (inet->dport != rmt_port) @@ -738,96 +739,117 @@ kfree_skb(skb); return(0); } - /* - * Sending + * Throw away all pending data and cancel the corking. Socket is locked. */ - -struct udpv6fakehdr +static void udp_v6_flush_pending_frames(struct sock *sk) { - struct udphdr uh; - struct iovec *iov; - __u32 wcheck; - __u32 pl_len; - struct in6_addr *daddr; -}; + struct udp_opt *up = udp_sk(sk); + + if (up->pending) { + up->pending = 0; + ip6_flush_pending_frames(sk); + } +} /* - * with checksum + * Sending */ -static int udpv6_getfrag(const void *data, struct in6_addr *addr, - char *buff, unsigned int offset, unsigned int len) +static int udp_v6_push_pending_frames(struct sock *sk, struct udp_opt *up) { - struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data; - char *dst; - int final = 0; - int clen = len; + struct sk_buff *skb; + struct udphdr *uh; + struct ipv6_pinfo *np = inet6_sk(sk); + struct flowi *fl = np->cork.fl; + int err = 0; - dst = buff; + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->write_queue)) == NULL) + goto out; - if (offset) { - offset -= sizeof(struct udphdr); + /* + * Create a UDP header + */ + uh = skb->h.uh; + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (sk->no_check == UDP_CSUM_NOXMIT) { + skb->ip_summed = CHECKSUM_NONE; + goto send; + } + + if (skb_queue_len(&sk->write_queue) == 1) { + skb->csum = csum_partial((char *)uh, + sizeof(struct udphdr), skb->csum); + uh->check = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + up->len, fl->proto, skb->csum); } else { - dst += sizeof(struct udphdr); - final = 1; - clen -= sizeof(struct udphdr); - } - - if (csum_partial_copy_fromiovecend(dst, udh->iov, offset, - clen, &udh->wcheck)) - return -EFAULT; + u32 tmp_csum = 0; - if (final) { - struct in6_addr *daddr; - - udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr), - udh->wcheck); - - if (udh->daddr) { - daddr = udh->daddr; - } else { - /* - * use packet destination address - * this should improve cache locality - */ - daddr = addr + 1; - } - udh->uh.check = csum_ipv6_magic(addr, daddr, - udh->pl_len, IPPROTO_UDP, - udh->wcheck); - if (udh->uh.check == 0) - udh->uh.check = -1; + skb_queue_walk(&sk->write_queue, skb) { + tmp_csum = csum_add(tmp_csum, skb->csum); + } + tmp_csum = csum_partial((char *)uh, + sizeof(struct udphdr), tmp_csum); + tmp_csum = csum_ipv6_magic(fl->fl6_src, + fl->fl6_dst, + up->len, fl->proto, tmp_csum); + uh->check = tmp_csum; - memcpy(buff, udh, sizeof(struct udphdr)); } - return 0; + if (uh->check == 0) + uh->check = -1; + +send: + err = ip6_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + return err; } -static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int ulen) +static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len) { struct ipv6_txoptions opt_space; - struct udpv6fakehdr udh; + struct udp_opt *up = udp_sk(sk); struct inet_opt *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *saddr = NULL; struct ipv6_txoptions *opt = NULL; struct ip6_flowlabel *flowlabel = NULL; struct flowi fl; + struct dst_entry *dst; int addr_len = msg->msg_namelen; - struct in6_addr *daddr; - int len = ulen + sizeof(struct udphdr); + int ulen = len; int addr_type; int hlimit = -1; - + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int err; /* Rough check on arithmetic overflow, better check is made in ip6_build_xmit */ - if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr)) + if (len < 0 || len > INT_MAX - sizeof(struct udphdr)) return -EMSGSIZE; + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) + goto do_append_data; + release_sock(sk); + } + ulen += sizeof(struct udphdr); + fl.fl6_flowlabel = 0; fl.oif = 0; @@ -835,7 +857,7 @@ if (sin6->sin6_family == AF_INET) { if (__ipv6_only_sock(sk)) return -ENETUNREACH; - return udp_sendmsg(iocb, sk, msg, ulen); + return udp_sendmsg(iocb, sk, msg, len); } if (addr_len < SIN6_LEN_RFC2133) @@ -847,7 +869,7 @@ if (sin6->sin6_port == 0) return -EINVAL; - udh.uh.dest = sin6->sin6_port; + up->dport = sin6->sin6_port; daddr = &sin6->sin6_addr; if (np->sndflow) { @@ -873,7 +895,7 @@ if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - udh.uh.dest = inet->dport; + up->dport = inet->dport; daddr = &np->daddr; fl.fl6_flowlabel = np->flow_label; } @@ -888,15 +910,14 @@ sin.sin_family = AF_INET; sin.sin_addr.s_addr = daddr->s6_addr32[3]; - sin.sin_port = udh.uh.dest; + sin.sin_port = up->dport; msg->msg_name = (struct sockaddr *)(&sin); msg->msg_namelen = sizeof(sin); fl6_sock_release(flowlabel); - return udp_sendmsg(iocb, sk, msg, ulen); + return udp_sendmsg(iocb, sk, msg, len); } - udh.daddr = NULL; if (!fl.oif) fl.oif = sk->bound_dev_if; fl.fl6_src = NULL; @@ -922,33 +943,172 @@ opt = np->opt; if (flowlabel) opt = fl6_merge_options(&opt_space, flowlabel, opt); - if (opt && opt->srcrt) - udh.daddr = daddr; - - udh.uh.source = inet->sport; - udh.uh.len = len < 0x10000 ? htons(len) : 0; - udh.uh.check = 0; - udh.iov = msg->msg_iov; - udh.wcheck = 0; - udh.pl_len = len; fl.proto = IPPROTO_UDP; fl.fl6_dst = daddr; if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr)) fl.fl6_src = &np->saddr; - fl.fl_ip_dport = udh.uh.dest; - fl.fl_ip_sport = udh.uh.source; + fl.fl_ip_dport = up->dport; + fl.fl_ip_sport = inet->sport; + + /* merge ip6_build_xmit from ip6_output */ + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + fl.fl6_dst = rt0->addr; + } - err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit, - msg->msg_flags); + if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr)) + fl.oif = np->mcast_oif; + err = ip6_dst_lookup(sk, &dst, &fl, &saddr); + if (err) goto out; + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit; + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 2\n")); + err = -EINVAL; + goto out; + } + + up->pending = 1; + +do_append_data: + up->len += ulen; + err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), + hlimit, opt, &fl, (struct rt6_info*)dst, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_v6_flush_pending_frames(sk); + else if (!corkreq) + err = udp_v6_push_pending_frames(sk, up); + + ip6_dst_store(sk, dst, fl.nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL); + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); +out: fl6_sock_release(flowlabel); + if (saddr) kfree(saddr); + if (!err) { + UDP6_INC_STATS_USER(UdpOutDatagrams); + return len; + } + return err; - if (err < 0) - return err; +do_confirm: + dst_confirm(dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +static int udpv6_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_v6_flush_pending_frames(sk); + release_sock(sk); + + inet6_destroy_sock(sk); + + return 0; +} + +/* + * Socket option code for UDP + */ +static int udpv6_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + struct udp_opt *up = udp_sk(sk); + int val; + int err = 0; + + if (level != SOL_UDP) + return ipv6_setsockopt(sk, level, optname, optval, optlen); - UDP6_INC_STATS_USER(UdpOutDatagrams); - return ulen; + if(optlencorkflag = 1; + } else { + up->corkflag = 0; + lock_sock(sk); + udp_v6_push_pending_frames(sk, up); + release_sock(sk); + } + break; + + case UDP_ENCAP: + up->encap_type = val; + break; + + default: + err = -ENOPROTOOPT; + break; + }; + + return err; +} + +static int udpv6_getsockopt(struct sock *sk, int level, int optname, + char *optval, int *optlen) +{ + struct udp_opt *up = udp_sk(sk); + int val, len; + + if (level != SOL_UDP) + return ipv6_getsockopt(sk, level, optname, optval, optlen); + + if(get_user(len,optlen)) + return -EFAULT; + + len = min_t(unsigned int, len, sizeof(int)); + + if(len < 0) + return -EINVAL; + + switch(optname) { + case UDP_CORK: + val = up->corkflag; + break; + + case UDP_ENCAP: + val = up->encap_type; + break; + + default: + return -ENOPROTOOPT; + }; + + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, &val,len)) + return -EFAULT; + return 0; } static struct inet6_protocol udpv6_protocol = { @@ -1038,9 +1198,9 @@ .connect = udpv6_connect, .disconnect = udp_disconnect, .ioctl = udp_ioctl, - .destroy = inet6_destroy_sock, - .setsockopt = ipv6_setsockopt, - .getsockopt = ipv6_getsockopt, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, .sendmsg = udpv6_sendmsg, .recvmsg = udpv6_recvmsg, .backlog_rcv = udpv6_queue_rcv_skb, diff -Nru a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c --- a/net/ipv6/xfrm6_state.c Mon May 12 20:55:46 2003 +++ b/net/ipv6/xfrm6_state.c Mon May 12 20:55:46 2003 @@ -57,7 +57,7 @@ spi == x->id.spi && !ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) && proto == x->id.proto) { - atomic_inc(&x->refcnt); + xfrm_state_hold(x); return x; } } @@ -91,7 +91,7 @@ } } if (x0) { - atomic_inc(&x0->refcnt); + xfrm_state_hold(x0); } else if (create && (x0 = xfrm_state_alloc()) != NULL) { memcpy(x0->sel.daddr.a6, daddr, sizeof(struct in6_addr)); memcpy(x0->sel.saddr.a6, saddr, sizeof(struct in6_addr)); @@ -105,9 +105,9 @@ x0->props.mode = mode; x0->props.reqid = reqid; x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; - atomic_inc(&x0->refcnt); + xfrm_state_hold(x0); mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ); - atomic_inc(&x0->refcnt); + xfrm_state_hold(x0); list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h); wake_up(&km_waitq); } diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c --- a/net/ipx/af_ipx.c Mon May 12 20:55:45 2003 +++ b/net/ipx/af_ipx.c Mon May 12 20:55:45 2003 @@ -15,7 +15,7 @@ * liability nor provide warranty for any of this software. This material * is provided as is and at no charge. * - * Portions Copyright (c) 2000-2002 Conectiva, Inc. + * Portions Copyright (c) 2000-2003 Conectiva, Inc. * Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor * provide warranty for any of this software. This material is provided * "AS-IS" and at no charge. @@ -81,10 +81,10 @@ static struct proto_ops ipx_dgram_ops; -struct ipx_route *ipx_routes; +LIST_HEAD(ipx_routes); rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED; -struct ipx_interface *ipx_interfaces; +LIST_HEAD(ipx_interfaces); spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED; struct ipx_interface *ipx_primary_net; @@ -95,11 +95,21 @@ atomic_t ipx_sock_nr; #endif +struct ipx_interface *ipx_interfaces_head(void) +{ + struct ipx_interface *rc = NULL; + + if (!list_empty(&ipx_interfaces)) + rc = list_entry(ipx_interfaces.next, + struct ipx_interface, node); + return rc; +} + static void ipxcfg_set_auto_select(char val) { ipxcfg_auto_select_primary = val; if (val && !ipx_primary_net) - ipx_primary_net = ipx_interfaces; + ipx_primary_net = ipx_interfaces_head(); } static int ipxcfg_get_config_data(struct ipx_config_data *arg) @@ -197,17 +207,21 @@ static void ipxitf_clear_primary_net(void) { - ipx_primary_net = ipxcfg_auto_select_primary ? ipx_interfaces : NULL; + ipx_primary_net = NULL; + if (ipxcfg_auto_select_primary) + ipx_primary_net = ipx_interfaces_head(); } static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev, unsigned short datalink) { - struct ipx_interface *i = ipx_interfaces; - - while (i && (i->if_dev != dev || i->if_dlink_type != datalink)) - i = i->if_next; + struct ipx_interface *i; + list_for_each_entry(i, &ipx_interfaces, node) + if (i->if_dev == dev && i->if_dlink_type == datalink) + goto out; + i = NULL; +out: return i; } @@ -229,16 +243,20 @@ struct ipx_interface *i; spin_lock_bh(&ipx_interfaces_lock); - if (net) - for (i = ipx_interfaces; i && i->if_netnum != net; - i = i->if_next) - ; - else - i = ipx_primary_net; + if (net) { + list_for_each_entry(i, &ipx_interfaces, node) + if (i->if_netnum == net) + goto hold; + i = NULL; + goto unlock; + } + + i = ipx_primary_net; if (i) +hold: ipxitf_hold(i); +unlock: spin_unlock_bh(&ipx_interfaces_lock); - return i; } @@ -342,15 +360,7 @@ spin_unlock_bh(&intrfc->if_sklist_lock); /* remove this interface from list */ - if (intrfc == ipx_interfaces) - ipx_interfaces = intrfc->if_next; - else { - struct ipx_interface *i = ipx_interfaces; - while (i && i->if_next != intrfc) - i = i->if_next; - if (i && i->if_next == intrfc) - i->if_next = intrfc->if_next; - } + list_del(&intrfc->node); /* remove this interface from *special* networks */ if (intrfc == ipx_primary_net) @@ -361,6 +371,7 @@ if (intrfc->if_dev) dev_put(intrfc->if_dev); kfree(intrfc); + module_put(THIS_MODULE); } static void ipxitf_down(struct ipx_interface *intrfc) @@ -380,16 +391,13 @@ goto out; spin_lock_bh(&ipx_interfaces_lock); - for (i = ipx_interfaces; i;) { - tmp = i->if_next; + list_for_each_entry_safe(i, tmp, &ipx_interfaces, node) if (i->if_dev == dev) { if (event == NETDEV_UP) ipxitf_hold(i); else __ipxitf_put(i); } - i = tmp; - } spin_unlock_bh(&ipx_interfaces_lock); out: return NOTIFY_DONE; @@ -872,7 +880,7 @@ IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum; /* xmit on all other interfaces... */ spin_lock_bh(&ipx_interfaces_lock); - for (ifcs = ipx_interfaces; ifcs; ifcs = ifcs->if_next) { + list_for_each_entry(ifcs, &ipx_interfaces, node) { /* Except unconfigured interfaces */ if (!ifcs->if_netnum) continue; @@ -902,16 +910,8 @@ static void ipxitf_insert(struct ipx_interface *intrfc) { - intrfc->if_next = NULL; spin_lock_bh(&ipx_interfaces_lock); - if (!ipx_interfaces) - ipx_interfaces = intrfc; - else { - struct ipx_interface *i = ipx_interfaces; - while (i->if_next) - i = i->if_next; - i->if_next = intrfc; - } + list_add_tail(&intrfc->node, &ipx_interfaces); spin_unlock_bh(&ipx_interfaces_lock); if (ipxcfg_auto_select_primary && !ipx_primary_net) @@ -937,6 +937,7 @@ intrfc->if_sklist = NULL; atomic_set(&intrfc->refcnt, 1); spin_lock_init(&intrfc->if_sklist_lock); + __module_get(THIS_MODULE); } return intrfc; @@ -1278,12 +1279,14 @@ struct ipx_route *r; read_lock_bh(&ipx_routes_lock); - for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next) - ; - if (r) - ipxrtr_hold(r); + list_for_each_entry(r, &ipx_routes, node) + if (r->ir_net == net) { + ipxrtr_hold(r); + goto unlock; + } + r = NULL; +unlock: read_unlock_bh(&ipx_routes_lock); - return r; } @@ -1306,8 +1309,7 @@ atomic_set(&rt->refcnt, 1); ipxrtr_hold(rt); write_lock_bh(&ipx_routes_lock); - rt->ir_next = ipx_routes; - ipx_routes = rt; + list_add(&rt->node, &ipx_routes); write_unlock_bh(&ipx_routes_lock); } else { rc = -EEXIST; @@ -1334,16 +1336,14 @@ static void ipxrtr_del_routes(struct ipx_interface *intrfc) { - struct ipx_route **r, *tmp; + struct ipx_route *r, *tmp; write_lock_bh(&ipx_routes_lock); - for (r = &ipx_routes; (tmp = *r) != NULL;) { - if (tmp->ir_intrfc == intrfc) { - *r = tmp->ir_next; - ipxrtr_put(tmp); - } else - r = &(tmp->ir_next); - } + list_for_each_entry_safe(r, tmp, &ipx_routes, node) + if (r->ir_intrfc == intrfc) { + list_del(&r->node); + ipxrtr_put(r); + } write_unlock_bh(&ipx_routes_lock); } @@ -1364,26 +1364,21 @@ static int ipxrtr_delete(long net) { - struct ipx_route **r; - struct ipx_route *tmp; + struct ipx_route *r, *tmp; int rc; write_lock_bh(&ipx_routes_lock); - for (r = &ipx_routes; (tmp = *r) != NULL;) { - if (tmp->ir_net == net) { + list_for_each_entry_safe(r, tmp, &ipx_routes, node) + if (r->ir_net == net) { /* Directly connected; can't lose route */ rc = -EPERM; - if (!tmp->ir_routed) + if (!r->ir_routed) goto out; - - *r = tmp->ir_next; - ipxrtr_put(tmp); + list_del(&r->node); + ipxrtr_put(r); rc = 0; goto out; } - - r = &(tmp->ir_next); - } rc = -ENOENT; out: write_unlock_bh(&ipx_routes_lock); @@ -2267,9 +2262,9 @@ static unsigned char ipx_8022_type = 0xE0; static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; static char ipx_banner[] __initdata = - KERN_INFO "NET4: Linux IPX 0.50 for NET4.0\n" + KERN_INFO "NET4: Linux IPX 0.51 for NET4.0\n" KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \ - KERN_INFO "IPX Portions Copyright (c) 2000-2002 Conectiva, Inc.\n"; + KERN_INFO "IPX Portions Copyright (c) 2000-2003 Conectiva, Inc.\n"; static char ipx_EII_err_msg[] __initdata = KERN_CRIT "IPX: Unable to register with Ethernet II\n"; static char ipx_8023_err_msg[] __initdata = @@ -2317,6 +2312,10 @@ * when a interface is created we increment the module usage count, so * the module will only be unloaded when there are no more interfaces */ + if (unlikely(!list_empty(&ipx_interfaces))) + BUG(); + if (unlikely(!list_empty(&ipx_routes))) + BUG(); ipx_proc_exit(); ipx_unregister_sysctl(); diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c --- a/net/ipx/ipx_proc.c Mon May 12 20:55:44 2003 +++ b/net/ipx/ipx_proc.c Mon May 12 20:55:44 2003 @@ -17,12 +17,23 @@ { struct ipx_interface *i; - for (i = ipx_interfaces; pos && i; i = i->if_next) - --pos; - + list_for_each_entry(i, &ipx_interfaces, node) + if (!pos--) + goto out; + i = NULL; +out: return i; } +static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i) +{ + struct ipx_interface *rc = NULL; + + if (i->node.next != &ipx_interfaces) + rc = list_entry(i->node.next, struct ipx_interface, node); + return rc; +} + static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) { loff_t l = *pos; @@ -36,15 +47,10 @@ struct ipx_interface *i; ++*pos; - if (v == (void *)1) { - i = NULL; - if (ipx_interfaces) - i = ipx_interfaces; - goto out; - } - i = v; - i = i->if_next; -out: + if (v == (void *)1) + i = ipx_interfaces_head(); + else + i = ipx_interfaces_next(v); return i; } @@ -83,13 +89,33 @@ return 0; } +static struct ipx_route *ipx_routes_head(void) +{ + struct ipx_route *rc = NULL; + + if (!list_empty(&ipx_routes)) + rc = list_entry(ipx_routes.next, struct ipx_route, node); + return rc; +} + +static struct ipx_route *ipx_routes_next(struct ipx_route *r) +{ + struct ipx_route *rc = NULL; + + if (r->node.next != &ipx_routes) + rc = list_entry(r->node.next, struct ipx_route, node); + return rc; +} + static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos) { struct ipx_route *r; - for (r = ipx_routes; pos && r; r = r->ir_next) - --pos; - + list_for_each_entry(r, &ipx_routes, node) + if (!pos--) + goto out; + r = NULL; +out: return r; } @@ -105,15 +131,10 @@ struct ipx_route *r; ++*pos; - if (v == (void *)1) { - r = NULL; - if (ipx_routes) - r = ipx_routes; - goto out; - } - r = v; - r = r->ir_next; -out: + if (v == (void *)1) + r = ipx_routes_head(); + else + r = ipx_routes_next(v); return r; } @@ -149,7 +170,9 @@ struct sock *s = NULL; struct ipx_interface *i; - for (i = ipx_interfaces; pos && i; i = i->if_next) { + list_for_each_entry(i, &ipx_interfaces, node) { + if (!pos) + break; spin_lock_bh(&i->if_sklist_lock); for (s = i->if_sklist; pos && s; s = s->next) --pos; @@ -181,11 +204,12 @@ ++*pos; if (v == (void *)1) { sk = NULL; - if (!ipx_interfaces) + i = ipx_interfaces_head(); + if (!i) goto out; - sk = ipx_interfaces->if_sklist; + sk = i->if_sklist; if (sk) - spin_lock_bh(&ipx_interfaces->if_sklist_lock); + spin_lock_bh(&i->if_sklist_lock); goto out; } sk = v; @@ -198,9 +222,9 @@ spin_unlock_bh(&i->if_sklist_lock); sk = NULL; for (;;) { - if (!i->if_next) + i = ipx_interfaces_next(i); + if (!i) break; - i = i->if_next; spin_lock_bh(&i->if_sklist_lock); if (i->if_sklist) { sk = i->if_sklist; @@ -295,6 +319,7 @@ } static struct file_operations ipx_seq_interface_fops = { + .owner = THIS_MODULE, .open = ipx_seq_interface_open, .read = seq_read, .llseek = seq_lseek, @@ -302,6 +327,7 @@ }; static struct file_operations ipx_seq_route_fops = { + .owner = THIS_MODULE, .open = ipx_seq_route_open, .read = seq_read, .llseek = seq_lseek, @@ -309,6 +335,7 @@ }; static struct file_operations ipx_seq_socket_fops = { + .owner = THIS_MODULE, .open = ipx_seq_socket_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/irda/irlap.c b/net/irda/irlap.c --- a/net/irda/irlap.c Mon May 12 20:55:48 2003 +++ b/net/irda/irlap.c Mon May 12 20:55:48 2003 @@ -1117,7 +1117,7 @@ len += sprintf(buf+len, " win size: %d, ", self->window_size); len += sprintf(buf+len, "win: %d, ", self->window); -#if CONFIG_IRDA_DYNAMIC_WINDOW +#ifdef CONFIG_IRDA_DYNAMIC_WINDOW len += sprintf(buf+len, "line capacity: %d, ", self->line_capacity); len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left); diff -Nru a/net/irda/irlap_event.c b/net/irda/irlap_event.c --- a/net/irda/irlap_event.c Mon May 12 20:55:47 2003 +++ b/net/irda/irlap_event.c Mon May 12 20:55:47 2003 @@ -43,7 +43,7 @@ #include -#if CONFIG_IRDA_FAST_RR +#ifdef CONFIG_IRDA_FAST_RR int sysctl_fast_poll_increase = 50; #endif diff -Nru a/net/key/af_key.c b/net/key/af_key.c --- a/net/key/af_key.c Mon May 12 20:55:45 2003 +++ b/net/key/af_key.c Mon May 12 20:55:45 2003 @@ -1090,15 +1090,7 @@ return x; out: - if (x->aalg) - kfree(x->aalg); - if (x->ealg) - kfree(x->ealg); - if (x->calg) - kfree(x->calg); - if (x->encap) - kfree(x->encap); - kfree(x); + xfrm_state_put(x); return ERR_PTR(-ENOBUFS); } @@ -1249,7 +1241,8 @@ } } - if (x1 && x1->id.spi && hdr->sadb_msg_type == SADB_ADD) { + if (x1 && ((x1->id.spi && hdr->sadb_msg_type == SADB_ADD) || + (hdr->sadb_msg_type == SADB_UPDATE && xfrm_state_kern(x1)))) { x->km.state = XFRM_STATE_DEAD; xfrm_state_put(x); xfrm_state_put(x1); @@ -1294,6 +1287,11 @@ if (x == NULL) return -ESRCH; + if (xfrm_state_kern(x)) { + xfrm_state_put(x); + return -EPERM; + } + xfrm_state_delete(x); xfrm_state_put(x); diff -Nru a/net/llc/llc_proc.c b/net/llc/llc_proc.c --- a/net/llc/llc_proc.c Mon May 12 20:55:44 2003 +++ b/net/llc/llc_proc.c Mon May 12 20:55:44 2003 @@ -211,6 +211,7 @@ } static struct file_operations llc_seq_socket_fops = { + .owner = THIS_MODULE, .open = llc_seq_socket_open, .read = seq_read, .llseek = seq_lseek, @@ -218,6 +219,7 @@ }; static struct file_operations llc_seq_core_fops = { + .owner = THIS_MODULE, .open = llc_seq_core_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c --- a/net/netlink/netlink_dev.c Mon May 12 20:55:46 2003 +++ b/net/netlink/netlink_dev.c Mon May 12 20:55:46 2003 @@ -220,14 +220,6 @@ }, }; -static void __init make_devfs_entries (const char *name, int minor) -{ - devfs_register (NULL, name, DEVFS_FL_DEFAULT, - NETLINK_MAJOR, minor, - S_IFCHR | S_IRUSR | S_IWUSR, - &netlink_fops, NULL); -} - int __init init_netlink(void) { int i; @@ -236,18 +228,20 @@ printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR); return -EIO; } + devfs_mk_dir("netlink"); + /* Someone tell me the official names for the uppercase ones */ for (i = 0; i < sizeof(entries)/sizeof(entries[0]); i++) { - char name[20]; - sprintf(name, "netlink/%s", entries[i].name); - make_devfs_entries(name, entries[i].minor); + devfs_mk_cdev(MKDEV(NETLINK_MAJOR, entries[i].minor), + S_IFCHR|S_IRUSR|S_IWUSR, "netlink/%s", entries[i].name); } + for (i = 0; i < 16; i++) { - char name[20]; - sprintf(name, "netlink/tap%d", i); - make_devfs_entries(name, i + 16); + devfs_mk_cdev(MKDEV(NETLINK_MAJOR, i + 16), + S_IFCHR|S_IRUSR|S_IWUSR, "netlink/tap%d", i); } + return 0; } diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Mon May 12 20:55:46 2003 +++ b/net/netsyms.c Mon May 12 20:55:46 2003 @@ -228,13 +228,11 @@ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) EXPORT_SYMBOL(dev_change_flags); #endif -EXPORT_SYMBOL(vlan_ioctl_set); EXPORT_SYMBOL(scm_detach_fds); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) EXPORT_SYMBOL(br_handle_frame_hook); -EXPORT_SYMBOL(brioctl_set); #endif #ifdef CONFIG_NET_DIVERT @@ -285,11 +283,6 @@ /* needed for ip_gre -cw */ EXPORT_SYMBOL(ip_statistics); -#ifdef CONFIG_DLCI_MODULE -extern int (*dlci_ioctl_hook)(unsigned int, void *); -EXPORT_SYMBOL(dlci_ioctl_hook); -#endif - EXPORT_SYMBOL(xfrm_user_policy); EXPORT_SYMBOL(km_waitq); EXPORT_SYMBOL(km_new_mapping); @@ -311,6 +304,7 @@ EXPORT_SYMBOL(xfrm_state_unregister_afinfo); EXPORT_SYMBOL(xfrm_state_get_afinfo); EXPORT_SYMBOL(xfrm_state_put_afinfo); +EXPORT_SYMBOL(xfrm_state_delete_tunnel); EXPORT_SYMBOL(xfrm_replay_check); EXPORT_SYMBOL(xfrm_replay_advance); EXPORT_SYMBOL(xfrm_check_selectors); @@ -473,6 +467,8 @@ EXPORT_SYMBOL(sysctl_max_syn_backlog); #endif +EXPORT_SYMBOL(ip_generic_getfrag); + #endif EXPORT_SYMBOL(tcp_read_sock); @@ -577,6 +573,7 @@ EXPORT_SYMBOL(netif_receive_skb); EXPORT_SYMBOL(dev_add_pack); EXPORT_SYMBOL(dev_remove_pack); +EXPORT_SYMBOL(__dev_remove_pack); EXPORT_SYMBOL(dev_get); EXPORT_SYMBOL(dev_alloc); EXPORT_SYMBOL(dev_alloc_name); @@ -673,10 +670,13 @@ EXPORT_SYMBOL(softnet_data); #ifdef CONFIG_NET_RADIO -/* Don't include the whole header mess for a single function */ -union iwreq_data; -extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); +#include /* Wireless Extensions driver API */ EXPORT_SYMBOL(wireless_send_event); +EXPORT_SYMBOL(iw_handler_set_spy); +EXPORT_SYMBOL(iw_handler_get_spy); +EXPORT_SYMBOL(iw_handler_set_thrspy); +EXPORT_SYMBOL(iw_handler_get_thrspy); +EXPORT_SYMBOL(wireless_spy_update); #endif /* CONFIG_NET_RADIO */ EXPORT_SYMBOL(linkwatch_fire_event); diff -Nru a/net/nonet.c b/net/nonet.c --- a/net/nonet.c Mon May 12 20:55:49 2003 +++ b/net/nonet.c Mon May 12 20:55:49 2003 @@ -24,5 +24,6 @@ } struct file_operations bad_sock_fops = { + .owner = THIS_MODULE, .open = sock_no_open, }; diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c --- a/net/packet/af_packet.c Mon May 12 20:55:47 2003 +++ b/net/packet/af_packet.c Mon May 12 20:55:47 2003 @@ -774,6 +774,7 @@ */ dev_remove_pack(&po->prot_hook); po->running = 0; + po->num = 0; __sock_put(sk); } @@ -819,9 +820,12 @@ spin_lock(&po->bind_lock); if (po->running) { - dev_remove_pack(&po->prot_hook); __sock_put(sk); po->running = 0; + po->num = 0; + spin_unlock(&po->bind_lock); + dev_remove_pack(&po->prot_hook); + spin_lock(&po->bind_lock); } po->num = protocol; @@ -1374,7 +1378,7 @@ if (dev->ifindex == po->ifindex) { spin_lock(&po->bind_lock); if (po->running) { - dev_remove_pack(&po->prot_hook); + __dev_remove_pack(&po->prot_hook); __sock_put(sk); po->running = 0; sk->err = ENETDOWN; @@ -1618,9 +1622,14 @@ /* Detach socket from network */ spin_lock(&po->bind_lock); - if (po->running) - dev_remove_pack(&po->prot_hook); + if (po->running) { + __dev_remove_pack(&po->prot_hook); + po->num = 0; + po->running = 0; + } spin_unlock(&po->bind_lock); + + synchronize_net(); err = -EBUSY; if (closing || atomic_read(&po->mapped) == 0) { diff -Nru a/net/rxrpc/proc.c b/net/rxrpc/proc.c --- a/net/rxrpc/proc.c Mon May 12 20:55:47 2003 +++ b/net/rxrpc/proc.c Mon May 12 20:55:47 2003 @@ -38,6 +38,7 @@ }; static struct file_operations rxrpc_proc_transports_fops = { + .owner = THIS_MODULE, .open = rxrpc_proc_transports_open, .read = seq_read, .llseek = seq_lseek, @@ -51,6 +52,7 @@ static int rxrpc_proc_peers_show(struct seq_file *m, void *v); static struct seq_operations rxrpc_proc_peers_ops = { + .owner = THIS_MODULE, .start = rxrpc_proc_peers_start, .next = rxrpc_proc_peers_next, .stop = rxrpc_proc_peers_stop, @@ -58,6 +60,7 @@ }; static struct file_operations rxrpc_proc_peers_fops = { + .owner = THIS_MODULE, .open = rxrpc_proc_peers_open, .read = seq_read, .llseek = seq_lseek, @@ -78,6 +81,7 @@ }; static struct file_operations rxrpc_proc_conns_fops = { + .owner = THIS_MODULE, .open = rxrpc_proc_conns_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/sched/sch_atm.c b/net/sched/sch_atm.c --- a/net/sched/sch_atm.c Mon May 12 20:55:46 2003 +++ b/net/sched/sch_atm.c Mon May 12 20:55:46 2003 @@ -509,7 +509,6 @@ memcpy(skb_push(skb,flow->hdr_len),flow->hdr, flow->hdr_len); atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc); - ATM_SKB(skb)->iovcnt = 0; /* atm.atm_options are already set by atm_tc_enqueue */ (void) flow->vcc->send(flow->vcc,skb); } diff -Nru a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c --- a/net/sched/sch_ingress.c Mon May 12 20:55:48 2003 +++ b/net/sched/sch_ingress.c Mon May 12 20:55:48 2003 @@ -222,11 +222,6 @@ */ if (dev->qdisc_ingress) { - /* FIXME: Push down to ->enqueue functions --RR */ - if (skb_is_nonlinear(*pskb) - && skb_linearize(*pskb, GFP_ATOMIC) != 0) - return NF_DROP; - spin_lock(&dev->queue_lock); if ((q = dev->qdisc_ingress) != NULL) fwres = q->enqueue(skb, q); diff -Nru a/net/sctp/Kconfig b/net/sctp/Kconfig --- a/net/sctp/Kconfig Mon May 12 20:55:45 2003 +++ b/net/sctp/Kconfig Mon May 12 20:55:45 2003 @@ -43,12 +43,12 @@ bool "SCTP: Use old checksum (Adler-32)" depends on IP_SCTP help - RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. + RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. This has been deprecated and replaced by an algorithm now referred to as crc32c. - If you say Y, this will use the Adler-32 algorithm, this might be useful - for interoperation with downlevel peers. + If you say Y, this will use the Adler-32 algorithm, this might be + useful for interoperation with downlevel peers. If unsure, say N. @@ -58,19 +58,47 @@ help If you say Y, this will enable verbose debugging messages. - If unsure, say N. However, if you are running into problems, use this - option to gather detailed trace information + If unsure, say N. However, if you are running into problems, use + this option to gather detailed trace information config SCTP_DBG_OBJCNT bool "SCTP: Debug object counts" depends on IP_SCTP help - If you say Y, this will enable debugging support for counting the types - of objects that are currently allocated. This is useful for identifying - memory leaks. If the /proc filesystem is enabled this debug information - can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt' + If you say Y, this will enable debugging support for counting the + type of objects that are currently allocated. This is useful for + identifying memory leaks. If the /proc filesystem is enabled this + debug information can be viewed by + 'cat /proc/net/sctp/sctp_dbg_objcnt' If unsure, say N -endmenu +choice + prompt "SCTP: Cookie HMAC Algorithm" + depends on IP_SCTP + help + HMAC algorithm to be used during association initialization. It + is strongly recommended to use HMAC-SHA1 or HMAC-MD5. See + configuration for Cryptographic API and enable those algorithms + to make usable by SCTP. + +config SCTP_HMAC_NONE + bool "None" + help + Choosing this disables the use of an HMAC during association + establishment. It is advised to use either HMAC-MD5 or HMAC-SHA1. + +config SCTP_HMAC_SHA1 + bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m + help + Enable the use of HMAC-SHA1 during association establishment. It + is advised to use either HMAC-MD5 or HMAC-SHA1. +config SCTP_HMAC_MD5 + bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m + help + Enable the use of HMAC-MD5 during association establishment. It is + advised to use either HMAC-MD5 or HMAC-SHA1. + +endchoice +endmenu diff -Nru a/net/sctp/Makefile b/net/sctp/Makefile --- a/net/sctp/Makefile Mon May 12 20:55:49 2003 +++ b/net/sctp/Makefile Mon May 12 20:55:49 2003 @@ -6,11 +6,10 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \ protocol.o endpointola.o associola.o \ - transport.o sm_make_chunk.o ulpevent.o \ + transport.o chunk.o sm_make_chunk.o ulpevent.o \ inqueue.o outqueue.o ulpqueue.o command.o \ tsnmap.o bind_addr.o socket.o primitive.o \ - output.o input.o hashdriver.o sla1.o \ - debug.o ssnmap.o proc.o + output.o input.o debug.o ssnmap.o proc.o ifeq ($(CONFIG_SCTP_ADLER32), y) sctp-y += adler32.o diff -Nru a/net/sctp/adler32.c b/net/sctp/adler32.c --- a/net/sctp/adler32.c Mon May 12 20:55:48 2003 +++ b/net/sctp/adler32.c Mon May 12 20:55:48 2003 @@ -2,43 +2,43 @@ * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2003 International Business Machines, Corp. - * + * * This file is part of the SCTP kernel reference Implementation - * - * This file has direct heritage from the SCTP user-level reference + * + * This file has direct heritage from the SCTP user-level reference * implementation by R. Stewart, et al. These functions implement the - * Adler-32 algorithm as specified by RFC 2960. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * Adler-32 algorithm as specified by RFC 2960. + * + * The SCTP reference implementation 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. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * Randall Stewart * Ken Morneau * Qiaobing Xie * Sridhar Samudrala - * + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ @@ -65,7 +65,7 @@ * tad, but I have commented the original lines below */ -#include +#include #include #define BASE 65521 /* largest prime smaller than 65536 */ @@ -111,7 +111,7 @@ * This would then be (2 * BASE) - 2, which * will still only do one subtract. On Intel * this is much better to do this way and - * avoid the divide. Have not -pg'd on + * avoid the divide. Have not -pg'd on * sparc. */ if (s2 >= BASE) { @@ -135,7 +135,7 @@ __u32 zero = 0L; /* Calculate the CRC up to the checksum field. */ - adler = update_adler32(adler, ptr, + adler = update_adler32(adler, ptr, sizeof(struct sctphdr) - sizeof(__u32)); /* Skip over the checksum field. */ adler = update_adler32(adler, (unsigned char *) &zero, @@ -152,6 +152,15 @@ __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler) { adler = update_adler32(adler, ptr, count); + + return adler; +} + +__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 count, __u32 adler) +{ + /* Its not worth it to try harder. Adler32 is obsolescent. */ + adler = update_adler32(adler, from, count); + memcpy(to, from, count); return adler; } diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c --- a/net/sctp/associola.c Mon May 12 20:55:44 2003 +++ b/net/sctp/associola.c Mon May 12 20:55:44 2003 @@ -58,23 +58,23 @@ #include /* Forward declarations for internal functions. */ -static void sctp_assoc_bh_rcv(sctp_association_t *asoc); +static void sctp_assoc_bh_rcv(struct sctp_association *asoc); /* 1st Level Abstractions. */ /* Allocate and initialize a new association */ -sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, +struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep, const struct sock *sk, - sctp_scope_t scope, int priority) + sctp_scope_t scope, int gfp) { - sctp_association_t *asoc; + struct sctp_association *asoc; - asoc = t_new(sctp_association_t, priority); + asoc = t_new(struct sctp_association, gfp); if (!asoc) goto fail; - if (!sctp_association_init(asoc, ep, sk, scope, priority)) + if (!sctp_association_init(asoc, ep, sk, scope, gfp)) goto fail_init; asoc->base.malloced = 1; @@ -89,23 +89,24 @@ } /* Initialize a new association from provided memory. */ -sctp_association_t *sctp_association_init(sctp_association_t *asoc, - const sctp_endpoint_t *ep, +struct sctp_association *sctp_association_init(struct sctp_association *asoc, + const struct sctp_endpoint *ep, const struct sock *sk, sctp_scope_t scope, - int priority) + int gfp) { struct sctp_opt *sp; + struct sctp_protocol *proto = sctp_get_protocol(); int i; /* Retrieve the SCTP per socket area. */ sp = sctp_sk((struct sock *)sk); /* Init all variables to a known value. */ - memset(asoc, 0, sizeof(sctp_association_t)); + memset(asoc, 0, sizeof(struct sctp_association)); /* Discarding const is appropriate here. */ - asoc->ep = (sctp_endpoint_t *)ep; + asoc->ep = (struct sctp_endpoint *)ep; sctp_endpoint_hold(asoc->ep); /* Hold the sock. */ @@ -136,10 +137,10 @@ asoc->frag_point = 0; /* Initialize the default association max_retrans and RTO values. */ - asoc->max_retrans = ep->proto->max_retrans_association; - asoc->rto_initial = ep->proto->rto_initial; - asoc->rto_max = ep->proto->rto_max; - asoc->rto_min = ep->proto->rto_min; + asoc->max_retrans = proto->max_retrans_association; + asoc->rto_initial = proto->rto_initial; + asoc->rto_max = proto->rto_max; + asoc->rto_min = proto->rto_min; asoc->overall_error_threshold = 0; asoc->overall_error_count = 0; @@ -147,7 +148,7 @@ /* Initialize the maximum mumber of new data packets that can be sent * in a burst. */ - asoc->max_burst = ep->proto->max_burst; + asoc->max_burst = proto->max_burst; /* Copy things from the endpoint. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { @@ -255,7 +256,7 @@ sctp_packet_transmit_chunk, sctp_packet_transmit); - if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc)) + if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; /* Set up the tsn tracking. */ @@ -265,7 +266,6 @@ asoc->need_ecne = 0; - asoc->debug_name = "unnamedasoc"; asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; /* Assume that peer would support both address types unless we are @@ -288,7 +288,7 @@ /* Free this association if possible. There may still be users, so * the actual deallocation may be delayed. */ -void sctp_association_free(sctp_association_t *asoc) +void sctp_association_free(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; struct sctp_transport *transport; @@ -298,8 +298,7 @@ list_del(&asoc->asocs); /* Decrement the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) sk->ack_backlog--; /* Mark as dead, so other users can know this structure is @@ -351,7 +350,7 @@ } /* Cleanup and free up an association. */ -static void sctp_association_destroy(sctp_association_t *asoc) +static void sctp_association_destroy(struct sctp_association *asoc) { SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return); @@ -379,31 +378,56 @@ */ if (transport->active) asoc->peer.active_path = transport; + + /* + * SFR-CACC algorithm: + * Upon the receipt of a request to change the primary + * destination address, on the data structure for the new + * primary destination, the sender MUST do the following: + * + * 1) If CHANGEOVER_ACTIVE is set, then there was a switch + * to this destination address earlier. The sender MUST set + * CYCLING_CHANGEOVER to indicate that this switch is a + * double switch to the same destination address. + */ + if (transport->cacc.changeover_active) + transport->cacc.cycling_changeover = 1; + + /* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that + * a changeover has occurred. + */ + transport->cacc.changeover_active = 1; + + /* 3) The sender MUST store the next TSN to be sent in + * next_tsn_at_change. + */ + transport->cacc.next_tsn_at_change = asoc->next_tsn; } /* Add a transport address to an association. */ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, const union sctp_addr *addr, - int priority) + int gfp) { struct sctp_transport *peer; struct sctp_opt *sp; unsigned short port; + sp = sctp_sk(asoc->base.sk); + /* AF_INET and AF_INET6 share common port field. */ port = addr->v4.sin_port; /* Set the port if it has not been set yet. */ - if (0 == asoc->peer.port) { + if (0 == asoc->peer.port) asoc->peer.port = port; - } /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); if (peer) return peer; - peer = sctp_transport_new(addr, priority); + peer = sctp_transport_new(addr, gfp); if (!peer) return NULL; @@ -425,7 +449,7 @@ SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " "%d\n", asoc, asoc->pmtu); - asoc->frag_point = sctp_frag_point(asoc->pmtu); + asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. @@ -470,14 +494,14 @@ /* Initialize the peer's heartbeat interval based on the * sock configured value. */ - sp = sctp_sk(asoc->base.sk); + peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; /* Attach the remote transport to our asoc. */ list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); /* If we do not yet have a primary path, set one. */ - if (NULL == asoc->peer.primary_path) { + if (!asoc->peer.primary_path) { sctp_assoc_set_primary(asoc, peer); asoc->peer.retran_path = peer; } @@ -489,8 +513,9 @@ } /* Lookup a transport by address. */ -struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc, - const union sctp_addr *address) +struct sctp_transport *sctp_assoc_lookup_paddr( + const struct sctp_association *asoc, + const union sctp_addr *address) { struct sctp_transport *t; struct list_head *pos; @@ -510,7 +535,7 @@ * Mark the transport up or down and send a notification to the user. * Select and update the new active and retran paths. */ -void sctp_assoc_control_transport(sctp_association_t *asoc, +void sctp_assoc_control_transport(struct sctp_association *asoc, struct sctp_transport *transport, sctp_transport_cmd_t command, sctp_sn_error_t error) @@ -589,7 +614,7 @@ /* If we failed to find a usable transport, just camp on the * primary, even if it is inactive. */ - if (NULL == first) { + if (!first) { first = asoc->peer.primary_path; second = asoc->peer.primary_path; } @@ -600,7 +625,7 @@ } /* Hold a reference to an association. */ -void sctp_association_hold(sctp_association_t *asoc) +void sctp_association_hold(struct sctp_association *asoc) { atomic_inc(&asoc->base.refcnt); } @@ -608,7 +633,7 @@ /* Release a reference to an association and cleanup * if there are no more references. */ -void sctp_association_put(sctp_association_t *asoc) +void sctp_association_put(struct sctp_association *asoc) { if (atomic_dec_and_test(&asoc->base.refcnt)) sctp_association_destroy(asoc); @@ -617,7 +642,7 @@ /* Allocate the next TSN, Transmission Sequence Number, for the given * association. */ -__u32 sctp_association_get_next_tsn(sctp_association_t *asoc) +__u32 sctp_association_get_next_tsn(struct sctp_association *asoc) { /* From Section 1.6 Serial Number Arithmetic: * Transmission Sequence Numbers wrap around when they reach @@ -632,7 +657,7 @@ } /* Allocate 'num' TSNs by incrementing the association's TSN by num. */ -__u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num) +__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num) { __u32 retval = asoc->next_tsn; @@ -662,7 +687,7 @@ * Note: We are sly and return a shared, prealloced chunk. FIXME: * No we don't, but we could/should. */ -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc) +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) { struct sctp_chunk *chunk; @@ -680,7 +705,7 @@ /* Use this function for the packet prepend callback when no ECNE * packet is desired (e.g. some packets don't like to be bundled). */ -sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc) +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc) { return NULL; } @@ -688,13 +713,14 @@ /* * Find which transport this TSN was sent on. */ -struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn) +struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, + __u32 tsn) { struct sctp_transport *active; struct sctp_transport *match; struct list_head *entry, *pos; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 key = htonl(tsn); match = NULL; @@ -717,7 +743,7 @@ active = asoc->peer.active_path; list_for_each(entry, &active->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, transmitted_list); + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = active; @@ -732,7 +758,7 @@ if (transport == active) break; list_for_each(entry, &transport->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = transport; @@ -745,7 +771,7 @@ } /* Is this the association we are looking for? */ -struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc, +struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc, const union sctp_addr *laddr, const union sctp_addr *paddr) { @@ -771,10 +797,10 @@ } /* Do delayed input processing. This is scheduled by sctp_rcv(). */ -static void sctp_assoc_bh_rcv(sctp_association_t *asoc) +static void sctp_assoc_bh_rcv(struct sctp_association *asoc) { - sctp_endpoint_t *ep; - sctp_chunk_t *chunk; + struct sctp_endpoint *ep; + struct sctp_chunk *chunk; struct sock *sk; struct sctp_inq *inqueue; int state, subtype; @@ -819,7 +845,7 @@ } /* This routine moves an association from its old sk to a new sk. */ -void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk) +void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk) { struct sctp_opt *newsp = sctp_sk(newsk); struct sock *oldsk = assoc->base.sk; @@ -830,7 +856,7 @@ list_del(&assoc->asocs); /* Decrement the backlog value for a TCP-style socket. */ - if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type) + if (sctp_style(oldsk, TCP)) oldsk->ack_backlog--; /* Release references to the old endpoint and the sock. */ @@ -850,7 +876,8 @@ } /* Update an association (possibly from unexpected COOKIE-ECHO processing). */ -void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new) +void sctp_assoc_update(struct sctp_association *asoc, + struct sctp_association *new) { /* Copy in new parameters of peer. */ asoc->c = new->c; @@ -872,7 +899,7 @@ * current next_tsn in case data sent to peer * has been discarded and needs retransmission. */ - if (SCTP_STATE_ESTABLISHED == asoc->state) { + if (sctp_state(asoc, ESTABLISHED)) { asoc->next_tsn = new->next_tsn; asoc->ctsn_ack_point = new->ctsn_ack_point; @@ -898,7 +925,7 @@ * through the inactive transports as this is the next best thing * we can try. */ -void sctp_assoc_update_retran_path(sctp_association_t *asoc) +void sctp_assoc_update_retran_path(struct sctp_association *asoc) { struct sctp_transport *t, *next; struct list_head *head = &asoc->peer.transport_addr_list; @@ -944,7 +971,8 @@ } /* Choose the transport for sending a SHUTDOWN packet. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc) +struct sctp_transport *sctp_assoc_choose_shutdown_transport( + struct sctp_association *asoc) { /* If this is the first time SHUTDOWN is sent, use the active path, * else use the retran path. If the last SHUTDOWN was sent over the @@ -963,7 +991,7 @@ /* Update the association's pmtu and frag_point by going through all the * transports. This routine is called when a transport's PMTU has changed. */ -void sctp_assoc_sync_pmtu(sctp_association_t *asoc) +void sctp_assoc_sync_pmtu(struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -980,8 +1008,9 @@ } if (pmtu) { + struct sctp_opt *sp = sctp_sk(asoc->base.sk); asoc->pmtu = pmtu; - asoc->frag_point = sctp_frag_point(pmtu); + asoc->frag_point = sctp_frag_point(sp, pmtu); } SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", @@ -1007,9 +1036,9 @@ } /* Increase asoc's rwnd by len and send any window update SACK if needed. */ -void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len) +void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len) { - sctp_chunk_t *sack; + struct sctp_chunk *sack; struct timer_list *timer; if (asoc->rwnd_over) { @@ -1053,7 +1082,7 @@ } /* Decrease asoc's rwnd by len. */ -void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len) +void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len) { SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); @@ -1092,7 +1121,7 @@ } /* Build the association's bind address list from the cookie. */ -int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *asoc, +int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc, sctp_cookie_t *cookie, int gfp) { int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); diff -Nru a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c --- a/net/sctp/bind_addr.c Mon May 12 20:55:48 2003 +++ b/net/sctp/bind_addr.c Mon May 12 20:55:48 2003 @@ -52,16 +52,17 @@ #include /* Forward declarations for internal helpers. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *, +static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *, sctp_scope_t scope, int gfp, int flags); -static void sctp_bind_addr_clean(sctp_bind_addr_t *); +static void sctp_bind_addr_clean(struct sctp_bind_addr *); /* First Level Abstractions. */ /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses * in 'src' which have a broader scope than 'scope'. */ -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp, int flags) { struct sockaddr_storage_list *addr; @@ -80,6 +81,22 @@ goto out; } + /* If there are no addresses matching the scope and + * this is global scope, try to get a link scope address, with + * the assumption that we must be sitting behind a NAT. + */ + if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { + list_for_each(pos, &src->address_list) { + addr = list_entry(pos, struct sockaddr_storage_list, + list); + error = sctp_copy_one_addr(dest, &addr->a, + SCTP_SCOPE_LINK, gfp, + flags); + if (error < 0) + goto out; + } + } + out: if (error) sctp_bind_addr_clean(dest); @@ -88,11 +105,11 @@ } /* Create a new SCTP_bind_addr from nothing. */ -sctp_bind_addr_t *sctp_bind_addr_new(int gfp) +struct sctp_bind_addr *sctp_bind_addr_new(int gfp) { - sctp_bind_addr_t *retval; + struct sctp_bind_addr *retval; - retval = t_new(sctp_bind_addr_t, gfp); + retval = t_new(struct sctp_bind_addr, gfp); if (!retval) goto nomem; @@ -107,7 +124,7 @@ /* Initialize the SCTP_bind_addr structure for either an endpoint or * an association. */ -void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) +void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) { bp->malloced = 0; @@ -116,7 +133,7 @@ } /* Dispose of the address list. */ -static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) +static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { struct sockaddr_storage_list *addr; struct list_head *pos, *temp; @@ -131,7 +148,7 @@ } /* Dispose of an SCTP_bind_addr structure */ -void sctp_bind_addr_free(sctp_bind_addr_t *bp) +void sctp_bind_addr_free(struct sctp_bind_addr *bp) { /* Empty the bind address list. */ sctp_bind_addr_clean(bp); @@ -143,7 +160,7 @@ } /* Add an address to the bind address list in the SCTP_bind_addr structure. */ -int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new, +int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, int gfp) { struct sockaddr_storage_list *addr; @@ -171,7 +188,7 @@ /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) +int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) { struct list_head *pos, *temp; struct sockaddr_storage_list *addr; @@ -196,7 +213,7 @@ * * The second argument is the return value for the length. */ -union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, +union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp) { union sctp_params addrparms; @@ -214,6 +231,14 @@ len += sizeof(sctp_addr_param_t); } + /* Don't even bother embedding an address if there + * is only one. + */ + if (len == sizeof(sctp_addr_param_t)) { + retval.v = NULL; + goto end_raw; + } + retval.v = kmalloc(len, gfp); if (!retval.v) goto end_raw; @@ -237,7 +262,7 @@ * Create an address list out of the raw address list format (IPv4 and IPv6 * address parameters). */ -int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, +int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, int addrs_len, __u16 port, int gfp) { sctp_addr_param_t *rawaddr; @@ -283,7 +308,8 @@ ********************************************************************/ /* Does this contain a specified address? Allow wildcarding. */ -int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, +int sctp_bind_addr_match(struct sctp_bind_addr *bp, + const union sctp_addr *addr, struct sctp_opt *opt) { struct sockaddr_storage_list *laddr; @@ -299,7 +325,8 @@ } /* Copy out addresses from the global local address list. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, +static int sctp_copy_one_addr(struct sctp_bind_addr *dest, + union sctp_addr *addr, sctp_scope_t scope, int gfp, int flags) { struct sctp_protocol *proto = sctp_get_protocol(); diff -Nru a/net/sctp/chunk.c b/net/sctp/chunk.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/sctp/chunk.c Mon May 12 20:55:49 2003 @@ -0,0 +1,327 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2003 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file contains the code relating the the chunk abstraction. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* This file is mostly in anticipation of future work, but initially + * populate with fragment tracking for an outbound message. + */ + +/* Initialize datamsg from memory. */ +void sctp_datamsg_init(struct sctp_datamsg *msg) +{ + atomic_set(&msg->refcnt, 1); + msg->send_failed = 0; + msg->send_error = 0; + msg->can_expire = 0; + INIT_LIST_HEAD(&msg->chunks); +} + +/* Allocate and initialize datamsg. */ +struct sctp_datamsg *sctp_datamsg_new(int gfp) +{ + struct sctp_datamsg *msg; + msg = kmalloc(sizeof(struct sctp_datamsg), gfp); + if (msg) + sctp_datamsg_init(msg); + SCTP_DBG_OBJCNT_INC(datamsg); + return msg; +} + +/* Final destructruction of datamsg memory. */ +static void sctp_datamsg_destroy(struct sctp_datamsg *msg) +{ + struct list_head *pos, *temp; + struct sctp_chunk *chunk; + struct sctp_opt *sp; + struct sctp_ulpevent *ev; + struct sctp_association *asoc = NULL; + int error = 0, notify; + + /* If we failed, we may need to notify. */ + notify = msg->send_failed ? -1 : 0; + + /* Release all references. */ + list_for_each_safe(pos, temp, &msg->chunks) { + list_del(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + /* Check whether we _really_ need to notify. */ + if (notify < 0) { + asoc = chunk->asoc; + if (msg->send_error) + error = msg->send_error; + else + error = asoc->outqueue.error; + + sp = sctp_sk(asoc->base.sk); + notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED, + &sp->subscribe); + } + + /* Generate a SEND FAILED event only if enabled. */ + if (notify > 0) { + int sent; + if (chunk->has_tsn) + sent = SCTP_DATA_SENT; + else + sent = SCTP_DATA_UNSENT; + + ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, + error, GFP_ATOMIC); + if (ev) + sctp_ulpq_tail_event(&asoc->ulpq, ev); + } + + sctp_chunk_put(chunk); + } + + SCTP_DBG_OBJCNT_DEC(datamsg); + kfree(msg); +} + +/* Hold a reference. */ +void sctp_datamsg_hold(struct sctp_datamsg *msg) +{ + atomic_inc(&msg->refcnt); +} + +/* Release a reference. */ +void sctp_datamsg_put(struct sctp_datamsg *msg) +{ + if (atomic_dec_and_test(&msg->refcnt)) + sctp_datamsg_destroy(msg); +} + +/* Free a message. Really just give up a reference, the + * really free happens in sctp_datamsg_destroy(). + */ +void sctp_datamsg_free(struct sctp_datamsg *msg) +{ + sctp_datamsg_put(msg); +} + +/* Hold on to all the fragments until all chunks have been sent. */ +void sctp_datamsg_track(struct sctp_chunk *chunk) +{ + sctp_chunk_hold(chunk); +} + +/* Assign a chunk to this datamsg. */ +void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk) +{ + sctp_datamsg_hold(msg); + chunk->msg = msg; +} + + +/* A data chunk can have a maximum payload of (2^16 - 20). Break + * down any such message into smaller chunks. Opportunistically, fragment + * the chunks down to the current MTU constraints. We may get refragmented + * later if the PMTU changes, but it is _much better_ to fragment immediately + * with a reasonable guess than always doing our fragmentation on the + * soft-interrupt. + */ +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, + struct sctp_sndrcvinfo *sinfo, + struct msghdr *msgh, int msg_len) +{ + int max, whole, i, offset, over, err; + int len, first_len; + struct sctp_chunk *chunk; + struct sctp_datamsg *msg; + struct list_head *pos, *temp; + __u8 frag; + + msg = sctp_datamsg_new(GFP_KERNEL); + if (!msg) + return NULL; + + /* Note: Calculate this outside of the loop, so that all fragments + * have the same expiration. + */ + if (sinfo->sinfo_timetolive) { + struct timeval tv; + __u32 ttl = sinfo->sinfo_timetolive; + + /* sinfo_timetolive is in milliseconds */ + tv.tv_sec = ttl / 1000; + tv.tv_usec = ttl % 1000 * 1000; + msg->expires_at = jiffies + timeval_to_jiffies(&tv); + msg->can_expire = 1; + } + + /* What is a reasonable fragmentation point right now? */ + max = asoc->pmtu; + if (max < SCTP_MIN_PMTU) + max = SCTP_MIN_PMTU; + max -= SCTP_IP_OVERHEAD; + + /* Make sure not beyond maximum chunk size. */ + if (max > SCTP_MAX_CHUNK_LEN) + max = SCTP_MAX_CHUNK_LEN; + + /* Subtract out the overhead of a data chunk header. */ + max -= sizeof(struct sctp_data_chunk); + whole = 0; + + /* If user has specified smaller fragmentation, make it so. */ + if (sctp_sk(asoc->base.sk)->user_frag) + max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag); + + first_len = max; + + /* Encourage Cookie-ECHO bundling. */ + if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { + whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); + + /* Account for the DATA to be bundled with the COOKIE-ECHO. */ + if (whole) { + first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; + msg_len -= first_len; + whole = 1; + } + } + + /* How many full sized? How many bytes leftover? */ + whole += msg_len / max; + over = msg_len % max; + offset = 0; + + if ((whole > 1) || (whole && over)) + SCTP_INC_STATS_USER(SctpFragUsrMsgs); + + /* Create chunks for all the full sized DATA chunks. */ + for (i=0, len=first_len; i < whole; i++) { + frag = SCTP_DATA_MIDDLE_FRAG; + + if (0 == i) + frag |= SCTP_DATA_FIRST_FRAG; + + if ((i == (whole - 1)) && !over) + frag |= SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); + + if (!chunk) + goto errout; + err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); + if (err < 0) + goto errout; + + offset += len; + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + + /* The first chunk, the first chunk was likely short + * to allow bundling, so reset to full size. + */ + if (0 == i) + len = max; + } + + /* .. now the leftover bytes. */ + if (over) { + if (!whole) + frag = SCTP_DATA_NOT_FRAG; + else + frag = SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); + + if (!chunk) + goto errout; + + err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + if (err < 0) + goto errout; + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + } + + return msg; + +errout: + list_for_each_safe(pos, temp, &msg->chunks) { + list_del(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_chunk_free(chunk); + } + sctp_datamsg_free(msg); + return NULL; +} + +/* Check whether this message has expired. */ +int sctp_datamsg_expires(struct sctp_chunk *chunk) +{ + struct sctp_datamsg *msg = chunk->msg; + + /* FIXME: When PR-SCTP is supported we can make this + * check more lenient. + */ + if (!msg->can_expire) + return 0; + + if (time_after(jiffies, msg->expires_at)) + return 1; + + return 0; +} + +/* This chunk (and consequently entire message) has failed in its sending. */ +void sctp_datamsg_fail(struct sctp_chunk *chunk, int error) +{ + chunk->msg->send_failed = 1; + chunk->msg->send_error = error; +} diff -Nru a/net/sctp/command.c b/net/sctp/command.c --- a/net/sctp/command.c Mon May 12 20:55:47 2003 +++ b/net/sctp/command.c Mon May 12 20:55:47 2003 @@ -43,9 +43,9 @@ #include /* Create a new sctp_command_sequence. */ -sctp_cmd_seq_t *sctp_new_cmd_seq(int priority) +sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp) { - sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority); + sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp); if (retval) sctp_init_cmd_seq(retval); diff -Nru a/net/sctp/crc32c.c b/net/sctp/crc32c.c --- a/net/sctp/crc32c.c Mon May 12 20:55:48 2003 +++ b/net/sctp/crc32c.c Mon May 12 20:55:48 2003 @@ -170,6 +170,23 @@ return crc32; } +__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 length, __u32 crc32) +{ + __u32 i; + __u32 *_to = (__u32 *)to; + __u32 *_from = (__u32 *)from; + + for (i = 0; i < (length/4); i++) { + _to[i] = _from[i]; + CRC32C(crc32, from[i*4]); + CRC32C(crc32, from[i*4+1]); + CRC32C(crc32, from[i*4+2]); + CRC32C(crc32, from[i*4+3]); + } + + return crc32; +} + __u32 sctp_end_cksum(__u32 crc32) { __u32 result; diff -Nru a/net/sctp/endpointola.c b/net/sctp/endpointola.c --- a/net/sctp/endpointola.c Mon May 12 20:55:44 2003 +++ b/net/sctp/endpointola.c Mon May 12 20:55:44 2003 @@ -54,27 +54,27 @@ #include #include #include /* get_random_bytes() */ +#include #include #include #include #include /* Forward declarations for internal helpers. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep); +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep); -/* Create a sctp_endpoint_t with all that boring stuff initialized. +/* Create a sctp_endpoint with all that boring stuff initialized. * Returns NULL if there isn't enough memory. */ -sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; /* Build a local endpoint. */ - ep = t_new(sctp_endpoint_t, priority); + ep = t_new(struct sctp_endpoint, gfp); if (!ep) goto fail; - if (!sctp_endpoint_init(ep, proto, sk, priority)) + if (!sctp_endpoint_init(ep, sk, gfp)) goto fail_init; ep->base.malloced = 1; SCTP_DBG_OBJCNT_INC(ep); @@ -89,12 +89,11 @@ /* * Initialize the base fields of the endpoint structure. */ -sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, - struct sctp_protocol *proto, - struct sock *sk, int priority) +struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, + struct sock *sk, int gfp) { struct sctp_opt *sp = sctp_sk(sk); - memset(ep, 0, sizeof(sctp_endpoint_t)); + memset(ep, 0, sizeof(struct sctp_endpoint)); /* Initialize the base structure. */ /* What type of endpoint are we? */ @@ -110,8 +109,7 @@ /* Set its top-half handler */ sctp_inq_set_th_handler(&ep->base.inqueue, - (void (*)(void *))sctp_endpoint_bh_rcv, - ep); + (void (*)(void *))sctp_endpoint_bh_rcv, ep); /* Initialize the bind addr area */ sctp_bind_addr_init(&ep->base.bind_addr, 0); @@ -121,21 +119,16 @@ ep->base.sk = sk; sock_hold(ep->base.sk); - /* This pointer is useful to access the default protocol parameter - * values. - */ - ep->proto = proto; - /* Create the lists of associations. */ INIT_LIST_HEAD(&ep->asocs); /* Set up the base timeout information. */ ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = SCTP_DEFAULT_TIMEOUT_T1_COOKIE; - ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = SCTP_DEFAULT_TIMEOUT_T1_INIT; - ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = + ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = sp->rtoinfo.srto_initial; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; @@ -146,11 +139,11 @@ ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] = 5 * sp->rtoinfo.srto_max; - ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = SCTP_DEFAULT_TIMEOUT_SACK; - ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; /* Set up the default send/receive buffer space. */ @@ -175,7 +168,8 @@ } /* Add an association to an endpoint. */ -void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc) +void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, + struct sctp_association *asoc) { struct sock *sk = ep->base.sk; @@ -183,22 +177,21 @@ list_add_tail(&asoc->asocs, &ep->asocs); /* Increment the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) sk->ack_backlog++; } /* Free the endpoint structure. Delay cleanup until * all users have released their reference count on this structure. */ -void sctp_endpoint_free(sctp_endpoint_t *ep) +void sctp_endpoint_free(struct sctp_endpoint *ep) { ep->base.dead = 1; sctp_endpoint_put(ep); } /* Final destructor for endpoint. */ -void sctp_endpoint_destroy(sctp_endpoint_t *ep) +void sctp_endpoint_destroy(struct sctp_endpoint *ep) { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); @@ -207,9 +200,12 @@ /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); - /* Cleanup the inqueue. */ - sctp_inq_free(&ep->base.inqueue); + /* Free up the HMAC transform. */ + if (sctp_sk(ep->base.sk)->hmac) + sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); + /* Cleanup. */ + sctp_inq_free(&ep->base.inqueue); sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ @@ -228,7 +224,7 @@ } /* Hold a reference to an endpoint. */ -void sctp_endpoint_hold(sctp_endpoint_t *ep) +void sctp_endpoint_hold(struct sctp_endpoint *ep) { atomic_inc(&ep->base.refcnt); } @@ -236,17 +232,17 @@ /* Release a reference to an endpoint and clean up if there are * no more references. */ -void sctp_endpoint_put(sctp_endpoint_t *ep) +void sctp_endpoint_put(struct sctp_endpoint *ep) { if (atomic_dec_and_test(&ep->base.refcnt)) sctp_endpoint_destroy(ep); } /* Is this the endpoint we are looking for? */ -sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, - const union sctp_addr *laddr) +struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, + const union sctp_addr *laddr) { - sctp_endpoint_t *retval; + struct sctp_endpoint *retval; sctp_read_lock(&ep->base.addr_lock); if (ep->base.bind_addr.port == laddr->v4.sin_port) { @@ -268,19 +264,19 @@ * We do a linear search of the associations for this endpoint. * We return the matching transport address too. */ -sctp_association_t *__sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *endpoint, +struct sctp_association *__sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { int rport; - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; rport = paddr->v4.sin_port; - list_for_each(pos, &endpoint->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, struct sctp_association, asocs); if (rport == asoc->peer.port) { sctp_read_lock(&asoc->base.addr_lock); *transport = sctp_assoc_lookup_paddr(asoc, paddr); @@ -296,12 +292,12 @@ } /* Lookup association on an endpoint based on a peer address. BH-safe. */ -sctp_association_t *sctp_endpoint_lookup_assoc( - const sctp_endpoint_t *ep, +struct sctp_association *sctp_endpoint_lookup_assoc( + const struct sctp_endpoint *ep, const union sctp_addr *paddr, struct sctp_transport **transport) { - sctp_association_t *asoc; + struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport); @@ -313,12 +309,12 @@ /* Look for any peeled off association from the endpoint that matches the * given peer address. */ -int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep, +int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, const union sctp_addr *paddr) { struct list_head *pos; struct sockaddr_storage_list *addr; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; sctp_read_lock(&ep->base.addr_lock); bp = &ep->base.bind_addr; @@ -337,12 +333,12 @@ /* Do delayed input processing. This is scheduled by sctp_rcv(). * This may be called on BH or task time. */ -static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) +static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; sctp_subtype_t subtype; sctp_state_t state; @@ -355,7 +351,7 @@ inqueue = &ep->base.inqueue; sk = ep->base.sk; - while (NULL != (chunk = sctp_inq_pop(inqueue))) { + while (NULL != (chunk = sctp_inq_pop(inqueue))) { subtype.chunk = chunk->chunk_hdr->type; /* We might have grown an association since last we diff -Nru a/net/sctp/input.c b/net/sctp/input.c --- a/net/sctp/input.c Mon May 12 20:55:44 2003 +++ b/net/sctp/input.c Mon May 12 20:55:44 2003 @@ -63,11 +63,11 @@ /* Forward declarations for internal helpers. */ static int sctp_rcv_ootb(struct sk_buff *); -sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, +struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *laddr, const union sctp_addr *paddr, struct sctp_transport **transportp); -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); +struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); /* Calculate the SCTP checksum of an SCTP packet. */ @@ -102,11 +102,11 @@ int sctp_rcv(struct sk_buff *skb) { struct sock *sk; - sctp_association_t *asoc; - sctp_endpoint_t *ep = NULL; - sctp_endpoint_common_t *rcvr; + struct sctp_association *asoc; + struct sctp_endpoint *ep = NULL; + struct sctp_ep_common *rcvr; struct sctp_transport *transport = NULL; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctphdr *sh; union sctp_addr src; union sctp_addr dest; @@ -128,11 +128,11 @@ if (sctp_rcv_checksum(skb) < 0) goto bad_packet; - skb_pull(skb, sizeof(struct sctphdr)); + skb_pull(skb, sizeof(struct sctphdr)); family = ipver2af(skb->nh.iph->version); af = sctp_get_af_specific(family); - if (unlikely(!af)) + if (unlikely(!af)) goto bad_packet; /* Initialize local addresses for lookups. */ @@ -224,9 +224,7 @@ return ret; bad_packet: -#if 0 /* FIXME */ - SCTP_INC_STATS(SctpInErrs); -#endif /* FIXME*/ + SCTP_INC_STATS(SctpChecksumErrors); discard_it: kfree_skb(skb); @@ -252,13 +250,13 @@ */ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; /* One day chunk will live inside the skb, but for * now this works. */ - chunk = (sctp_chunk_t *) skb; + chunk = (struct sctp_chunk *) skb; inqueue = &chunk->rcvr->inqueue; sctp_inq_push(inqueue, chunk); @@ -286,8 +284,8 @@ /* Common lookup code for icmp/icmpv6 error handler. */ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, struct sctphdr *sctphdr, - struct sctp_endpoint **epp, - struct sctp_association **app, + struct sctp_endpoint **epp, + struct sctp_association **app, struct sctp_transport **tpp) { union sctp_addr saddr; @@ -309,15 +307,15 @@ af->from_skb(&saddr, skb, 1); af->from_skb(&daddr, skb, 0); - /* Look for an association that matches the incoming ICMP error + /* Look for an association that matches the incoming ICMP error * packet. */ asoc = __sctp_lookup_association(&saddr, &daddr, &transport); if (!asoc) { /* If there is no matching association, see if it matches any - * endpoint. This may happen for an ICMP error generated in - * response to an INIT_ACK. - */ + * endpoint. This may happen for an ICMP error generated in + * response to an INIT_ACK. + */ ep = __sctp_rcv_lookup_endpoint(&daddr); if (!ep) { return NULL; @@ -345,25 +343,25 @@ *app = asoc; *tpp = transport; return sk; - + out: sock_put(sk); if (asoc) sctp_association_put(asoc); - if (ep) + if (ep) sctp_endpoint_put(ep); return NULL; } /* Common cleanup code for icmp/icmpv6 error handler. */ -void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, +void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, struct sctp_association *asoc) { sctp_bh_unlock_sock(sk); sock_put(sk); if (asoc) sctp_association_put(asoc); - if (ep) + if (ep) sctp_endpoint_put(ep); } @@ -389,8 +387,8 @@ int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; struct inet_opt *inet; char *saveip, *savesctp; @@ -414,7 +412,7 @@ ICMP_INC_STATS_BH(IcmpInErrors); return; } - /* Warning: The sock lock is held. Remember to call + /* Warning: The sock lock is held. Remember to call * sctp_err_finish! */ @@ -520,10 +518,10 @@ } /* Insert endpoint into the hash table. */ -void __sctp_hash_endpoint(sctp_endpoint_t *ep) +void __sctp_hash_endpoint(struct sctp_endpoint *ep) { - sctp_endpoint_common_t **epp; - sctp_endpoint_common_t *epb; + struct sctp_ep_common **epp; + struct sctp_ep_common *epb; sctp_hashbucket_t *head; epb = &ep->base; @@ -542,7 +540,7 @@ } /* Add an endpoint to the hash. Local BH-safe. */ -void sctp_hash_endpoint(sctp_endpoint_t *ep) +void sctp_hash_endpoint(struct sctp_endpoint *ep) { sctp_local_bh_disable(); __sctp_hash_endpoint(ep); @@ -550,10 +548,10 @@ } /* Remove endpoint from the hash table. */ -void __sctp_unhash_endpoint(sctp_endpoint_t *ep) +void __sctp_unhash_endpoint(struct sctp_endpoint *ep) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; + struct sctp_ep_common *epb; epb = &ep->base; @@ -574,7 +572,7 @@ } /* Remove endpoint from the hash. Local BH-safe. */ -void sctp_unhash_endpoint(sctp_endpoint_t *ep) +void sctp_unhash_endpoint(struct sctp_endpoint *ep) { sctp_local_bh_disable(); __sctp_unhash_endpoint(ep); @@ -582,11 +580,11 @@ } /* Look up an endpoint. */ -sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) +struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; - sctp_endpoint_t *ep; + struct sctp_ep_common *epb; + struct sctp_endpoint *ep; int hash; hash = sctp_ep_hashfn(laddr->v4.sin_port); @@ -609,7 +607,7 @@ } /* Add an association to the hash. Local BH-safe. */ -void sctp_hash_established(sctp_association_t *asoc) +void sctp_hash_established(struct sctp_association *asoc) { sctp_local_bh_disable(); __sctp_hash_established(asoc); @@ -617,10 +615,10 @@ } /* Insert association into the hash table. */ -void __sctp_hash_established(sctp_association_t *asoc) +void __sctp_hash_established(struct sctp_association *asoc) { - sctp_endpoint_common_t **epp; - sctp_endpoint_common_t *epb; + struct sctp_ep_common **epp; + struct sctp_ep_common *epb; sctp_hashbucket_t *head; epb = &asoc->base; @@ -641,7 +639,7 @@ } /* Remove association from the hash table. Local BH-safe. */ -void sctp_unhash_established(sctp_association_t *asoc) +void sctp_unhash_established(struct sctp_association *asoc) { sctp_local_bh_disable(); __sctp_unhash_established(asoc); @@ -649,10 +647,10 @@ } /* Remove association from the hash table. */ -void __sctp_unhash_established(sctp_association_t *asoc) +void __sctp_unhash_established(struct sctp_association *asoc) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; + struct sctp_ep_common *epb; epb = &asoc->base; @@ -674,13 +672,14 @@ } /* Look up an association. */ -sctp_association_t *__sctp_lookup_association(const union sctp_addr *local, - const union sctp_addr *peer, - struct sctp_transport **pt) +struct sctp_association *__sctp_lookup_association( + const union sctp_addr *local, + const union sctp_addr *peer, + struct sctp_transport **pt) { sctp_hashbucket_t *head; - sctp_endpoint_common_t *epb; - sctp_association_t *asoc; + struct sctp_ep_common *epb; + struct sctp_association *asoc; struct sctp_transport *transport; int hash; @@ -710,11 +709,11 @@ } /* Look up an association. BH-safe. */ -sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr, +struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, const union sctp_addr *paddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; sctp_local_bh_disable(); asoc = __sctp_lookup_association(laddr, paddr, transportp); @@ -727,7 +726,7 @@ int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sctp_transport *transport; if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { @@ -757,10 +756,10 @@ * in certain circumstances. * */ -static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, const union sctp_addr *laddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr addr; union sctp_addr *paddr = &addr; struct sctphdr *sh = (struct sctphdr *) skb->h.raw; @@ -815,12 +814,12 @@ } /* Lookup an association for an inbound skb. */ -sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb, +struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, const union sctp_addr *paddr, const union sctp_addr *laddr, struct sctp_transport **transportp) { - sctp_association_t *asoc; + struct sctp_association *asoc; asoc = __sctp_lookup_association(laddr, paddr, transportp); diff -Nru a/net/sctp/inqueue.c b/net/sctp/inqueue.c --- a/net/sctp/inqueue.c Mon May 12 20:55:47 2003 +++ b/net/sctp/inqueue.c Mon May 12 20:55:47 2003 @@ -75,17 +75,17 @@ /* Release the memory associated with an SCTP inqueue. */ void sctp_inq_free(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, * free it as well. */ if (queue->in_progress) - sctp_free_chunk(queue->in_progress); + sctp_chunk_free(queue->in_progress); if (queue->malloced) { /* Dump the master memory segment. */ @@ -96,7 +96,7 @@ /* Put a new packet in an SCTP inqueue. * We assume that packet->sctp_hdr is set and in host byte order. */ -void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet) +void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) { /* Directly call the packet handling routine. */ @@ -114,23 +114,23 @@ * WARNING: If you need to put the chunk on another queue, you need to * make a shallow copy (clone) of it. */ -sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue) +struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_chunkhdr_t *ch = NULL; /* The assumption is that we are safe to process the chunks * at this time. */ - if ((chunk = queue->in_progress) != NULL) { + if ((chunk = queue->in_progress)) { /* There is a packet that we have been working on. * Any post processing work to do before we move on? */ if (chunk->singleton || chunk->end_of_packet || chunk->pdiscard) { - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); chunk = queue->in_progress = NULL; } else { /* Nothing to do. Next chunk in the packet, please. */ @@ -149,7 +149,7 @@ return NULL; chunk = queue->in_progress = - (sctp_chunk_t *) skb_dequeue(&queue->in); + (struct sctp_chunk *) skb_dequeue(&queue->in); /* This is the first chunk in the packet. */ chunk->singleton = 1; diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c --- a/net/sctp/ipv6.c Mon May 12 20:55:47 2003 +++ b/net/sctp/ipv6.c Mon May 12 20:55:47 2003 @@ -96,8 +96,8 @@ struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; struct sctphdr *sh = (struct sctphdr *)(skb->data + offset); struct sock *sk; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; struct ipv6_pinfo *np; char *saveip, *savesctp; @@ -119,7 +119,7 @@ goto out; } - /* Warning: The sock lock is held. Remember to call + /* Warning: The sock lock is held. Remember to call * sctp_err_finish! */ @@ -148,21 +148,19 @@ } /* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, +static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, int ipfragok) { struct sock *sk = skb->sk; struct ipv6_pinfo *np = inet6_sk(sk); struct flowi fl; - struct dst_entry *dst = skb->dst; - struct rt6_info *rt6 = (struct rt6_info *)dst; fl.proto = sk->protocol; /* Fill in the dest address from the route entry passed with the skb * and the source address from the transport. */ - fl.fl6_dst = &rt6->rt6i_dst.addr; + fl.fl6_dst = &transport->ipaddr.v6.sin6_addr; fl.fl6_src = &transport->saddr.v6.sin6_addr; fl.fl6_flowlabel = np->flow_label; @@ -193,7 +191,7 @@ /* Returns the dst cache entry for the given source and destination ip * addresses. */ -struct dst_entry *sctp_v6_get_dst(sctp_association_t *asoc, +struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, union sctp_addr *saddr) { @@ -251,10 +249,10 @@ /* Fills in the source address(saddr) based on the destination address(daddr) * and asoc's bind address list. */ -void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst, +void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, union sctp_addr *saddr) { - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; struct sockaddr_storage_list *laddr; struct list_head *pos; @@ -376,11 +374,17 @@ } /* Initialize sk->rcv_saddr from sctp_addr. */ -static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk) +static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; } +/* Initialize sk->daddr from sctp_addr. */ +static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) +{ + inet6_sk(sk)->daddr = addr->v6.sin6_addr; +} + /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, unsigned short port) @@ -391,7 +395,7 @@ ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); } -/* Compare addresses exactly. +/* Compare addresses exactly. * FIXME: v4-mapped-v6. */ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, @@ -521,6 +525,7 @@ newsk->family = PF_INET6; newsk->protocol = IPPROTO_SCTP; newsk->backlog_rcv = sk->prot->backlog_rcv; + newsk->shutdown = sk->shutdown; newsctp6sk = (struct sctp6_sock *)newsk; newsctp6sk->pinet6 = &newsctp6sk->inet6; @@ -530,10 +535,28 @@ memcpy(newnp, np, sizeof(struct ipv6_pinfo)); - ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr); - + /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() + * and getpeername(). + */ newinet->sport = inet->sport; - newinet->dport = asoc->peer.port; + newnp->saddr = np->saddr; + newnp->rcv_saddr = np->rcv_saddr; + newinet->dport = htons(asoc->peer.port); + newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr; + + /* Init the ipv4 part of the socket since we can have sockets + * using v6 API for ipv4. + */ + newinet->ttl = sysctl_ip_default_ttl; + newinet->mc_loop = 1; + newinet->mc_ttl = 1; + newinet->mc_index = 0; + newinet->mc_list = NULL; + + if (ipv4_config.no_pmtu_disc) + newinet->pmtudisc = IP_PMTUDISC_DONT; + else + newinet->pmtudisc = IP_PMTUDISC_WANT; #ifdef INET_REFCNT_DEBUG atomic_inc(&inet6_sock_nr); @@ -556,6 +579,12 @@ return opt->iif; } +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v6_is_ce(const struct sk_buff *skb) +{ + return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20); +} + /* Initialize a PF_INET6 socket msg_name. */ static void sctp_inet6_msgname(char *msgname, int *addr_len) { @@ -569,7 +598,7 @@ } /* Initialize a PF_INET msgname from a ulpevent. */ -static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, +static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addrlen) { struct sockaddr_in6 *sin6, *sin6from; @@ -596,7 +625,7 @@ sin6from = &event->asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; } } @@ -696,7 +725,7 @@ if (addr->v6.sin6_scope_id) sk->bound_dev_if = addr->v6.sin6_scope_id; if (!sk->bound_dev_if) - return 0; + return 0; } af = opt->pf->af; } @@ -726,11 +755,11 @@ if (addr->v6.sin6_scope_id) sk->bound_dev_if = addr->v6.sin6_scope_id; if (!sk->bound_dev_if) - return 0; + return 0; } af = opt->pf->af; } - + return af != NULL; } @@ -807,7 +836,8 @@ .copy_addrlist = sctp_v6_copy_addrlist, .from_skb = sctp_v6_from_skb, .from_sk = sctp_v6_from_sk, - .to_sk = sctp_v6_to_sk, + .to_sk_saddr = sctp_v6_to_sk_saddr, + .to_sk_daddr = sctp_v6_to_sk_daddr, .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, @@ -816,6 +846,7 @@ .is_any = sctp_v6_is_any, .available = sctp_v6_available, .skb_iif = sctp_v6_skb_iif, + .is_ce = sctp_v6_is_ce, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, diff -Nru a/net/sctp/objcnt.c b/net/sctp/objcnt.c --- a/net/sctp/objcnt.c Mon May 12 20:55:44 2003 +++ b/net/sctp/objcnt.c Mon May 12 20:55:44 2003 @@ -55,6 +55,7 @@ SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(ssnmap); +SCTP_DBG_OBJCNT(datamsg); /* An array to make it easy to pretty print the debug information * to the proc fs. @@ -68,6 +69,7 @@ SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(ssnmap), + SCTP_DBG_OBJCNT_ENTRY(datamsg), }; /* Callback from procfs to read out objcount information. diff -Nru a/net/sctp/output.c b/net/sctp/output.c --- a/net/sctp/output.c Mon May 12 20:55:45 2003 +++ b/net/sctp/output.c Mon May 12 20:55:45 2003 @@ -114,7 +114,7 @@ struct sctp_chunk *chunk; while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); if (packet->malloced) kfree(packet); @@ -166,11 +166,11 @@ /* If sending DATA and haven't aleady bundled a SACK, try to * bundle one in to the packet. */ - if (sctp_chunk_is_data(chunk) && !pkt->has_sack && + if (sctp_chunk_is_data(chunk) && !pkt->has_sack && !pkt->has_cookie_echo) { struct sctp_association *asoc; asoc = pkt->transport->asoc; - + if (asoc->a_rwnd > asoc->rwnd) { struct sctp_chunk *sack; asoc->a_rwnd = asoc->rwnd; @@ -205,7 +205,7 @@ if (retval != SCTP_XMIT_OK) goto finish; - + pmtu = ((packet->transport->asoc) ? (packet->transport->asoc->pmtu) : (packet->transport->pmtu)); @@ -219,21 +219,16 @@ /* Both control chunks and data chunks with TSNs are * non-fragmentable. */ - int fragmentable = sctp_chunk_is_data(chunk) && - (!chunk->has_tsn); if (packet_empty) { - if (fragmentable) { - retval = SCTP_XMIT_MUST_FRAG; - goto finish; - } else { - /* The packet is too big but we can - * not fragment it--we have to just - * transmit and rely on IP - * fragmentation. - */ - packet->ipfragok = 1; - goto append; - } + + /* We no longer do refragmentation at all. + * Just fragment at the IP layer, if we + * actually hit this condition + */ + + packet->ipfragok = 1; + goto append; + } else { /* !packet_empty */ retval = SCTP_XMIT_PMTU_FULL; goto finish; @@ -259,7 +254,7 @@ goto finish; } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) packet->has_cookie_echo = 1; - else if (SCTP_CID_SACK == chunk->chunk_hdr->type) + else if (SCTP_CID_SACK == chunk->chunk_hdr->type) packet->has_sack = 1; /* It is OK to send this chunk. */ @@ -276,8 +271,8 @@ */ int sctp_packet_transmit(struct sctp_packet *packet) { - struct sctp_transport *transport = packet->transport; - struct sctp_association *asoc = transport->asoc; + struct sctp_transport *tp = packet->transport; + struct sctp_association *asoc = tp->asoc; struct sctphdr *sh; __u32 crc32; struct sk_buff *nskb; @@ -311,6 +306,31 @@ */ skb_set_owner_w(nskb, sk); + /* Build the SCTP header. */ + sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); + sh->source = htons(packet->source_port); + sh->dest = htons(packet->destination_port); + + /* From 6.8 Adler-32 Checksum Calculation: + * After the packet is constructed (containing the SCTP common + * header and one or more control or DATA chunks), the + * transmitter shall: + * + * 1) Fill in the proper Verification Tag in the SCTP common + * header and initialize the checksum field to 0's. + */ + sh->vtag = htonl(packet->vtag); + sh->checksum = 0; + + /* 2) Calculate the Adler-32 checksum of the whole packet, + * including the SCTP common header and all the + * chunks. + * + * Note: Adler-32 is no longer applicable, as has been replaced + * by CRC32-C as described in . + */ + crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr)); + /** * 6.10 Bundling * @@ -332,10 +352,12 @@ */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { - chunk->num_times_sent++; - chunk->sent_at = jiffies; + if (sctp_chunk_is_data(chunk)) { - sctp_chunk_assign_tsn(chunk); + + if (!chunk->has_tsn) { + sctp_chunk_assign_ssn(chunk); + sctp_chunk_assign_tsn(chunk); /* 6.3.1 C4) When data is in flight and when allowed * by rule C5, a new RTT measurement MUST be made each @@ -343,19 +365,27 @@ * SHOULD be made no more than once per round-trip * for a given destination transport address. */ - if ((1 == chunk->num_times_sent) && - (!transport->rto_pending)) { - chunk->rtt_in_progress = 1; - transport->rto_pending = 1; - } + + if (!tp->rto_pending) { + chunk->rtt_in_progress = 1; + tp->rto_pending = 1; + } + } else + chunk->resent = 1; + + chunk->sent_at = jiffies; has_data = 1; } - memcpy(skb_put(nskb, chunk->skb->len), - chunk->skb->data, chunk->skb->len); + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; - memset(skb_put(nskb, padding), 0, padding); - SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " - "%s %d\n", + if (padding) + memset(skb_put(chunk->skb, padding), 0, padding); + + crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len), + chunk->skb->data, + chunk->skb->len, crc32); + + SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n", "*** Chunk", chunk, sctp_cname(SCTP_ST_CHUNK( chunk->chunk_hdr->type)), @@ -364,7 +394,6 @@ ntohl(chunk->subh.data_hdr->tsn) : 0, "length", ntohs(chunk->chunk_hdr->length), "chunk->skb->len", chunk->skb->len, - "num_times_sent", chunk->num_times_sent, "rtt_in_progress", chunk->rtt_in_progress); /* @@ -373,33 +402,10 @@ * acknowledged or have failed. */ if (!sctp_chunk_is_data(chunk)) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); } - /* Build the SCTP header. */ - sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr)); - sh->source = htons(packet->source_port); - sh->dest = htons(packet->destination_port); - - /* From 6.8 Adler-32 Checksum Calculation: - * After the packet is constructed (containing the SCTP common - * header and one or more control or DATA chunks), the - * transmitter shall: - * - * 1) Fill in the proper Verification Tag in the SCTP common - * header and initialize the checksum field to 0's. - */ - sh->vtag = htonl(packet->vtag); - sh->checksum = 0; - - /* 2) Calculate the Adler-32 checksum of the whole packet, - * including the SCTP common header and all the - * chunks. - * - * Note: Adler-32 is no longer applicable, as has been replaced - * by CRC32-C as described in . - */ - crc32 = sctp_start_cksum((__u8 *)sh, nskb->len); + /* Perform final transformation on checksum. */ crc32 = sctp_end_cksum(crc32); /* 3) Put the resultant value into the checksum field in the @@ -413,17 +419,13 @@ * data sender to indicate that the end-points of the * transport protocol are ECN-capable." * - * If ECN capable && negotiated && it makes sense for - * this packet to support it (e.g. post ECN negotiation) - * then lets set the ECT bit + * Now setting the ECT bit all the time, as it should not cause + * any problems protocol-wise even if our peer ignores it. * - * FIXME: Need to do something else for IPv6 + * Note: The works for IPv6 layer checks this bit too later + * in transmission. See IP6_ECN_flow_xmit(). */ - if (packet->ecn_capable) { - INET_ECN_xmit(nskb->sk); - } else { - INET_ECN_dontxmit(nskb->sk); - } + INET_ECN_xmit(nskb->sk); /* Set up the IP options. */ /* BUG: not implemented @@ -431,22 +433,21 @@ */ /* Dump that on IP! */ - if (asoc && asoc->peer.last_sent_to != transport) { + if (asoc && asoc->peer.last_sent_to != tp) { /* Considering the multiple CPU scenario, this is a * "correcter" place for last_sent_to. --xguo */ - asoc->peer.last_sent_to = transport; + asoc->peer.last_sent_to = tp; } if (has_data) { struct timer_list *timer; unsigned long timeout; - transport->last_time_used = jiffies; + tp->last_time_used = jiffies; /* Restart the AUTOCLOSE timer when sending data. */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (asoc->autoclose)) { + if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) { timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; @@ -455,21 +456,21 @@ } } - dst = transport->dst; + dst = tp->dst; /* The 'obsolete' field of dst is set to 2 when a dst is freed. */ if (!dst || (dst->obsolete > 1)) { dst_release(dst); - sctp_transport_route(transport, NULL, sctp_sk(sk)); + sctp_transport_route(tp, NULL, sctp_sk(sk)); sctp_assoc_sync_pmtu(asoc); } - nskb->dst = dst_clone(transport->dst); + nskb->dst = dst_clone(tp->dst); if (!nskb->dst) goto no_route; SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", nskb->len); - (*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok); + (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); out: packet->size = SCTP_IP_OVERHEAD; return err; @@ -596,8 +597,8 @@ * if any previously transmitted data on the connection remains * unacknowledged. */ - if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && - q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { + if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && + q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { unsigned len = datasize + q->out_qlen; /* Check whether this chunk and all the rest of pending @@ -623,6 +624,8 @@ rwnd = 0; asoc->peer.rwnd = rwnd; + /* Has been accepted for transmission. */ + chunk->msg->can_expire = 0; finish: return retval; diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c --- a/net/sctp/outqueue.c Mon May 12 20:55:45 2003 +++ b/net/sctp/outqueue.c Mon May 12 20:55:45 2003 @@ -55,13 +55,19 @@ #include /* Declare internal functions here. */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn); +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn, + int count_of_newacks); + /* Add data to the front of the queue. */ static inline void sctp_outq_head_data(struct sctp_outq *q, struct sctp_chunk *ch) @@ -94,13 +100,105 @@ struct sctp_chunk *ch, struct sctp_chunk *pos) { - __skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, + __skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, (struct sk_buff *)pos, pos->list); q->out_qlen += ch->skb->len; } +/* + * SFR-CACC algorithm: + * D) If count_of_newacks is greater than or equal to 2 + * and t was not sent to the current primary then the + * sender MUST NOT increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks >=2 && transport != primary) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * F) If count_of_newacks is less than 2, let d be the + * destination to which t was sent. If cacc_saw_newack + * is 0 for destination d, then the sender MUST NOT + * increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD + * execute steps C, D, F. + * + * C has been implemented in sctp_outq_sack + */ +static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (!primary->cacc.cycling_changeover) { + if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks)) + return 1; + if (sctp_cacc_skip_3_1_f(transport, count_of_newacks)); + return 1; + return 0; + } + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less + * than next_tsn_at_change of the current primary, then + * the sender MUST NOT increment missing report count + * for t. + */ +static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) +{ + if (primary->cacc.cycling_changeover && + TSN_lt(tsn, primary->cacc.next_tsn_at_change)) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3) If the missing report count for TSN t is to be + * incremented according to [RFC2960] and + * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, + * then the sender MUST futher execute steps 3.1 and + * 3.2 to determine if the missing report count for + * TSN t SHOULD NOT be incremented. + * + * 3.3) If 3.1 and 3.2 do not dictate that the missing + * report count for t should not be incremented, then + * the sender SOULD increment missing report count for + * t (according to [RFC2960] and [SCTP_STEWART_2002]). + */ +static inline int sctp_cacc_skip(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks, + __u32 tsn) +{ + if (primary->cacc.changeover_active && + (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) + || sctp_cacc_skip_3_2(primary, tsn))) + return 1; + return 0; +} + /* Generate a new outqueue. */ -struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) +struct sctp_outq *sctp_outq_new(struct sctp_association *asoc) { struct sctp_outq *q; @@ -116,7 +214,7 @@ * You still need to define handlers if you really want to DO * something with this structure... */ -void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) +void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) { q->asoc = asoc; skb_queue_head_init(&q->out); @@ -132,6 +230,7 @@ q->outstanding_bytes = 0; q->empty = 1; + q->cork = 0; q->malloced = 0; q->out_qlen = 0; @@ -143,59 +242,51 @@ { struct sctp_transport *transport; struct list_head *lchunk, *pos, *temp; - sctp_chunk_t *chunk; - struct sctp_ulpevent *ev; + struct sctp_chunk *chunk; /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); - - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_SENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as part of a failed message. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } } /* Throw away chunks that have been gap ACKed. */ list_for_each_safe(lchunk, temp, &q->sacked) { list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any chunks in the retransmit queue. */ list_for_each_safe(lchunk, temp, &q->retransmit) { list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any leftover data chunks. */ while ((chunk = sctp_outq_dequeue_data(q))) { - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_UNSENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as send failure. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control))) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + sctp_chunk_free(chunk); } /* Free the outqueue structure and any related pending chunks. */ @@ -210,7 +301,7 @@ } /* Put a new chunk in an sctp_outq. */ -int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) +int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) { int error = 0; @@ -265,7 +356,8 @@ if (error < 0) return error; - error = sctp_outq_flush(q, 0); + if (!q->cork) + error = sctp_outq_flush(q, 0); return error; } @@ -276,15 +368,16 @@ void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) { struct list_head *rlchunk; - sctp_chunk_t *tchunk, *rchunk; + struct sctp_chunk *tchunk, *rchunk; __u32 ttsn, rtsn; int done = 0; - tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list); ttsn = ntohl(tchunk->subh.data_hdr->tsn); list_for_each(rlchunk, &q->retransmit) { - rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list); + rchunk = list_entry(rlchunk, struct sctp_chunk, + transmitted_list); rtsn = ntohl(rchunk->subh.data_hdr->tsn); if (TSN_lt(ttsn, rtsn)) { list_add(tlchunk, rlchunk->prev); @@ -303,11 +396,12 @@ __u8 fast_retransmit) { struct list_head *lchunk, *ltemp; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Walk through the specified transmitted queue. */ list_for_each_safe(lchunk, ltemp, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* If we are doing retransmission due to a fast retransmit, * only the chunk's that are marked for fast retransmit @@ -416,8 +510,8 @@ struct list_head *lchunk; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; - sctp_chunk_t *chunk; - sctp_association_t *asoc; + struct sctp_chunk *chunk; + struct sctp_association *asoc; int error = 0; asoc = q->asoc; @@ -442,7 +536,8 @@ lchunk = sctp_list_dequeue(lqueue); while (lchunk) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the @@ -504,215 +599,19 @@ return error; } -/* This routine either transmits the fragment or puts it on the output - * queue. 'pos' points to the next chunk in the output queue after the - * chunk that is currently in the process of fragmentation. - */ -void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos, - struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn) +/* Cork the outqueue so queued chunks are really queued. */ +int sctp_outq_uncork(struct sctp_outq *q) { - struct sctp_transport *transport = packet->transport; - struct sk_buff_head *queue = &q->out; - sctp_xmit_t status; - int error; - - frag->subh.data_hdr->tsn = htonl(tsn); - frag->has_tsn = 1; - - /* An inner fragment may be smaller than the earlier one and may get - * in if we call q->build_output. This ensures that all the fragments - * are sent in order. - */ - if (!skb_queue_empty(queue)) { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - return; - } - - /* Add the chunk fragment to the packet. */ - status = (*q->build_output)(packet, frag); - switch (status) { - case SCTP_XMIT_RWND_FULL: - /* RWND is full, so put the chunk in the output queue. */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - break; - - case SCTP_XMIT_OK: - error = (*q->force_output)(packet); - if (error < 0) { - /* Packet could not be transmitted, put the chunk in - * the output queue - */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "failed. adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - } else { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "success. 0x%x sent\n", - ntohl(frag->subh.data_hdr->tsn)); - list_add_tail(&frag->transmitted_list, - &transport->transmitted); - - sctp_transport_reset_timers(transport); - } - break; - - default: - BUG(); - }; -} - -/* This routine calls sctp_xmit_frag() for all the fragments of a message. - * The argument 'frag' point to the first fragment and it holds the list - * of all the other fragments in the 'frag_list' field. - */ -void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt, - sctp_chunk_t *frag) -{ - sctp_association_t *asoc = frag->asoc; - struct list_head *lfrag, *frag_list; - __u32 tsn; - int nfrags = 1; - struct sctp_chunk *pos; - - /* Count the number of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - nfrags++; - } - - /* Get a TSN block of nfrags TSNs. */ - tsn = sctp_association_get_tsn_block(asoc, nfrags); - - pos = (struct sctp_chunk *)skb_peek(&q->out); - /* Transmit the first fragment. */ - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - - /* Transmit the rest of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - } -} - -/* This routine breaks the given chunk into 'max_frag_data_len' size - * fragments. It returns the first fragment with the frag_list field holding - * the remaining fragments. - */ -sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, - size_t max_frag_data_len) -{ - sctp_association_t *asoc = chunk->asoc; - void *data_ptr = chunk->subh.data_hdr; - struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; - __u16 chunk_data_len = sctp_data_size(chunk); - __u16 ssn = ntohs(chunk->subh.data_hdr->ssn); - sctp_chunk_t *first_frag, *frag; - struct list_head *frag_list; - int nfrags; - __u8 old_flags, flags; - - /* nfrags = no. of max size fragments + any smaller last fragment. */ - nfrags = ((chunk_data_len / max_frag_data_len) + - ((chunk_data_len % max_frag_data_len) ? 1 : 0)); - - /* Start of the data in the chunk. */ - data_ptr += sizeof(sctp_datahdr_t); - - /* Are we fragmenting an already fragmented large message? */ - old_flags = chunk->chunk_hdr->flags; - if (old_flags & SCTP_DATA_FIRST_FRAG) - flags = SCTP_DATA_FIRST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the first fragment. */ - first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, flags, ssn); - - if (!first_frag) - goto err; - first_frag->has_ssn = 1; - /* All the fragments are added to the frag_list of the first chunk. */ - frag_list = &first_frag->frag_list; - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - - /* Make the middle fragments. */ - while (chunk_data_len > max_frag_data_len) { - frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, SCTP_DATA_MIDDLE_FRAG, - ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - /* Add the middle fragment to the first fragment's - * frag_list. - */ - list_add_tail(&frag->frag_list, frag_list); - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - } - - if (old_flags & SCTP_DATA_LAST_FRAG) - flags = SCTP_DATA_LAST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the last fragment. */ - frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, - flags, ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - - /* Add the last fragment to the first fragment's frag_list. */ - list_add_tail(&frag->frag_list, frag_list); - - /* Free the original chunk. */ - sctp_free_chunk(chunk); - - return first_frag; - -err: - /* Free any fragments that are created before the failure. */ - if (first_frag) { - struct list_head *flist, *lfrag; - - /* Free all the fragments off the first one. */ - flist = &first_frag->frag_list; - while (NULL != (lfrag = sctp_list_dequeue(flist))) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_free_chunk(frag); - } - - /* Free the first fragment. */ - sctp_free_chunk(first_frag); + int error = 0; + if (q->cork) { + q->cork = 0; + error = sctp_outq_flush(q, 0); } - - return NULL; + return error; } /* - * sctp_outq_flush - Try to flush an outqueue. + * Try to flush an outqueue. * * Description: Send everything in q which we legally can, subject to * congestion limitations. @@ -724,7 +623,7 @@ { struct sctp_packet *packet; struct sctp_packet singleton; - sctp_association_t *asoc = q->asoc; + struct sctp_association *asoc = q->asoc; int ecn_capable = asoc->peer.ecn_capable; __u16 sport = asoc->base.bind_addr.port; __u16 dport = asoc->peer.port; @@ -735,7 +634,7 @@ struct sk_buff_head *queue; struct sctp_transport *transport = NULL; struct sctp_transport *new_transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_xmit_t status; int error = 0; int start_timer = 0; @@ -762,7 +661,7 @@ } queue = &q->control; - while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { /* Pick the right transport to use. */ new_transport = chunk->transport; @@ -902,32 +801,25 @@ */ if (chunk->sinfo.sinfo_stream >= asoc->c.sinit_num_ostreams) { - struct sctp_ulpevent *ev; - - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(asoc, - chunk, SCTP_DATA_UNSENT, - SCTP_ERROR_INV_STRM, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&asoc->ulpq, ev); - /* Free the chunk. */ - sctp_free_chunk(chunk); + /* Mark as s failed send. */ + sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM); + sctp_chunk_free(chunk); continue; } - /* Now do delayed assignment of SSN. This will - * probably change again when we start supporting - * large (> approximately 2^16) size messages. - */ - sctp_chunk_assign_ssn(chunk); + /* Has this chunk expired? */ + if (sctp_datamsg_expires(chunk)) { + sctp_datamsg_fail(chunk, 0); + sctp_chunk_free(chunk); + continue; + } /* If there is a specified transport, use it. * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - if (new_transport == NULL || - !new_transport->active) + if (!new_transport || !new_transport->active) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -979,26 +871,6 @@ goto sctp_flush_out; break; - case SCTP_XMIT_MUST_FRAG: { - sctp_chunk_t *frag; - - frag = sctp_fragment_chunk(chunk, - packet->transport->asoc->frag_point); - if (!frag) { - /* We could not fragment due to out of - * memory condition. Free the original - * chunk and return ENOMEM. - */ - sctp_free_chunk(chunk); - error = -ENOMEM; - return error; - } - - sctp_xmit_fragmented_chunks(q, packet, frag); - goto sctp_flush_out; - break; - } - case SCTP_XMIT_OK: break; @@ -1077,8 +949,8 @@ } /* Update unack_data based on the incoming SACK chunk */ -static void sctp_sack_update_unack_data(sctp_association_t *assoc, - sctp_sackhdr_t *sack) +static void sctp_sack_update_unack_data(struct sctp_association *assoc, + struct sctp_sackhdr *sack) { sctp_sack_variable_t *frags; __u16 unack_data; @@ -1096,12 +968,12 @@ } /* Return the highest new tsn that is acknowledged by the given SACK chunk. */ -static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, - sctp_association_t *asoc) +static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, + struct sctp_association *asoc) { struct list_head *ltransport, *lchunk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 highest_new_tsn, tsn; struct list_head *transport_list = &asoc->peer.transport_addr_list; @@ -1111,7 +983,7 @@ transport = list_entry(ltransport, struct sctp_transport, transports); list_for_each(lchunk, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); tsn = ntohl(chunk->subh.data_hdr->tsn); @@ -1130,26 +1002,64 @@ * Process the SACK against the outqueue. Mostly, this just frees * things off the transmitted queue. */ -int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) +int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) { - sctp_association_t *asoc = q->asoc; + struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; - sctp_chunk_t *tchunk; + struct sctp_chunk *tchunk; struct list_head *lchunk, *transport_list, *pos; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; __u32 highest_tsn, highest_new_tsn; __u32 sack_a_rwnd; int outstanding; + struct sctp_transport *primary = asoc->peer.primary_path; + int count_of_newacks = 0; /* Grab the association's destination address list. */ transport_list = &asoc->peer.transport_addr_list; sack_ctsn = ntohl(sack->cum_tsn_ack); + /* + * SFR-CACC algorithm: + * On receipt of a SACK the sender SHOULD execute the + * following statements. + * + * 1) If the cumulative ack in the SACK passes next tsn_at_change + * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be + * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for + * all destinations. + */ + if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { + primary->cacc.changeover_active = 0; + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cycling_changeover = 0; + } + } + + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE + * is set the receiver of the SACK MUST take the following actions: + * + * A) Initialize the cacc_saw_newack to 0 for all destination + * addresses. + */ + if (sack->num_gap_ack_blocks > 0 && + primary->cacc.changeover_active) { + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cacc_saw_newack = 0; + } + } + /* Get the highest TSN in the sack. */ highest_tsn = sack_ctsn + - ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); + ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); if (TSN_lt(asoc->highest_sacked, highest_tsn)) { highest_new_tsn = highest_tsn; @@ -1162,6 +1072,7 @@ * and free those chunks that we can. */ sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn); + sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0); /* Run through the transmitted queue. * Credit bytes received and free those chunks which we can. @@ -1173,6 +1084,20 @@ transports); sctp_check_transmitted(q, &transport->transmitted, transport, sack, highest_new_tsn); + /* + * SFR-CACC algorithm: + * C) Let count_of_newacks be the number of + * destinations for which cacc_saw_newack is set. + */ + if (transport->cacc.cacc_saw_newack) + count_of_newacks ++; + } + + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + sctp_mark_missing(q, &transport->transmitted, transport, + highest_new_tsn, count_of_newacks); } /* Move the Cumulative TSN Ack Point if appropriate. */ @@ -1191,11 +1116,12 @@ /* Throw away stuff rotting on the sack queue. */ list_for_each(lchunk, &q->sacked) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); if (TSN_lte(tsn, ctsn)) { lchunk = lchunk->prev; - sctp_free_chunk(tchunk); + sctp_chunk_free(tchunk); } } @@ -1244,12 +1170,9 @@ * 2nd Level Abstractions ********************************************************************/ -/* Go through a transport's transmitted list or the assocication's retransmit +/* Go through a transport's transmitted list or the association's retransmit * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. - * The retransmit list will not have an associated transport. In case of a - * transmitted list with a transport, the transport's congestion, rto and fast - * retransmit parameters are also updated and if needed a fast retransmit - * process is started. + * The retransmit list will not have an associated transport. * * I added coherent debug information output. --xguo * @@ -1260,17 +1183,16 @@ static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn_in_sack) { struct list_head *lchunk; - sctp_chunk_t *tchunk; + struct sctp_chunk *tchunk; struct list_head tlist; __u32 tsn; __u32 sack_ctsn; __u32 rtt; __u8 restart_timer = 0; - __u8 do_fast_retransmit = 0; int bytes_acked = 0; /* These state variables are for coherent debug output. --xguo */ @@ -1294,7 +1216,8 @@ /* The while loop will skip empty transmitted queues. */ while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); if (sctp_acked(sack, tsn)) { @@ -1315,9 +1238,9 @@ * first instance of the packet or a later * instance). */ - if ((!tchunk->tsn_gap_acked) && - (1 == tchunk->num_times_sent) && - (tchunk->rtt_in_progress)) { + if (!tchunk->tsn_gap_acked && + !tchunk->resent && + tchunk->rtt_in_progress) { rtt = jiffies - tchunk->sent_at; sctp_transport_update_rto(transport, rtt); @@ -1338,6 +1261,25 @@ if (!tchunk->tsn_gap_acked) { tchunk->tsn_gap_acked = 1; bytes_acked += sctp_data_size(tchunk); + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks + * and the flag CHANGEOVER_ACTIVE is + * set the receiver of the SACK MUST + * take the following action: + * + * B) For each TSN t being acked that + * has not been acked in any SACK so + * far, set cacc_saw_newack to 1 for + * the destination that the TSN was + * sent to. + */ + if (transport && + sack->num_gap_ack_blocks && + q->asoc->peer.primary_path->cacc. + changeover_active) + transport->cacc.cacc_saw_newack + = 1; } list_add_tail(&tchunk->transmitted_list, @@ -1524,8 +1466,8 @@ * receiver's advertised window is zero, and there is * only one data chunk in flight to the receiver. */ - if ((0 == q->asoc->peer.rwnd) && - (!list_empty(&tlist)) && + if (!q->asoc->peer.rwnd && + !list_empty(&tlist) && (sack_ctsn+2 == q->asoc->next_tsn)) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", @@ -1553,12 +1495,26 @@ } } - /* Reconstruct the transmitted list with chunks that are not yet - * acked by the Cumulative TSN Ack. - */ - while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - tsn = ntohl(tchunk->subh.data_hdr->tsn); + list_splice(&tlist, transmitted_queue); +} + +/* Mark chunks as missing and consequently may get retransmitted. */ +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn_in_sack, + int count_of_newacks) +{ + struct sctp_chunk *chunk; + struct list_head *pos; + __u32 tsn; + char do_fast_retransmit = 0; + struct sctp_transport *primary = q->asoc->peer.primary_path; + + list_for_each(pos, transmitted_queue) { + + chunk = list_entry(pos, struct sctp_chunk, transmitted_list); + tsn = ntohl(chunk->subh.data_hdr->tsn); /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all * 'Unacknowledged TSN's', if the TSN number of an @@ -1566,26 +1522,35 @@ * value, increment the 'TSN.Missing.Report' count on that * chunk if it has NOT been fast retransmitted or marked for * fast retransmit already. - * + */ + if (!chunk->fast_retransmit && + !chunk->tsn_gap_acked && + TSN_lt(tsn, highest_new_tsn_in_sack)) { + + /* SFR-CACC may require us to skip marking + * this chunk as missing. + */ + if (!transport || !sctp_cacc_skip(primary, transport, + count_of_newacks, tsn)) { + chunk->tsn_missing_report++; + + SCTP_DEBUG_PRINTK( + "%s: TSN 0x%x missing counter: %d\n", + __FUNCTION__, tsn, + chunk->tsn_missing_report); + } + } + /* * M4) If any DATA chunk is found to have a * 'TSN.Missing.Report' * value larger than or equal to 4, mark that chunk for * retransmission and start the fast retransmit procedure. */ - if ((!tchunk->fast_retransmit) && - (!tchunk->tsn_gap_acked) && - (TSN_lt(tsn, highest_new_tsn_in_sack))) { - tchunk->tsn_missing_report++; - SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", - __FUNCTION__, tsn, - tchunk->tsn_missing_report); - } - if (tchunk->tsn_missing_report >= 4) { - tchunk->fast_retransmit = 1; + + if (chunk->tsn_missing_report >= 4) { + chunk->fast_retransmit = 1; do_fast_retransmit = 1; } - - list_add_tail(lchunk, transmitted_queue); } if (transport) { @@ -1601,7 +1566,7 @@ } /* Is the given TSN acked by this packet? */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn) { int i; sctp_sack_variable_t *frags; diff -Nru a/net/sctp/primitive.c b/net/sctp/primitive.c --- a/net/sctp/primitive.c Mon May 12 20:55:49 2003 +++ b/net/sctp/primitive.c Mon May 12 20:55:49 2003 @@ -55,12 +55,12 @@ #define DECLARE_PRIMITIVE(name) \ /* This is called in the code as sctp_primitive_ ## name. */ \ -int sctp_primitive_ ## name(sctp_association_t *asoc, \ +int sctp_primitive_ ## name(struct sctp_association *asoc, \ void *arg) { \ int error = 0; \ sctp_event_t event_type; sctp_subtype_t subtype; \ sctp_state_t state; \ - sctp_endpoint_t *ep; \ + struct sctp_endpoint *ep; \ \ event_type = SCTP_EVENT_T_PRIMITIVE; \ subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \ diff -Nru a/net/sctp/proc.c b/net/sctp/proc.c --- a/net/sctp/proc.c Mon May 12 20:55:46 2003 +++ b/net/sctp/proc.c Mon May 12 20:55:46 2003 @@ -102,6 +102,7 @@ } static struct file_operations sctp_snmp_seq_fops = { + .owner = THIS_MODULE, .open = sctp_snmp_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c --- a/net/sctp/protocol.c Mon May 12 20:55:47 2003 +++ b/net/sctp/protocol.c Mon May 12 20:55:47 2003 @@ -56,6 +56,7 @@ #include #include #include +#include /* Global data structures. */ struct sctp_protocol sctp_proto; @@ -203,7 +204,7 @@ /* Copy the local addresses which are valid for 'scope' into 'bp'. */ int sctp_copy_local_addr_list(struct sctp_protocol *proto, struct sctp_bind_addr *bp, sctp_scope_t scope, - int priority, int copy_flags) + int gfp, int copy_flags) { struct sockaddr_storage_list *addr; int error = 0; @@ -223,8 +224,8 @@ (((AF_INET6 == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { - error = sctp_add_bind_addr(bp, &addr->a, - priority); + error = sctp_add_bind_addr(bp, &addr->a, + GFP_ATOMIC); if (error) goto end_copy; } @@ -267,11 +268,16 @@ } /* Initialize sk->rcv_saddr from sctp_addr. */ -static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk) +static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; } +/* Initialize sk->daddr from sctp_addr. */ +static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) +{ + inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr; +} /* Initialize a sctp_addr from a dst_entry. */ static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, @@ -388,7 +394,7 @@ { struct rtable *rt; struct flowi fl; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; struct sockaddr_storage_list *laddr; struct list_head *pos; @@ -471,21 +477,33 @@ /* For v4, the source address is cached in the route entry(dst). So no need * to cache it separately and hence this is an empty routine. */ -void sctp_v4_get_saddr(sctp_association_t *asoc, +void sctp_v4_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, union sctp_addr *saddr) { + struct rtable *rt = (struct rtable *)dst; + if (rt) { + saddr->v4.sin_family = AF_INET; + saddr->v4.sin_port = asoc->base.bind_addr.port; + saddr->v4.sin_addr.s_addr = rt->rt_src; + } } /* What interface did this skb arrive on? */ -int sctp_v4_skb_iif(const struct sk_buff *skb) +static int sctp_v4_skb_iif(const struct sk_buff *skb) +{ + return ((struct rtable *)skb->dst)->rt_iif; +} + +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v4_is_ce(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return INET_ECN_is_ce(skb->nh.iph->tos); } -/* Create and initialize a new sk for the socket returned by accept(). */ +/* Create and initialize a new sk for the socket returned by accept(). */ struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sctp_association *asoc) { @@ -506,22 +524,27 @@ newsk->prot = sk->prot; newsk->no_check = sk->no_check; newsk->reuse = sk->reuse; + newsk->shutdown = sk->shutdown; newsk->destruct = inet_sock_destruct; newsk->zapped = 0; newsk->family = PF_INET; newsk->protocol = IPPROTO_SCTP; newsk->backlog_rcv = sk->prot->backlog_rcv; - + newinet = inet_sk(newsk); + + /* Initialize sk's sport, dport, rcv_saddr and daddr for + * getsockname() and getpeername() + */ newinet->sport = inet->sport; newinet->saddr = inet->saddr; - newinet->rcv_saddr = inet->saddr; - newinet->dport = asoc->peer.port; + newinet->rcv_saddr = inet->rcv_saddr; + newinet->dport = htons(asoc->peer.port); newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->pmtudisc = inet->pmtudisc; newinet->id = 0; - + newinet->ttl = sysctl_ip_default_ttl; newinet->mc_loop = 1; newinet->mc_ttl = 1; @@ -568,7 +591,7 @@ if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; - else + else family = PF_INET; err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, @@ -695,7 +718,7 @@ return sctp_v4_available(addr); } -/* Verify that sockaddr looks sendable. Common verification has already +/* Verify that sockaddr looks sendable. Common verification has already * been taken care of. */ static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr) @@ -706,7 +729,7 @@ /* Fill in Supported Address Type information for INIT and INIT-ACK * chunks. Returns number of addresses supported. */ -static int sctp_inet_supported_addrs(const struct sctp_opt *opt, +static int sctp_inet_supported_addrs(const struct sctp_opt *opt, __u16 *types) { types[0] = SCTP_PARAM_IPV4_ADDRESS; @@ -805,7 +828,8 @@ .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, .from_sk = sctp_v4_from_sk, - .to_sk = sctp_v4_to_sk, + .to_sk_saddr = sctp_v4_to_sk_saddr, + .to_sk_daddr = sctp_v4_to_sk_daddr, .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, @@ -814,6 +838,7 @@ .available = sctp_v4_available, .scope = sctp_v4_scope, .skb_iif = sctp_v4_skb_iif, + .is_ce = sctp_v4_is_ce, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c --- a/net/sctp/sm_make_chunk.c Mon May 12 20:55:44 2003 +++ b/net/sctp/sm_make_chunk.c Mon May 12 20:55:44 2003 @@ -59,6 +59,8 @@ #include #include #include +#include +#include #include #include @@ -95,7 +97,7 @@ * provided chunk, as most cause codes will be embedded inside an * abort chunk. */ -void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, +void sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { sctp_errhdr_t err; @@ -156,14 +158,14 @@ * Host Name Address (Note 3) Optional 11 * Supported Address Types (Note 4) Optional 12 */ -sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, - const sctp_bind_addr_t *bp, +struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, + const struct sctp_bind_addr *bp, int gfp, int vparam_len) { sctp_inithdr_t init; union sctp_params addrs; size_t chunksize; - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; int num_types, addrs_len = 0; struct sctp_opt *sp; sctp_supported_addrs_param_t sat; @@ -175,12 +177,9 @@ * can be IPv4 and/or IPv6 in any combination. */ retval = NULL; - addrs.v = NULL; - /* Convert the provided bind address list to raw format */ + /* Convert the provided bind address list to raw format. */ addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp); - if (!addrs.v) - goto nodata; init.init_tag = htonl(asoc->c.my_vtag); init.a_rwnd = htonl(asoc->rwnd); @@ -236,12 +235,12 @@ return retval; } -sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, int gfp, int unkparam_len) { sctp_inithdr_t initack; - sctp_chunk_t *retval; + struct sctp_chunk *retval; union sctp_params addrs; int addrs_len; sctp_cookie_param_t *cookie; @@ -250,9 +249,8 @@ retval = NULL; + /* Note: there may be no addresses to embed. */ addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp); - if (!addrs.v) - goto nomem_rawaddr; initack.init_tag = htonl(asoc->c.my_vtag); initack.a_rwnd = htonl(asoc->rwnd); @@ -294,7 +292,7 @@ sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); /* We need to remove the const qualifier at this point. */ - retval->asoc = (sctp_association_t *) asoc; + retval->asoc = (struct sctp_association *) asoc; /* RFC 2960 6.4 Multi-homed SCTP Endpoints * @@ -311,8 +309,8 @@ nomem_chunk: kfree(cookie); nomem_cookie: - kfree(addrs.v); -nomem_rawaddr: + if (addrs.v) + kfree(addrs.v); return retval; } @@ -350,10 +348,10 @@ * An implementation SHOULD make the cookie as small as possible * to insure interoperability. */ -sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *cookie; int cookie_len; @@ -401,10 +399,10 @@ * * Set to zero on transmit and ignored on receipt. */ -sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); @@ -446,11 +444,11 @@ * * Note: The CWR is considered a Control chunk. */ -sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, const __u32 lowest_tsn, - const sctp_chunk_t *chunk) + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_cwrhdr_t cwr; cwr.lowest_tsn = htonl(lowest_tsn); @@ -481,10 +479,10 @@ } /* Make an ECNE chunk. This is a congestion experienced report. */ -sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, const __u32 lowest_tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_ecnehdr_t ecne; ecne.lowest_tsn = htonl(lowest_tsn); @@ -502,25 +500,27 @@ /* Make a DATA chunk for the given association from the provided * parameters. However, do not populate the data payload. */ -sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; - sctp_datahdr_t dp; + struct sctp_chunk *retval; + struct sctp_datahdr dp; int chunk_len; /* We assign the TSN as LATE as possible, not here when * creating the chunk. */ - dp.tsn= 1000000; /* This marker is a debugging aid. */ + dp.tsn = 0; dp.stream = htons(sinfo->sinfo_stream); dp.ppid = htonl(sinfo->sinfo_ppid); - dp.ssn = htons(ssn); /* Set the flags for an unordered send. */ - if (sinfo->sinfo_flags & MSG_UNORDERED) + if (sinfo->sinfo_flags & MSG_UNORDERED) { flags |= SCTP_DATA_UNORDERED; + dp.ssn = 0; + } else + dp.ssn = htons(ssn); chunk_len = sizeof(dp) + data_len; retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); @@ -537,12 +537,12 @@ /* Make a DATA chunk for the given association. Populate the data * payload. */ -sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); if (retval) @@ -554,11 +554,11 @@ /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body of 'data'. */ -sctp_chunk_t *sctp_make_data(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_data(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data) { - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; retval = sctp_make_data_empty(asoc, sinfo, data_len); if (retval) @@ -571,7 +571,7 @@ * hold 'data_len' octets of data. We use this version when we need * to build the message AFTER allocating memory. */ -sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len) { @@ -584,9 +584,9 @@ * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. */ -sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc) +struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_sackhdr_t sack; sctp_gap_ack_block_t gab; int length; @@ -599,11 +599,13 @@ SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); /* Count the number of Gap Ack Blocks. */ - sctp_tsnmap_iter_init(map, &iter); - for (num_gabs = 0; - sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end); - num_gabs++) { - /* Do nothing. */ + num_gabs = 0; + + if (sctp_tsnmap_has_gap(map)) { + sctp_tsnmap_iter_init(map, &iter); + while (sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) + num_gabs++; } num_dup_tsns = sctp_tsnmap_num_dups(map); @@ -659,11 +661,15 @@ sctp_addto_chunk(retval, sizeof(sack), &sack); /* Put the Gap Ack Blocks into the chunk. */ - sctp_tsnmap_iter_init(map, &iter); - while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) { - gab.start = htons(gab.start); - gab.end = htons(gab.end); - sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab); + if (num_gabs) { + sctp_tsnmap_iter_init(map, &iter); + while(sctp_tsnmap_next_gap_ack(map, &iter, + &gab.start, &gab.end)) { + gab.start = htons(gab.start); + gab.end = htons(gab.end); + sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), + &gab); + } } /* Register the duplicates. */ @@ -675,9 +681,9 @@ } /* Make a SHUTDOWN chunk. */ -sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc) +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_shutdownhdr_t shut; __u32 ctsn; @@ -695,10 +701,10 @@ return retval; } -sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); @@ -717,10 +723,11 @@ return retval; } -sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_complete( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -747,11 +754,11 @@ /* Create an ABORT. Note that we set the T bit if we have no * association. */ -sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const size_t hint) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -775,10 +782,11 @@ } /* Helper to create ABORT with a NO_USER_DATA error. */ -sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, __u32 tsn) +struct sctp_chunk *sctp_make_abort_no_data( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u32 tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u32 payload; retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) @@ -809,17 +817,22 @@ } /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ -sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const struct msghdr *msg) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *payload = NULL, *payoff; - size_t paylen; - struct iovec *iov = msg->msg_iov; - int iovlen = msg->msg_iovlen; + size_t paylen = 0; + struct iovec *iov = NULL; + int iovlen = 0; + + if (msg) { + iov = msg->msg_iov; + iovlen = msg->msg_iovlen; + paylen = get_user_iov_size(iov, iovlen); + } - paylen = get_user_iov_size(iov, iovlen); retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen); if (!retval) goto err_chunk; @@ -832,7 +845,7 @@ payoff = payload; for (; iovlen > 0; --iovlen) { - if (copy_from_user(payoff, iov->iov_base, iov->iov_len)) + if (copy_from_user(payoff, iov->iov_base,iov->iov_len)) goto err_copy; payoff += iov->iov_len; iov++; @@ -849,18 +862,18 @@ err_copy: kfree(payload); err_payload: - sctp_free_chunk(retval); + sctp_chunk_free(retval); retval = NULL; err_chunk: return retval; } /* Make a HEARTBEAT chunk. */ -sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, + struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, paylen); if (!retval) @@ -876,15 +889,16 @@ return retval; } -sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, - 0, paylen); + struct sctp_chunk *retval; + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); if (!retval) goto nodata; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints @@ -906,11 +920,12 @@ /* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ -sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, - size_t size) +struct sctp_chunk *sctp_make_op_error_space( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, + size_t size) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, sizeof(sctp_errhdr_t) + size); @@ -933,13 +948,14 @@ } /* Create an Operation Error chunk. */ -sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { - sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen); + struct sctp_chunk *retval; + retval = sctp_make_op_error_space(asoc, chunk, paylen); if (!retval) goto nodata; @@ -956,26 +972,27 @@ /* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */ -sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc, +struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, + const struct sctp_association *asoc, struct sock *sk) { - sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); + struct sctp_chunk *retval = t_new(struct sctp_chunk, GFP_ATOMIC); if (!retval) goto nodata; - memset(retval, 0, sizeof(sctp_chunk_t)); + memset(retval, 0, sizeof(struct sctp_chunk)); if (!sk) { SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); } retval->skb = skb; - retval->asoc = (sctp_association_t *) asoc; - retval->num_times_sent = 0; + retval->asoc = (struct sctp_association *)asoc; + retval->resent = 0; retval->has_tsn = 0; retval->has_ssn = 0; retval->rtt_in_progress = 0; - retval->sent_at = jiffies; + retval->sent_at = 0; retval->singleton = 1; retval->end_of_packet = 0; retval->ecn_ce_done = 0; @@ -991,17 +1008,24 @@ retval->tsn_gap_acked = 0; retval->fast_retransmit = 0; + /* If this is a fragmented message, track all fragments + * of the message (for SEND_FAILED). + */ + retval->msg = NULL; + /* Polish the bead hole. */ INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); + atomic_set(&retval->refcnt, 1); + nodata: return retval; } /* Set chunk->source and dest based on the IP header in chunk->skb. */ -void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src, +void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src, union sctp_addr *dest) { memcpy(&chunk->source, src, sizeof(union sctp_addr)); @@ -1009,7 +1033,7 @@ } /* Extract the source address from a chunk. */ -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) { /* If we have a known transport, use that. */ if (chunk->transport) { @@ -1023,16 +1047,16 @@ /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ -sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, __u8 type, __u8 flags, int paylen) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_chunkhdr_t *chunk_hdr; struct sk_buff *skb; struct sock *sk; /* No need to allocate LL here, as this is only a chunk. */ - skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), + skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), GFP_ATOMIC); if (!skb) goto nodata; @@ -1046,7 +1070,7 @@ sk = asoc ? asoc->base.sk : NULL; retval = sctp_chunkify(skb, asoc, sk); if (!retval) { - dev_kfree_skb(skb); + kfree_skb(skb); goto nodata; } @@ -1062,12 +1086,10 @@ return NULL; } + /* Release the memory occupied by a chunk. */ -void sctp_free_chunk(sctp_chunk_t *chunk) +static void sctp_chunk_destroy(struct sctp_chunk *chunk) { - /* Make sure that we are not on any list. */ - skb_unlink((struct sk_buff *) chunk); - list_del(&chunk->transmitted_list); /* Free the chunk skb data and the SCTP_chunk stub itself. */ dev_kfree_skb(chunk->skb); @@ -1076,11 +1098,37 @@ SCTP_DBG_OBJCNT_DEC(chunk); } +/* Possibly, free the chunk. */ +void sctp_chunk_free(struct sctp_chunk *chunk) +{ + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *) chunk); + list_del(&chunk->transmitted_list); + + /* Release our reference on the message tracker. */ + if (chunk->msg) + sctp_datamsg_put(chunk->msg); + + sctp_chunk_put(chunk); +} + +/* Grab a reference to the chunk. */ +void sctp_chunk_hold(struct sctp_chunk *ch) +{ + atomic_inc(&ch->refcnt); +} + +/* Release a reference to the chunk. */ +void sctp_chunk_put(struct sctp_chunk *ch) +{ + if (atomic_dec_and_test(&ch->refcnt)) + sctp_chunk_destroy(ch); +} /* Append bytes to the end of a chunk. Will panic if chunk is not big * enough. */ -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) { void *target; void *padding; @@ -1104,8 +1152,8 @@ * chunk is not big enough. * Returns a kernel err value. */ -static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len, - struct iovec *data) +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data) { __u8 *target; int err = 0; @@ -1126,132 +1174,10 @@ return err; } -/* A data chunk can have a maximum payload of (2^16 - 20). Break - * down any such message into smaller chunks. Opportunistically, fragment - * the chunks down to the current MTU constraints. We may get refragmented - * later if the PMTU changes, but it is _much better_ to fragment immediately - * with a reasonable guess than always doing our fragmentation on the - * soft-interrupt. - */ - - -int sctp_datachunks_from_user(sctp_association_t *asoc, - const struct sctp_sndrcvinfo *sinfo, - struct msghdr *msg, int msg_len, - struct sk_buff_head *chunks) -{ - int max, whole, i, offset, over, err; - int len, first_len; - sctp_chunk_t *chunk; - __u8 frag; - - /* What is a reasonable fragmentation point right now? */ - max = asoc->pmtu; - if (max < SCTP_MIN_PMTU) - max = SCTP_MIN_PMTU; - max -= SCTP_IP_OVERHEAD; - - /* Make sure not beyond maximum chunk size. */ - if (max > SCTP_MAX_CHUNK_LEN) - max = SCTP_MAX_CHUNK_LEN; - - /* Subtract out the overhead of a data chunk header. */ - max -= sizeof(struct sctp_data_chunk); - - whole = 0; - first_len = max; - - /* Encourage Cookie-ECHO bundling. */ - if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { - whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); - - /* Account for the DATA to be bundled with the COOKIE-ECHO. */ - if (whole) { - first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; - msg_len -= first_len; - whole = 1; - } - } - - /* How many full sized? How many bytes leftover? */ - whole += msg_len / max; - over = msg_len % max; - offset = 0; - - if (whole && over) - SCTP_INC_STATS_USER(SctpFragUsrMsgs); - - /* Create chunks for all the full sized DATA chunks. */ - for (i=0, len=first_len; i < whole; i++) { - frag = SCTP_DATA_MIDDLE_FRAG; - - if (0 == i) - frag |= SCTP_DATA_FIRST_FRAG; - - if ((i == (whole - 1)) && !over) - frag |= SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); - - if (!chunk) - goto nomem; - err = sctp_user_addto_chunk(chunk, offset, len, msg->msg_iov); - if (err < 0) - goto errout; - - offset += len; - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - - /* The first chunk, the first chunk was likely short - * to allow bundling, so reset to full size. - */ - if (0 == i) - len = max; - } - - /* .. now the leftover bytes. */ - if (over) { - if (!whole) - frag = SCTP_DATA_NOT_FRAG; - else - frag = SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); - - if (!chunk) - goto nomem; - - err = sctp_user_addto_chunk(chunk, offset, over, msg->msg_iov); - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - if (err < 0) - goto errout; - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - } - err = 0; - goto out; - -nomem: - err = -ENOMEM; -errout: - while ((chunk = (sctp_chunk_t *)__skb_dequeue(chunks))) - sctp_free_chunk(chunk); -out: - return err; -} - /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_ssn(sctp_chunk_t *chunk) +void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) { __u16 ssn; __u16 sid; @@ -1278,7 +1204,7 @@ /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +void sctp_chunk_assign_tsn(struct sctp_chunk *chunk) { if (!chunk->has_tsn) { /* This is the last possible instant to @@ -1291,10 +1217,10 @@ } /* Create a CLOSED association to use with an incoming packet. */ -sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep, +struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, struct sctp_chunk *chunk, int gfp) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sk_buff *skb; sctp_scope_t scope; @@ -1303,6 +1229,7 @@ asoc = sctp_association_new(ep, ep->base.sk, scope, gfp); if (!asoc) goto nodata; + asoc->temp = 1; skb = chunk->skb; /* Create an entry for the source address of the packet. */ /* FIXME: Use the af specific helpers. */ @@ -1339,15 +1266,18 @@ /* Build a cookie representing asoc. * This INCLUDES the param header needed to put the cookie in the INIT ACK. */ -sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *init_chunk, +sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *init_chunk, int *cookie_len, const __u8 *raw_addrs, int addrs_len) { sctp_cookie_param_t *retval; sctp_signed_cookie_t *cookie; + struct scatterlist sg; int headersize, bodysize; + unsigned int keylen; + char *key; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; bodysize = sizeof(sctp_cookie_t) @@ -1361,8 +1291,8 @@ - (bodysize % SCTP_COOKIE_MULTIPLE); *cookie_len = headersize + bodysize; - retval = (sctp_cookie_param_t *) - kmalloc(*cookie_len, GFP_ATOMIC); + retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC); + if (!retval) { *cookie_len = 0; goto nodata; @@ -1393,30 +1323,39 @@ /* Copy the raw local address list of the association. */ memcpy((__u8 *)&cookie->c.peer_init[0] + - ntohs(init_chunk->chunk_hdr->length), raw_addrs, - addrs_len); + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); - /* Sign the message. */ - sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE, - (__u8 *) &cookie->c, bodysize, cookie->signature); + if (sctp_sk(ep->base.sk)->hmac) { + /* Sign the message. */ + sg.page = virt_to_page(&cookie->c); + sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE; + sg.length = bodysize; + keylen = SCTP_SECRET_SIZE; + key = (char *)ep->secret_key[ep->current_key]; + + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + &sg, 1, cookie->signature); + } nodata: return retval; } /* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */ -sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, int gfp, - int *error, sctp_chunk_t **err_chk_p) +struct sctp_association *sctp_unpack_cookie( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, int gfp, + int *error, struct sctp_chunk **errp) { - sctp_association_t *retval = NULL; + struct sctp_association *retval = NULL; sctp_signed_cookie_t *cookie; sctp_cookie_t *bear_cookie; - int headersize, bodysize; - int fixed_size; - __u8 digest_buf[SCTP_SIGNATURE_SIZE]; - int secret; + int headersize, bodysize, fixed_size; + __u8 digest[SCTP_SIGNATURE_SIZE]; + struct scatterlist sg; + unsigned int keylen; + char *key; sctp_scope_t scope; struct sk_buff *skb = chunk->skb; @@ -1440,23 +1379,35 @@ cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; + if (!sctp_sk(ep->base.sk)->hmac) + goto no_hmac; + /* Check the signature. */ - secret = ep->current_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, - digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + keylen = SCTP_SECRET_SIZE; + sg.page = virt_to_page(bear_cookie); + sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE; + sg.length = bodysize; + key = (char *)ep->secret_key[ep->current_key]; + + memset(digest, 0x00, sizeof(digest)); + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, + 1, digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Try the previous key. */ - secret = ep->last_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, digest_buf); - if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) { + key = (char *)ep->secret_key[ep->last_key]; + memset(digest, 0x00, sizeof(digest)); + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + &sg, 1, digest); + + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Yikes! Still bad signature! */ *error = -SCTP_IERROR_BAD_SIG; goto fail; } } +no_hmac: /* Check to see if the cookie is stale. If there is already * an association, there is no need to check cookie's expiration * for init collision case of lost COOKIE ACK. @@ -1472,15 +1423,15 @@ * Cookie that has expired. */ len = ntohs(chunk->chunk_hdr->length); - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + *errp = sctp_make_op_error_space(asoc, chunk, len); + if (*errp) { suseconds_t usecs = (skb->stamp.tv_sec - bear_cookie->expiration.tv_sec) * 1000000L + skb->stamp.tv_usec - bear_cookie->expiration.tv_usec; usecs = htonl(usecs); - sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE, + sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, &usecs, sizeof(usecs)); *error = -SCTP_IERROR_STALE_COOKIE; } else @@ -1509,6 +1460,12 @@ goto fail; } + /* Also, add the destination address. */ + if (list_empty(&retval->base.bind_addr.address_list)) { + sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, + GFP_ATOMIC); + } + retval->next_tsn = retval->c.initial_tsn; retval->ctsn_ack_point = retval->next_tsn - 1; @@ -1541,10 +1498,10 @@ /* * Report a missing mandatory parameter. */ -static int sctp_process_missing_param(const sctp_association_t *asoc, +static int sctp_process_missing_param(const struct sctp_association *asoc, sctp_param_t paramtype, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { struct __sctp_missing report; __u16 len; @@ -1554,13 +1511,13 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) { + if (*errp) { report.num_missing = htonl(1); report.type = paramtype; - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, &report, sizeof(report)); } @@ -1569,17 +1526,17 @@ } /* Report an Invalid Mandatory Parameter. */ -static int sctp_process_inv_mandatory(const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) +static int sctp_process_inv_mandatory(const struct sctp_association *asoc, + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { /* Invalid Mandatory Parameter Error has no payload. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, 0); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, 0); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0); + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); /* Stop processing this chunk. */ return 0; @@ -1588,19 +1545,19 @@ /* Do not attempt to handle the HOST_NAME parm. However, do * send back an indicator to the peer. */ -static int sctp_process_hn_param(const sctp_association_t *asoc, +static int sctp_process_hn_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { __u16 len = ntohs(param.p->length); /* Make an ERROR chunk. */ - if (!*err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, len); + if (!*errp) + *errp = sctp_make_op_error_space(asoc, chunk, len); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, param.v, len); /* Stop processing this chunk. */ @@ -1633,10 +1590,10 @@ * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_process_unk_param(const sctp_association_t *asoc, +static int sctp_process_unk_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { int retval = 1; @@ -1649,12 +1606,12 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); @@ -1665,12 +1622,12 @@ /* Make an ERROR chunk, preparing enough room for * returning multiple unknown parameters. */ - if (NULL == *err_chk_p) - *err_chk_p = sctp_make_op_error_space(asoc, chunk, + if (NULL == *errp) + *errp = sctp_make_op_error_space(asoc, chunk, ntohs(chunk->chunk_hdr->length)); - if (*err_chk_p) { - sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + if (*errp) { + sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, param.v, WORD_ROUND(ntohs(param.p->length))); } else { @@ -1695,11 +1652,11 @@ * 0 - discard the chunk * 1 - continue with the chunk */ -static int sctp_verify_param(const sctp_association_t *asoc, +static int sctp_verify_param(const struct sctp_association *asoc, union sctp_params param, sctp_cid_t cid, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chunk) + struct sctp_chunk *chunk, + struct sctp_chunk **err_chunk) { int retval = 1; @@ -1733,11 +1690,11 @@ } /* Verify the INIT packet before we process it. */ -int sctp_verify_init(const sctp_association_t *asoc, +int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t cid, sctp_init_chunk_t *peer_init, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chk_p) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { union sctp_params param; int has_cookie = 0; @@ -1746,7 +1703,7 @@ if ((0 == peer_init->init_hdr.num_outbound_streams) || (0 == peer_init->init_hdr.num_inbound_streams)) { - sctp_process_inv_mandatory(asoc, chunk, err_chk_p); + sctp_process_inv_mandatory(asoc, chunk, errp); return 0; } @@ -1762,9 +1719,8 @@ * the state cookie for an INIT-ACK chunk. */ if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) { - sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE, - chunk, err_chk_p); + chunk, errp); return 0; } @@ -1772,7 +1728,7 @@ sctp_walk_params(param, peer_init, init_hdr.params) { - if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) + if (!sctp_verify_param(asoc, param, cid, chunk, errp)) return 0; } /* for (loop through all parameters) */ @@ -1784,7 +1740,7 @@ * Returns 0 on failure, else success. * FIXME: This is an association method. */ -int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, +int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, const union sctp_addr *peer_addr, sctp_init_chunk_t *peer_init, int gfp) { @@ -1923,7 +1879,7 @@ * work we do. In particular, we should not build transport * structures for the addresses. */ -int sctp_process_param(sctp_association_t *asoc, union sctp_params param, +int sctp_process_param(struct sctp_association *asoc, union sctp_params param, const union sctp_addr *peer_addr, int gfp) { union sctp_addr addr; @@ -2032,7 +1988,7 @@ } /* Select a new verification tag. */ -__u32 sctp_generate_tag(const sctp_endpoint_t *ep) +__u32 sctp_generate_tag(const struct sctp_endpoint *ep) { /* I believe that this random number generator complies with RFC1750. * A tag of 0 is reserved for special cases (e.g. INIT). @@ -2047,7 +2003,7 @@ } /* Select an initial TSN to send during startup. */ -__u32 sctp_generate_tsn(const sctp_endpoint_t *ep) +__u32 sctp_generate_tsn(const struct sctp_endpoint *ep) { __u32 retval; diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- a/net/sctp/sm_sideeffect.c Mon May 12 20:55:47 2003 +++ b/net/sctp/sm_sideeffect.c Mon May 12 20:55:47 2003 @@ -60,7 +60,8 @@ ********************************************************************/ /* A helper function for delayed processing of INET ECN CE bit. */ -static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn) +static void sctp_do_ecn_ce_work(struct sctp_association *asoc, + __u32 lowest_tsn) { /* Save the TSN away for comparison when we receive CWR */ @@ -80,11 +81,11 @@ * This element represents the lowest TSN number in the datagram * that was originally marked with the CE bit. */ -static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, +static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc, __u32 lowest_tsn, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Our previously transmitted packet ran into some congestion * so we should take action by reducing cwnd and ssthresh @@ -123,7 +124,7 @@ } /* Helper function to do delayed processing of ECN CWR chunk. */ -static void sctp_do_ecn_cwr_work(sctp_association_t *asoc, +static void sctp_do_ecn_cwr_work(struct sctp_association *asoc, __u32 lowest_tsn) { /* Turn off ECNE getting auto-prepended to every outgoing @@ -200,7 +201,7 @@ { int error; struct sctp_transport *transport = (struct sctp_transport *) peer; - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; /* Check whether a task is in the sock. */ @@ -238,7 +239,7 @@ /* This is a sa interface for producing timeout events. It works * for timeouts which use the association as their parameter. */ -static void sctp_generate_timeout_event(sctp_association_t *asoc, +static void sctp_generate_timeout_event(struct sctp_association *asoc, sctp_event_timeout_t timeout_type) { int error = 0; @@ -265,8 +266,7 @@ error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(timeout_type), asoc->state, asoc->ep, asoc, - (void *)timeout_type, - GFP_ATOMIC); + (void *)timeout_type, GFP_ATOMIC); if (error) asoc->base.sk->err = -error; @@ -278,25 +278,25 @@ void sctp_generate_t1_cookie_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE); } void sctp_generate_t1_init_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT); } void sctp_generate_t2_shutdown_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); } void sctp_generate_t5_shutdown_guard_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *)data; + struct sctp_association *asoc = (struct sctp_association *)data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD); @@ -304,7 +304,7 @@ void sctp_generate_autoclose_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE); } @@ -315,7 +315,7 @@ { int error = 0; struct sctp_transport *transport = (struct sctp_transport *) data; - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; sctp_bh_lock_sock(asoc->base.sk); if (sock_owned_by_user(asoc->base.sk)) { @@ -335,8 +335,7 @@ error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT, SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT), - asoc->state, - asoc->ep, asoc, + asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC); if (error) @@ -350,7 +349,7 @@ /* Inject a SACK Timeout event into the state machine. */ void sctp_generate_sack_event(unsigned long data) { - sctp_association_t *asoc = (sctp_association_t *) data; + struct sctp_association *asoc = (struct sctp_association *) data; sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK); } @@ -382,7 +381,7 @@ * notification SHOULD be sent to the upper layer. * */ -static void sctp_do_8_2_transport_strike(sctp_association_t *asoc, +static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, struct sctp_transport *transport) { /* The check for association's overall error counter exceeding the @@ -410,7 +409,7 @@ /* Worker routine to handle INIT command failure. */ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, - sctp_association_t *asoc, + struct sctp_association *asoc, unsigned error) { struct sctp_ulpevent *event; @@ -483,7 +482,7 @@ /* Helper function to break out starting up of heartbeat timers. */ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -501,7 +500,7 @@ } static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_transport *t; struct list_head *pos; @@ -517,7 +516,7 @@ /* Helper function to update the heartbeat timer. */ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t) { /* Update the heartbeat timer. */ @@ -527,9 +526,9 @@ /* Helper function to handle the reception of an HEARTBEAT ACK. */ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { sctp_sender_hb_info_t *hbinfo; @@ -560,7 +559,7 @@ * timer. */ static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, struct sctp_transport *t) { sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE); @@ -571,7 +570,7 @@ /* Helper function to process the process SACK command. */ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds, - sctp_association_t *asoc, + struct sctp_association *asoc, sctp_sackhdr_t *sackh) { int err; @@ -595,8 +594,9 @@ /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set * the transport for a shutdown chunk. */ -static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, - sctp_chunk_t *chunk) +static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc, + struct sctp_chunk *chunk) { struct sctp_transport *t; @@ -607,18 +607,30 @@ } /* Helper function to change the state of an association. */ -static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, +static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, sctp_state_t state) { - struct sock *sk = asoc->base.sk; - struct sctp_opt *sp = sctp_sk(sk); asoc->state = state; asoc->state_timestamp = jiffies; - if ((SCTP_STATE_ESTABLISHED == asoc->state) || - (SCTP_STATE_CLOSED == asoc->state)) { + if (sctp_style(sk, TCP)) { + /* Change the sk->state of a TCP-style socket that has + * sucessfully completed a connect() call. + */ + if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) + sk->state = SCTP_SS_ESTABLISHED; + + /* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */ + if (sctp_state(asoc, SHUTDOWN_RECEIVED) && + sctp_sstate(sk, ESTABLISHED)) + sk->shutdown |= RCV_SHUTDOWN; + } + + if (sctp_state(asoc, ESTABLISHED) || + sctp_state(asoc, CLOSED) || + sctp_state(asoc, SHUTDOWN_RECEIVED)) { /* Wake up any processes waiting in the asoc's wait queue in * sctp_wait_for_connect() or sctp_wait_for_sndbuf(). */ @@ -631,16 +643,26 @@ * For a UDP-style socket, the waiters are woken up by the * notifications. */ - if (SCTP_SOCKET_UDP != sp->type) + if (!sctp_style(sk, UDP)) sk->state_change(sk); } +} - /* Change the sk->state of a TCP-style socket that has successfully - * completed a connect() call. - */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state)) - sk->state = SCTP_SS_ESTABLISHED; +/* Helper function to delete an association. */ +static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc) +{ + struct sock *sk = asoc->base.sk; + + /* If it is a non-temporary association belonging to a TCP-style + * listening socket, do not free it so that accept() can pick it + * up later. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp)) + return; + + sctp_unhash_established(asoc); + sctp_association_free(asoc); } /* These three macros allow us to pull the debugging code out of the @@ -673,10 +695,10 @@ */ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, - int priority) + int gfp) { sctp_cmd_seq_t commands; sctp_sm_table_entry_t *state_fn; @@ -701,9 +723,8 @@ DEBUG_POST; error = sctp_side_effects(event_type, subtype, state, - ep, asoc, event_arg, - status, &commands, - priority); + ep, asoc, event_arg, status, + &commands, gfp); DEBUG_POST_SFX; return error; @@ -717,12 +738,12 @@ *****************************************************************/ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype, sctp_state_t state, - sctp_endpoint_t *ep, - sctp_association_t *asoc, + struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority) + int gfp) { int error; @@ -735,7 +756,7 @@ if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state, ep, asoc, event_arg, status, - commands, priority))) + commands, gfp))) goto bail; switch (status) { @@ -803,25 +824,26 @@ /* This is the side-effect interpreter. */ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, sctp_endpoint_t *ep, - sctp_association_t *asoc, void *event_arg, + sctp_state_t state, struct sctp_endpoint *ep, + struct sctp_association *asoc, void *event_arg, sctp_disposition_t status, sctp_cmd_seq_t *commands, - int priority) + int gfp) { int error = 0; int force; sctp_cmd_t *cmd; - sctp_chunk_t *new_obj; - sctp_chunk_t *chunk = NULL; + struct sctp_chunk *new_obj; + struct sctp_chunk *chunk = NULL; struct sctp_packet *packet; struct list_head *pos; struct timer_list *timer; unsigned long timeout; struct sctp_transport *t; sctp_sackhdr_t sackh; + int local_cork = 0; - if(SCTP_EVENT_T_TIMEOUT != event_type) - chunk = (sctp_chunk_t *) event_arg; + if (SCTP_EVENT_T_TIMEOUT != event_type) + chunk = (struct sctp_chunk *) event_arg; /* Note: This whole file is a huge candidate for rework. * For example, each command could either have its own handler, so @@ -838,6 +860,10 @@ case SCTP_CMD_NEW_ASOC: /* Register a new association. */ + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } asoc = cmd->obj.ptr; /* Register with the endpoint. */ sctp_endpoint_add_asoc(ep, asoc); @@ -852,10 +878,13 @@ sctp_outq_teardown(&asoc->outqueue); break; - case SCTP_CMD_DELETE_TCB: + case SCTP_CMD_DELETE_TCB: + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } /* Delete the current association. */ - sctp_unhash_established(asoc); - sctp_association_free(asoc); + sctp_cmd_delete_tcb(commands, asoc); asoc = NULL; break; @@ -903,7 +932,7 @@ * layer which will bail. */ error = sctp_cmd_process_init(commands, asoc, chunk, - cmd->obj.ptr, priority); + cmd->obj.ptr, gfp); break; case SCTP_CMD_GEN_COOKIE_ECHO: @@ -911,7 +940,7 @@ new_obj = sctp_make_cookie_echo(asoc, chunk); if (!new_obj) { if (cmd->obj.ptr) - sctp_free_chunk(cmd->obj.ptr); + sctp_chunk_free(cmd->obj.ptr); goto nomem; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, @@ -957,9 +986,13 @@ break; case SCTP_CMD_REPLY: + /* If an caller has not already corked, do cork. */ + if (!asoc->outqueue.cork) { + sctp_outq_cork(&asoc->outqueue); + local_cork = 1; + } /* Send a chunk to our peer. */ - error = sctp_outq_tail(&asoc->outqueue, - cmd->obj.ptr); + error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr); break; case SCTP_CMD_SEND_PKT: @@ -977,7 +1010,8 @@ case SCTP_CMD_TRANSMIT: /* Kick start transmission. */ - error = sctp_outq_flush(&asoc->outqueue, 0); + error = sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; break; case SCTP_CMD_ECN_CE: @@ -1148,13 +1182,15 @@ break; }; if (error) - return error; + break; } +out: + if (local_cork) + sctp_outq_uncork(&asoc->outqueue); return error; - nomem: error = -ENOMEM; - return error; + goto out; } diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- a/net/sctp/sm_statefuns.c Mon May 12 20:55:44 2003 +++ b/net/sctp/sm_statefuns.c Mon May 12 20:55:44 2003 @@ -95,13 +95,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; /* RFC 2960 6.10 Bundling @@ -179,16 +179,16 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; - sctp_association_t *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; + struct sctp_association *new_asoc; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; struct sock *sk; @@ -212,9 +212,8 @@ * on the TCP-style socket exceed the max backlog, respond with an * ABORT. */ - if ((SCTP_SS_LISTENING != sk->state) || - ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (sk->ack_backlog >= sk->max_ack_backlog))) + if (!sctp_sstate(sk, LISTENING) || + (sctp_style(sk, TCP) && (sk->ack_backlog >= sk->max_ack_backlog))) return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); /* Verify the INIT chunk before processing it. */ @@ -232,7 +231,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -260,8 +259,8 @@ /* The call, sctp_process_init(), can fail on memory allocation. */ if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), - (sctp_init_chunk_t *)chunk->chunk_hdr, + sctp_source(chunk), + (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC)) goto nomem_init; @@ -303,7 +302,7 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); @@ -320,7 +319,7 @@ nomem_ack: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); nomem_init: sctp_association_free(new_asoc); nomem: @@ -355,16 +354,16 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_init_chunk_t *initchunk; __u32 init_tag; - sctp_chunk_t *err_chunk; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_disposition_t ret; @@ -386,7 +385,7 @@ * error and close the association by transmitting an ABORT. */ if (!init_tag) { - sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); + struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0); if (!reply) goto nomem; @@ -416,7 +415,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -514,18 +513,18 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_association_t *new_asoc; + struct sctp_chunk *chunk = arg; + struct sctp_association *new_asoc; sctp_init_chunk_t *peer_init; - sctp_chunk_t *repl; + struct sctp_chunk *repl; struct sctp_ulpevent *ev; int error = 0; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. @@ -623,7 +622,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem_repl: nomem_init: sctp_association_free(new_asoc); @@ -652,8 +651,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { @@ -697,14 +696,14 @@ } /* Generate and sendout a heartbeat packet. */ -sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_transport *transport = (struct sctp_transport *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *reply; sctp_sender_hb_info_t hbinfo; size_t paylen = 0; @@ -730,8 +729,8 @@ } /* Generate a HEARTBEAT packet on the given transport. */ -sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -740,7 +739,7 @@ if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -795,14 +794,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; size_t paylen = 0; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure @@ -862,13 +861,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; union sctp_addr from_addr; struct sctp_transport *link; sctp_sender_hb_info_t *hbinfo; @@ -919,14 +918,14 @@ * condition. */ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, - sctp_chunk_t *init, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { int len; struct sctp_packet *pkt; sctp_addr_param_t *addrparm; sctp_errhdr_t *errhdr; - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; /* Build the error on the stack. We are way to malloc crazy @@ -969,9 +968,9 @@ /* A restart is occurring, check to make sure no new addresses * are being added as we may be under a takeover attack. */ -static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, - const sctp_association_t *asoc, - sctp_chunk_t *init, +static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, + const struct sctp_association *asoc, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { struct sctp_transport *new_addr, *addr; @@ -1022,8 +1021,8 @@ * * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. */ -static void sctp_tietags_populate(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static void sctp_tietags_populate(struct sctp_association *new_asoc, + const struct sctp_association *asoc) { switch (asoc->state) { @@ -1069,8 +1068,8 @@ * Returns value representing action to be taken. These action values * correspond to Action/Description values in RFC 2960, Table 2. */ -static char sctp_tietags_compare(sctp_association_t *new_asoc, - const sctp_association_t *asoc) +static char sctp_tietags_compare(struct sctp_association *new_asoc, + const struct sctp_association *asoc) { /* In this case, the peer may have restarted. */ if ((asoc->c.my_vtag != new_asoc->c.my_vtag) && @@ -1106,16 +1105,16 @@ * chunk handling. */ static sctp_disposition_t sctp_sf_do_unexpected_init( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; - sctp_association_t *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; + struct sctp_association *new_asoc; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; int len; @@ -1191,7 +1190,7 @@ * since there are no peer addresses to check against. * Upon return an ABORT will have been sent if needed. */ - if (asoc->state != SCTP_STATE_COOKIE_WAIT) { + if (!sctp_state(asoc, COOKIE_WAIT)) { if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { retval = SCTP_DISPOSITION_CONSUME; @@ -1238,7 +1237,7 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); @@ -1254,7 +1253,7 @@ cleanup: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); return retval; nomem: retval = SCTP_DISPOSITION_NOMEM; @@ -1303,11 +1302,11 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* Call helper to do the real work for both simulataneous and * duplicate INIT chunk handling. @@ -1356,11 +1355,11 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* Call helper to do the real work for both simulataneous and * duplicate INIT chunk handling. @@ -1375,15 +1374,15 @@ * Section 5.2.4 * A) In this case, the peer may have restarted. */ -static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. @@ -1391,7 +1390,7 @@ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1429,7 +1428,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1442,22 +1441,22 @@ * after responding to the local endpoint's INIT */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. */ peer_init = &chunk->subh.cookie_hdr->c.peer_init[0]; if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, - sctp_source(chunk), peer_init, + sctp_source(chunk), peer_init, GFP_ATOMIC)) goto nomem; @@ -1492,7 +1491,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1506,11 +1505,11 @@ * but a new tag of its own. */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { /* The cookie should be silently discarded. * The endpoint SHOULD NOT change states and should leave @@ -1527,14 +1526,14 @@ * enter the ESTABLISHED state, if it has not already done so. */ /* This case represents an initialization collision. */ -static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - sctp_association_t *new_asoc) +static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { struct sctp_ulpevent *ev = NULL; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Clarification from Implementor's Guide: * D) When both local and remote tags match the endpoint should @@ -1603,18 +1602,18 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_association_t *new_asoc; + struct sctp_chunk *chunk = arg; + struct sctp_association *new_asoc; int error = 0; char action; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* "Decode" the chunk. We have no optional parameters so we * are in good shape. @@ -1701,13 +1700,14 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_pending_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1724,13 +1724,13 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1751,11 +1751,12 @@ * * See sctp_sf_do_9_1_abort(). */ -sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_shutdown_ack_sent_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* The same T2 timer, so we should be able to use * common function with the SHUTDOWN-SENT state. @@ -1777,13 +1778,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_errhdr_t *err; err = (sctp_errhdr_t *)(chunk->skb->data); @@ -1792,7 +1793,7 @@ if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] > asoc->max_init_attempts) { /* INIT_FAILED will issue an ulpevent. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(err->cause)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -1831,26 +1832,26 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; time_t stale; sctp_cookie_preserve_param_t bht; sctp_errhdr_t *err; struct list_head *pos; struct sctp_transport *t; - sctp_chunk_t *reply; - sctp_bind_addr_t *bp; + struct sctp_chunk *reply; + struct sctp_bind_addr *bp; int attempts; attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; if (attempts >= asoc->max_init_attempts) { - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_STALE_COOKIE)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -1879,7 +1880,7 @@ bht.lifespan_increment = htonl(stale); /* Build that new INIT chunk. */ - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht)); if (!reply) goto nomem; @@ -1946,20 +1947,20 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + + (sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)))) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; @@ -1977,13 +1978,13 @@ * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) @@ -1996,7 +1997,7 @@ SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + + (sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)))) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; @@ -2011,8 +2012,8 @@ * * See sctp_sf_do_9_1_abort() above. */ -sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -2056,13 +2057,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_shutdownhdr_t *sdh; sctp_disposition_t disposition; @@ -2111,14 +2112,14 @@ * that belong to this association, it should discard the INIT chunk and * retransmit the SHUTDOWN ACK chunk. */ -sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; reply = sctp_make_shutdown_ack(asoc, chunk); if (NULL == reply) @@ -2165,14 +2166,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_cwrhdr_t *cwr; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2221,14 +2222,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { sctp_ecnehdr_t *ecne; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2279,15 +2280,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; sctp_verb_t deliver; int tmp; @@ -2309,9 +2310,7 @@ skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); tsn = ntohl(data_hdr->tsn); - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); /* ASSERT: Now skb->data is really the user data. */ @@ -2326,11 +2325,15 @@ */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); } } @@ -2371,7 +2374,8 @@ * PMTU. In cases, such as loopback, this might be a rather * large spill over. */ - if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point)) { /* If this is the next TSN, consider reneging to make * room. Note: Playing nice with a confused sender. A @@ -2409,7 +2413,7 @@ * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -2537,15 +2541,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; int tmp; __u32 tsn; @@ -2581,11 +2585,15 @@ * chunk later. */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, + sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); } } @@ -2625,7 +2633,7 @@ * processing the rest of the chunks in the packet. */ sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_DATA)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -2712,13 +2720,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_sackhdr_t *sackh; __u32 ctsn; @@ -2773,15 +2781,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *abort; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -2819,13 +2827,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; while (chunk->chunk_end > chunk->skb->data) { @@ -2856,14 +2864,14 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; struct sctp_ulpevent *ev; /* 10.2 H) SHUTDOWN COMPLETE notification @@ -2924,13 +2932,13 @@ * TCB was found. After sending this ABORT, the receiver of the OOTB * packet shall discard the OOTB packet and take no further action. */ -sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; __u8 *ch_end; @@ -2975,15 +2983,15 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *shut; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *shut; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -3024,8 +3032,8 @@ * chunks. --piggy ] * */ -sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3061,14 +3069,14 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *unk_chunk = arg; - sctp_chunk_t *err_chunk; + struct sctp_chunk *unk_chunk = arg; + struct sctp_chunk *err_chunk; sctp_chunkhdr_t *hdr; SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk); @@ -3140,8 +3148,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3169,8 +3177,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3198,13 +3206,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t lucky(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t lucky(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -3235,13 +3243,13 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t other_stupid(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t other_stupid(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -3271,8 +3279,8 @@ * We simply tag the chunk as a violation. The state machine will log * the violation and continue. */ -sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3309,7 +3317,7 @@ * will be returned on successful establishment of the association. If * SCTP is not able to open an SCTP association with the peer endpoint, * an error is returned. - * [In the kernel implementation, the sctp_association_t needs to + * [In the kernel implementation, the struct sctp_association needs to * be created BEFORE causing this primitive to run.] * * Other association parameters may be returned, including the @@ -3340,13 +3348,13 @@ * * The return value is a disposition. */ -sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* The comment below says that we enter COOKIE-WAIT AFTER * sending the INIT, but that doesn't actually work in our @@ -3371,7 +3379,7 @@ * rerun it through as a sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, - SCTP_ASOC((sctp_association_t *) asoc)); + SCTP_ASOC((struct sctp_association *) asoc)); /* After sending the INIT, "A" starts the T1-init timer and * enters the COOKIE-WAIT state. @@ -3446,13 +3454,13 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); return SCTP_DISPOSITION_CONSUME; @@ -3484,11 +3492,12 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_prm_shutdown( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { int disposition; @@ -3545,11 +3554,12 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_1_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* From 9.1 Abort of an Association * Upon receipt of the ABORT primitive from its upper @@ -3560,7 +3570,7 @@ * if necessary to fill gaps. */ struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; retval = SCTP_DISPOSITION_CONSUME; @@ -3577,7 +3587,7 @@ */ /* Delete the established association. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); SCTP_INC_STATS(SctpAborteds); @@ -3587,8 +3597,8 @@ } /* We tried an illegal operation on an association which is closed. */ -sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3600,8 +3610,8 @@ /* We tried an illegal operation on an association which is shutting * down. */ -sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3626,8 +3636,8 @@ * (timers) */ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3660,8 +3670,8 @@ * (timers) */ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { @@ -3685,14 +3695,15 @@ * Outputs * (timers) */ -sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_wait_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; /* Stop T1-init timer */ @@ -3717,7 +3728,7 @@ */ /* Delete the established association. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_USER_ABORT)); return retval; @@ -3737,11 +3748,12 @@ * Outputs * (timers) */ -sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_cookie_echoed_prm_abort( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { /* There is a single T1 timer, so we should be able to use * common function with the COOKIE-WAIT state. @@ -3762,8 +3774,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3788,8 +3800,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3818,8 +3830,8 @@ * (timers) */ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3853,8 +3865,8 @@ * association on which a heartbeat should be issued. */ sctp_disposition_t sctp_sf_do_prm_requestheartbeat( - const sctp_endpoint_t *ep, - const sctp_association_t *asoc, + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -3868,11 +3880,12 @@ * * The return value is the disposition of the primitive. */ -sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_ignore_primitive( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive); return SCTP_DISPOSITION_DISCARD; @@ -3895,13 +3908,14 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_start_shutdown( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply; + struct sctp_chunk *reply; /* Once all its outstanding data has been acknowledged, the * endpoint shall send a SHUTDOWN chunk to its peer including @@ -3956,14 +3970,15 @@ * * The return value is the disposition. */ -sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_do_9_2_shutdown_ack( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver * shall send a SHUTDOWN ACK ... @@ -4009,8 +4024,8 @@ * * The return value is the disposition of the event. */ -sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4034,8 +4049,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4044,7 +4059,7 @@ if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -4102,8 +4117,8 @@ * allow. However, an SCTP transmitter MUST NOT be more aggressive than * the following algorithms allow. */ -sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4137,14 +4152,14 @@ * (timers, events) * */ -sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; - sctp_bind_addr_t *bp; + struct sctp_chunk *repl; + struct sctp_bind_addr *bp; sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; int timeout; int attempts; @@ -4159,7 +4174,7 @@ (attempts < asoc->max_init_attempts)) { switch (timer) { case SCTP_EVENT_TIMEOUT_T1_INIT: - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); break; @@ -4180,7 +4195,7 @@ SCTP_TO(timer)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); } else { - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; } @@ -4204,18 +4219,18 @@ * the T2-Shutdown timer, giving its peer ample opportunity to transmit * all of its queued DATA chunks that have not yet been sent. */ -sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); if (asoc->overall_error_count >= asoc->overall_error_threshold) { /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); @@ -4264,13 +4279,13 @@ * At the expiration of this timer the sender SHOULD abort the association * by sending an ABORT chunk. */ -sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); @@ -4279,7 +4294,7 @@ goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply)); - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); return SCTP_DISPOSITION_DELETE_TCB; @@ -4292,11 +4307,12 @@ * The work that needs to be done is same as when SHUTDOWN is initiated by * the user. So this routine looks same as sctp_sf_do_9_2_prm_shutdown(). */ -sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) +sctp_disposition_t sctp_sf_autoclose_timer_expire( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) { int disposition; @@ -4337,8 +4353,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4354,8 +4370,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4374,8 +4390,8 @@ * * The return value is the disposition of the chunk. */ -sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, +sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) @@ -4389,7 +4405,7 @@ ********************************************************************/ /* Pull the SACK chunk based on the SACK header. */ -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) +sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *chunk) { sctp_sackhdr_t *sack; __u16 num_blocks; @@ -4411,14 +4427,14 @@ /* Create an ABORT packet to be sent as a response, with the specified * error causes. */ -struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, +struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + struct sctp_chunk *chunk, const void *payload, size_t paylen) { struct sctp_packet *packet; - sctp_chunk_t *abort; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -4447,8 +4463,8 @@ } /* Allocate a packet for responding in the OOTB conditions. */ -struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc, - const sctp_chunk_t *chunk) +struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { struct sctp_packet *packet; struct sctp_transport *transport; @@ -4512,11 +4528,11 @@ } /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ -void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - const sctp_chunk_t *chunk, +void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk) + struct sctp_chunk *err_chunk) { struct sctp_packet *packet; @@ -4530,6 +4546,6 @@ SCTP_PACKET(packet)); SCTP_INC_STATS(SctpOutCtrlChunks); } else - sctp_free_chunk (err_chunk); + sctp_chunk_free (err_chunk); } } diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c Mon May 12 20:55:49 2003 +++ b/net/sctp/socket.c Mon May 12 20:55:49 2003 @@ -55,7 +55,6 @@ #include #include -#include #include #include #include @@ -63,6 +62,7 @@ #include #include #include +#include #include #include @@ -82,13 +82,14 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(sctp_chunk_t *chunk); +static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, int msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); +static void sctp_wait_for_close(struct sock *sk, long timeo); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); @@ -96,31 +97,33 @@ static int sctp_autobind(struct sock *sk); static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); +static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ -sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) +struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) { - sctp_association_t *asoc = NULL; + struct sctp_association *asoc = NULL; - /* If this is not a UDP-style socket, assoc id should be + /* If this is not a UDP-style socket, assoc id should be * ignored. */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { + if (!sctp_style(sk, UDP)) { if (!list_empty(&sctp_sk(sk)->ep->asocs)) asoc = list_entry(sctp_sk(sk)->ep->asocs.next, - sctp_association_t, asocs); + struct sctp_association, asocs); return asoc; } /* First, verify that this is a kernel address. */ if (sctp_is_valid_kaddr((unsigned long) id)) { - sctp_association_t *temp = (sctp_association_t *) id; + struct sctp_association *temp; - /* Verify that this _is_ an sctp_association_t + /* Verify that this _is_ an sctp_association * data structure and if so, that the socket matches. */ + temp = (struct sctp_association *)id; if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && (temp->base.sk == sk)) asoc = temp; @@ -188,13 +191,12 @@ return af; } - /* Bind a local address either to an endpoint or to an association. */ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_endpoint *ep = sp->ep; + struct sctp_bind_addr *bp = &ep->base.bind_addr; struct sctp_af *af; unsigned short snum; int ret = 0; @@ -260,7 +262,7 @@ /* Copy back into socket for getsockname() use. */ if (!ret) { inet_sk(sk)->sport = htons(inet_sk(sk)->num); - af->to_sk(addr, sk); + af->to_sk_saddr(addr, sk); } return ret; @@ -446,16 +448,16 @@ * --daisy */ -#if CONFIG_IP_SCTP_ADDIP +#ifdef CONFIG_IP_SCTP_ADDIP /* Add these addresses to all associations on this endpoint. */ if (retval >= 0) { struct list_head *pos; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; ep = sctp_sk(sk)->ep; list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); sctp_addip_addr_config(asoc, SCTP_PARAM_ADD_IP, @@ -485,9 +487,9 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; int cnt; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_bind_addr *bp = &ep->base.bind_addr; int retval = 0; union sctp_addr saveaddr; @@ -566,16 +568,16 @@ * ADDIP code. * --daisy */ -#if CONFIG_IP_SCTP_ADDIP +#ifdef CONFIG_IP_SCTP_ADDIP /* Remove these addresses from all associations on this endpoint. */ if (retval >= 0) { struct list_head *pos; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; ep = sctp_sk(sk)->ep; list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, addrs, addrcnt); } @@ -637,7 +639,7 @@ /* Alloc space for the address array in kernel memory. */ kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); - if (unlikely(NULL == kaddrs)) + if (unlikely(!kaddrs)) return -ENOMEM; if (copy_from_user(kaddrs, addrs, addrssize)) { @@ -670,14 +672,45 @@ * * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. + * + * 4.1.6 close() - TCP Style Syntax + * + * Applications use close() to gracefully close down an association. + * + * The syntax is: + * + * int close(int sd); + * + * sd - the socket descriptor of the association to be closed. + * + * After an application calls close() on a socket descriptor, no further + * socket operations will succeed on that descriptor. + * + * API 7.1.4 SO_LINGER + * + * An application using the TCP-style socket can use this option to + * perform the SCTP ABORT primitive. The linger option structure is: + * + * struct linger { + * int l_onoff; // option on/off + * int l_linger; // linger time + * }; + * + * To enable the option, set l_onoff to 1. If the l_linger value is set + * to 0, calling close() is the same as the ABORT primitive. If the + * value is set to a negative value, the setsockopt() call will return + * an error. If the value is set to a positive value linger_time, the + * close() can be blocked for at most linger_time ms. If the graceful + * shutdown phase does not finish during this period, close() will + * return but the graceful shutdown phase continues in the system. */ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) { - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct list_head *pos, *temp; - SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); + printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); sctp_lock_sock(sk); sk->shutdown = SHUTDOWN_MASK; @@ -686,14 +719,35 @@ /* Walk all associations on a socket, not on an endpoint. */ list_for_each_safe(pos, temp, &ep->asocs) { - asoc = list_entry(pos, sctp_association_t, asocs); - sctp_primitive_SHUTDOWN(asoc, NULL); + asoc = list_entry(pos, struct sctp_association, asocs); + + if (sctp_style(sk, TCP)) { + /* A closed association can still be in the list if + * it belongs to a TCP-style listening socket that is + * not yet accepted. If so, free it. If not, send an + * ABORT or SHUTDOWN based on the linger options. + */ + if (sctp_state(asoc, CLOSED)) { + sctp_unhash_established(asoc); + sctp_association_free(asoc); + + } else if (test_bit(SOCK_LINGER, &sk->flags) && + !sk->lingertime) + sctp_primitive_ABORT(asoc, NULL); + else + sctp_primitive_SHUTDOWN(asoc, NULL); + } else + sctp_primitive_SHUTDOWN(asoc, NULL); } /* Clean up any skbs sitting on the receive queue. */ skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sctp_sk(sk)->pd_lobby); + /* On a TCP-style socket, block for at most linger_time if set. */ + if (sctp_style(sk, TCP) && timeout) + sctp_wait_for_close(sk, timeout); + /* This will run the backlog queue. */ sctp_release_sock(sk); @@ -717,6 +771,16 @@ SCTP_DBG_OBJCNT_DEC(sock); } +/* Handle EPIPE error. */ +static int sctp_error(struct sock *sk, int flags, int err) +{ + if (err == -EPIPE) + err = sock_error(sk) ? : -EPIPE; + if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); + return err; +} + /* API 3.1.3 sendmsg() - UDP Style Syntax * * An application uses sendmsg() and recvmsg() calls to transmit data to @@ -746,10 +810,10 @@ struct msghdr *msg, int msg_len) { struct sctp_opt *sp; - sctp_endpoint_t *ep; - sctp_association_t *new_asoc=NULL, *asoc=NULL; - struct sctp_transport *transport; - sctp_chunk_t *chunk = NULL; + struct sctp_endpoint *ep; + struct sctp_association *new_asoc=NULL, *asoc=NULL; + struct sctp_transport *transport, *chunk_tp; + struct sctp_chunk *chunk; union sctp_addr to; struct sockaddr *msg_name = NULL; struct sctp_sndrcvinfo default_sinfo = { 0 }; @@ -761,7 +825,9 @@ sctp_scope_t scope; long timeo; __u16 sinfo_flags = 0; - struct sk_buff_head chunks; + struct sctp_datamsg *datamsg; + struct list_head *pos; + int msg_flags = msg->msg_flags; SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", sk, msg, msg_len); @@ -772,6 +838,12 @@ SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); + /* We cannot send a message over a TCP-style listening socket. */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) { + err = -EPIPE; + goto out_nounlock; + } + /* Parse out the SCTP CMSGs. */ err = sctp_msghdr_parse(msg, &cmsgs); @@ -785,7 +857,7 @@ * the address we will send to. * For a peeled-off socket, msg_name is ignored. */ - if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { + if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { int msg_namelen = msg->msg_namelen; err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, @@ -816,6 +888,12 @@ SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); + /* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */ + if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) { + err = -EINVAL; + goto out_nounlock; + } + /* If MSG_EOF is set, no data can be sent. Disallow sending zero * length messages when MSG_EOF|MSG_ABORT is not set. * If MSG_ABORT is set, the message length could be non zero with @@ -827,22 +905,33 @@ goto out_nounlock; } - sctp_lock_sock(sk); + /* If MSG_ADDR_OVER is set, there must be an address + * specified in msg_name. + */ + if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) { + err = -EINVAL; + goto out_nounlock; + } transport = NULL; SCTP_DEBUG_PRINTK("About to look up association.\n"); + sctp_lock_sock(sk); + /* If a msg_name has been specified, assume this is to be used. */ if (msg_name) { /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); if (!asoc) { /* If we could not find a matching association on the - * endpoint, make sure that there is no peeled-off - * association on another socket. + * endpoint, make sure that it is not a TCP-style + * socket that already has an association or there is + * no peeled-off association on another socket. */ - if (sctp_endpoint_is_peeled_off(ep, &to)) { + if ((sctp_style(sk, TCP) && + sctp_sstate(sk, ESTABLISHED)) || + sctp_endpoint_is_peeled_off(ep, &to)) { err = -EADDRNOTAVAIL; goto out_unlock; } @@ -850,14 +939,24 @@ } else { asoc = sctp_id2assoc(sk, associd); if (!asoc) { - err = -EINVAL; + err = -EPIPE; goto out_unlock; } } if (asoc) { - SCTP_DEBUG_PRINTK("Just looked up association: " - "%s. \n", asoc->debug_name); + SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc); + + /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED + * socket that has an association in CLOSED state. This can + * happen when an accepted socket has an association that is + * already CLOSED. + */ + if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) { + err = -EPIPE; + goto out_unlock; + } + if (sinfo_flags & MSG_EOF) { SCTP_DEBUG_PRINTK("Shutting down association: %p\n", asoc); @@ -1004,69 +1103,76 @@ goto out_free; } - /* Break the message into multiple chunks of maximum size. */ - skb_queue_head_init(&chunks); - err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks); - if (err) - goto out_free; + /* If an address is passed with the sendto/sendmsg call, it is used + * to override the primary destination address in the TCP model, or + * when MSG_ADDR_OVER flag is set in the UDP model. + */ + if ((sctp_style(sk, TCP) && msg_name) || + (sinfo_flags & MSG_ADDR_OVER)) { + chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk_tp) { + err = -EINVAL; + goto out_free; + } + } else + chunk_tp = NULL; /* Auto-connect, if we aren't connected already. */ - if (SCTP_STATE_CLOSED == asoc->state) { + if (sctp_state(asoc, CLOSED)) { err = sctp_primitive_ASSOCIATE(asoc, NULL); if (err < 0) goto out_free; SCTP_DEBUG_PRINTK("We associated primitively.\n"); } + /* Break the message into multiple chunks of maximum size. */ + datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); + if (!datamsg) { + err = -ENOMEM; + goto out_free; + } + /* Now send the (possibly) fragmented message. */ - while ((chunk = (sctp_chunk_t *)__skb_dequeue(&chunks))) { + list_for_each(pos, &datamsg->chunks) { + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_datamsg_track(chunk); /* Do accounting for the write space. */ sctp_set_owner_w(chunk); - /* This flag, in the UDP model, requests the SCTP stack to - * override the primary destination address with the - * address found with the sendto/sendmsg call. - */ - if (sinfo_flags & MSG_ADDR_OVER) { - if (!msg->msg_name) { - err = -EINVAL; - goto out_free; - } - chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); - if (!chunk->transport) { - err = -EINVAL; - goto out_free; - } - } + chunk->transport = chunk_tp; - /* Send it to the lower layers. */ - sctp_primitive_SEND(asoc, chunk); + /* Send it to the lower layers. Note: all chunks + * must either fail or succeed. The lower layer + * works that way today. Keep it that way or this + * breaks. + */ + err = sctp_primitive_SEND(asoc, chunk); + /* Did the lower layer accept the chunk? */ + if (err) + sctp_chunk_free(chunk); SCTP_DEBUG_PRINTK("We sent primitively.\n"); } - if (!err) { + sctp_datamsg_free(datamsg); + if (err) + goto out_free; + else err = msg_len; - goto out_unlock; - } + /* If we are already past ASSOCIATE, the lower * layers are responsible for association cleanup. */ - goto out_free_chunk; + goto out_unlock; out_free: if (new_asoc) sctp_association_free(asoc); - -out_free_chunk: - if (chunk) - sctp_free_chunk(chunk); - out_unlock: sctp_release_sock(sk); out_nounlock: - return err; + return sctp_error(sk, msg_flags, err); #if 0 do_sock_err: @@ -1134,8 +1240,9 @@ */ static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *); -SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - int len, int noblock, int flags, int *addr_len) +SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, int len, int noblock, + int flags, int *addr_len) { struct sctp_ulpevent *event = NULL; struct sctp_opt *sp = sctp_sk(sk); @@ -1151,12 +1258,11 @@ sctp_lock_sock(sk); - if ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_ESTABLISHED != sk->state)) { + if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { err = -ENOTCONN; goto out; } - + skb = sctp_skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -1259,7 +1365,7 @@ struct sctp_opt *sp = sctp_sk(sk); /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sp->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (optlen != sizeof(int)) return -EINVAL; @@ -1271,10 +1377,10 @@ } static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char *optval, int optlen) + char *optval, int optlen) { struct sctp_paddrparams params; - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr *addr; struct sctp_transport *trans; int error; @@ -1329,8 +1435,7 @@ return 0; } -static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, - int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) { if (optlen != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -1340,7 +1445,6 @@ } /* - * * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * * Applications that wish to use the sendto() system call may wish to @@ -1358,7 +1462,7 @@ char *optval, int optlen) { struct sctp_sndrcvinfo info; - sctp_association_t *asoc; + struct sctp_association *asoc; if (optlen != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -1413,7 +1517,6 @@ } /* - * * 7.1.5 SCTP_NODELAY * * Turn on/off any Nagle-like algorithm. This means that packets are @@ -1424,15 +1527,61 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, int optlen) { - __u8 val; + int val; - if (optlen < sizeof(__u8)) + if (optlen < sizeof(int)) return -EINVAL; - - if (get_user(val, (__u8 *)optval)) + if (get_user(val, (int *)optval)) return -EFAULT; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; + return 0; +} + +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + /* FIXME: Put real support here. */ + + return -ENOPROTOOPT; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) + return -EINVAL; + sctp_sk(sk)->user_frag = val; return 0; } @@ -1526,20 +1675,22 @@ case SCTP_INITMSG: retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: retval = sctp_setsockopt_peer_prim(sk, optval, optlen); break; - case SCTP_NODELAY: retval = sctp_setsockopt_nodelay(sk, optval, optlen); break; - + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_setsockopt_mappedv4(sk, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_setsockopt_maxseg(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -1572,10 +1723,11 @@ int addr_len) { struct sctp_opt *sp; - sctp_endpoint_t *ep; - sctp_association_t *asoc; + struct sctp_endpoint *ep; + struct sctp_association *asoc; struct sctp_transport *transport; union sctp_addr to; + struct sctp_af *af; sctp_scope_t scope; long timeo; int err = 0; @@ -1590,12 +1742,11 @@ /* connect() cannot be done on a socket that is already in ESTABLISHED * state - UDP-style peeled off socket or a TCP-style socket that - * is already connected. + * is already connected. * It cannot be done even on a TCP-style listening socket. */ - if ((SCTP_SS_ESTABLISHED == sk->state) || - ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_LISTENING == sk->state))) { + if (sctp_sstate(sk, ESTABLISHED) || + (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { err = -EISCONN; goto out_unlock; } @@ -1663,6 +1814,11 @@ goto out_unlock; } + /* Initialize sk's dport and daddr for getpeername() */ + inet_sk(sk)->dport = htons(asoc->peer.port); + af = sctp_get_af_specific(to.sa.sa_family); + af->to_sk_daddr(&to, sk); + timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); @@ -1690,21 +1846,21 @@ struct sctp_opt *sp; struct sctp_endpoint *ep; struct sock *newsk = NULL; - struct sctp_association *assoc; + struct sctp_association *asoc; long timeo; int error = 0; - + sctp_lock_sock(sk); sp = sctp_sk(sk); ep = sp->ep; - if (SCTP_SOCKET_TCP != sp->type) { + if (!sctp_style(sk, TCP)) { error = -EOPNOTSUPP; goto out; } - if (SCTP_SS_LISTENING != sk->state) { + if (!sctp_sstate(sk, LISTENING)) { error = -EINVAL; goto out; } @@ -1715,21 +1871,21 @@ if (error) goto out; - /* We treat the list of associations on the endpoint as the accept - * queue and pick the first association on the list. + /* We treat the list of associations on the endpoint as the accept + * queue and pick the first association on the list. */ - assoc = list_entry(ep->asocs.next, struct sctp_association, asocs); + asoc = list_entry(ep->asocs.next, struct sctp_association, asocs); - newsk = sp->pf->create_accept_sk(sk, assoc); + newsk = sp->pf->create_accept_sk(sk, asoc); if (!newsk) { error = -ENOMEM; goto out; } /* Populate the fields of the newsk from the oldsk and migrate the - * assoc to the newsk. - */ - sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP); + * asoc to the newsk. + */ + sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP); out: sctp_release_sock(sk); @@ -1737,10 +1893,10 @@ return newsk; } -/* FIXME: Write Comments. */ +/* The SCTP ioctl handler. */ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) { - return -EOPNOTSUPP; /* STUB */ + return -ENOIOCTLCMD; } /* This is the function which gets called during socket creation to @@ -1749,7 +1905,7 @@ */ SCTP_STATIC int sctp_init_sock(struct sock *sk) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; struct sctp_protocol *proto; struct sctp_opt *sp; @@ -1800,7 +1956,7 @@ * enable the events needed. By default, UDP-style * sockets enable io and association change notifications. */ - if (SCTP_SOCKET_UDP == sp->type) { + if (sctp_style(sk, UDP)) { sp->subscribe.sctp_data_io_event = 1; sp->subscribe.sctp_association_event = 1; } @@ -1819,12 +1975,19 @@ /* Turn on/off any Nagle-like algorithm. */ sp->nodelay = 1; + /* Enable by default. */ + sp->v4mapped = 1; + /* Auto-close idle associations after the configured * number of seconds. A value of 0 disables this * feature. Configure through the SCTP_AUTOCLOSE socket option, * for UDP-style sockets only. */ sp->autoclose = 0; + + /* User specified fragmentation limit. */ + sp->user_frag = 0; + sp->pf = sctp_get_pf_specific(sk->family); /* Control variables for partial data delivery. */ @@ -1835,11 +1998,12 @@ * change the data structure relationships, this may still * be useful for storing pre-connect address information. */ - ep = sctp_endpoint_new(proto, sk, GFP_KERNEL); - if (NULL == ep) + ep = sctp_endpoint_new(sk, GFP_KERNEL); + if (!ep) return -ENOMEM; sp->ep = ep; + sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); return 0; @@ -1848,7 +2012,7 @@ /* Cleanup any SCTP per socket resources. */ SCTP_STATIC int sctp_destroy_sock(struct sock *sk) { - sctp_endpoint_t *ep; + struct sctp_endpoint *ep; SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk); @@ -1859,11 +2023,38 @@ return 0; } -/* FIXME: Comments needed. */ +/* API 4.1.7 shutdown() - TCP Style Syntax + * int shutdown(int socket, int how); + * + * sd - the socket descriptor of the association to be closed. + * how - Specifies the type of shutdown. The values are + * as follows: + * SHUT_RD + * Disables further receive operations. No SCTP + * protocol action is taken. + * SHUT_WR + * Disables further send operations, and initiates + * the SCTP shutdown sequence. + * SHUT_RDWR + * Disables further send and receive operations + * and initiates the SCTP shutdown sequence. + */ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how) { - /* UDP-style sockets do not support shutdown. */ - /* STUB */ + struct sctp_endpoint *ep; + struct sctp_association *asoc; + + if (!sctp_style(sk, TCP)) + return; + + if (how & SEND_SHUTDOWN) { + ep = sctp_sk(sk)->ep; + if (!list_empty(&ep->asocs)) { + asoc = list_entry(ep->asocs.next, + struct sctp_association, asocs); + sctp_primitive_SHUTDOWN(asoc, NULL); + } + } } /* 7.2.1 Association Status (SCTP_STATUS) @@ -1877,7 +2068,7 @@ int *optlen) { struct sctp_status status; - sctp_association_t *assoc = NULL; + struct sctp_association *asoc = NULL; struct sctp_transport *transport; sctp_assoc_t associd; int retval = 0; @@ -1893,22 +2084,26 @@ } associd = status.sstat_assoc_id; - assoc = sctp_id2assoc(sk, associd); - if (!assoc) { + asoc = sctp_id2assoc(sk, associd); + if (!asoc) { retval = -EINVAL; goto out; } - transport = assoc->peer.primary_path; + transport = asoc->peer.primary_path; - status.sstat_assoc_id = sctp_assoc2id(assoc); - status.sstat_state = assoc->state; - status.sstat_rwnd = assoc->peer.rwnd; - status.sstat_unackdata = assoc->unack_data; - status.sstat_penddata = assoc->peer.tsn_map.pending_data; - status.sstat_instrms = assoc->c.sinit_max_instreams; - status.sstat_outstrms = assoc->c.sinit_num_ostreams; - status.sstat_fragmentation_point = assoc->frag_point; + status.sstat_assoc_id = sctp_assoc2id(asoc); + status.sstat_state = asoc->state; + status.sstat_rwnd = asoc->peer.rwnd; + status.sstat_unackdata = asoc->unack_data; + status.sstat_penddata = asoc->peer.tsn_map.pending_data; + status.sstat_instrms = asoc->c.sinit_max_instreams; + status.sstat_outstrms = asoc->c.sinit_num_ostreams; + /* Just in time frag_point update. */ + if (sctp_sk(sk)->user_frag) + asoc->frag_point + = min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag); + status.sstat_fragmentation_point = asoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(union sctp_addr)); @@ -1965,7 +2160,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) { /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (len != sizeof(int)) return -EINVAL; @@ -1975,33 +2170,29 @@ } /* Helper routine to branch off an association to a new socket. */ -SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock) +SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc, + struct socket **sockp) { - struct sock *oldsk = assoc->base.sk; - struct sock *newsk; - struct socket *tmpsock; + struct sock *sk = asoc->base.sk; + struct socket *sock; int err = 0; /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ - if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type) - return -EOPNOTSUPP; + if (!sctp_style(sk, UDP)) + return -EINVAL; /* Create a new socket. */ - err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP, - &tmpsock); + err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (err < 0) return err; - newsk = tmpsock->sk; - /* Populate the fields of the newsk from the oldsk and migrate the - * assoc to the newsk. - */ - sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); - - *newsock = tmpsock; + * asoc to the newsk. + */ + sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); + *sockp = sock; return err; } @@ -2011,22 +2202,22 @@ sctp_peeloff_arg_t peeloff; struct socket *newsock; int retval = 0; - sctp_association_t *assoc; + struct sctp_association *asoc; if (len != sizeof(sctp_peeloff_arg_t)) return -EINVAL; if (copy_from_user(&peeloff, optval, len)) return -EFAULT; - assoc = sctp_id2assoc(sk, peeloff.associd); - if (NULL == assoc) { + asoc = sctp_id2assoc(sk, peeloff.associd); + if (!asoc) { retval = -EINVAL; goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc); - retval = sctp_do_peeloff(assoc, &newsock); + retval = sctp_do_peeloff(asoc, &newsock); if (retval < 0) goto out; @@ -2037,8 +2228,8 @@ goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n", - __FUNCTION__, sk, assoc, newsock->sk, retval); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", + __FUNCTION__, sk, asoc, newsock->sk, retval); /* Return the fd mapped to the new socket. */ peeloff.sd = retval; @@ -2049,11 +2240,11 @@ return retval; } -static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, +static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_paddrparams params; - sctp_association_t *asoc; + struct sctp_association *asoc; union sctp_addr *addr; struct sctp_transport *trans; @@ -2088,7 +2279,9 @@ if (copy_to_user(optval, ¶ms, len)) return -EFAULT; - *optlen = len; + + if (put_user(len, optlen)) + return -EFAULT; return 0; } @@ -2102,11 +2295,11 @@ return 0; } -static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, +static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, char *optval, int *optlen) { sctp_assoc_t id; - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; @@ -2135,7 +2328,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, char *optval, int *optlen) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; @@ -2176,8 +2369,8 @@ char *optval, int *optlen) { sctp_assoc_t id; - sctp_bind_addr_t *bp; - sctp_association_t *asoc; + struct sctp_bind_addr *bp; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; @@ -2214,8 +2407,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, char *optval, int *optlen) { - sctp_bind_addr_t *bp; - sctp_association_t *asoc; + struct sctp_bind_addr *bp; + struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; @@ -2317,7 +2510,7 @@ int len, char *optval, int *optlen) { struct sctp_sndrcvinfo info; - sctp_association_t *asoc; + struct sctp_association *asoc; if (len != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -2350,15 +2543,15 @@ * integer boolean flag. */ -static int sctp_getsockopt_nodelay(struct sock *sk, int len, - char *optval, int *optlen) +static int sctp_getsockopt_nodelay(struct sock *sk, int len, + char *optval, int *optlen) { - __u8 val; + int val; - if (len < sizeof(__u8)) + if (len < sizeof(int)) return -EINVAL; - len = sizeof(__u8); + len = sizeof(int); val = (sctp_sk(sk)->nodelay == 1); if (put_user(len, optlen)) return -EFAULT; @@ -2366,6 +2559,62 @@ return -EFAULT; return 0; } +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_getsockopt_mappedv4(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + /* FIXME: Until we have support, return disabled. */ + val = 0; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_getsockopt_maxseg(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + + val = sctp_sk(sk)->user_frag; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) @@ -2418,7 +2667,7 @@ retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); break; case SCTP_GET_PEER_ADDRS_NUM: - retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, + retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, optlen); break; case SCTP_GET_LOCAL_ADDRS_NUM: @@ -2443,6 +2692,12 @@ case SCTP_NODELAY: retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); break; + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -2553,7 +2808,7 @@ } - if (pp != NULL && pp->sk != NULL) { + if (pp && pp->sk) { /* We had a port hash table hit - there is an * available port (pp != NULL) and it is being * used by other socket (pp->sk != NULL); that other @@ -2578,7 +2833,7 @@ * in an endpoint. */ for ( ; sk2 != NULL; sk2 = sk2->bind_next) { - sctp_endpoint_t *ep2; + struct sctp_endpoint *ep2; ep2 = sctp_sk(sk2)->ep; if (sk_reuse && sk2->reuse) @@ -2601,18 +2856,17 @@ /* If there was a hash table miss, create a new port. */ ret = 1; - if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL) + if (!pp && !(pp = sctp_bucket_create(head, snum))) goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only * if sk->reuse is too (that is, if the caller requested * SO_REUSEADDR on this socket -sk-). */ - if (pp->sk == NULL) { + if (!pp->sk) pp->fastreuse = sk->reuse ? 1 : 0; - } else if (pp->fastreuse && sk->reuse == 0) { + else if (pp->fastreuse && sk->reuse == 0) pp->fastreuse = 0; - } /* We are set, so fill up all the data in the hash table * entry, tie the socket list information with the rest of the @@ -2669,15 +2923,15 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; /* Only UDP style sockets that are not peeled off are allowed to * listen(). */ - if (SCTP_SOCKET_UDP != sp->type) + if (!sctp_style(sk, UDP)) return -EINVAL; - if (sk->state == SCTP_SS_LISTENING) + if (sctp_sstate(sk, LISTENING)) return 0; /* @@ -2702,15 +2956,15 @@ /* * 4.1.3 listen() - TCP Style Syntax * - * Applications uses listen() to ready the SCTP endpoint for accepting + * Applications uses listen() to ready the SCTP endpoint for accepting * inbound associations. */ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) { struct sctp_opt *sp = sctp_sk(sk); - sctp_endpoint_t *ep = sp->ep; + struct sctp_endpoint *ep = sp->ep; - if (sk->state == SCTP_SS_LISTENING) + if (sctp_sstate(sk, LISTENING)) return 0; /* @@ -2739,15 +2993,25 @@ int sctp_inet_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - int err; + struct crypto_tfm *tfm=NULL; + int err = -EINVAL; + + if (unlikely(backlog < 0)) + goto out; sctp_lock_sock(sk); - err = -EINVAL; if (sock->state != SS_UNCONNECTED) goto out; - if (unlikely(backlog < 0)) - goto out; + + /* Allocate HMAC for generating cookie. */ + if (sctp_hmac_alg) { + tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0); + if (!tfm) { + err = -ENOSYS; + goto out; + } + } switch (sock->type) { case SOCK_SEQPACKET: @@ -2756,14 +3020,21 @@ case SOCK_STREAM: err = sctp_stream_listen(sk, backlog); break; - default: - goto out; + break; }; + if (err) + goto cleanup; + /* Store away the transform reference. */ + sctp_sk(sk)->hmac = tfm; out: sctp_release_sock(sk); return err; +cleanup: + if (tfm) + sctp_crypto_free_tfm(tfm); + goto out; } /* @@ -2782,9 +3053,18 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; + struct sctp_opt *sp = sctp_sk(sk); unsigned int mask; poll_wait(file, sk->sleep, wait); + + /* A TCP-style listening socket becomes readable when the accept queue + * is not empty. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + return (!list_empty(&sp->ep->asocs)) ? + (POLLIN | POLLRDNORM) : 0; + mask = 0; /* Is there any exceptional events? */ @@ -2798,19 +3078,9 @@ (sk->shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - /* - * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and - * peeled off sockets. Additionally, TCP-style needs to consider - * other establishment conditions. - */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { - /* The association is going away. */ - if (SCTP_SS_DISCONNECTING == sk->state) - mask |= POLLHUP; - /* The association is either gone or not ready. */ - if (SCTP_SS_CLOSED == sk->state) - return mask; - } + /* The association is either gone or not ready. */ + if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) + return mask; /* Is it writable? */ if (sctp_writeable(sk)) { @@ -2967,7 +3237,7 @@ /* Strictly check lengths following example in SCM code. */ switch (cmsg->cmsg_type) { case SCTP_INIT: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for @@ -2987,7 +3257,7 @@ break; case SCTP_SNDRCV: - /* SCTP Socket API Extension (draft 1) + /* SCTP Socket API Extension * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for @@ -3002,7 +3272,8 @@ CMSG_LEN(sizeof(struct sctp_sndrcvinfo))) return -EINVAL; - cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + cmsgs->info = + (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); /* Minimally, validate the sinfo_flags. */ if (cmsgs->info->sinfo_flags & @@ -3026,10 +3297,9 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p) { int error; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(sk->sleep, &wait); + prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); /* Socket errors? */ error = sock_error(sk); @@ -3049,8 +3319,7 @@ error = -ENOTCONN; /* Is there a good reason to think that we may receive some data? */ - if ((list_empty(&sctp_sk(sk)->ep->asocs)) && - (sk->state != SCTP_SS_LISTENING)) + if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) goto out; /* Handle signals. */ @@ -3067,16 +3336,14 @@ sctp_lock_sock(sk); ready: - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); return 0; interrupted: error = sock_intr_errno(*timeo_p); out: - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); *err = error; return error; } @@ -3085,13 +3352,14 @@ * Note: This is pretty much the same routine as in core/datagram.c * with a few changes to make lksctp work. */ -static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err) +static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, + int noblock, int *err) { int error; struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + /* Caller is allowed not to check sk->err before calling. */ error = sock_error(sk); if (error) goto no_packet; @@ -3126,6 +3394,9 @@ if (skb) return skb; + if (sk->shutdown & RCV_SHUTDOWN) + break; + /* User doesn't want to wait. */ error = -EAGAIN; if (!timeo) @@ -3140,7 +3411,7 @@ } /* Verify that this is a valid address. */ -static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) { struct sctp_af *af; @@ -3161,7 +3432,7 @@ } /* Get the sndbuf space available at the time on the association. */ -static inline int sctp_wspace(sctp_association_t *asoc) +static inline int sctp_wspace(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; int amt = 0; @@ -3181,9 +3452,9 @@ * destructor in the data chunk skb for the purpose of the sndbuf space * tracking. */ -static inline void sctp_set_owner_w(sctp_chunk_t *chunk) +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) { - sctp_association_t *asoc = chunk->asoc; + struct sctp_association *asoc = chunk->asoc; struct sock *sk = asoc->base.sk; /* The sndbuf space is tracked per association. */ @@ -3191,14 +3462,14 @@ chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); } /* If sndbuf has changed, wake up per association sndbuf waiters. */ -static void __sctp_write_space(sctp_association_t *asoc) +static void __sctp_write_space(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; struct socket *sock = sk->socket; @@ -3228,12 +3499,12 @@ */ static void sctp_wfree(struct sk_buff *skb) { - sctp_association_t *asoc; - sctp_chunk_t *chunk; + struct sctp_association *asoc; + struct sctp_chunk *chunk; struct sock *sk; /* Get the saved chunk pointer. */ - chunk = *((sctp_chunk_t **)(skb->cb)); + chunk = *((struct sctp_chunk **)(skb->cb)); asoc = chunk->asoc; sk = asoc->base.sk; asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); @@ -3244,24 +3515,24 @@ } /* Helper function to wait for space in the sndbuf. */ -static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, +static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, int msg_len) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", asoc, (long)(*timeo_p), msg_len); - /* Wait on the association specific sndbuf space. */ - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); + + /* Wait on the association specific sndbuf space. */ for (;;) { - set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(&asoc->wait, &wait, + TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || @@ -3283,12 +3554,11 @@ } out: - remove_wait_queue(&asoc->wait, &wait); + finish_wait(&asoc->wait, &wait); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); return err; do_error: @@ -3307,12 +3577,12 @@ /* If socket sndbuf has changed, wake up all per association waiters. */ void sctp_write_space(struct sock *sk) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct list_head *pos; /* Wake up the tasks in each wait queue. */ list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { - asoc = list_entry(pos, sctp_association_t, asocs); + asoc = list_entry(pos, struct sctp_association, asocs); __sctp_write_space(asoc); } } @@ -3341,32 +3611,33 @@ /* Wait for an association to go into ESTABLISHED state. If timeout is 0, * returns immediately with EINPROGRESS. */ -static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p) +static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, (long)(*timeo_p)); - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(&asoc->wait, &wait, + TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; + if (sk->shutdown & RCV_SHUTDOWN) + break; if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) goto do_interrupted; - if (asoc->state == SCTP_STATE_ESTABLISHED) + if (sctp_state(asoc, ESTABLISHED)) break; /* Let another process have a go. Since we are going @@ -3380,13 +3651,11 @@ } out: - remove_wait_queue(&asoc->wait, &wait); + finish_wait(&asoc->wait, &wait); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); - return err; do_error: @@ -3406,14 +3675,14 @@ { struct sctp_endpoint *ep; int err = 0; - DECLARE_WAITQUEUE(wait, current); + DEFINE_WAIT(wait); ep = sctp_sk(sk)->ep; - add_wait_queue_exclusive(sk->sleep, &wait); for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + if (list_empty(&ep->asocs)) { sctp_release_sock(sk); timeo = schedule_timeout(timeo); @@ -3421,7 +3690,7 @@ } err = -EINVAL; - if (sk->state != SCTP_SS_LISTENING) + if (!sctp_sstate(sk, LISTENING)) break; err = 0; @@ -3437,21 +3706,37 @@ break; } - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + finish_wait(sk->sleep, &wait); return err; } -/* Populate the fields of the newsk from the oldsk and migrate the assoc +void sctp_wait_for_close(struct sock *sk, long timeout) +{ + DEFINE_WAIT(wait); + + do { + prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + if (list_empty(&sctp_sk(sk)->ep->asocs)) + break; + sctp_release_sock(sk); + timeout = schedule_timeout(timeout); + sctp_lock_sock(sk); + } while (!signal_pending(current) && timeout); + + finish_wait(sk->sleep, &wait); +} + +/* Populate the fields of the newsk from the oldsk and migrate the assoc * and its messages to the newsk. - */ -void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, - struct sctp_association *assoc, sctp_socket_type_t type) + */ +static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, + struct sctp_association *assoc, + sctp_socket_type_t type) { struct sctp_opt *oldsp = sctp_sk(oldsk); struct sctp_opt *newsp = sctp_sk(newsk); - sctp_endpoint_t *newep = newsp->ep; + struct sctp_endpoint *newep = newsp->ep; struct sk_buff *skb, *tmp; struct sctp_ulpevent *event; @@ -3466,6 +3751,7 @@ * copy. */ newsp->ep = newep; + newsp->hmac = NULL; /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. @@ -3524,9 +3810,15 @@ /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); + /* If the association on the newsk is already closed before accept() + * is called, set RCV_SHUTDOWN flag. + */ + if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) + newsk->shutdown |= RCV_SHUTDOWN; + newsk->state = SCTP_SS_ESTABLISHED; } - + /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", diff -Nru a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c --- a/net/sctp/ssnmap.c Mon May 12 20:55:48 2003 +++ b/net/sctp/ssnmap.c Mon May 12 20:55:48 2003 @@ -53,11 +53,11 @@ /* Create a new sctp_ssnmap. * Allocate room to store at least 'len' contiguous TSNs. */ -struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority) +struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp) { struct sctp_ssnmap *retval; - retval = kmalloc(sctp_ssnmap_size(in, out), priority); + retval = kmalloc(sctp_ssnmap_size(in, out), gfp); if (!retval) goto fail; diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c --- a/net/sctp/transport.c Mon May 12 20:55:45 2003 +++ b/net/sctp/transport.c Mon May 12 20:55:45 2003 @@ -54,16 +54,15 @@ /* 1st Level Abstractions. */ /* Allocate and initialize a new transport. */ -struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, - int priority) +struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp) { struct sctp_transport *transport; - transport = t_new(struct sctp_transport, priority); + transport = t_new(struct sctp_transport, gfp); if (!transport) goto fail; - if (!sctp_transport_init(transport, addr, priority)) + if (!sctp_transport_init(transport, addr, gfp)) goto fail_init; transport->malloced = 1; @@ -81,7 +80,7 @@ /* Initialize a new transport from provided memory. */ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, const union sctp_addr *addr, - int priority) + int gfp) { struct sctp_protocol *proto = sctp_get_protocol(); @@ -117,8 +116,6 @@ peer->error_threshold = 0; peer->error_count = 0; - peer->debug_name = "unnamedtransport"; - INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); @@ -138,6 +135,13 @@ peer->dead = 0; peer->malloced = 0; + + /* Initialize the state information for SFR-CACC */ + peer->cacc.changeover_active = 0; + peer->cacc.cycling_changeover = 0; + peer->cacc.next_tsn_at_change = 0; + peer->cacc.cacc_saw_newack = 0; + return peer; } @@ -199,13 +203,13 @@ * Register the reference count in the association. */ void sctp_transport_set_owner(struct sctp_transport *transport, - sctp_association_t *asoc) + struct sctp_association *asoc) { transport->asoc = asoc; sctp_association_hold(asoc); } -/* Initialize the pmtu of a transport. */ +/* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport) { struct dst_entry *dst; @@ -225,7 +229,7 @@ void sctp_transport_route(struct sctp_transport *transport, union sctp_addr *saddr, struct sctp_opt *opt) { - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; struct dst_entry *dst; @@ -238,9 +242,15 @@ af->get_saddr(asoc, dst, daddr, &transport->saddr); transport->dst = dst; - if (dst) + if (dst) { transport->pmtu = dst_pmtu(dst); - else + + /* Initialize sk->rcv_saddr, if the transport is the + * association's active path for getsockname(). + */ + if (asoc && (transport == asoc->peer.active_path)) + af->to_sk_saddr(&transport->saddr, asoc->base.sk); + } else transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; } @@ -359,7 +369,7 @@ * two conditions are met can the cwnd be increased otherwise * the cwnd MUST not be increased. If these conditions are met * then cwnd MUST be increased by at most the lesser of - * 1) the total size of the previously outstanding DATA + * 1) the total size of the previously outstanding DATA * chunk(s) acknowledged, and 2) the destination's path MTU. */ if (bytes_acked > pmtu) @@ -373,17 +383,17 @@ transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } else { - /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, - * upon each SACK arrival that advances the Cumulative TSN Ack - * Point, increase partial_bytes_acked by the total number of - * bytes of all new chunks acknowledged in that SACK including - * chunks acknowledged by the new Cumulative TSN Ack and by + /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, + * upon each SACK arrival that advances the Cumulative TSN Ack + * Point, increase partial_bytes_acked by the total number of + * bytes of all new chunks acknowledged in that SACK including + * chunks acknowledged by the new Cumulative TSN Ack and by * Gap Ack Blocks. * - * When partial_bytes_acked is equal to or greater than cwnd - * and before the arrival of the SACK the sender had cwnd or - * more bytes of data outstanding (i.e., before arrival of the - * SACK, flightsize was greater than or equal to cwnd), + * When partial_bytes_acked is equal to or greater than cwnd + * and before the arrival of the SACK the sender had cwnd or + * more bytes of data outstanding (i.e., before arrival of the + * SACK, flightsize was greater than or equal to cwnd), * increase cwnd by MTU, and reset partial_bytes_acked to * (partial_bytes_acked - cwnd). */ diff -Nru a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c --- a/net/sctp/tsnmap.c Mon May 12 20:55:49 2003 +++ b/net/sctp/tsnmap.c Mon May 12 20:55:49 2003 @@ -55,13 +55,12 @@ /* Create a new sctp_tsnmap. * Allocate room to store at least 'len' contiguous TSNs. */ -struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority) +struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp) { struct sctp_tsnmap *retval; retval = kmalloc(sizeof(struct sctp_tsnmap) + - sctp_tsnmap_storage_size(len), - priority); + sctp_tsnmap_storage_size(len), gfp); if (!retval) goto fail; diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c --- a/net/sctp/ulpevent.c Mon May 12 20:55:45 2003 +++ b/net/sctp/ulpevent.c Mon May 12 20:55:45 2003 @@ -52,12 +52,12 @@ const struct sctp_association *asoc); /* Create a new sctp_ulpevent. */ -struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority) +struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) { struct sctp_ulpevent *event; struct sk_buff *skb; - skb = alloc_skb(size, priority); + skb = alloc_skb(size, gfp); if (!skb) goto fail; @@ -106,16 +106,16 @@ * zero'd out. */ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( - const sctp_association_t *asoc, + const struct sctp_association *asoc, __u16 flags, __u16 state, __u16 error, __u16 outbound, - __u16 inbound, int priority) + __u16 inbound, int gfp) { struct sctp_ulpevent *event; struct sctp_assoc_change *sac; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; skb = sctp_event2skb(event); @@ -207,15 +207,16 @@ * an interface details event is sent. */ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( - const sctp_association_t *asoc, const struct sockaddr_storage *aaddr, - int flags, int state, int error, int priority) + const struct sctp_association *asoc, + const struct sockaddr_storage *aaddr, + int flags, int state, int error, int gfp) { struct sctp_ulpevent *event; struct sctp_paddr_change *spc; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -315,8 +316,8 @@ * error formats. */ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( - const sctp_association_t *asoc, sctp_chunk_t *chunk, - __u16 flags, int priority) + const struct sctp_association *asoc, struct sctp_chunk *chunk, + __u16 flags, int gfp) { struct sctp_ulpevent *event; struct sctp_remote_error *sre; @@ -327,7 +328,7 @@ ch = (sctp_errhdr_t *)(chunk->skb->data); cause = ch->cause; - elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); + elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t); /* Pull off the ERROR header. */ skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); @@ -335,10 +336,8 @@ /* Copy the skb to a new skb with room for us to prepend * notification with. */ - skb = skb_copy_expand(chunk->skb, - sizeof(struct sctp_remote_error), /* headroom */ - 0, /* tailroom */ - priority); + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), + 0, gfp); /* Pull off the rest of the cause TLV from the chunk. */ skb_pull(chunk->skb, elen); @@ -419,23 +418,27 @@ * 5.3.1.4 SCTP_SEND_FAILED */ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( - const sctp_association_t *asoc, sctp_chunk_t *chunk, - __u16 flags, __u32 error, int priority) + const struct sctp_association *asoc, struct sctp_chunk *chunk, + __u16 flags, __u32 error, int gfp) { struct sctp_ulpevent *event; struct sctp_send_failed *ssf; struct sk_buff *skb; + /* Pull off any padding. */ + int len = ntohs(chunk->chunk_hdr->length); + /* Make skb with more room so we can prepend notification. */ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_send_failed), /* headroom */ 0, /* tailroom */ - priority); + gfp); if (!skb) goto fail; /* Pull off the common chunk header and DATA header. */ - skb_pull(skb, sizeof(sctp_data_chunk_t)); + skb_pull(skb, sizeof(struct sctp_data_chunk)); + len -= sizeof(struct sctp_data_chunk); /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); @@ -476,7 +479,8 @@ * This field is the total length of the notification data, including * the notification header. */ - ssf->ssf_length = skb->len; + ssf->ssf_length = sizeof(struct sctp_send_failed) + len; + skb_trim(skb, ssf->ssf_length); /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED @@ -497,6 +501,11 @@ */ memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); + /* Per TSVWG discussion with Randy. Allow the application to + * ressemble a fragmented message. + */ + ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * @@ -521,15 +530,15 @@ * 5.3.1.5 SCTP_SHUTDOWN_EVENT */ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( - const sctp_association_t *asoc, - __u16 flags, int priority) + const struct sctp_association *asoc, + __u16 flags, int gfp) { struct sctp_ulpevent *event; struct sctp_shutdown_event *sse; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -586,8 +595,9 @@ * Socket Extensions for SCTP * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) */ -struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, - sctp_chunk_t *chunk, int priority) +struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, + struct sctp_chunk *chunk, + int gfp) { struct sctp_ulpevent *event; struct sctp_sndrcvinfo *info; @@ -595,7 +605,7 @@ size_t padding, len; /* Clone the original skb, sharing the data. */ - skb = skb_clone(chunk->skb, priority); + skb = skb_clone(chunk->skb, gfp); if (!skb) goto fail; @@ -631,7 +641,7 @@ event->iif = sctp_chunk_iif(chunk); /* Note: Not clearing the entire event struct as * this is just a fragment of the real event. However, - * we still need to do rwnd accounting. + * we still need to do rwnd accounting. */ for (list = skb_shinfo(skb)->frag_list; list; list = list->next) sctp_ulpevent_set_owner_r(list, asoc); @@ -690,16 +700,16 @@ info->sinfo_flags |= MSG_UNORDERED; /* sinfo_cumtsn: 32 bit (unsigned integer) - * - * This field will hold the current cumulative TSN as - * known by the underlying SCTP layer. Note this field is - * ignored when sending and only valid for a receive + * + * This field will hold the current cumulative TSN as + * known by the underlying SCTP layer. Note this field is + * ignored when sending and only valid for a receive * operation when sinfo_flags are set to MSG_UNORDERED. */ info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); } - /* Note: For reassembly, we need to have the fragmentation bits. + /* Note: For reassembly, we need to have the fragmentation bits. * For now, merge these into the msg_flags, since those bit * possitions are not used. */ @@ -732,7 +742,7 @@ return NULL; } -/* Create a partial delivery related event. +/* Create a partial delivery related event. * * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * @@ -741,14 +751,14 @@ * various events. */ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( - const sctp_association_t *asoc, __u32 indication, int priority) + const struct sctp_association *asoc, __u32 indication, int gfp) { struct sctp_ulpevent *event; struct sctp_rcv_pdapi_event *pd; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), - MSG_NOTIFICATION, priority); + MSG_NOTIFICATION, gfp); if (!event) goto fail; @@ -780,7 +790,7 @@ pd->pdapi_indication = indication; /* pdapi_assoc_id: sizeof (sctp_assoc_t) - * + * * The association id field, holds the identifier for the association. */ pd->pdapi_assoc_id = sctp_assoc2id(asoc); @@ -817,7 +827,7 @@ /* Do accounting for bytes just read by user. */ static void sctp_rcvmsg_rfree(struct sk_buff *skb) { - sctp_association_t *asoc; + struct sctp_association *asoc; struct sctp_ulpevent *event; /* Current stack structures assume that the rcv buffer is @@ -834,7 +844,7 @@ /* Charge receive window for bytes received. */ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - sctp_association_t *asoc) + struct sctp_association *asoc) { struct sctp_ulpevent *event; diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c --- a/net/sctp/ulpqueue.c Mon May 12 20:55:49 2003 +++ b/net/sctp/ulpqueue.c Mon May 12 20:55:49 2003 @@ -57,11 +57,11 @@ /* 1st Level Abstractions */ /* Create a new ULP queue. */ -struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority) +struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp) { struct sctp_ulpq *ulpq; - ulpq = kmalloc(sizeof(struct sctp_ulpq), priority); + ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp); if (!ulpq) goto fail; if (!sctp_ulpq_init(ulpq, asoc)) @@ -77,7 +77,7 @@ /* Initialize a ULP queue from a block of memory. */ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq, - sctp_association_t *asoc) + struct sctp_association *asoc) { memset(ulpq, sizeof(struct sctp_ulpq), 0x00); @@ -118,8 +118,8 @@ } /* Process an incoming DATA chunk. */ -int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, - int priority) +int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, + int gfp) { struct sk_buff_head temp; sctp_data_chunk_t *hdr; @@ -128,7 +128,7 @@ hdr = (sctp_data_chunk_t *) chunk->chunk_hdr; /* Create an event from the incoming chunk. */ - event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority); + event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp); if (!event) return -ENOMEM; @@ -253,6 +253,21 @@ tsn = event->sndrcvinfo.sinfo_tsn; + /* See if it belongs at the end. */ + pos = skb_peek_tail(&ulpq->reasm); + if (!pos) { + __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + return; + } + + /* Short circuit just dropping it at the end. */ + cevent = sctp_skb2event(pos); + ctsn = cevent->sndrcvinfo.sinfo_tsn; + if (TSN_lt(ctsn, tsn)) { + __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + return; + } + /* Find the right place in this list. We store them by TSN. */ skb_queue_walk(&ulpq->reasm, pos) { cevent = sctp_skb2event(pos); @@ -262,12 +277,9 @@ break; } - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->reasm)) - __skb_insert(sctp_event2skb(event), pos->prev, pos, - &ulpq->reasm); - else - __skb_queue_tail(&ulpq->reasm, sctp_event2skb(event)); + /* Insert before pos. */ + __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->reasm); + } /* Helper function to return an event corresponding to the reassembled @@ -592,8 +604,27 @@ __u16 sid, csid; __u16 ssn, cssn; + pos = skb_peek_tail(&ulpq->lobby); + if (!pos) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } + sid = event->sndrcvinfo.sinfo_stream; ssn = event->sndrcvinfo.sinfo_ssn; + + cevent = (struct sctp_ulpevent *) pos->cb; + csid = cevent->sndrcvinfo.sinfo_stream; + cssn = cevent->sndrcvinfo.sinfo_ssn; + if (sid > csid) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } + + if ((sid == csid) && SSN_lt(cssn, ssn)) { + __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + return; + } /* Find the right place in this list. We store them by * stream ID and then by SSN. @@ -609,12 +640,10 @@ break; } - /* If the queue is empty, we have a different function to call. */ - if (skb_peek(&ulpq->lobby)) - __skb_insert(sctp_event2skb(event), pos->prev, pos, - &ulpq->lobby); - else - __skb_queue_tail(&ulpq->lobby, sctp_event2skb(event)); + + /* Insert before pos. */ + __skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->lobby); + } static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq, @@ -705,7 +734,7 @@ /* Partial deliver the first message as there is pressure on rwnd. */ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq, - struct sctp_chunk *chunk, int priority) + struct sctp_chunk *chunk, int gfp) { struct sctp_ulpevent *event; struct sctp_association *asoc; @@ -729,7 +758,7 @@ /* Renege some packets to make room for an incoming chunk. */ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, - int priority) + int gfp) { struct sctp_association *asoc; __u16 needed, freed; @@ -755,9 +784,9 @@ __u32 tsn; tsn = ntohl(chunk->subh.data_hdr->tsn); sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn); - sctp_ulpq_tail_data(ulpq, chunk, priority); + sctp_ulpq_tail_data(ulpq, chunk, gfp); - sctp_ulpq_partial_delivery(ulpq, chunk, priority); + sctp_ulpq_partial_delivery(ulpq, chunk, gfp); } return; @@ -768,7 +797,7 @@ /* Notify the application if an association is aborted and in * partial delivery mode. Send up any pending received messages. */ -void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority) +void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int gfp) { struct sctp_ulpevent *ev = NULL; struct sock *sk; @@ -781,7 +810,7 @@ &sctp_sk(sk)->subscribe)) ev = sctp_ulpevent_make_pdapi(ulpq->asoc, SCTP_PARTIAL_DELIVERY_ABORTED, - priority); + gfp); if (ev) __skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev)); diff -Nru a/net/socket.c b/net/socket.c --- a/net/socket.c Mon May 12 20:55:45 2003 +++ b/net/socket.c Mon May 12 20:55:45 2003 @@ -95,9 +95,9 @@ #include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); -static ssize_t sock_aio_read(struct kiocb *iocb, char *buf, +static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, size_t size, loff_t pos); -static ssize_t sock_aio_write(struct kiocb *iocb, const char *buf, +static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf, size_t size, loff_t pos); static int sock_mmap(struct file *file, struct vm_area_struct * vma); @@ -121,6 +121,7 @@ */ static struct file_operations socket_file_ops = { + .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, .aio_write = sock_aio_write, @@ -217,7 +218,7 @@ * invalid addresses -EFAULT is returned. On a success 0 is returned. */ -int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr) +int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) { if(ulen<0||ulen>MAX_SOCK_ADDR) return -EINVAL; @@ -245,7 +246,7 @@ * specified. Zero is returned for a success. */ -int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen) +int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen) { int err; int len; @@ -490,6 +491,7 @@ } struct file_operations bad_sock_fops = { + .owner = THIS_MODULE, .open = sock_no_open, }; @@ -589,7 +591,7 @@ * area ubuf...ubuf+size-1 is writable before asking the protocol. */ -static ssize_t sock_aio_read(struct kiocb *iocb, char *ubuf, +static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t size, loff_t pos) { struct sock_iocb *x = kiocb_to_siocb(iocb); @@ -622,7 +624,7 @@ * is readable by the user process. */ -static ssize_t sock_aio_write(struct kiocb *iocb, const char *ubuf, +static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t size, loff_t pos) { struct sock_iocb *x = kiocb_to_siocb(iocb); @@ -644,7 +646,7 @@ x->async_msg.msg_flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; if (sock->type == SOCK_SEQPACKET) x->async_msg.msg_flags |= MSG_EOR; - x->async_iov.iov_base = (void *)ubuf; + x->async_iov.iov_base = (void __user *)ubuf; x->async_iov.iov_len = size; return __sock_sendmsg(iocb, sock, &x->async_msg, size); @@ -731,6 +733,7 @@ br_ioctl_hook = hook; up(&br_ioctl_mutex); } +EXPORT_SYMBOL(brioctl_set); static DECLARE_MUTEX(vlan_ioctl_mutex); static int (*vlan_ioctl_hook)(unsigned long arg); @@ -741,12 +744,18 @@ vlan_ioctl_hook = hook; up(&vlan_ioctl_mutex); } +EXPORT_SYMBOL(vlan_ioctl_set); -#ifdef CONFIG_DLCI -extern int dlci_ioctl(unsigned int, void *); -#else -int (*dlci_ioctl_hook)(unsigned int, void *); -#endif +static DECLARE_MUTEX(dlci_ioctl_mutex); +static int (*dlci_ioctl_hook)(unsigned int, void *); + +void dlci_ioctl_set(int (*hook)(unsigned int, void *)) +{ + down(&dlci_ioctl_mutex); + dlci_ioctl_hook = hook; + up(&dlci_ioctl_mutex); +} +EXPORT_SYMBOL(dlci_ioctl_set); /* * With an ioctl, arg may well be a user mode pointer, but we don't know @@ -820,24 +829,16 @@ break; case SIOCADDDLCI: case SIOCDELDLCI: - /* Convert this to always call through a hook */ -#ifdef CONFIG_DLCI - lock_kernel(); - err = dlci_ioctl(cmd, (void *)arg); - unlock_kernel(); - break; -#else err = -ENOPKG; #ifdef CONFIG_KMOD if (!dlci_ioctl_hook) request_module("dlci"); #endif if (dlci_ioctl_hook) { - lock_kernel(); + down(&dlci_ioctl_mutex); err = dlci_ioctl_hook(cmd, (void *)arg); - unlock_kernel(); + up(&dlci_ioctl_mutex); } -#endif break; default: err = sock->ops->ioctl(sock, cmd, arg); @@ -1123,7 +1124,7 @@ * Create a pair of connected sockets. */ -asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2]) +asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec) { struct socket *sock1, *sock2; int fd1, fd2, err; @@ -1193,7 +1194,7 @@ * the protocol layer (having also checked the address is ok). */ -asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen) +asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1255,7 +1256,7 @@ * clean when we restucture accept also. */ -asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) +asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) { struct socket *sock, *newsock; int err, len; @@ -1280,26 +1281,26 @@ * We don't need try_module_get here, as the listening socket (sock) * has the protocol module (sock->ops->owner) held. */ - __module_get(sock->ops->owner); + __module_get(newsock->ops->owner); err = sock->ops->accept(sock, newsock, sock->file->f_flags); if (err < 0) - goto out_module_put; + goto out_release; if (upeer_sockaddr) { if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { err = -ECONNABORTED; - goto out_module_put; + goto out_release; } err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); if (err < 0) - goto out_module_put; + goto out_release; } /* File flags are not inherited via accept() unlike another OSes. */ if ((err = sock_map_fd(newsock)) < 0) - goto out_module_put; + goto out_release; security_socket_post_accept(sock, newsock); @@ -1307,8 +1308,6 @@ sockfd_put(sock); out: return err; -out_module_put: - module_put(sock->ops->owner); out_release: sock_release(newsock); goto out_put; @@ -1327,7 +1326,7 @@ * include the -EINPROGRESS status for such sockets. */ -asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen) +asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1357,7 +1356,7 @@ * name to user space. */ -asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1387,7 +1386,7 @@ * name to user space. */ -asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1415,8 +1414,8 @@ * the protocol. */ -asmlinkage long sys_sendto(int fd, void * buff, size_t len, unsigned flags, - struct sockaddr *addr, int addr_len) +asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags, + struct sockaddr __user *addr, int addr_len) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -1458,7 +1457,7 @@ * Send a datagram down a socket. */ -asmlinkage long sys_send(int fd, void * buff, size_t len, unsigned flags) +asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned flags) { return sys_sendto(fd, buff, len, flags, NULL, 0); } @@ -1469,8 +1468,8 @@ * sender address from kernel to user space. */ -asmlinkage long sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, - struct sockaddr *addr, int *addr_len) +asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags, + struct sockaddr __user *addr, int __user *addr_len) { struct socket *sock; struct iovec iov; @@ -1509,7 +1508,7 @@ * Receive a datagram from a socket. */ -asmlinkage long sys_recv(int fd, void * ubuf, size_t size, unsigned flags) +asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags) { return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); } @@ -1519,7 +1518,7 @@ * to pass the user mode parameter for the protocols to sort out. */ -asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int optlen) +asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) { int err; struct socket *sock; @@ -1549,7 +1548,7 @@ * to pass a user mode parameter for the protocols to sort out. */ -asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen) +asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) { int err; struct socket *sock; @@ -1608,9 +1607,9 @@ * BSD sendmsg interface */ -asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags) +asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) { - struct compat_msghdr *msg_compat = (struct compat_msghdr *)msg; + struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; struct socket *sock; char address[MAX_SOCK_ADDR]; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; @@ -1671,7 +1670,12 @@ goto out_freeiov; } err = -EFAULT; - if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) + /* + * Careful! Before this, msg_sys.msg_control contains a user pointer. + * Afterwards, it will be a kernel pointer. Thus the compiler-assisted + * checking falls down on this. + */ + if (copy_from_user(ctl_buf, (void __user *) msg_sys.msg_control, ctl_len)) goto out_freectl; msg_sys.msg_control = ctl_buf; } @@ -1697,9 +1701,9 @@ * BSD recvmsg interface */ -asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) +asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags) { - struct compat_msghdr *msg_compat = (struct compat_msghdr *)msg; + struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; struct socket *sock; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack; @@ -1711,8 +1715,8 @@ char addr[MAX_SOCK_ADDR]; /* user mode address pointers */ - struct sockaddr *uaddr; - int *uaddr_len; + struct sockaddr __user *uaddr; + int __user *uaddr_len; if (MSG_CMSG_COMPAT & flags) { if (get_compat_msghdr(&msg_sys, msg_compat)) @@ -1743,7 +1747,7 @@ * kernel msghdr to use the kernel address space) */ - uaddr = msg_sys.msg_name; + uaddr = (void __user *) msg_sys.msg_name; uaddr_len = COMPAT_NAMELEN(msg); if (MSG_CMSG_COMPAT & flags) { err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); @@ -1807,7 +1811,7 @@ * it is set by the callees. */ -asmlinkage long sys_socketcall(int call, unsigned long *args) +asmlinkage long sys_socketcall(int call, unsigned long __user *args) { unsigned long a[6]; unsigned long a0,a1; @@ -1829,54 +1833,54 @@ err = sys_socket(a0,a1,a[2]); break; case SYS_BIND: - err = sys_bind(a0,(struct sockaddr *)a1, a[2]); + err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]); break; case SYS_CONNECT: - err = sys_connect(a0, (struct sockaddr *)a1, a[2]); + err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); break; case SYS_LISTEN: err = sys_listen(a0,a1); break; case SYS_ACCEPT: - err = sys_accept(a0,(struct sockaddr *)a1, (int *)a[2]); + err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_GETSOCKNAME: - err = sys_getsockname(a0,(struct sockaddr *)a1, (int *)a[2]); + err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_GETPEERNAME: - err = sys_getpeername(a0, (struct sockaddr *)a1, (int *)a[2]); + err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]); break; case SYS_SOCKETPAIR: - err = sys_socketpair(a0,a1, a[2], (int *)a[3]); + err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]); break; case SYS_SEND: - err = sys_send(a0, (void *)a1, a[2], a[3]); + err = sys_send(a0, (void __user *)a1, a[2], a[3]); break; case SYS_SENDTO: - err = sys_sendto(a0,(void *)a1, a[2], a[3], - (struct sockaddr *)a[4], a[5]); + err = sys_sendto(a0,(void __user *)a1, a[2], a[3], + (struct sockaddr __user *)a[4], a[5]); break; case SYS_RECV: - err = sys_recv(a0, (void *)a1, a[2], a[3]); + err = sys_recv(a0, (void __user *)a1, a[2], a[3]); break; case SYS_RECVFROM: - err = sys_recvfrom(a0, (void *)a1, a[2], a[3], - (struct sockaddr *)a[4], (int *)a[5]); + err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], + (struct sockaddr __user *)a[4], (int __user *)a[5]); break; case SYS_SHUTDOWN: err = sys_shutdown(a0,a1); break; case SYS_SETSOCKOPT: - err = sys_setsockopt(a0, a1, a[2], (char *)a[3], a[4]); + err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); break; case SYS_GETSOCKOPT: - err = sys_getsockopt(a0, a1, a[2], (char *)a[3], (int *)a[4]); + err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]); break; case SYS_SENDMSG: - err = sys_sendmsg(a0, (struct msghdr *) a1, a[2]); + err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]); break; case SYS_RECVMSG: - err = sys_recvmsg(a0, (struct msghdr *) a1, a[2]); + err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]); break; default: err = -EINVAL; diff -Nru a/net/sunrpc/cache.c b/net/sunrpc/cache.c --- a/net/sunrpc/cache.c Mon May 12 20:55:47 2003 +++ b/net/sunrpc/cache.c Mon May 12 20:55:47 2003 @@ -733,6 +733,7 @@ static struct file_operations cache_file_operations = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = cache_read, .write = cache_write, diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c Mon May 12 20:55:46 2003 +++ b/net/sunrpc/clnt.c Mon May 12 20:55:46 2003 @@ -57,8 +57,7 @@ static void call_refreshresult(struct rpc_task *task); static void call_timeout(struct rpc_task *task); static void call_connect(struct rpc_task *task); -static void child_connect(struct rpc_task *task); -static void child_connect_status(struct rpc_task *task); +static void call_connect_status(struct rpc_task *task); static u32 * call_header(struct rpc_task *task); static u32 * call_verify(struct rpc_task *task); @@ -602,40 +601,48 @@ call_connect(struct rpc_task *task) { struct rpc_clnt *clnt = task->tk_client; - struct rpc_task *child; dprintk("RPC: %4d call_connect status %d\n", task->tk_pid, task->tk_status); - task->tk_action = call_transmit; - if (task->tk_status < 0 || !clnt->cl_xprt->stream) + if (xprt_connected(clnt->cl_xprt)) { + task->tk_action = call_transmit; return; - - /* Run as a child to ensure it runs as an rpciod task. Rpciod - * guarantees we have the correct capabilities for socket bind - * to succeed. */ - child = rpc_new_child(clnt, task); - if (child) { - child->tk_action = child_connect; - rpc_run_child(task, child, NULL); } + task->tk_action = call_connect_status; + if (task->tk_status < 0) + return; + xprt_connect(task); } +/* + * 4b. Sort out connect result + */ static void -child_connect(struct rpc_task *task) +call_connect_status(struct rpc_task *task) { + struct rpc_clnt *clnt = task->tk_client; + int status = task->tk_status; + task->tk_status = 0; - task->tk_action = child_connect_status; - xprt_connect(task); -} + if (status >= 0) { + clnt->cl_stats->netreconn++; + task->tk_action = call_transmit; + return; + } -static void -child_connect_status(struct rpc_task *task) -{ - if (task->tk_status == -EAGAIN) - task->tk_action = child_connect; - else - task->tk_action = NULL; + /* Something failed: we may have to rebind */ + if (clnt->cl_autobind) + clnt->cl_port = 0; + switch (status) { + case -ENOTCONN: + case -ETIMEDOUT: + case -EAGAIN: + task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect; + break; + default: + rpc_exit(task, -EIO); + } } /* @@ -696,6 +703,7 @@ break; case -ECONNREFUSED: case -ENOTCONN: + req->rq_bytes_sent = 0; if (clnt->cl_autobind) clnt->cl_port = 0; task->tk_action = call_bind; diff -Nru a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c --- a/net/sunrpc/rpc_pipe.c Mon May 12 20:55:45 2003 +++ b/net/sunrpc/rpc_pipe.c Mon May 12 20:55:45 2003 @@ -310,6 +310,7 @@ } static struct file_operations rpc_info_operations = { + .owner = THIS_MODULE, .open = rpc_info_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c --- a/net/sunrpc/sched.c Mon May 12 20:55:47 2003 +++ b/net/sunrpc/sched.c Mon May 12 20:55:47 2003 @@ -1110,9 +1110,10 @@ alltask_for_each(t, le, &all_tasks) printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n", t->tk_pid, - (t->tk_msg.rpc_proc->p_proc ? t->tk_msg.rpc_proc->p_proc : -1), + (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), t->tk_flags, t->tk_status, - t->tk_client, t->tk_client->cl_prog, + t->tk_client, + (t->tk_client ? t->tk_client->cl_prog : 0), t->tk_rqstp, t->tk_timeout, rpc_qname(t->tk_rpcwait), t->tk_action, t->tk_exit); diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c --- a/net/sunrpc/xdr.c Mon May 12 20:55:47 2003 +++ b/net/sunrpc/xdr.c Mon May 12 20:55:47 2003 @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -314,8 +316,113 @@ } while ((pglen -= len) != 0); copy_tail: len = xdr->tail[0].iov_len; - if (len) - copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len); + if (base < len) + copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base); +} + + +int +xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, + struct xdr_buf *xdr, unsigned int base, int msgflags) +{ + struct page **ppage = xdr->pages; + unsigned int len, pglen = xdr->page_len; + int err, ret = 0; + ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); + mm_segment_t oldfs; + + len = xdr->head[0].iov_len; + if (base < len || (addr != NULL && base == 0)) { + struct iovec iov = { + .iov_base = xdr->head[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_name = addr, + .msg_namelen = addrlen, + .msg_flags = msgflags, + }; + + if (iov.iov_len != 0) { + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + } + if (xdr->len > len) + msg.msg_flags |= MSG_MORE; + oldfs = get_fs(); set_fs(get_ds()); + err = sock_sendmsg(sock, &msg, iov.iov_len); + set_fs(oldfs); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + if (err != iov.iov_len) + goto out; + base = 0; + } else + base -= len; + + if (pglen == 0) + goto copy_tail; + if (base >= pglen) { + base -= pglen; + goto copy_tail; + } + if (base || xdr->page_base) { + pglen -= base; + base += xdr->page_base; + ppage += base >> PAGE_CACHE_SHIFT; + base &= ~PAGE_CACHE_MASK; + } + + sendpage = sock->ops->sendpage ? : sock_no_sendpage; + do { + int flags = msgflags; + + len = PAGE_CACHE_SIZE; + if (base) + len -= base; + if (pglen < len) + len = pglen; + + if (pglen != len || xdr->tail[0].iov_len != 0) + flags |= MSG_MORE; + + /* Hmm... We might be dealing with highmem pages */ + if (PageHighMem(*ppage)) + sendpage = sock_no_sendpage; + err = sendpage(sock, *ppage, base, len, flags); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + if (err != len) + goto out; + base = 0; + ppage++; + } while ((pglen -= len) != 0); +copy_tail: + len = xdr->tail[0].iov_len; + if (base < len) { + struct iovec iov = { + .iov_base = xdr->tail[0].iov_base + base, + .iov_len = len - base, + }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_flags = msgflags, + }; + oldfs = get_fs(); set_fs(get_ds()); + err = sock_sendmsg(sock, &msg, iov.iov_len); + set_fs(oldfs); + if (ret == 0) + ret = err; + else if (err > 0) + ret += err; + } +out: + return ret; } diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Mon May 12 20:55:47 2003 +++ b/net/sunrpc/xprt.c Mon May 12 20:55:47 2003 @@ -85,7 +85,7 @@ static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static inline void do_xprt_reserve(struct rpc_task *); static void xprt_disconnect(struct rpc_xprt *); -static void xprt_conn_status(struct rpc_task *task); +static void xprt_connect_status(struct rpc_task *task); static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to); static struct socket *xprt_create_socket(int, struct rpc_timeout *, int); @@ -213,11 +213,10 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req) { struct socket *sock = xprt->sock; - struct msghdr msg; struct xdr_buf *xdr = &req->rq_snd_buf; - struct iovec niv[MAX_IOVEC]; - unsigned int niov, slen, skip; - mm_segment_t oldfs; + struct sockaddr *addr = NULL; + int addrlen = 0; + unsigned int skip; int result; if (!sock) @@ -227,27 +226,18 @@ req->rq_svec->iov_base, req->rq_svec->iov_len); + /* For UDP, we need to provide an address */ + if (!xprt->stream) { + addr = (struct sockaddr *) &xprt->addr; + addrlen = sizeof(xprt->addr); + } /* Dont repeat bytes */ skip = req->rq_bytes_sent; - slen = xdr->len - skip; - niov = xdr_kmap(niv, xdr, skip); - - msg.msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL; - msg.msg_iov = niv; - msg.msg_iovlen = niov; - msg.msg_name = (struct sockaddr *) &xprt->addr; - msg.msg_namelen = sizeof(xprt->addr); - msg.msg_control = NULL; - msg.msg_controllen = 0; - oldfs = get_fs(); set_fs(get_ds()); clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags); - result = sock_sendmsg(sock, &msg, slen); - set_fs(oldfs); + result = xdr_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT); - xdr_kunmap(xdr, skip); - - dprintk("RPC: xprt_sendmsg(%d) = %d\n", slen, result); + dprintk("RPC: xprt_sendmsg(%d) = %d\n", xdr->len - skip, result); if (result >= 0) return result; @@ -259,6 +249,7 @@ */ case -EAGAIN: break; + case -ECONNRESET: case -ENOTCONN: case -EPIPE: /* connection broken */ @@ -376,6 +367,7 @@ if (!sk) return; + write_lock_bh(&sk->callback_lock); xprt->inet = NULL; xprt->sock = NULL; @@ -383,6 +375,7 @@ sk->data_ready = xprt->old_data_ready; sk->state_change = xprt->old_state_change; sk->write_space = xprt->old_write_space; + write_unlock_bh(&sk->callback_lock); xprt_disconnect(xprt); sk->no_check = 0; @@ -397,14 +390,15 @@ xprt_disconnect(struct rpc_xprt *xprt) { dprintk("RPC: disconnected transport %p\n", xprt); + spin_lock_bh(&xprt->sock_lock); xprt_clear_connected(xprt); rpc_wake_up_status(&xprt->pending, -ENOTCONN); + spin_unlock_bh(&xprt->sock_lock); } /* * Attempt to connect a TCP socket. * - * NB: This never collides with TCP reads, as both run from rpciod */ void xprt_connect(struct rpc_task *task) @@ -442,6 +436,10 @@ goto out_write; } xprt_bind_socket(xprt, sock); + + if (!xprt->stream) + goto out_write; + inet = sock->sk; /* @@ -452,6 +450,9 @@ dprintk("RPC: %4d connect status %d connected %d sock state %d\n", task->tk_pid, -status, xprt_connected(xprt), inet->state); + if (status >= 0) + return; + switch (status) { case -EINPROGRESS: case -EALREADY: @@ -464,53 +465,37 @@ /* if the socket is already closing, delay briefly */ if ((1 << inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) task->tk_timeout = RPC_REESTABLISH_TIMEOUT; - rpc_sleep_on(&xprt->pending, task, xprt_conn_status, + rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); - release_sock(inet); - /* task status set when task wakes up again */ - return; } release_sock(inet); - task->tk_status = 0; break; - - case 0: - case -EISCONN: /* not likely, but just in case */ - /* Half closed state. No race -- this socket is dead. */ - if (inet->state != TCP_ESTABLISHED) { - xprt_close(xprt); - task->tk_status = -EAGAIN; - goto out_write; + case -ECONNREFUSED: + case -ECONNRESET: + case -ENOTCONN: + if (!task->tk_client->cl_softrtry) { + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + task->tk_status = -ENOTCONN; + break; } - - /* Otherwise, the connection is already established. */ - task->tk_status = 0; - break; - - case -EPIPE: - xprt_close(xprt); - task->tk_status = -ENOTCONN; - goto out_write; - default: /* Report myriad other possible returns. If this file * system is soft mounted, just error out, like Solaris. */ - xprt_close(xprt); if (task->tk_client->cl_softrtry) { printk(KERN_WARNING "RPC: error %d connecting to server %s, exiting\n", -status, task->tk_client->cl_server); task->tk_status = -EIO; - } else { - printk(KERN_WARNING - "RPC: error %d connecting to server %s\n", - -status, task->tk_client->cl_server); - rpc_delay(task, RPC_REESTABLISH_TIMEOUT); - task->tk_status = status; + goto out_write; } + printk(KERN_WARNING "RPC: error %d connecting to server %s\n", + -status, task->tk_client->cl_server); + /* This will prevent anybody else from reconnecting */ + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + task->tk_status = status; break; } - + return; out_write: xprt_release_write(xprt, task); } @@ -519,33 +504,32 @@ * We arrive here when awoken from waiting on connection establishment. */ static void -xprt_conn_status(struct rpc_task *task) +xprt_connect_status(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - switch (task->tk_status) { - case 0: - dprintk("RPC: %4d xprt_conn_status: connection established\n", + if (task->tk_status >= 0) { + dprintk("RPC: %4d xprt_connect_status: connection established\n", task->tk_pid); - goto out; + return; + } + + /* if soft mounted, just cause this RPC to fail */ + if (task->tk_client->cl_softrtry) + task->tk_status = -EIO; + + switch (task->tk_status) { + case -ENOTCONN: + rpc_delay(task, RPC_REESTABLISH_TIMEOUT); + return; case -ETIMEDOUT: - dprintk("RPC: %4d xprt_conn_status: timed out\n", + dprintk("RPC: %4d xprt_connect_status: timed out\n", task->tk_pid); - /* prevent TCP from continuing to retry SYNs */ - xprt_close(xprt); break; default: printk(KERN_ERR "RPC: error %d connecting to server %s\n", -task->tk_status, task->tk_client->cl_server); - xprt_close(xprt); - rpc_delay(task, RPC_REESTABLISH_TIMEOUT); - break; } - /* if soft mounted, cause this RPC to fail */ - if (task->tk_client->cl_softrtry) - task->tk_status = -EIO; - - out: xprt_release_write(xprt, task); } @@ -695,6 +679,7 @@ struct sk_buff *skb; int err, repsize, copied; + read_lock(&sk->callback_lock); dprintk("RPC: udp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) { printk("RPC: udp_data_ready request not found!\n"); @@ -745,6 +730,7 @@ out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); + read_unlock(&sk->callback_lock); } /* @@ -939,7 +925,7 @@ } /* Skip over any trailing bytes on short reads */ tcp_read_discard(xprt, &desc); - } while (desc.count && xprt_connected(xprt)); + } while (desc.count); dprintk("RPC: tcp_data_recv done\n"); return len - desc.count; } @@ -949,18 +935,21 @@ struct rpc_xprt *xprt; read_descriptor_t rd_desc; + read_lock(&sk->callback_lock); dprintk("RPC: tcp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) { printk("RPC: tcp_data_ready socket info not found!\n"); - return; + goto out; } if (xprt->shutdown) - return; + goto out; /* We use rd_desc to pass struct xprt to tcp_data_recv */ rd_desc.buf = (char *)xprt; rd_desc.count = 65536; tcp_read_sock(sk, &rd_desc, tcp_data_recv); +out: + read_unlock(&sk->callback_lock); } static void @@ -968,6 +957,7 @@ { struct rpc_xprt *xprt; + read_lock(&sk->callback_lock); if (!(xprt = xprt_from_sock(sk))) goto out; dprintk("RPC: tcp_state_change client %p...\n", xprt); @@ -977,19 +967,19 @@ switch (sk->state) { case TCP_ESTABLISHED: - if (xprt_test_and_set_connected(xprt)) - break; + spin_lock_bh(&xprt->sock_lock); + if (!xprt_test_and_set_connected(xprt)) { + /* Reset TCP record info */ + xprt->tcp_offset = 0; + xprt->tcp_reclen = 0; + xprt->tcp_copied = 0; + xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - /* Reset TCP record info */ - xprt->tcp_offset = 0; - xprt->tcp_reclen = 0; - xprt->tcp_copied = 0; - xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID; - - spin_lock(&xprt->sock_lock); - if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) - rpc_wake_up_task(xprt->snd_task); - spin_unlock(&xprt->sock_lock); + if (xprt->snd_task) + rpc_wake_up_task(xprt->snd_task); + rpc_wake_up(&xprt->pending); + } + spin_unlock_bh(&xprt->sock_lock); break; case TCP_SYN_SENT: case TCP_SYN_RECV: @@ -1001,6 +991,7 @@ out: if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible_all(sk->sleep); + read_unlock(&sk->callback_lock); } /* @@ -1015,24 +1006,25 @@ struct rpc_xprt *xprt; struct socket *sock; + read_lock(&sk->callback_lock); if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->socket)) - return; + goto out; if (xprt->shutdown) - return; + goto out; /* Wait until we have enough socket memory */ if (xprt->stream) { /* from net/ipv4/tcp.c:tcp_write_space */ if (tcp_wspace(sk) < tcp_min_write_space(sk)) - return; + goto out; } else { /* from net/core/sock.c:sock_def_write_space */ if (!sock_writeable(sk)) - return; + goto out; } if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags)) - return; + goto out; spin_lock_bh(&xprt->sock_lock); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) @@ -1040,6 +1032,8 @@ spin_unlock_bh(&xprt->sock_lock); if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); +out: + read_unlock(&sk->callback_lock); } /* @@ -1107,9 +1101,6 @@ if (xprt->shutdown) return -EIO; - if (!xprt_connected(xprt)) - return -ENOTCONN; - if (task->tk_rpcwait) rpc_remove_wait_queue(task); @@ -1118,6 +1109,12 @@ err = -EAGAIN; goto out_unlock; } + + if (!xprt_connected(xprt)) { + err = -ENOTCONN; + goto out_unlock; + } + if (list_empty(&req->rq_list)) { list_add_tail(&req->rq_list, &xprt->recv); req->rq_received = 0; @@ -1192,7 +1189,10 @@ if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) { /* Protect against races with xprt_write_space */ spin_lock_bh(&xprt->sock_lock); - if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) { task->tk_timeout = req->rq_timeout.to_current; rpc_sleep_on(&xprt->pending, task, NULL, NULL); } @@ -1203,20 +1203,17 @@ rpc_delay(task, HZ>>4); return; case -ECONNREFUSED: + task->tk_timeout = RPC_REESTABLISH_TIMEOUT; + rpc_sleep_on(&xprt->sending, task, NULL, NULL); case -ENOTCONN: - if (!xprt->stream) { - task->tk_timeout = RPC_REESTABLISH_TIMEOUT; - rpc_sleep_on(&xprt->sending, task, NULL, NULL); - return; - } - /* fall through */ + return; default: if (xprt->stream) xprt_disconnect(xprt); - req->rq_bytes_sent = 0; } out_release: xprt_release_write(xprt, task); + req->rq_bytes_sent = 0; return; out_receive: dprintk("RPC: %4d xmit complete\n", task->tk_pid); @@ -1230,10 +1227,14 @@ } else task->tk_timeout = req->rq_timeout.to_current; spin_lock_bh(&xprt->sock_lock); - if (!req->rq_received) + /* Don't race with disconnect */ + if (!xprt_connected(xprt)) + task->tk_status = -ENOTCONN; + else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); __xprt_release_write(xprt, task); spin_unlock_bh(&xprt->sock_lock); + req->rq_bytes_sent = 0; } /* @@ -1417,6 +1418,9 @@ req->rq_next = NULL; xprt->free = xprt->slot; + /* Check whether we want to use a reserved port */ + xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; + dprintk("RPC: created transport %p\n", xprt); return xprt; @@ -1430,6 +1434,12 @@ { struct sockaddr_in myaddr; int err, port; + kernel_cap_t saved_cap = current->cap_effective; + + /* Override capabilities. + * They were checked in xprt_create_proto i.e. at mount time + */ + cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE); memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; @@ -1439,6 +1449,7 @@ err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)); } while (err == -EADDRINUSE && --port > 0); + current->cap_effective = saved_cap; if (err < 0) printk("RPC: Can't bind to reserved port (%d).\n", -err); @@ -1454,6 +1465,7 @@ if (xprt->inet) return; + write_lock_bh(&sk->callback_lock); sk->user_data = xprt; xprt->old_data_ready = sk->data_ready; xprt->old_state_change = sk->state_change; @@ -1474,6 +1486,7 @@ /* Reset to new socket */ xprt->sock = sock; xprt->inet = sk; + write_unlock_bh(&sk->callback_lock); return; } @@ -1543,16 +1556,6 @@ xprt = xprt_setup(proto, sap, to); if (!xprt) goto out_bad; - - xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; - if (!xprt->stream) { - struct socket *sock; - - sock = xprt_create_socket(proto, to, xprt->resvport); - if (!sock) - goto out_bad; - xprt_bind_socket(xprt, sock); - } dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); return xprt; diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c --- a/net/unix/af_unix.c Mon May 12 20:55:47 2003 +++ b/net/unix/af_unix.c Mon May 12 20:55:47 2003 @@ -625,7 +625,7 @@ goto put_fail; if (u->type == type) - UPDATE_ATIME(nd.dentry->d_inode); + update_atime(nd.dentry->d_inode); path_release(&nd); @@ -641,7 +641,7 @@ struct dentry *dentry; dentry = unix_sk(u)->dentry; if (dentry) - UPDATE_ATIME(dentry->d_inode); + update_atime(dentry->d_inode); } else goto fail; } diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c --- a/net/wanrouter/wanproc.c Mon May 12 20:55:46 2003 +++ b/net/wanrouter/wanproc.c Mon May 12 20:55:46 2003 @@ -202,6 +202,7 @@ static struct file_operations config_fops = { + .owner = THIS_MODULE, .open = config_open, .read = seq_read, .llseek = seq_lseek, @@ -210,6 +211,7 @@ static struct file_operations status_fops = { + .owner = THIS_MODULE, .open = status_open, .read = seq_read, .llseek = seq_lseek, @@ -285,6 +287,7 @@ static struct file_operations wandev_fops = { + .owner = THIS_MODULE, .open = wandev_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/x25/x25_proc.c b/net/x25/x25_proc.c --- a/net/x25/x25_proc.c Mon May 12 20:55:45 2003 +++ b/net/x25/x25_proc.c Mon May 12 20:55:45 2003 @@ -189,6 +189,7 @@ } static struct file_operations x25_seq_socket_fops = { + .owner = THIS_MODULE, .open = x25_seq_socket_open, .read = seq_read, .llseek = seq_lseek, @@ -196,6 +197,7 @@ }; static struct file_operations x25_seq_route_fops = { + .owner = THIS_MODULE, .open = x25_seq_route_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c --- a/net/xfrm/xfrm_policy.c Mon May 12 20:55:46 2003 +++ b/net/xfrm/xfrm_policy.c Mon May 12 20:55:46 2003 @@ -100,7 +100,7 @@ fle->dir == dir) { if (fle->genid == xfrm_policy_genid) { if ((pol = fle->pol) != NULL) - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); local_bh_enable(); return pol; } @@ -118,7 +118,7 @@ xfrm_pol_put(fle->pol); fle->pol = pol; if (pol) - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); } else { if (flow_count(cpu) > flow_hwm) flow_cache_shrink(cpu); @@ -131,7 +131,7 @@ fle->dir = dir; fle->pol = pol; if (pol) - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); fle->next = flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash]; flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash] = fle; } @@ -274,7 +274,7 @@ } if (next != LONG_MAX && !mod_timer(&xp->timer, jiffies + make_jiffies(next))) - atomic_inc(&xp->refcnt); + xfrm_pol_hold(xp); out: xfrm_pol_put(xp); @@ -392,7 +392,7 @@ break; } } - atomic_inc(&policy->refcnt); + xfrm_pol_hold(policy); policy->next = pol ? pol->next : NULL; *p = policy; xfrm_policy_genid++; @@ -401,7 +401,7 @@ policy->curlft.use_time = 0; if (policy->lft.hard_add_expires_seconds && !mod_timer(&policy->timer, jiffies + HZ)) - atomic_inc(&policy->refcnt); + xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); if (pol) { @@ -445,7 +445,7 @@ if (delete) xfrm_policy_genid++; else - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); } write_unlock_bh(&xfrm_policy_lock); return pol; @@ -522,7 +522,7 @@ match = xfrm_selector_match(sel, fl, family); if (match) { - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); break; } } @@ -540,7 +540,7 @@ match = xfrm_selector_match(&pol->selector, fl, sk->family); if (match) - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); else pol = NULL; } @@ -552,7 +552,7 @@ { pol->next = xfrm_policy_list[XFRM_POLICY_MAX+dir]; xfrm_policy_list[XFRM_POLICY_MAX+dir] = pol; - atomic_inc(&pol->refcnt); + xfrm_pol_hold(pol); } void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) diff -Nru a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c --- a/net/xfrm/xfrm_state.c Mon May 12 20:55:48 2003 +++ b/net/xfrm/xfrm_state.c Mon May 12 20:55:48 2003 @@ -144,7 +144,7 @@ resched: if (next != LONG_MAX && !mod_timer(&x->timer, jiffies + make_jiffies(next))) - atomic_inc(&x->refcnt); + xfrm_state_hold(x); goto out; expired: @@ -172,6 +172,7 @@ if (x) { memset(x, 0, sizeof(struct xfrm_state)); atomic_set(&x->refcnt, 1); + atomic_set(&x->tunnel_users, 0); INIT_LIST_HEAD(&x->bydst); INIT_LIST_HEAD(&x->byspi); init_timer(&x->timer); @@ -234,6 +235,7 @@ void xfrm_state_delete(struct xfrm_state *x) { + xfrm_state_delete_tunnel(x); spin_lock_bh(&x->lock); __xfrm_state_delete(x); spin_unlock_bh(&x->lock); @@ -248,8 +250,9 @@ for (i = 0; i < XFRM_DST_HSIZE; i++) { restart: list_for_each_entry(x, xfrm_state_bydst+i, bydst) { - if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) { - atomic_inc(&x->refcnt); + if (!xfrm_state_kern(x) && + (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) { + xfrm_state_hold(x); spin_unlock_bh(&xfrm_state_lock); xfrm_state_delete(x); @@ -329,7 +332,7 @@ } if (best) { - atomic_inc(&best->refcnt); + xfrm_state_hold(best); spin_unlock_bh(&xfrm_state_lock); return best; } @@ -344,14 +347,14 @@ if (km_query(x, tmpl, pol) == 0) { x->km.state = XFRM_STATE_ACQ; list_add_tail(&x->bydst, xfrm_state_bydst+h); - atomic_inc(&x->refcnt); + xfrm_state_hold(x); if (x->id.spi) { h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); list_add(&x->byspi, xfrm_state_byspi+h); - atomic_inc(&x->refcnt); + xfrm_state_hold(x); } x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES; - atomic_inc(&x->refcnt); + xfrm_state_hold(x); mod_timer(&x->timer, XFRM_ACQ_EXPIRES*HZ); } else { x->km.state = XFRM_STATE_DEAD; @@ -373,15 +376,15 @@ spin_lock_bh(&xfrm_state_lock); list_add(&x->bydst, xfrm_state_bydst+h); - atomic_inc(&x->refcnt); + xfrm_state_hold(x); h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); list_add(&x->byspi, xfrm_state_byspi+h); - atomic_inc(&x->refcnt); + xfrm_state_hold(x); if (!mod_timer(&x->timer, jiffies + HZ)) - atomic_inc(&x->refcnt); + xfrm_state_hold(x); spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); @@ -399,7 +402,7 @@ x->curlft.packets >= x->lft.hard_packet_limit) { km_expired(x); if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) - atomic_inc(&x->refcnt); + xfrm_state_hold(x); return -EINVAL; } @@ -466,7 +469,7 @@ for (i = 0; i < XFRM_DST_HSIZE; i++) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) { if (x->km.seq == seq) { - atomic_inc(&x->refcnt); + xfrm_state_hold(x); spin_unlock_bh(&xfrm_state_lock); return x; } @@ -521,7 +524,7 @@ spin_lock_bh(&xfrm_state_lock); h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); list_add(&x->byspi, xfrm_state_byspi+h); - atomic_inc(&x->refcnt); + xfrm_state_hold(x); spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); } @@ -788,6 +791,20 @@ if (unlikely(afinfo == NULL)) return; read_unlock(&afinfo->lock); +} + +/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ +void xfrm_state_delete_tunnel(struct xfrm_state *x) +{ + if (x->tunnel) { + struct xfrm_state *t = x->tunnel; + + if (atomic_read(&t->tunnel_users) == 2) + xfrm_state_delete(t); + atomic_dec(&t->tunnel_users); + xfrm_state_put(t); + x->tunnel = NULL; + } } void __init xfrm_state_init(void) diff -Nru a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c --- a/net/xfrm/xfrm_user.c Mon May 12 20:55:47 2003 +++ b/net/xfrm/xfrm_user.c Mon May 12 20:55:47 2003 @@ -281,6 +281,11 @@ if (x == NULL) return -ESRCH; + if (xfrm_state_kern(x)) { + xfrm_state_put(x); + return -EPERM; + } + xfrm_state_delete(x); xfrm_state_put(x); diff -Nru a/scripts/Makefile.build b/scripts/Makefile.build --- a/scripts/Makefile.build Mon May 12 20:55:48 2003 +++ b/scripts/Makefile.build Mon May 12 20:55:48 2003 @@ -66,6 +66,12 @@ $(subdir-ym) $(always) @: +# Linus' kernel sanity checking tool +ifneq ($(KBUILD_CHECKSRC),0) +quiet_cmd_checksrc = CHECK $< + cmd_checksrc = $(CHECK) $(c_flags) $< ; +endif + # Module versioning # --------------------------------------------------------------------------- @@ -91,6 +97,8 @@ cmd_vcc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< define rule_vcc_o_c + $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ + $(cmd_checksrc) \ $(if $($(quiet)cmd_vcc_o_c),echo ' $($(quiet)cmd_vcc_o_c)';) \ $(cmd_vcc_o_c); \ \ @@ -158,6 +166,15 @@ quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< +define rule_cc_o_c + $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ + $(cmd_checksrc) \ + $(if $($(quiet)cmd_cc_o_c),echo ' $($(quiet)cmd_cc_o_c)';) \ + $(cmd_cc_o_c); \ + scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp; \ + rm -f $(depfile); \ + mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd +endef # Built-in and composite module parts @@ -165,7 +182,7 @@ ifdef CONFIG_MODVERSIONS $(call if_changed_rule,vcc_o_c) else - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) endif # Single-part modules are special since we need to mark them in $(MODVERDIR) @@ -174,7 +191,7 @@ ifdef CONFIG_MODVERSIONS $(call if_changed_rule,vcc_o_c) else - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) endif $(touch-module) diff -Nru a/security/dummy.c b/security/dummy.c --- a/security/dummy.c Mon May 12 20:55:45 2003 +++ b/security/dummy.c Mon May 12 20:55:45 2003 @@ -334,6 +334,11 @@ return 0; } +static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value, + size_t size, int flags) +{ +} + static int dummy_inode_getxattr (struct dentry *dentry, char *name) { return 0; @@ -803,6 +808,7 @@ set_to_dummy_if_null(ops, inode_getattr); set_to_dummy_if_null(ops, inode_delete); set_to_dummy_if_null(ops, inode_setxattr); + set_to_dummy_if_null(ops, inode_post_setxattr); set_to_dummy_if_null(ops, inode_getxattr); set_to_dummy_if_null(ops, inode_listxattr); set_to_dummy_if_null(ops, inode_removexattr); diff -Nru a/sound/core/info.c b/sound/core/info.c --- a/sound/core/info.c Mon May 12 20:55:49 2003 +++ b/sound/core/info.c Mon May 12 20:55:49 2003 @@ -1079,15 +1079,9 @@ p->data = (void *) entry; entry->p = p; up(&info_mutex); -#ifdef CONFIG_DEVFS_FS - if (strncmp(name, "controlC", 8)) { /* created in sound.c */ - char dname[32]; - sprintf(dname, "snd/%s", name); - devfs_register(NULL, dname, DEVFS_FL_DEFAULT, - _major, minor, mode, - &snd_fops, NULL); - } -#endif + + if (strncmp(name, "controlC", 8) == 0) /* created in sound.c */ + devfs_mk_cdev(MKDEV(_major, minor), mode, "snd/%s", name); return entry; } diff -Nru a/sound/core/sound.c b/sound/core/sound.c --- a/sound/core/sound.c Mon May 12 20:55:47 2003 +++ b/sound/core/sound.c Mon May 12 20:55:47 2003 @@ -323,13 +323,8 @@ static int __init alsa_sound_init(void) { -#ifdef CONFIG_DEVFS_FS short controlnum; - char controlname[24]; -#endif -#ifdef CONFIG_SND_OSSEMUL - int err; -#endif + int err = 0; int card; snd_ecards_limit = cards_limit; @@ -356,21 +351,19 @@ #ifdef CONFIG_SND_OSSEMUL snd_info_minor_register(); #endif -#ifdef CONFIG_DEVFS_FS + for (controlnum = 0; controlnum < cards_limit; controlnum++) { - sprintf(controlname, "snd/controlC%d", controlnum); - devfs_register(NULL, controlname, DEVFS_FL_DEFAULT, - major, controlnum<<5, device_mode | S_IFCHR, - &snd_fops, NULL); + devfs_mk_cdev(MKDEV(major, controlnum<<5), + device_mode | S_IFCHR, "snd/controlC%d", controlnum); } -#endif + #ifndef MODULE printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM) pm_init(); #endif - return 0; + return err; } static void __exit alsa_sound_exit(void) diff -Nru a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c --- a/sound/oss/opl3sa2.c Mon May 12 20:55:44 2003 +++ b/sound/oss/opl3sa2.c Mon May 12 20:55:44 2003 @@ -353,7 +353,8 @@ } } - +/* Currently only used for power management */ +#ifdef CONFIG_PM static void opl3sa2_mixer_restore(opl3sa2_state_t* devc) { if (devc) { @@ -366,7 +367,7 @@ } } } - +#endif static inline void arg_to_vol_mono(unsigned int vol, int* value) { @@ -961,7 +962,6 @@ spin_unlock_irqrestore(&opl3sa2_lock,flags); return 0; } -#endif /* CONFIG_PM */ static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) { @@ -976,6 +976,7 @@ } return 0; } +#endif /* CONFIG_PM */ /* * Install OPL3-SA2 based card(s). @@ -1127,10 +1128,11 @@ int card; for(card = 0; card < opl3sa2_cards_num; card++) { +#ifdef CONFIG_PM if (opl3sa2_state[card].pmdev) pm_unregister(opl3sa2_state[card].pmdev); - - if(opl3sa2_state[card].cfg_mpu.slots[1] != -1) { +#endif + if (opl3sa2_state[card].cfg_mpu.slots[1] != -1) { unload_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu); } unload_opl3sa2_mss(&opl3sa2_state[card].cfg_mss); diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c --- a/sound/oss/soundcard.c Mon May 12 20:55:46 2003 +++ b/sound/oss/soundcard.c Mon May 12 20:55:46 2003 @@ -549,7 +549,6 @@ static int __init oss_init(void) { int err; - char name_buf[32]; int i, j; /* drag in sound_syms.o */ @@ -573,19 +572,18 @@ sound_dmap_flag = (dmabuf > 0 ? 1 : 0); for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { - sprintf(name_buf, "sound/%s", dev_list[i].name); - devfs_register (NULL, name_buf, DEVFS_FL_NONE, - SOUND_MAJOR, dev_list[i].minor, - S_IFCHR | dev_list[i].mode, - &oss_sound_fops, NULL); + devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), + S_IFCHR | dev_list[i].mode, + "sound/%s", dev_list[i].name); + if (!dev_list[i].num) continue; + for (j = 1; j < *dev_list[i].num; j++) { - sprintf(name_buf, "sound/%s%d", dev_list[i].name, j); - devfs_register (NULL, name_buf, DEVFS_FL_NONE, - SOUND_MAJOR, dev_list[i].minor + (j * 0x10), - S_IFCHR | dev_list[i].mode, - &oss_sound_fops, NULL); + devfs_mk_cdev(MKDEV(SOUND_MAJOR, + dev_list[i].minor + (j*0x10)), + S_IFCHR | dev_list[i].mode, + "sound/%s%d", dev_list[i].name, j); } } diff -Nru a/sound/sound_core.c b/sound/sound_core.c --- a/sound/sound_core.c Mon May 12 20:55:49 2003 +++ b/sound/sound_core.c Mon May 12 20:55:49 2003 @@ -168,8 +168,8 @@ else sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP); - devfs_register(NULL, s->name, 0, SOUND_MAJOR, s->unit_minor, - S_IFCHR | mode, fops, NULL); + devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), + S_IFCHR | mode, s->name); return r; fail: