# 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.1089 # drivers/i2c/chips/w83781d.c 1.5 -> 1.6 # drivers/hotplug/cpqphp_core.c 1.15.1.1 -> 1.17 # Documentation/DocBook/kernel-api.tmpl 1.23.1.2 -> 1.25 # arch/ppc64/kernel/signal.c 1.26 -> 1.27 # include/linux/proc_fs.h 1.15 -> 1.16 # drivers/i2c/chips/lm75.c 1.14 -> 1.15 # drivers/media/video/tda9887.c 1.5 -> 1.6 # include/linux/netfilter_ipv4/ip_nat_core.h 1.1 -> 1.2 # include/net/dn_dev.h 1.4 -> 1.5 # net/ipx/ipx_proc.c 1.2 -> 1.4 # include/asm-ppc64/page.h 1.18 -> 1.19 # net/ipv4/netfilter/ip_nat_proto_tcp.c 1.3 -> 1.4 # kernel/ksyms.c 1.195 -> 1.196 # include/asm-ppc64/unistd.h 1.19 -> 1.20 # arch/ppc64/kernel/entry.S 1.24 -> 1.26 # drivers/i2c/chips/adm1021.c 1.15 -> 1.16 # include/net/dn_route.h 1.6 -> 1.7 # net/ipv6/exthdrs.c 1.9 -> 1.10 # net/core/neighbour.c 1.11 -> 1.13 # arch/ppc64/kernel/udbg.c 1.7 -> 1.8 # drivers/media/video/mxb.c 1.3 -> 1.4 # include/asm-ppc64/processor.h 1.27 -> 1.29 # include/net/ipx.h 1.6 -> 1.9 # include/asm-ppc64/module.h 1.2 -> 1.3 # 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/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 # net/ipv6/netfilter/ip6t_ah.c 1.4 -> 1.5 # drivers/i2c/i2c-core.c 1.32 -> 1.35 # arch/ppc64/kernel/rtas.c 1.9 -> 1.11 # net/ipv4/netfilter/ip_nat_core.c 1.22 -> 1.23 # drivers/media/video/saa7134/saa7134-i2c.c 1.7 -> 1.9 # net/ipv4/netfilter/ip_nat_helper.c 1.12 -> 1.13 # net/ipx/af_ipx.c 1.29 -> 1.31 # include/linux/i2c.h 1.25 -> 1.28 # net/ipv4/netfilter/ip_nat_proto_udp.c 1.1 -> 1.3 # include/asm-ppc64/sigcontext.h 1.3 -> 1.4 # net/ipv6/netfilter/ip6t_frag.c 1.4 -> 1.5 # net/decnet/Makefile 1.5 -> 1.6 # arch/ppc64/kernel/LparData.c 1.8 -> 1.9 # net/decnet/dn_table.c 1.5 -> 1.6 # include/linux/netfilter_ipv4/ip_nat_helper.h 1.4 -> 1.5 # net/ipv6/netfilter/ip6t_rt.c 1.4 -> 1.5 # drivers/char/n_hdlc.c 1.14 -> 1.15 # include/asm-ppc64/types.h 1.2 -> 1.3 # drivers/i2c/busses/i2c-piix4.c 1.8 -> 1.9 # arch/ppc64/kernel/ras.c 1.3 -> 1.4 # net/ipv4/netfilter/ip_nat_tftp.c 1.2 -> 1.3 # include/asm-ppc64/machdep.h 1.14 -> 1.16 # net/ipv4/netfilter/ip_nat_proto_icmp.c 1.1 -> 1.3 # drivers/media/video/tvaudio.c 1.17 -> 1.18 # drivers/hotplug/acpiphp_glue.c 1.8 -> 1.9 # net/decnet/dn_dev.c 1.10 -> 1.11 # drivers/acpi/acpi_ksyms.c 1.23 -> 1.24 # net/decnet/dn_nsp_in.c 1.9 -> 1.10 # drivers/hotplug/cpqphp_ctrl.c 1.9.1.1 -> 1.11 # drivers/char/synclink.c 1.34 -> 1.35 # drivers/media/video/bttvp.h 1.10 -> 1.11 # include/asm-ppc64/proc_fs.h 1.1 -> 1.2 # net/ipv4/netfilter/ipfwadm_core.c 1.14 -> 1.15 # drivers/media/video/dpc7146.c 1.1 -> 1.2 # drivers/hotplug/Kconfig 1.6 -> 1.7 # drivers/media/video/tda9875.c 1.12 -> 1.13 # arch/ppc64/kernel/irq.c 1.23 -> 1.25 # fs/binfmt_elf.c 1.44 -> 1.45 # arch/ppc64/kernel/rtas-proc.c 1.4 -> 1.6 # arch/ppc64/kernel/setup.c 1.21.1.1 -> 1.24 # include/asm-ppc64/naca.h 1.5 -> 1.6 # drivers/i2c/busses/i2c-i801.c 1.8 -> 1.9 # include/net/dn_fib.h 1.3 -> 1.4 # drivers/i2c/busses/i2c-ali15x3.c 1.7 -> 1.8 # arch/ppc64/kernel/traps.c 1.14 -> 1.16 # arch/ppc64/kernel/head.S 1.26 -> 1.31 # include/asm-ppc64/xics.h 1.4 -> 1.5 # net/ipv4/netfilter/ip_nat_proto_unknown.c 1.2 -> 1.3 # net/decnet/af_decnet.c 1.24 -> 1.25 # include/linux/netfilter_ipv4/ip_nat_protocol.h 1.1 -> 1.2 # arch/ppc64/kernel/xics.c 1.19 -> 1.22 # include/linux/list.h 1.28 -> 1.29 # drivers/i2c/busses/i2c-isa.c 1.2 -> 1.3 # net/ipv6/af_inet6.c 1.32 -> 1.33 # 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 # arch/ppc64/kernel/process.c 1.30 -> 1.31 # MAINTAINERS 1.136 -> 1.137 # net/ipv6/netfilter/ip6t_esp.c 1.4 -> 1.5 # arch/ppc64/kernel/pci_dma.c 1.11 -> 1.14 # drivers/media/video/msp3400.c 1.17 -> 1.18 # arch/ppc64/kernel/open_pic_defs.h 1.1 -> 1.2 # net/atm/svc.c 1.5 -> 1.6 # arch/ppc64/kernel/asm-offsets.c 1.12 -> 1.13 # include/asm-ppc64/mmu.h 1.6 -> 1.7 # net/decnet/dn_neigh.c 1.5 -> 1.6 # drivers/i2c/i2c-keywest.c 1.1 -> 1.2 # arch/ppc64/mm/numa.c 1.2 -> 1.4 # arch/ppc64/kernel/syscalls.c 1.9 -> 1.10 # include/asm-ppc64/ptrace.h 1.1 -> 1.2 # arch/ppc64/kernel/sys_ppc32.c 1.53.1.5 -> 1.59 # net/decnet/TODO 1.4 -> 1.5 # drivers/media/video/tda7432.c 1.10 -> 1.11 # fs/seq_file.c 1.9 -> 1.10 # arch/ppc64/kernel/prom.c 1.22 -> 1.25 # drivers/i2c/busses/i2c-viapro.c 1.2 -> 1.3 # arch/ppc64/kernel/iSeries_setup.c 1.10.1.1 -> 1.12 # arch/ppc64/kernel/smp.c 1.31.2.1 -> 1.34 # drivers/media/video/bt832.c 1.2 -> 1.3 # drivers/media/video/saa5249.c 1.14 -> 1.15 # net/ipv6/route.c 1.26 -> 1.27 # arch/ppc64/mm/fault.c 1.9 -> 1.10 # arch/ppc64/kernel/pacaData.c 1.5 -> 1.6 # drivers/i2c/chips/it87.c 1.3 -> 1.6 # drivers/i2c/i2c-dev.c 1.27 -> 1.28 # net/ipv4/netfilter/ip_nat_standalone.c 1.22 -> 1.23 # net/atm/mpc.c 1.10 -> 1.11 # drivers/hotplug/cpqphp.h 1.6.1.1 -> 1.9 # drivers/i2c/busses/i2c-amd8111.c 1.7 -> 1.8 # drivers/media/video/tuner.c 1.17 -> 1.18 # include/linux/pfkeyv2.h 1.5 -> 1.6 # net/ipv4/netfilter/ipchains_core.c 1.13 -> 1.14 # drivers/char/hvc_console.c 1.13.1.4 -> 1.15 # drivers/i2c/busses/i2c-amd756.c 1.6 -> 1.7 # arch/ppc64/kernel/pci.c 1.29 -> 1.30 # arch/ppc64/xmon/xmon.c 1.24 -> 1.26 # arch/ppc64/kernel/misc.S 1.52.2.3 -> 1.57 # arch/sparc64/kernel/power.c 1.12 -> 1.13 # drivers/media/video/tvmixer.c 1.13 -> 1.15 # arch/ppc64/kernel/signal32.c 1.38 -> 1.39 # include/linux/ipx.h 1.2 -> 1.3 # drivers/net/ppp_deflate.c 1.9 -> 1.10 # arch/ppc64/kernel/rtas_flash.c 1.4 -> 1.5 # drivers/bluetooth/hci_usb.c 1.26 -> 1.27 # drivers/hotplug/cpqphp_pci.c 1.16 -> 1.18 # 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.19 # include/asm-ppc64/io.h 1.7 -> 1.8 # include/asm-ppc64/topology.h 1.6 -> 1.7 # net/decnet/dn_nsp_out.c 1.7 -> 1.8 # arch/ppc64/kernel/Makefile 1.22 -> 1.23 # arch/ppc64/kernel/module.c 1.2 -> 1.4 # include/asm-ppc64/rtas.h 1.5 -> 1.6 # net/decnet/Kconfig 1.1 -> 1.2 # arch/ppc64/kernel/align.c 1.6 -> 1.8 # include/linux/seq_file.h 1.4 -> 1.5 # arch/ppc64/kernel/ioctl32.c 1.25.1.2 -> 1.30 # arch/ppc64/kernel/pSeries_lpar.c 1.20 -> 1.21 # net/ipv6/netfilter/ip6t_ipv6header.c 1.4 -> 1.5 # net/decnet/dn_fib.c 1.4 -> 1.5 # drivers/hotplug/ibmphp_core.c 1.24 -> 1.26 # (new) -> 1.1 net/decnet/netfilter/dn_rtmsg.c # (new) -> 1.1 include/asm-ppc64/systemcfg.h # (new) -> 1.1 net/decnet/netfilter/Makefile # (new) -> 1.1 arch/ppc64/kernel/proc_ppc64.c # (new) -> 1.1 net/decnet/netfilter/Kconfig # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/04 torvalds@home.transmeta.com 1.1042.92.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 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.89.2 # o list.h: implement list_for_each_entry_safe # -------------------------------------------- # 03/05/05 acme@conectiva.com.br 1.1042.89.3 # o ipx: convert ipx_interface handling to use list_head # -------------------------------------------- # 03/05/05 acme@conectiva.com.br 1.1042.89.4 # o ipx: convert ipx_route to use list_head # -------------------------------------------- # 03/05/05 davem@nuts.ninka.net 1.1064 # 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.1065 # [IPSEC]: Fix SADB_EALG_{3,}DESCBC values. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1066 # 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.1067 # [ATM]: Fix some CPP pasting in ambassador driver. # -------------------------------------------- # 03/05/06 chas@locutus.cmf.nrl.navy.mil 1.1068 # [ATM]: Fix excessive stack usage in iphase driver. # -------------------------------------------- # 03/05/06 chas@locutus.cmf.nrl.navy.mil 1.1069 # [ATM]: svcs possible race with sigd. # -------------------------------------------- # 03/05/06 steve@gw.chygwyn.com 1.1070 # [FS]: Add seq_release_private and proc_net_fops_create helpers. # -------------------------------------------- # 03/05/06 steve@gw.chygwyn.com 1.1071 # [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.1072 # [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.1073 # [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.1074 # [NETFILTER]: ip_nat_proto_{icmp,udp}.c need ip_nat_core.h # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1075 # [IPV6]: Kill spurious module_{get,put}(). # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1076 # [BLUETOOTH]: Fix hci_usb build. # -------------------------------------------- # 03/05/06 yoshfuji@linux-ipv6.org 1.1077 # [IPV6]: Fix offset in ICMPV6_HDR_FIELD messages. # -------------------------------------------- # 03/05/06 yoshfuji@linux-ipv6.org 1.1078 # [IPV^]: Use correct icmp6 type in ip6_pkt_discard. # -------------------------------------------- # 03/05/06 davem@nuts.ninka.net 1.1063.1.1 # [SPARC64]: Only use power interrupt when button property exists. # -------------------------------------------- # 03/05/06 torvalds@home.transmeta.com 1.1079 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1080 # Merge gregkh@kernel.bkbits.net:/home/gregkh/linux/i2c-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1079.1.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.1079.2.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 greg@kroah.com 1.1079.1.2 # [PATCH] PCI Hotplug: fix up the compaq driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1079.1.3 # [PATCH] PCI Hotplug: fix up the ibm driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1079.1.4 # [PATCH] PCI Hotplug: fix compiler warning in ibm driver. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1079.1.5 # [PATCH] PCI Hotplug: fix up the acpi driver to work properly again. # -------------------------------------------- # 03/05/06 greg@kroah.com 1.1079.1.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.1079.1.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.1081 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/05/06 kraxel@bytesex.org 1.1082 # [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.1083 # [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.1084 # [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.1079.1.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.1085 # [PATCH] i2c: fix compile error due to previous patches. # -------------------------------------------- # 03/05/06 warp@mercury.d2dc.net 1.1086 # [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 torvalds@home.transmeta.com 1.1087 # 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.1088 # [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.1089 # [PATCH] n_hdlc update # # - Use C99 initializers # -------------------------------------------- # diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Tue May 6 22:56:23 2003 +++ b/MAINTAINERS Tue May 6 22:56:23 2003 @@ -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 diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c --- a/arch/ppc64/kernel/LparData.c Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/LparData.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/Makefile Tue May 6 22:56:24 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/align.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/asm-offsets.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/chrp_setup.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/entry.S Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/head.S Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/htab.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/iSeries_setup.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/ioctl32.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/irq.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/misc.S Tue May 6 22:56:24 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/module.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/open_pic.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/open_pic_defs.h Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/pSeries_lpar.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/pacaData.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/pci.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/pci_dma.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/process.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/prom.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/ras.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/rtas-proc.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/rtas.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/rtas_flash.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/setup.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/signal.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/kernel/signal32.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/smp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/sys_ppc32.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/syscalls.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/traps.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/udbg.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/kernel/xics.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/mm/fault.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/mm/init.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/arch/ppc64/mm/numa.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/arch/ppc64/xmon/xmon.c Tue May 6 22:56:24 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/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c --- a/arch/sparc64/kernel/power.c Tue May 6 22:56:24 2003 +++ b/arch/sparc64/kernel/power.c Tue May 6 22:56:24 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/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c --- a/drivers/acpi/acpi_ksyms.c Tue May 6 22:56:23 2003 +++ b/drivers/acpi/acpi_ksyms.c Tue May 6 22:56:23 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/ambassador.c b/drivers/atm/ambassador.c --- a/drivers/atm/ambassador.c Tue May 6 22:56:23 2003 +++ b/drivers/atm/ambassador.c Tue May 6 22:56:23 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/iphase.c b/drivers/atm/iphase.c --- a/drivers/atm/iphase.c Tue May 6 22:56:24 2003 +++ b/drivers/atm/iphase.c Tue May 6 22:56:24 2003 @@ -2792,11 +2792,15 @@ 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; @@ -2804,8 +2808,11 @@ for (i=0; i<(sizeof (ffredn_t))/4; i++) ((u_int *)ffL)[i] = ((u_int *)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/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Tue May 6 22:56:24 2003 +++ b/drivers/bluetooth/hci_usb.c Tue May 6 22:56:24 2003 @@ -64,8 +64,8 @@ #endif #ifndef CONFIG_BT_USB_ZERO_PACKET -#undef USB_ZERO_PACKET -#define USB_ZERO_PACKET 0 +#undef URB_ZERO_PACKET +#define URB_ZERO_PACKET 0 #endif static struct usb_driver hci_usb_driver; @@ -458,7 +458,7 @@ pipe = usb_sndbulkpipe(husb->udev, 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/hvc_console.c b/drivers/char/hvc_console.c --- a/drivers/char/hvc_console.c Tue May 6 22:56:23 2003 +++ b/drivers/char/hvc_console.c Tue May 6 22:56:23 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) { diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c --- a/drivers/char/n_hdlc.c Tue May 6 22:56:23 2003 +++ b/drivers/char/n_hdlc.c Tue May 6 22:56:23 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/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Tue May 6 22:56:23 2003 +++ b/drivers/char/synclink.c Tue May 6 22:56:23 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/hotplug/Kconfig b/drivers/hotplug/Kconfig --- a/drivers/hotplug/Kconfig Tue May 6 22:56:23 2003 +++ b/drivers/hotplug/Kconfig Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/hotplug/acpiphp_glue.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/hotplug/cpqphp.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/hotplug/cpqphp_core.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/hotplug/cpqphp_ctrl.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/drivers/hotplug/cpqphp_pci.c Tue May 6 22:56:24 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 Tue May 6 22:56:24 2003 +++ b/drivers/hotplug/ibmphp_core.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-ali15x3.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/drivers/i2c/busses/i2c-amd756.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-amd8111.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-i801.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-isa.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-piix4.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/busses/i2c-viapro.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/chips/adm1021.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/chips/it87.c Tue May 6 22:56:23 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 @@ -238,6 +238,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 +253,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 = { @@ -350,6 +351,10 @@ show_in_offset(2); show_in_offset(3); show_in_offset(4); +show_in_offset(5); +show_in_offset(6); +show_in_offset(7); +show_in_offset(8); /* 3 temperatures */ static ssize_t show_temp(struct device *dev, char *buf, int nr) @@ -430,7 +435,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); @@ -508,6 +558,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 +576,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 +627,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 +639,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 +708,28 @@ 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_min8); 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_in_max8); 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 +739,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,7 +827,7 @@ } /* 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 */ @@ -814,9 +888,9 @@ 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, diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c --- a/drivers/i2c/chips/lm75.c Tue May 6 22:56:23 2003 +++ b/drivers/i2c/chips/lm75.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/chips/via686a.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/chips/w83781d.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/i2c-core.c Tue May 6 22:56:23 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 */ @@ -75,23 +75,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 +93,65 @@ */ if (adap->dev.parent == NULL) adap->dev.parent = &legacy_bus; - sprintf(adap->dev.bus_id, "i2c-%d", i); + sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); adap->dev.driver = &i2c_generic_driver; device_register(&adap->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 */ device_unregister(&adap->dev); - - adapters[i] = NULL; + list_del(&adap->list); DEB(dev_dbg(&adap->dev, "adapter unregistered\n")); @@ -187,24 +169,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 +185,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 +203,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 +233,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 +265,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 +282,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 +292,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 +309,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 +331,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 +346,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 +411,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) { @@ -516,9 +469,9 @@ 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 { @@ -542,9 +495,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 +525,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 +696,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 +1161,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 +1204,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 +1212,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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/i2c-dev.c Tue May 6 22:56:23 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; @@ -377,33 +372,28 @@ int i2cdev_attach_adapter(struct i2c_adapter *adap) { - int i; char name[12]; + int i; - 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); sprintf (name, "i2c/%d", i); - if (! i2cdev_adaps[i]) { - i2cdev_adaps[i] = adap; - devfs_register (NULL, name, + + 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"); - } + dev_dbg(&adap->dev, "Registered as minor %d\n", i); + return 0; +} + +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 Tue May 6 22:56:23 2003 +++ b/drivers/i2c/i2c-keywest.c Tue May 6 22:56:23 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/media/video/bt832.c b/drivers/media/video/bt832.c --- a/drivers/media/video/bt832.c Tue May 6 22:56:23 2003 +++ b/drivers/media/video/bt832.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/bttv-if.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/bttv.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/bttvp.h Tue May 6 22:56:23 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/dpc7146.c b/drivers/media/video/dpc7146.c --- a/drivers/media/video/dpc7146.c Tue May 6 22:56:23 2003 +++ b/drivers/media/video/dpc7146.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/msp3400.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/mxb.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/saa5249.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/saa7134/saa7134-i2c.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/tda7432.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/tda9875.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/tda9887.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/tuner.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/drivers/media/video/tvaudio.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/drivers/media/video/tvmixer.c Tue May 6 22:56:24 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/net/ppp_deflate.c b/drivers/net/ppp_deflate.c --- a/drivers/net/ppp_deflate.c Tue May 6 22:56:24 2003 +++ b/drivers/net/ppp_deflate.c Tue May 6 22:56:24 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/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Tue May 6 22:56:23 2003 +++ b/fs/binfmt_elf.c Tue May 6 22:56:23 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/seq_file.c b/fs/seq_file.c --- a/fs/seq_file.c Tue May 6 22:56:23 2003 +++ b/fs/seq_file.c Tue May 6 22:56:23 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/include/asm-ppc64/io.h b/include/asm-ppc64/io.h --- a/include/asm-ppc64/io.h Tue May 6 22:56:24 2003 +++ b/include/asm-ppc64/io.h Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/mmu.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/proc_fs.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/processor.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/ptrace.h Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/include/asm-ppc64/rtas.h Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/sigcontext.h Tue May 6 22:56:23 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 Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/unistd.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/asm-ppc64/xics.h Tue May 6 22:56:23 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/linux/i2c.h b/include/linux/i2c.h --- a/include/linux/i2c.h Tue May 6 22:56:23 2003 +++ b/include/linux/i2c.h Tue May 6 22:56:23 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,12 +234,10 @@ 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 */ @@ -250,6 +246,10 @@ /* 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 +265,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 +279,12 @@ #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_DIGINAL (1<<2) /* dbv cards */ +#define I2C_ADAP_CLASS_DDC (1<<3) /* i2c-matroxfb ? */ + /* 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 +341,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 +367,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/ipx.h b/include/linux/ipx.h --- a/include/linux/ipx.h Tue May 6 22:56:24 2003 +++ b/include/linux/ipx.h Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/include/linux/list.h Tue May 6 22:56:23 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/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h --- a/include/linux/netfilter_ipv4/ip_nat_core.h Tue May 6 22:56:23 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_core.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_helper.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/linux/netfilter_ipv4/ip_nat_protocol.h Tue May 6 22:56:23 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/pfkeyv2.h b/include/linux/pfkeyv2.h --- a/include/linux/pfkeyv2.h Tue May 6 22:56:23 2003 +++ b/include/linux/pfkeyv2.h Tue May 6 22:56:23 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/proc_fs.h b/include/linux/proc_fs.h --- a/include/linux/proc_fs.h Tue May 6 22:56:23 2003 +++ b/include/linux/proc_fs.h Tue May 6 22:56:23 2003 @@ -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/seq_file.h b/include/linux/seq_file.h --- a/include/linux/seq_file.h Tue May 6 22:56:24 2003 +++ b/include/linux/seq_file.h Tue May 6 22:56:24 2003 @@ -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/net/dn_dev.h b/include/net/dn_dev.h --- a/include/net/dn_dev.h Tue May 6 22:56:23 2003 +++ b/include/net/dn_dev.h Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/include/net/dn_fib.h Tue May 6 22:56:23 2003 @@ -101,10 +101,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 +179,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 Tue May 6 22:56:23 2003 +++ b/include/net/dn_route.h Tue May 6 22:56:23 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/ipx.h b/include/net/ipx.h --- a/include/net/ipx.h Tue May 6 22:56:23 2003 +++ b/include/net/ipx.h Tue May 6 22:56:23 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/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Tue May 6 22:56:23 2003 +++ b/kernel/ksyms.c Tue May 6 22:56:23 2003 @@ -540,6 +540,7 @@ EXPORT_SYMBOL(seq_lseek); EXPORT_SYMBOL(single_open); EXPORT_SYMBOL(single_release); +EXPORT_SYMBOL(seq_release_private); /* Program loader interfaces */ #ifdef CONFIG_MMU diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c --- a/net/atm/mpc.c Tue May 6 22:56:23 2003 +++ b/net/atm/mpc.c Tue May 6 22:56:23 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; } diff -Nru a/net/atm/svc.c b/net/atm/svc.c --- a/net/atm/svc.c Tue May 6 22:56:23 2003 +++ b/net/atm/svc.c Tue May 6 22:56:23 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(); @@ -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(); @@ -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/core/neighbour.c b/net/core/neighbour.c --- a/net/core/neighbour.c Tue May 6 22:56:23 2003 +++ b/net/core/neighbour.c Tue May 6 22:56:23 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/decnet/Kconfig b/net/decnet/Kconfig --- a/net/decnet/Kconfig Tue May 6 22:56:24 2003 +++ b/net/decnet/Kconfig Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/net/decnet/Makefile Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/decnet/TODO Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/decnet/af_decnet.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/decnet/dn_dev.c Tue May 6 22:56:23 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; @@ -858,7 +866,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 +928,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 +954,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 +998,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 +1025,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 +1336,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 +1408,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]; - + 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, "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; - - 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 +1503,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 Tue May 6 22:56:24 2003 +++ b/net/decnet/dn_fib.c Tue May 6 22:56:24 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) @@ -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 Tue May 6 22:56:23 2003 +++ b/net/decnet/dn_neigh.c Tue May 6 22:56:23 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,23 @@ 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 = { .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 Tue May 6 22:56:23 2003 +++ b/net/decnet/dn_nsp_in.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/net/decnet/dn_nsp_out.c Tue May 6 22:56:24 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 Tue May 6 22:56:24 2003 +++ b/net/decnet/dn_route.c Tue May 6 22:56:24 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_table.c b/net/decnet/dn_table.c --- a/net/decnet/dn_table.c Tue May 6 22:56:23 2003 +++ b/net/decnet/dn_table.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 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 Tue May 6 22:56:24 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 Tue May 6 22:56:24 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/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c --- a/net/ipv4/netfilter/ip_nat_core.c Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_core.c Tue May 6 22:56:23 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,26 @@ 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; if (maniptype == IP_NAT_MANIP_SRC) { iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip, @@ -716,17 +730,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 +758,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 +773,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) < 0) { + READ_UNLOCK(&ip_nat_lock); + return NF_DROP; + } } } helper = info->helper; @@ -839,12 +831,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 +849,51 @@ /* 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; - IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr)); + 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 + && (u16)csum_fold(skb_checksum(*pskb, (*pskb)->nh.iph->ihl*4, + (*pskb)->len, 0))) + return 0; + /* 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 +924,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) < 0) + goto unlock_fail; + /* Outer packet needs to have IP header NATed like it's a reply. */ @@ -932,22 +940,82 @@ 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) < 0) + 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); + inside->icmp.checksum = 0; + inside->icmp.checksum = csum_fold(skb_checksum(*pskb, + (*pskb)->nh.iph->ihl*4, + (*pskb)->len, 0)); + return 1; - return NF_ACCEPT; + 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_helper.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_standalone.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ip_nat_tftp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ipchains_core.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv4/netfilter/ipfwadm_core.c Tue May 6 22:56:23 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/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c Tue May 6 22:56:23 2003 +++ b/net/ipv6/af_inet6.c Tue May 6 22:56:23 2003 @@ -111,7 +111,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) @@ -243,11 +242,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 +253,6 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - module_put(THIS_MODULE); inet_sock_release(sk); return err; } diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c --- a/net/ipv6/exthdrs.c Tue May 6 22:56:23 2003 +++ b/net/ipv6/exthdrs.c Tue May 6 22:56:23 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/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c --- a/net/ipv6/netfilter/ip6t_ah.c Tue May 6 22:56:23 2003 +++ b/net/ipv6/netfilter/ip6t_ah.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv6/netfilter/ip6t_esp.c Tue May 6 22:56:23 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 Tue May 6 22:56:23 2003 +++ b/net/ipv6/netfilter/ip6t_frag.c Tue May 6 22:56:23 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 Tue May 6 22:56:24 2003 +++ b/net/ipv6/netfilter/ip6t_ipv6header.c Tue May 6 22:56:24 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 Tue May 6 22:56:23 2003 +++ b/net/ipv6/netfilter/ip6t_rt.c Tue May 6 22:56:23 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/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c Tue May 6 22:56:23 2003 +++ b/net/ipv6/route.c Tue May 6 22:56:23 2003 @@ -1173,7 +1173,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; } diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c --- a/net/ipx/af_ipx.c Tue May 6 22:56:23 2003 +++ b/net/ipx/af_ipx.c Tue May 6 22:56:23 2003 @@ -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) @@ -380,16 +390,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 +879,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 +909,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) @@ -1278,12 +1277,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 +1307,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 +1334,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 +1362,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); diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c --- a/net/ipx/ipx_proc.c Tue May 6 22:56:23 2003 +++ b/net/ipx/ipx_proc.c Tue May 6 22:56:23 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;