From 3ca5befb279799957fe3594a84213bab2182a85a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 23 Jun 2003 01:23:02 +0000 Subject: [PATCH] Merge with Linux 2.5.73. --- Documentation/firmware_class/README | 58 + .../firmware_class/firmware_sample_driver.c | 126 + .../firmware_sample_firmware_class.c | 205 + Documentation/firmware_class/hotplug-script | 16 + Documentation/kobject.txt | 11 +- Documentation/sched-coding.txt | 2 +- Documentation/usb/dma.txt | 32 +- Documentation/vm/hugetlbpage.txt | 11 +- MAINTAINERS | 6 +- Makefile | 2 +- arch/alpha/Kconfig | 100 +- arch/alpha/kernel/alpha_ksyms.c | 2 +- arch/alpha/kernel/entry.S | 61 +- arch/alpha/kernel/osf_sys.c | 7 +- arch/alpha/kernel/srmcons.c | 1 + arch/alpha/kernel/traps.c | 4 +- arch/alpha/lib/memmove.S | 10 +- arch/alpha/oprofile/common.c | 2 +- arch/arm/Kconfig | 88 +- arch/arm/common/Makefile | 2 + arch/arm/common/amba.c | 243 + arch/arm/common/icst525.c | 160 + arch/arm/kernel/pm.c | 2 + arch/arm/lib/lib1funcs.S | 4 - arch/arm/mach-integrator/core.c | 50 +- arch/arm/mach-integrator/cpu.c | 112 +- arch/arm/mach-sa1100/generic.c | 25 + arch/arm/mach-sa1100/irq.c | 4 +- arch/arm/mm/fault-armv.c | 2 +- arch/arm/mm/mm-armv.c | 4 +- arch/arm/tools/mach-types | 22 +- arch/arm/vmlinux-armv.lds.in | 4 +- arch/arm26/Kconfig | 2 + arch/cris/Kconfig | 31 +- arch/h8300/Kconfig | 7 +- arch/i386/Kconfig | 78 +- arch/i386/kernel/acpi/Makefile | 1 + arch/i386/kernel/acpi/acpitable.c | 553 + arch/i386/kernel/acpi/acpitable.h | 260 + arch/i386/kernel/entry.S | 3 +- arch/i386/kernel/nmi.c | 46 +- arch/i386/kernel/process.c | 2 +- arch/i386/kernel/setup.c | 21 +- arch/i386/kernel/time.c | 10 +- arch/i386/kernel/traps.c | 16 +- arch/i386/mm/hugetlbpage.c | 56 +- arch/i386/mm/init.c | 7 + arch/i386/oprofile/Makefile | 1 + arch/i386/oprofile/init.c | 12 +- arch/i386/oprofile/nmi_int.c | 2 +- arch/i386/oprofile/nmi_timer_int.c | 57 + arch/i386/pci/common.c | 23 +- arch/i386/pci/direct.c | 82 +- arch/i386/pci/fixup.c | 6 +- arch/i386/pci/irq.c | 2 +- arch/i386/pci/legacy.c | 6 +- arch/i386/pci/numa.c | 26 +- arch/i386/pci/pcbios.c | 22 +- arch/i386/pci/pci.h | 2 +- arch/ia64/Kconfig | 87 +- arch/ia64/Makefile | 43 +- arch/ia64/boot/bootloader.c | 7 +- arch/ia64/hp/common/sba_iommu.c | 16 +- arch/ia64/hp/sim/Kconfig | 4 + arch/ia64/hp/sim/Makefile | 3 +- arch/ia64/hp/sim/hpsim_setup.c | 11 +- arch/ia64/hp/sim/simserial.c | 3 + arch/ia64/ia32/binfmt_elf32.c | 3 +- arch/ia64/ia32/ia32_entry.S | 38 +- arch/ia64/ia32/ia32_ioctl.c | 209 +- arch/ia64/ia32/ia32_ldt.c | 3 +- arch/ia64/ia32/ia32_signal.c | 37 +- arch/ia64/ia32/ia32_support.c | 30 +- arch/ia64/ia32/ia32_traps.c | 3 +- .../asm-ia64/ia32.h => arch/ia64/ia32/ia32priv.h | 12 +- arch/ia64/ia32/sys_ia32.c | 98 +- arch/ia64/kernel/Makefile | 34 +- arch/ia64/kernel/acpi-ext.c | 1 - arch/ia64/kernel/acpi.c | 25 +- arch/ia64/kernel/asm-offsets.c | 189 + arch/ia64/kernel/efi_stub.S | 4 +- arch/ia64/kernel/entry.S | 474 +- arch/ia64/kernel/entry.h | 6 +- arch/ia64/kernel/fsys.S | 649 +- arch/ia64/kernel/gate-data.S | 3 + arch/ia64/kernel/gate.S | 115 +- arch/ia64/kernel/gate.lds.S | 95 + arch/ia64/kernel/head.S | 149 +- arch/ia64/kernel/ia64_ksyms.c | 48 +- arch/ia64/kernel/init_task.c | 2 +- arch/ia64/kernel/irq.c | 119 +- arch/ia64/kernel/ivt.S | 453 +- arch/ia64/kernel/mca.c | 58 +- arch/ia64/kernel/mca_asm.S | 12 +- arch/ia64/kernel/minstate.h | 501 +- arch/ia64/kernel/module.c | 55 +- arch/ia64/kernel/pal.S | 10 +- arch/ia64/kernel/patch.c | 194 + arch/ia64/kernel/perfmon.c | 10967 +++++++++++-------- arch/ia64/kernel/perfmon_default_smpl.c | 309 + arch/ia64/kernel/perfmon_generic.h | 25 +- arch/ia64/kernel/perfmon_itanium.h | 41 +- arch/ia64/kernel/perfmon_mckinley.h | 95 +- arch/ia64/kernel/process.c | 128 +- arch/ia64/kernel/ptrace.c | 198 +- arch/ia64/kernel/setup.c | 74 +- arch/ia64/kernel/signal.c | 96 +- arch/ia64/kernel/smpboot.c | 9 +- arch/ia64/kernel/sys_ia64.c | 2 +- arch/ia64/kernel/time.c | 68 +- arch/ia64/kernel/traps.c | 29 +- arch/ia64/kernel/unaligned.c | 3 +- arch/ia64/kernel/unwind.c | 265 +- arch/ia64/lib/Makefile | 6 + arch/ia64/lib/idiv64.S | 35 +- arch/ia64/lib/memcpy_mck.S | 6 +- arch/ia64/lib/xor.S | 184 + arch/ia64/mm/discontig.c | 8 +- arch/ia64/mm/fault.c | 37 + arch/ia64/mm/hugetlbpage.c | 2 +- arch/ia64/mm/init.c | 142 +- arch/ia64/mm/tlb.c | 46 +- arch/ia64/pci/pci.c | 33 +- arch/ia64/scripts/check-gas | 7 +- arch/ia64/scripts/check-segrel.S | 4 + arch/ia64/scripts/check-segrel.lds | 11 + arch/ia64/scripts/toolchain-flags | 22 + arch/ia64/sn/Makefile | 2 +- arch/ia64/sn/fakeprom/README | 2 +- arch/ia64/sn/fakeprom/fpmem.c | 52 +- arch/ia64/sn/fakeprom/fpmem.h | 33 +- arch/ia64/sn/fakeprom/fpromasm.S | 18 +- arch/ia64/sn/fakeprom/fw-emu.c | 56 +- .../{io/klgraph_hack.c => fakeprom/klgraph_init.c} | 220 +- arch/ia64/sn/fakeprom/main.c | 18 +- arch/ia64/sn/fakeprom/make_textsym | 7 +- arch/ia64/sn/io/Makefile | 15 +- arch/ia64/sn/io/alenlist.c | 899 -- arch/ia64/sn/io/ate_utils.c | 3 +- arch/ia64/sn/io/cdl.c | 140 +- arch/ia64/sn/io/drivers/Makefile | 12 + arch/ia64/sn/io/{ => drivers}/ifconfig_net.c | 8 +- arch/ia64/sn/io/{ => drivers}/ioconfig_bus.c | 35 +- arch/ia64/sn/io/eeprom.c | 1454 --- arch/ia64/sn/io/efi-rtc.c | 185 - arch/ia64/sn/io/hcl.c | 1515 --- arch/ia64/sn/io/hubdev.c | 132 - arch/ia64/sn/io/hubspc.c | 251 - arch/ia64/sn/io/hwgfs/Makefile | 13 + arch/ia64/sn/io/hwgfs/hcl.c | 938 ++ arch/ia64/sn/io/{ => hwgfs}/hcl_util.c | 38 +- arch/ia64/sn/io/hwgfs/interface.c | 353 + arch/ia64/sn/io/hwgfs/invent_stub.c | 148 + arch/ia64/sn/io/{ => hwgfs}/labelcl.c | 61 +- arch/ia64/sn/io/hwgfs/ramfs.c | 233 + arch/ia64/sn/io/invent.c | 224 - arch/ia64/sn/io/io.c | 198 +- arch/ia64/sn/io/klconflib.c | 1040 -- arch/ia64/sn/io/klgraph.c | 804 -- arch/ia64/sn/io/l1.c | 3056 ------ arch/ia64/sn/io/l1_command.c | 1377 --- arch/ia64/sn/io/machvec/Makefile | 12 + arch/ia64/sn/{kernel/sn2 => io/machvec}/iomv.c | 2 +- arch/ia64/sn/io/machvec/pci.c | 135 + arch/ia64/sn/io/{sn2 => machvec}/pci_bus_cvlink.c | 321 +- arch/ia64/sn/io/{ => machvec}/pci_dma.c | 353 +- arch/ia64/sn/io/ml_SN_init.c | 235 - arch/ia64/sn/io/ml_iograph.c | 1570 --- arch/ia64/sn/io/module.c | 312 - arch/ia64/sn/io/pci.c | 294 - arch/ia64/sn/io/pci_bus_cvlink.c | 737 -- arch/ia64/sn/io/pciba.c | 950 -- arch/ia64/sn/io/pciio.c | 1507 --- arch/ia64/sn/io/platform_init/Makefile | 12 + arch/ia64/sn/io/platform_init/irix_io_init.c | 88 + arch/ia64/sn/io/platform_init/sgi_io_init.c | 109 + arch/ia64/sn/io/sgi_if.c | 39 +- arch/ia64/sn/io/sgi_io_init.c | 308 - arch/ia64/sn/io/sgi_io_sim.c | 77 +- arch/ia64/sn/io/sn1/hub_intr.c | 307 - arch/ia64/sn/io/sn1/hubcounters.c | 283 - arch/ia64/sn/io/sn1/huberror.c | 228 - arch/ia64/sn/io/sn1/ip37.c | 47 - arch/ia64/sn/io/sn1/mem_refcnt.c | 220 - arch/ia64/sn/io/sn1/ml_SN_intr.c | 1154 -- arch/ia64/sn/io/sn1/pcibr.c | 7704 ------------- arch/ia64/sn/io/sn2/Makefile | 7 +- arch/ia64/sn/io/sn2/bte_error.c | 410 +- arch/ia64/sn/io/sn2/kdba_io.c | 76 + arch/ia64/sn/io/sn2/klconflib.c | 270 +- arch/ia64/sn/io/sn2/klgraph.c | 74 +- arch/ia64/sn/io/sn2/l1.c | 87 +- arch/ia64/sn/io/sn2/l1_command.c | 104 +- arch/ia64/sn/io/sn2/ml_SN_init.c | 26 - arch/ia64/sn/io/sn2/ml_SN_intr.c | 95 +- arch/ia64/sn/io/sn2/ml_iograph.c | 441 +- arch/ia64/sn/io/sn2/module.c | 1 - arch/ia64/sn/io/sn2/pcibr/Makefile | 10 +- arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c | 95 +- arch/ia64/sn/io/sn2/pcibr/pcibr_config.c | 196 +- arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c | 1219 +-- arch/ia64/sn/io/sn2/pcibr/pcibr_error.c | 445 +- arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c | 35 +- arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c | 147 - arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c | 187 +- arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c | 190 +- arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c | 457 +- arch/ia64/sn/io/sn2/pciio.c | 442 +- arch/ia64/sn/io/sn2/pic.c | 57 +- arch/ia64/sn/io/sn2/sgi_io_init.c | 226 - arch/ia64/sn/io/sn2/shub.c | 269 +- arch/ia64/sn/io/sn2/shub_intr.c | 33 +- arch/ia64/sn/io/sn2/shuberror.c | 306 +- arch/ia64/sn/io/sn2/shubio.c | 34 +- arch/ia64/sn/io/sn2/xbow.c | 355 +- arch/ia64/sn/io/sn2/xtalk.c | 281 +- arch/ia64/sn/io/stubs.c | 140 - arch/ia64/sn/io/xbow.c | 1325 --- arch/ia64/sn/io/xswitch.c | 71 +- arch/ia64/sn/io/xtalk.c | 1024 -- arch/ia64/sn/kernel/Makefile | 6 +- arch/ia64/sn/kernel/bte.c | 321 +- arch/ia64/sn/kernel/idle.c | 36 + arch/ia64/sn/kernel/iomv.c | 115 - arch/ia64/sn/kernel/irq.c | 328 +- arch/ia64/sn/kernel/llsc4.c | 1044 -- arch/ia64/sn/kernel/llsc4.h | 107 - arch/ia64/sn/kernel/machvec.c | 31 +- arch/ia64/sn/kernel/mca.c | 414 +- arch/ia64/sn/kernel/misctest.c | 371 - arch/ia64/sn/kernel/probe.c | 2 +- arch/ia64/sn/kernel/setup.c | 281 +- arch/ia64/sn/kernel/sn1/Makefile | 45 - arch/ia64/sn/kernel/sn1/cache.c | 81 - arch/ia64/sn/kernel/sn1/error.c | 187 - arch/ia64/sn/kernel/sn1/iomv.c | 65 - arch/ia64/sn/kernel/sn1/sn1_smp.c | 476 - arch/ia64/sn/kernel/sn1/synergy.c | 533 - arch/ia64/sn/kernel/sn2/Makefile | 3 +- arch/ia64/sn/kernel/sn2/cache.c | 5 +- arch/ia64/sn/kernel/sn2/io.c | 9 +- arch/ia64/sn/kernel/sn2/prominfo_proc.c | 361 + arch/ia64/sn/kernel/sn2/sn2_smp.c | 333 +- arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 52 +- arch/ia64/sn/kernel/sn2/timer.c | 76 + arch/ia64/sn/kernel/sn_asm.S | 107 - arch/ia64/sn/kernel/sn_ksyms.c | 43 +- arch/ia64/sn/kernel/sv.c | 2 +- arch/ia64/tools/Makefile | 51 - arch/ia64/tools/print_offsets.awk | 72 - arch/ia64/tools/print_offsets.c | 220 - arch/ia64/vmlinux.lds.S | 68 +- arch/m68k/Kconfig | 490 +- arch/m68knommu/Kconfig | 13 +- arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S | 7 + arch/m68knommu/platform/5249/config.c | 6 + arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S | 7 + arch/m68knommu/platform/5272/config.c | 5 +- arch/mips/Kconfig-shared | 59 +- arch/mips/defconfig | 21 +- arch/mips/defconfig-atlas | 13 +- arch/mips/defconfig-capcella | 5 + arch/mips/defconfig-cobalt | 5 + arch/mips/defconfig-ddb5476 | 5 + arch/mips/defconfig-ddb5477 | 5 + arch/mips/defconfig-decstation | 19 +- arch/mips/defconfig-e55 | 5 + arch/mips/defconfig-eagle | 5 + arch/mips/defconfig-ev64120 | 7 +- arch/mips/defconfig-ev96100 | 7 +- arch/mips/defconfig-hp-lj | 5 + arch/mips/defconfig-ip22 | 21 +- arch/mips/defconfig-it8172 | 5 + arch/mips/defconfig-ivr | 5 + arch/mips/defconfig-jmr3927 | 7 +- arch/mips/defconfig-lasat200 | 5 + arch/mips/defconfig-malta | 19 +- arch/mips/defconfig-mpc30x | 5 + arch/mips/defconfig-ocelot | 7 +- arch/mips/defconfig-osprey | 5 + arch/mips/defconfig-pb1000 | 5 + arch/mips/defconfig-pb1100 | 5 + arch/mips/defconfig-pb1500 | 5 + arch/mips/defconfig-rm200 | 7 +- arch/mips/defconfig-sb1250-swarm | 7 +- arch/mips/defconfig-sead | 5 + arch/mips/defconfig-tb0226 | 19 +- arch/mips/defconfig-tb0229 | 5 + arch/mips/defconfig-workpad | 5 + arch/mips/kernel/syscalls.h | 2 + arch/mips/kernel/traps.c | 14 +- arch/mips64/defconfig | 13 +- arch/mips64/defconfig-atlas | 21 +- arch/mips64/defconfig-decstation | 21 +- arch/mips64/defconfig-ip22 | 21 +- arch/mips64/defconfig-ip27 | 13 +- arch/mips64/defconfig-ip32 | 13 +- arch/mips64/defconfig-malta | 21 +- arch/mips64/defconfig-rm200 | 9 +- arch/mips64/defconfig-sb1250-swarm | 7 +- arch/mips64/defconfig-sead | 7 +- arch/mips64/kernel/binfmt_elfn32.c | 14 +- arch/mips64/kernel/binfmt_elfo32.c | 14 +- arch/mips64/kernel/scall_n32.S | 2 + arch/mips64/kernel/scall_o32.S | 2 + arch/mips64/kernel/traps.c | 14 +- arch/parisc/Kconfig | 63 +- arch/ppc/Kconfig | 35 +- arch/ppc64/Kconfig | 34 +- arch/ppc64/kernel/process.c | 17 +- arch/s390/Kconfig | 74 +- arch/sh/Kconfig | 59 +- arch/sparc/Kconfig | 305 +- arch/sparc/kernel/time.c | 8 +- arch/sparc64/Kconfig | 693 +- arch/sparc64/defconfig | 78 +- arch/sparc64/kernel/time.c | 8 +- arch/um/Kconfig | 11 +- arch/v850/Kconfig | 13 +- arch/v850/vmlinux.lds.S | 15 +- arch/x86_64/Kconfig | 28 +- drivers/acpi/Kconfig | 31 +- drivers/acpi/Makefile | 1 + drivers/acpi/asus_acpi.c | 951 ++ drivers/acpi/dispatcher/dsmthdat.c | 25 +- drivers/acpi/events/evgpe.c | 8 +- drivers/acpi/events/evgpeblk.c | 29 +- drivers/acpi/executer/exoparg1.c | 77 +- drivers/acpi/executer/exstore.c | 4 +- drivers/acpi/executer/exsystem.c | 4 +- drivers/acpi/executer/exutils.c | 5 +- drivers/acpi/hardware/hwregs.c | 47 +- drivers/acpi/hardware/hwsleep.c | 4 +- drivers/acpi/osl.c | 41 +- drivers/acpi/pci_root.c | 2 - drivers/acpi/tables/tbconvrt.c | 26 +- drivers/acpi/utilities/utmisc.c | 2 + drivers/atm/he.c | 3 +- drivers/base/Kconfig | 10 + drivers/base/Makefile | 1 + drivers/base/firmware_class.c | 505 + drivers/base/sys.c | 8 +- drivers/block/cciss_scsi.c | 4 +- drivers/block/ll_rw_blk.c | 3 - drivers/block/rd.c | 5 +- drivers/char/keyboard.c | 2 +- drivers/char/moxa.c | 3 +- drivers/char/raw.c | 16 + drivers/char/vt.c | 3 +- drivers/char/vt_ioctl.c | 2 + drivers/i2c/busses/i2c-ali15x3.c | 18 +- drivers/i2c/busses/i2c-i801.c | 10 +- drivers/i2c/chips/Kconfig | 14 + drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/adm1021.c | 18 +- drivers/i2c/chips/lm78.c | 895 ++ drivers/i2c/chips/lm85.c | 41 +- drivers/i2c/chips/w83781d.c | 84 +- drivers/ide/pci/sis5513.c | 464 +- drivers/ieee1394/sbp2.c | 8 +- drivers/input/gameport/gameport.c | 4 +- drivers/input/joystick/gamecon.c | 18 +- drivers/input/joystick/sidewinder.c | 11 +- drivers/input/keyboard/atkbd.c | 8 +- drivers/input/misc/uinput.c | 5 +- drivers/input/mouse/Kconfig | 17 +- drivers/input/mouse/Makefile | 5 +- drivers/input/mouse/logips2pp.c | 228 + drivers/input/mouse/logips2pp.h | 17 + drivers/input/mouse/psmouse-base.c | 193 +- drivers/input/mouse/psmouse.h | 2 + drivers/input/mouse/synaptics.c | 7 +- drivers/input/mouse/synaptics.h | 10 - drivers/input/serio/ambakmi.c | 89 +- drivers/input/serio/serio.c | 13 + drivers/isdn/act2000/Makefile | 2 +- drivers/isdn/capi/Makefile | 1 - drivers/isdn/divert/Makefile | 2 +- drivers/isdn/eicon/Makefile | 40 +- drivers/isdn/eicon/eicon_isa.c | 4 +- drivers/isdn/hardware/avm/b1pci.c | 4 +- drivers/isdn/hardware/avm/b1pcmcia.c | 2 +- drivers/isdn/hardware/avm/t1pci.c | 2 +- drivers/isdn/hardware/eicon/Makefile | 48 +- drivers/isdn/hisax/Makefile | 124 +- drivers/isdn/hisax/avma1_cs.c | 6 + drivers/isdn/hysdn/Makefile | 13 +- drivers/isdn/hysdn/hysdn_proclog.c | 6 +- drivers/isdn/i4l/Makefile | 45 +- drivers/isdn/i4l/isdn_bsdcomp.c | 4 +- drivers/isdn/i4l/isdn_ppp_ccp.c | 100 +- drivers/isdn/i4l/isdn_tty.c | 15 +- drivers/isdn/i4l/isdn_ttyfax.c | 2 +- drivers/isdn/isdnloop/Makefile | 2 - drivers/isdn/pcbit/Makefile | 2 +- drivers/isdn/sc/Makefile | 4 +- drivers/isdn/tpam/Makefile | 5 +- drivers/isdn/tpam/tpam_queues.c | 1 + drivers/md/dm-ioctl.c | 3 +- drivers/message/i2o/i2o_scsi.c | 29 - drivers/net/amd8111e.c | 12 +- drivers/net/bonding/bond_main.c | 257 +- drivers/net/bonding/bonding.h | 2 +- drivers/net/hamradio/baycom_epp.c | 2 - drivers/net/hamradio/yam.c | 12 +- drivers/net/ixgb/ixgb_ethtool.c | 1 - drivers/net/myri_sbus.c | 11 +- drivers/net/pcmcia/xirc2ps_cs.c | 93 +- drivers/net/pcnet32.c | 2 +- drivers/net/plip.c | 5 +- drivers/net/ppp_async.c | 4 +- drivers/net/pppoe.c | 1 + drivers/net/rcpci45.c | 24 +- drivers/net/shaper.c | 37 +- drivers/net/sis900.c | 1 + drivers/net/sundance.c | 6 +- drivers/net/tulip/Kconfig | 2 +- drivers/net/wan/syncppp.c | 102 +- drivers/net/wireless/airo.c | 2 +- drivers/net/wireless/atmel.c | 2 +- drivers/oprofile/buffer_sync.c | 10 +- drivers/pci/bus.c | 6 + drivers/pci/hotplug.c | 34 +- drivers/pci/hotplug/acpiphp.h | 16 +- drivers/pci/hotplug/acpiphp_core.c | 15 +- drivers/pci/hotplug/acpiphp_glue.c | 50 +- drivers/pci/hotplug/acpiphp_pci.c | 4 +- drivers/pci/hotplug/acpiphp_res.c | 4 +- drivers/pci/pci-driver.c | 20 +- drivers/pci/pci-sysfs.c | 24 +- drivers/pci/pci.h | 3 + drivers/pci/probe.c | 2 +- drivers/pci/proc.c | 46 +- drivers/pci/quirks.c | 4 + drivers/pci/search.c | 151 +- drivers/pcmcia/Makefile | 2 +- drivers/pcmcia/cistpl.c | 3 +- drivers/pcmcia/cs.c | 6 +- drivers/pcmcia/cs_internal.h | 2 +- drivers/pcmcia/i82365.c | 7 +- drivers/pcmcia/rsrc_mgr.c | 163 +- drivers/pcmcia/{yenta.c => yenta_socket.c} | 4 +- drivers/pcmcia/{yenta.h => yenta_socket.h} | 0 drivers/pnp/base.h | 46 +- drivers/pnp/core.c | 6 +- drivers/pnp/interface.c | 206 +- drivers/pnp/isapnp/core.c | 203 +- drivers/pnp/manager.c | 1294 +-- drivers/pnp/pnpbios/core.c | 4 + drivers/pnp/quirks.c | 18 +- drivers/pnp/resource.c | 510 +- drivers/pnp/support.c | 141 +- drivers/scsi/53c700.c | 34 +- drivers/scsi/53c700.h | 124 +- drivers/scsi/AM53C974.c | 17 - drivers/scsi/Kconfig | 314 +- drivers/scsi/NCR53c406a.c | 47 +- drivers/scsi/NCR_D700.c | 4 +- drivers/scsi/aacraid/aachba.c | 10 +- drivers/scsi/aha152x.c | 11 - drivers/scsi/aha1542.c | 31 +- drivers/scsi/aha1740.c | 30 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 +- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 4 + drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 +- drivers/scsi/amiga7xx.c | 13 + drivers/scsi/arm/acornscsi.c | 5 +- drivers/scsi/arm/arxescsi.c | 1 - drivers/scsi/arm/cumana_1.c | 6 +- drivers/scsi/arm/cumana_2.c | 1 - drivers/scsi/arm/ecoscsi.c | 6 +- drivers/scsi/arm/eesox.c | 1 - drivers/scsi/arm/fas216.c | 72 +- drivers/scsi/arm/fas216.h | 9 - drivers/scsi/arm/oak.c | 6 +- drivers/scsi/arm/powertec.c | 6 +- drivers/scsi/atp870u.c | 20 - drivers/scsi/atp870u.h | 1 - drivers/scsi/blz1230.c | 1 - drivers/scsi/bvme6000.c | 13 + drivers/scsi/constants.c | 14 +- drivers/scsi/dc395x.c | 8 +- drivers/scsi/dec_esp.c | 12 +- drivers/scsi/dpt_i2o.c | 24 - drivers/scsi/dtc.c | 11 + drivers/scsi/eata.c | 214 +- drivers/scsi/eata.h | 15 - drivers/scsi/esp.c | 11 - drivers/scsi/fd_mcs.c | 19 - drivers/scsi/fdomain.c | 96 - drivers/scsi/hosts.c | 876 +- drivers/scsi/hosts.h | 671 +- drivers/scsi/ibmmca.c | 10 - drivers/scsi/ide-scsi.c | 6 +- drivers/scsi/imm.c | 34 - drivers/scsi/ini9100u.c | 10 - drivers/scsi/inia100.c | 8 +- drivers/scsi/ips.c | 6 +- drivers/scsi/jazz_esp.c | 14 +- drivers/scsi/lasi700.c | 159 +- drivers/scsi/mac_esp.c | 12 +- drivers/scsi/megaraid.c | 250 +- drivers/scsi/megaraid.h | 12 +- drivers/scsi/mesh.c | 3 - drivers/scsi/mvme16x.c | 13 + drivers/scsi/nsp32.c | 4 +- drivers/scsi/pas16.c | 13 + drivers/scsi/pci2000.c | 36 - drivers/scsi/pci2220i.c | 23 - drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/scsi/ppa.c | 34 - drivers/scsi/psi240i.c | 38 +- drivers/scsi/qlogicfas.c | 54 +- drivers/scsi/scsi.c | 67 +- drivers/scsi/scsi.h | 930 +- drivers/scsi/scsi_debug.c | 7 +- drivers/scsi/scsi_devinfo.c | 41 +- drivers/scsi/scsi_error.c | 109 +- drivers/scsi/scsi_ioctl.c | 202 +- drivers/scsi/scsi_lib.c | 44 +- drivers/scsi/scsi_module.c | 144 +- drivers/scsi/scsi_priv.h | 16 +- drivers/scsi/scsi_proc.c | 64 +- drivers/scsi/scsi_scan.c | 73 +- drivers/scsi/scsi_syms.c | 6 +- drivers/scsi/scsi_sysfs.c | 2 +- drivers/scsi/scsi_typedefs.h | 6 + drivers/scsi/sd.c | 218 +- drivers/scsi/seagate.c | 8 - drivers/scsi/sim710.c | 16 +- drivers/scsi/sr.c | 1 - drivers/scsi/st.c | 20 +- drivers/scsi/sun3x_esp.c | 1 - drivers/scsi/sym53c416.c | 15 - drivers/scsi/t128.c | 11 + drivers/scsi/u14-34f.c | 210 +- drivers/scsi/u14-34f.h | 14 - drivers/scsi/ultrastor.c | 13 + drivers/scsi/wd7000.c | 33 +- drivers/serial/8250_pnp.c | 62 +- drivers/serial/Kconfig | 10 +- drivers/serial/Makefile | 3 +- drivers/telephony/ixj.c | 4 +- drivers/telephony/ixj.h | 6 +- drivers/usb/Makefile.lib | 1 + drivers/usb/class/audio.c | 28 +- drivers/usb/class/bluetty.c | 2 +- drivers/usb/class/cdc-acm.c | 189 +- drivers/usb/class/usb-midi.c | 4 +- drivers/usb/class/usblp.c | 36 +- drivers/usb/core/hcd.c | 28 +- drivers/usb/core/hub.c | 2 +- drivers/usb/core/message.c | 3 +- drivers/usb/core/urb.c | 2 +- drivers/usb/core/usb.c | 56 +- drivers/usb/gadget/net2280.c | 4 +- drivers/usb/host/ehci-dbg.c | 48 +- drivers/usb/host/ehci-hcd.c | 16 +- drivers/usb/host/ehci-q.c | 47 +- drivers/usb/host/ehci.h | 5 +- drivers/usb/image/hpusbscsi.c | 4 +- drivers/usb/image/microtek.c | 4 +- drivers/usb/input/aiptek.c | 2 +- drivers/usb/input/hid-core.c | 14 +- drivers/usb/input/kbtab.c | 2 +- drivers/usb/input/powermate.c | 4 +- drivers/usb/input/usbkbd.c | 5 +- drivers/usb/input/usbmouse.c | 2 +- drivers/usb/input/wacom.c | 2 +- drivers/usb/input/xpad.c | 2 +- drivers/usb/misc/auerswald.c | 10 +- drivers/usb/misc/brlvger.c | 10 +- drivers/usb/misc/rio500.c | 10 +- drivers/usb/misc/rio500_usb.h | 2 +- drivers/usb/misc/speedtch.c | 109 +- drivers/usb/misc/tiglusb.c | 4 +- drivers/usb/misc/usblcd.c | 8 +- drivers/usb/misc/usbtest.c | 2 +- drivers/usb/net/Kconfig | 24 +- drivers/usb/net/Makefile | 1 + drivers/usb/net/Makefile.mii | 1 + drivers/usb/net/ax8817x.c | 1341 +++ drivers/usb/net/catc.c | 4 +- drivers/usb/net/kaweth.c | 50 +- drivers/usb/net/pegasus.c | 6 +- drivers/usb/net/rtl8150.c | 4 +- drivers/usb/net/usbnet.c | 12 +- drivers/usb/storage/isd200.c | 31 +- drivers/usb/storage/protocol.c | 4 + drivers/usb/storage/protocol.h | 2 + drivers/usb/storage/scsiglue.c | 195 +- drivers/usb/storage/scsiglue.h | 2 +- drivers/usb/storage/transport.c | 35 +- drivers/usb/storage/transport.h | 8 +- drivers/usb/storage/unusual_devs.h | 104 +- drivers/usb/storage/usb.c | 74 +- drivers/usb/storage/usb.h | 6 +- fs/Kconfig.binfmt | 116 + fs/adfs/super.c | 4 +- fs/affs/super.c | 4 +- fs/befs/linuxvfs.c | 4 +- fs/bfs/inode.c | 2 +- fs/binfmt_elf.c | 2 +- fs/cifs/CHANGES | 14 + fs/cifs/asn1.c | 2 +- fs/cifs/cifs_fs_sb.h | 4 + fs/cifs/cifsfs.c | 24 +- fs/cifs/cifsproto.h | 4 +- fs/cifs/cifssmb.c | 7 +- fs/cifs/connect.c | 19 +- fs/cifs/file.c | 34 +- fs/cifs/inode.c | 26 +- fs/cifs/misc.c | 8 +- fs/cifs/netmisc.c | 6 +- fs/cifs/transport.c | 2 +- fs/coda/inode.c | 4 +- fs/coda/upcall.c | 2 +- fs/compat.c | 16 +- fs/cramfs/inode.c | 2 +- fs/efs/super.c | 2 +- fs/ext2/super.c | 4 +- fs/ext3/acl.c | 6 +- fs/ext3/balloc.c | 375 +- fs/ext3/bitmap.c | 2 +- fs/ext3/dir.c | 15 +- fs/ext3/file.c | 6 +- fs/ext3/hash.c | 12 +- fs/ext3/ialloc.c | 185 +- fs/ext3/inode.c | 538 +- fs/ext3/ioctl.c | 18 +- fs/ext3/namei.c | 124 +- fs/ext3/super.c | 99 +- fs/ext3/xattr.c | 16 +- fs/fat/inode.c | 2 +- fs/freevxfs/vxfs_super.c | 4 +- fs/fs-writeback.c | 19 +- fs/hfs/super.c | 4 +- fs/hpfs/hpfs_fn.h | 2 +- fs/hpfs/super.c | 2 +- fs/hugetlbfs/inode.c | 237 +- fs/intermezzo/intermezzo_fs.h | 2 +- fs/isofs/inode.c | 4 +- fs/jbd/checkpoint.c | 286 +- fs/jbd/commit.c | 263 +- fs/jbd/journal.c | 685 +- fs/jbd/recovery.c | 62 +- fs/jbd/revoke.c | 141 +- fs/jbd/transaction.c | 830 +- fs/jfs/super.c | 2 +- fs/libfs.c | 2 +- fs/lockd/svc.c | 7 +- fs/minix/inode.c | 4 +- fs/namei.c | 4 + fs/ncpfs/inode.c | 4 +- fs/ncpfs/sock.c | 4 +- fs/nfs/inode.c | 5 +- fs/nfsd/auth.c | 4 - fs/nfsd/export.c | 8 +- fs/nfsd/nfs3xdr.c | 2 +- fs/nfsd/nfs4proc.c | 6 - fs/nfsd/nfs4state.c | 127 +- fs/nfsd/nfs4xdr.c | 29 +- fs/nfsd/nfsctl.c | 1 - fs/nfsd/nfsfh.c | 7 +- fs/nfsd/nfsproc.c | 1 + fs/nfsd/nfssvc.c | 1 + fs/nfsd/nfsxdr.c | 2 +- fs/nfsd/vfs.c | 70 +- fs/ntfs/super.c | 2 +- fs/open.c | 115 +- fs/partitions/Kconfig | 12 +- fs/partitions/acorn.c | 241 +- fs/partitions/acorn.h | 67 +- fs/partitions/check.c | 28 +- fs/proc/base.c | 6 +- fs/proc/kcore.c | 16 +- fs/proc/task_mmu.c | 6 +- fs/qnx4/inode.c | 4 +- fs/reiserfs/super.c | 6 +- fs/romfs/inode.c | 2 +- fs/smbfs/inode.c | 4 +- fs/smbfs/proc.c | 2 +- fs/smbfs/proto.h | 2 +- fs/super.c | 2 +- fs/sysv/inode.c | 2 +- fs/udf/super.c | 4 +- fs/ufs/super.c | 6 +- fs/xfs/linux/xfs_super.c | 4 +- fs/xfs/linux/xfs_vfs.c | 2 +- fs/xfs/linux/xfs_vfs.h | 6 +- fs/xfs/xfs_vfsops.c | 4 +- include/acpi/acconfig.h | 2 +- include/acpi/acglobal.h | 1 + include/acpi/achware.h | 2 +- include/acpi/acpiosxf.h | 8 +- include/acpi/actypes.h | 19 +- include/asm-alpha/pci.h | 12 + include/asm-alpha/smp.h | 9 + include/asm-alpha/statfs.h | 21 +- include/asm-alpha/unistd.h | 8 +- include/asm-alpha/xor.h | 20 +- include/asm-arm/hardware/amba.h | 44 + include/asm-arm/hardware/icst525.h | 36 + include/asm-arm/memory.h | 8 +- include/asm-arm/proc-armv/uaccess.h | 12 +- include/asm-arm/statfs.h | 21 +- include/asm-cris/statfs.h | 21 +- include/asm-generic/statfs.h | 37 + include/asm-h8300/statfs.h | 21 +- include/asm-h8300/uaccess.h | 4 +- include/asm-i386/acpi.h | 5 + include/asm-i386/apic.h | 2 + include/asm-i386/genapic.h | 2 + include/asm-i386/mach-default/mach_resources.h | 8 +- include/asm-i386/mach-generic/mach_apic.h | 1 + include/asm-i386/mach-pc9800/setup_arch_pre.h | 4 +- include/asm-i386/processor.h | 1 + include/asm-i386/smp.h | 4 +- include/asm-i386/statfs.h | 21 +- include/asm-i386/uaccess.h | 3 + include/asm-i386/unistd.h | 4 +- include/asm-ia64/a.out.h | 5 +- include/asm-ia64/asmmacro.h | 26 +- include/asm-ia64/compat.h | 10 +- include/asm-ia64/elf.h | 147 +- include/asm-ia64/ia32.h | 503 +- include/asm-ia64/io.h | 13 + include/asm-ia64/ioctl32.h | 1 + include/asm-ia64/kregs.h | 2 +- include/asm-ia64/machvec.h | 2 - include/asm-ia64/mca.h | 2 + include/asm-ia64/mca_asm.h | 2 +- include/asm-ia64/nodedata.h | 1 + include/asm-ia64/page.h | 7 +- include/asm-ia64/patch.h | 25 + include/asm-ia64/pci.h | 26 +- include/asm-ia64/perfmon.h | 459 +- include/asm-ia64/perfmon_default_smpl.h | 81 + include/asm-ia64/pgalloc.h | 25 - include/asm-ia64/pgtable.h | 48 +- include/asm-ia64/processor.h | 118 +- include/asm-ia64/ptrace.h | 60 +- include/asm-ia64/ptrace_offsets.h | 65 +- include/asm-ia64/resource.h | 4 +- include/asm-ia64/sal.h | 19 +- include/asm-ia64/sigcontext.h | 2 +- include/asm-ia64/siginfo.h | 24 +- include/asm-ia64/smp.h | 4 +- include/asm-ia64/sn/addrs.h | 100 +- include/asm-ia64/sn/alenlist.h | 2 +- include/asm-ia64/sn/arc/hinv.h | 4 +- include/asm-ia64/sn/arc/types.h | 2 +- include/asm-ia64/sn/arch.h | 13 +- include/asm-ia64/sn/ate_utils.h | 2 +- include/asm-ia64/sn/bte.h | 142 +- include/asm-ia64/sn/bte_copy.h | 385 - include/asm-ia64/sn/cdl.h | 236 +- include/asm-ia64/sn/clksupport.h | 22 +- include/asm-ia64/sn/dmamap.h | 5 +- include/asm-ia64/sn/driver.h | 6 +- include/asm-ia64/sn/eeprom.h | 384 - include/asm-ia64/sn/fetchop.h | 42 +- include/asm-ia64/sn/gda.h | 109 - include/asm-ia64/sn/geo.h | 8 - include/asm-ia64/sn/hack.h | 69 - include/asm-ia64/sn/hcl.h | 225 +- include/asm-ia64/sn/hcl_util.h | 14 +- include/asm-ia64/sn/hires_clock.h | 52 - include/asm-ia64/sn/hwgfs.h | 35 + include/asm-ia64/sn/idle.h | 57 - include/asm-ia64/sn/ifconfig_net.h | 2 +- include/asm-ia64/sn/intr.h | 11 +- include/asm-ia64/sn/intr_public.h | 19 - include/asm-ia64/sn/invent.h | 19 +- include/asm-ia64/sn/io.h | 19 - include/asm-ia64/sn/ioc3.h | 2 +- include/asm-ia64/sn/ioc4.h | 801 ++ include/asm-ia64/sn/ioerror.h | 4 +- include/asm-ia64/sn/ioerror_handling.h | 35 +- include/asm-ia64/sn/iograph.h | 10 +- include/asm-ia64/sn/klclock.h | 2 +- include/asm-ia64/sn/klconfig.h | 102 +- include/asm-ia64/sn/kldir.h | 2 +- include/asm-ia64/sn/ksys/elsc.h | 78 +- include/asm-ia64/sn/ksys/l1.h | 228 +- include/asm-ia64/sn/labelcl.h | 22 +- include/asm-ia64/sn/leds.h | 25 +- include/asm-ia64/sn/mca.h | 128 - include/asm-ia64/sn/mmtimer_private.h | 2 +- include/asm-ia64/sn/module.h | 130 +- include/asm-ia64/sn/nag.h | 2 +- include/asm-ia64/sn/nic.h | 129 - include/asm-ia64/sn/nodepda.h | 85 +- include/asm-ia64/sn/pci/bridge.h | 345 +- include/asm-ia64/sn/pci/pci_bus_cvlink.h | 7 +- include/asm-ia64/sn/pci/pci_defs.h | 111 +- include/asm-ia64/sn/pci/pciba.h | 121 - include/asm-ia64/sn/pci/pcibr.h | 102 +- include/asm-ia64/sn/pci/pcibr_private.h | 80 +- include/asm-ia64/sn/pci/pciio.h | 141 +- include/asm-ia64/sn/pci/pciio_private.h | 12 +- include/asm-ia64/sn/pda.h | 35 +- include/asm-ia64/sn/pio.h | 58 +- include/asm-ia64/sn/pio_flush.h | 65 - include/asm-ia64/sn/prio.h | 2 +- include/asm-ia64/sn/router.h | 17 +- include/asm-ia64/sn/sgi.h | 65 +- include/asm-ia64/sn/simulator.h | 2 +- include/asm-ia64/sn/slotnum.h | 11 +- include/asm-ia64/sn/sn1/addrs.h | 275 - include/asm-ia64/sn/sn1/arch.h | 89 - include/asm-ia64/sn/sn1/bedrock.h | 74 - include/asm-ia64/sn/sn1/hubdev.h | 21 - include/asm-ia64/sn/sn1/hubio.h | 5016 --------- include/asm-ia64/sn/sn1/hubio_next.h | 762 -- include/asm-ia64/sn/sn1/hublb.h | 1607 --- include/asm-ia64/sn/sn1/hublb_next.h | 109 - include/asm-ia64/sn/sn1/hubmd.h | 2476 ----- include/asm-ia64/sn/sn1/hubmd_next.h | 812 -- include/asm-ia64/sn/sn1/hubni.h | 1781 --- include/asm-ia64/sn/sn1/hubni_next.h | 174 - include/asm-ia64/sn/sn1/hubpi.h | 4263 ------- include/asm-ia64/sn/sn1/hubpi_next.h | 331 - include/asm-ia64/sn/sn1/hubspc.h | 24 - include/asm-ia64/sn/sn1/hubstat.h | 56 - include/asm-ia64/sn/sn1/hubxb.h | 1288 --- include/asm-ia64/sn/sn1/hubxb_next.h | 32 - include/asm-ia64/sn/sn1/hwcntrs.h | 96 - include/asm-ia64/sn/sn1/intr.h | 237 - include/asm-ia64/sn/sn1/intr_public.h | 53 - include/asm-ia64/sn/sn1/ip27config.h | 657 -- include/asm-ia64/sn/sn1/mem_refcnt.h | 25 - include/asm-ia64/sn/sn1/mmzone_sn1.h | 149 - include/asm-ia64/sn/sn1/slotnum.h | 87 - include/asm-ia64/sn/sn1/sn_private.h | 292 - include/asm-ia64/sn/sn1/synergy.h | 184 - include/asm-ia64/sn/sn2/addrs.h | 4 +- include/asm-ia64/sn/sn2/arch.h | 3 +- include/asm-ia64/sn/sn2/intr.h | 8 +- include/asm-ia64/sn/sn2/io.h | 10 +- include/asm-ia64/sn/sn2/mmzone_sn2.h | 165 - include/asm-ia64/sn/sn2/shub.h | 2 +- include/asm-ia64/sn/sn2/shub_md.h | 2 +- include/asm-ia64/sn/sn2/shub_mmr.h | 8 +- include/asm-ia64/sn/sn2/shub_mmr_t.h | 2 +- include/asm-ia64/sn/sn2/shubio.h | 143 +- include/asm-ia64/sn/sn2/slotnum.h | 2 +- include/asm-ia64/sn/sn2/sn_private.h | 21 +- include/asm-ia64/sn/sn_cpuid.h | 92 +- include/asm-ia64/sn/sn_fru.h | 3 +- include/asm-ia64/sn/sn_pio_sync.h | 53 - include/asm-ia64/sn/sn_private.h | 6 +- include/asm-ia64/sn/sn_sal.h | 269 +- include/asm-ia64/sn/snconfig.h | 18 - .../kernel/probe.c => include/asm-ia64/sn/sndrv.h | 89 +- include/asm-ia64/sn/sv.h | 2 +- include/asm-ia64/sn/systeminfo.h | 2 +- include/asm-ia64/sn/types.h | 9 +- include/asm-ia64/sn/uart16550.h | 2 +- include/asm-ia64/sn/vector.h | 46 +- include/asm-ia64/sn/xtalk/xbow.h | 9 +- include/asm-ia64/sn/xtalk/xbow_info.h | 8 +- include/asm-ia64/sn/xtalk/xswitch.h | 21 +- include/asm-ia64/sn/xtalk/xtalk.h | 69 +- include/asm-ia64/sn/xtalk/xtalk_private.h | 12 +- include/asm-ia64/sn/xtalk/xtalkaddrs.h | 3 +- include/asm-ia64/sn/xtalk/xwidget.h | 28 +- include/asm-ia64/spinlock.h | 5 +- include/asm-ia64/statfs.h | 27 +- include/asm-ia64/system.h | 12 +- include/asm-ia64/thread_info.h | 23 +- include/asm-ia64/timex.h | 2 +- include/asm-ia64/tlb.h | 4 +- include/asm-ia64/topology.h | 2 + include/asm-ia64/unistd.h | 12 +- include/asm-ia64/unwind.h | 5 +- include/asm-ia64/ustack.h | 16 + include/asm-ia64/xor.h | 316 +- include/asm-m68k/statfs.h | 21 +- include/asm-m68knommu/uaccess.h | 4 +- include/asm-mips/statfs.h | 17 + include/asm-mips/unistd.h | 4 +- include/asm-mips64/statfs.h | 16 + include/asm-mips64/unistd.h | 10 +- include/asm-parisc/compat.h | 3 +- include/asm-parisc/smp.h | 4 +- include/asm-parisc/statfs.h | 21 +- include/asm-ppc/pci.h | 7 + include/asm-ppc/smp.h | 4 +- include/asm-ppc/statfs.h | 22 +- include/asm-ppc64/compat.h | 3 +- include/asm-ppc64/pci.h | 7 + include/asm-ppc64/statfs.h | 20 +- include/asm-s390/smp.h | 4 +- include/asm-sparc/statfs.h | 33 +- include/asm-sparc/xor.h | 10 +- include/asm-sparc64/pci.h | 7 + include/asm-sparc64/smp.h | 4 +- include/asm-sparc64/statfs.h | 17 +- include/asm-sparc64/xor.h | 10 +- include/asm-v850/hardirq.h | 12 +- include/asm-v850/io.h | 11 +- include/asm-x86_64/compat.h | 3 +- include/asm-x86_64/smp.h | 4 +- include/asm-x86_64/statfs.h | 21 +- include/linux/acpi.h | 4 +- include/linux/atmdev.h | 2 +- include/linux/bitops.h | 2 +- include/linux/coda_psdev.h | 2 +- include/linux/efs_fs.h | 2 +- include/linux/ext3_fs.h | 9 +- include/linux/ext3_fs_i.h | 2 +- include/linux/ext3_fs_sb.h | 9 +- include/linux/ext3_jbd.h | 38 +- include/linux/firmware.h | 19 + include/linux/fs.h | 8 +- include/linux/gfp.h | 2 +- include/linux/highmem.h | 2 + include/linux/hugetlb.h | 23 +- include/linux/input.h | 1 + include/linux/isdn.h | 2 +- include/linux/isdn_ppp.h | 3 +- include/linux/jbd.h | 601 +- include/linux/journal-head.h | 155 +- include/linux/msdos_fs.h | 2 +- include/linux/netdevice.h | 8 +- include/linux/netfilter_arp.h | 3 +- include/linux/nfsd/nfsd.h | 5 +- include/linux/nfsd/state.h | 5 + include/linux/nfsd/xdr.h | 2 +- include/linux/nfsd/xdr3.h | 2 +- include/linux/page-flags.h | 1 + include/linux/pci.h | 46 +- include/linux/pci_ids.h | 7 + include/linux/pnp.h | 127 +- include/linux/rmap-locking.h | 70 +- include/linux/sched.h | 16 +- include/linux/sem.h | 4 +- include/linux/serio.h | 1 - include/linux/skbuff.h | 30 +- include/linux/smbno.h | 4 +- include/linux/spinlock.h | 79 +- include/linux/statfs.h | 22 + include/linux/sunrpc/cache.h | 9 +- include/linux/sunrpc/svc.h | 8 +- include/linux/sysdev.h | 1 - include/linux/tcp.h | 2 +- include/linux/time.h | 3 +- include/linux/timex.h | 2 +- include/linux/usb.h | 51 +- include/linux/vfs.h | 2 +- include/net/llc_pdu.h | 22 +- include/net/sctp/structs.h | 1 + include/net/sock.h | 40 +- include/net/syncppp.h | 1 + include/net/tcp.h | 3 +- include/scsi/scsi_cmnd.h | 164 + include/scsi/scsi_device.h | 106 + include/scsi/scsi_eh.h | 21 + include/scsi/scsi_host.h | 525 + include/scsi/scsi_request.h | 58 + include/scsi/scsi_tcq.h | 94 + ipc/sem.c | 298 +- ipc/util.c | 8 +- kernel/acct.c | 14 +- kernel/compat.c | 2 + kernel/exit.c | 2 +- kernel/fork.c | 10 +- kernel/kmod.c | 12 +- kernel/ksyms.c | 4 +- kernel/sched.c | 26 +- kernel/timer.c | 4 +- kernel/workqueue.c | 85 +- lib/kobject.c | 11 + mm/page-writeback.c | 7 +- mm/shmem.c | 4 +- mm/slab.c | 28 +- mm/swap_state.c | 9 - net/atm/clip.c | 4 +- net/atm/common.c | 639 +- net/atm/common.h | 19 +- net/atm/lec.c | 4 +- net/atm/mpoa_caches.c | 4 +- net/atm/pvc.c | 56 +- net/atm/resources.c | 236 + net/atm/resources.h | 1 + net/atm/signaling.c | 8 +- net/atm/svc.c | 304 +- net/bluetooth/af_bluetooth.c | 4 +- net/bridge/br_netfilter.c | 51 +- net/core/dev.c | 66 +- net/core/flow.c | 37 +- net/core/skbuff.c | 60 +- net/decnet/af_decnet.c | 2 +- net/econet/af_econet.c | 4 +- net/ethernet/eth.c | 8 +- net/ipv4/arp.c | 17 +- net/ipv4/igmp.c | 23 +- net/ipv4/ip_output.c | 5 +- net/ipv4/netfilter/arp_tables.c | 9 +- net/ipv4/netfilter/arptable_filter.c | 67 +- net/ipv4/netfilter/ipt_MIRROR.c | 5 +- net/ipv4/raw.c | 5 +- net/ipv4/tcp.c | 4 +- net/ipv4/tcp_ipv4.c | 26 +- net/ipv4/tcp_minisocks.c | 8 +- net/ipv4/udp.c | 2 - net/ipv6/icmp.c | 6 - net/ipv6/ip6_output.c | 5 +- net/ipv6/ip6_tunnel.c | 4 +- net/ipv6/mcast.c | 23 +- net/ipv6/ndisc.c | 13 +- net/ipv6/raw.c | 5 +- net/ipv6/tcp_ipv6.c | 6 +- net/ipv6/udp.c | 2 - net/ipv6/xfrm6_policy.c | 15 +- net/ipx/af_ipx.c | 6 +- net/irda/irda_device.c | 4 +- net/irda/irnet/irnet_irda.c | 86 +- net/irda/irnet/irnet_ppp.c | 58 +- net/irda/irttp.c | 2 +- net/key/af_key.c | 4 +- net/llc/llc_c_ac.c | 26 +- net/llc/llc_c_ev.c | 152 +- net/llc/llc_conn.c | 2 +- net/llc/llc_evnt.c | 16 +- net/llc/llc_s_ev.c | 20 +- net/llc/llc_sap.c | 4 +- net/netlink/af_netlink.c | 4 +- net/netsyms.c | 3 +- net/packet/af_packet.c | 4 +- net/sched/sch_htb.c | 48 +- net/sctp/endpointola.c | 2 +- net/sctp/socket.c | 12 +- net/sunrpc/cache.c | 40 +- net/sunrpc/sched.c | 3 + net/sunrpc/svc.c | 2 + net/sunrpc/svcauth_unix.c | 6 +- net/sunrpc/svcsock.c | 20 +- net/unix/af_unix.c | 4 +- net/wanrouter/af_wanpipe.c | 11 +- net/x25/af_x25.c | 4 +- scripts/kconfig/mconf.c | 2 +- sound/pci/korg1212/korg1212.c | 13 +- usr/gen_init_cpio.c | 8 +- 1045 files changed, 37759 insertions(+), 86251 deletions(-) create mode 100644 Documentation/firmware_class/README create mode 100644 Documentation/firmware_class/firmware_sample_driver.c create mode 100644 Documentation/firmware_class/firmware_sample_firmware_class.c create mode 100644 Documentation/firmware_class/hotplug-script create mode 100644 arch/arm/common/amba.c create mode 100644 arch/arm/common/icst525.c create mode 100644 arch/i386/kernel/acpi/acpitable.c create mode 100644 arch/i386/kernel/acpi/acpitable.h create mode 100644 arch/i386/oprofile/nmi_timer_int.c copy include/asm-ia64/ia32.h => arch/ia64/ia32/ia32priv.h (96%) create mode 100644 arch/ia64/kernel/asm-offsets.c create mode 100644 arch/ia64/kernel/gate-data.S create mode 100644 arch/ia64/kernel/gate.lds.S rewrite arch/ia64/kernel/minstate.h (63%) create mode 100644 arch/ia64/kernel/patch.c rewrite arch/ia64/kernel/perfmon.c (68%) create mode 100644 arch/ia64/kernel/perfmon_default_smpl.c create mode 100644 arch/ia64/lib/xor.S create mode 100644 arch/ia64/scripts/check-segrel.S create mode 100644 arch/ia64/scripts/check-segrel.lds create mode 100644 arch/ia64/scripts/toolchain-flags rename arch/ia64/sn/{io/klgraph_hack.c => fakeprom/klgraph_init.c} (69%) delete mode 100644 arch/ia64/sn/io/alenlist.c create mode 100644 arch/ia64/sn/io/drivers/Makefile rename arch/ia64/sn/io/{ => drivers}/ifconfig_net.c (97%) rename arch/ia64/sn/io/{ => drivers}/ioconfig_bus.c (94%) delete mode 100644 arch/ia64/sn/io/eeprom.c delete mode 100644 arch/ia64/sn/io/efi-rtc.c delete mode 100644 arch/ia64/sn/io/hcl.c delete mode 100644 arch/ia64/sn/io/hubdev.c delete mode 100644 arch/ia64/sn/io/hubspc.c create mode 100644 arch/ia64/sn/io/hwgfs/Makefile create mode 100644 arch/ia64/sn/io/hwgfs/hcl.c rename arch/ia64/sn/io/{ => hwgfs}/hcl_util.c (80%) create mode 100644 arch/ia64/sn/io/hwgfs/interface.c create mode 100644 arch/ia64/sn/io/hwgfs/invent_stub.c rename arch/ia64/sn/io/{ => hwgfs}/labelcl.c (90%) create mode 100644 arch/ia64/sn/io/hwgfs/ramfs.c delete mode 100644 arch/ia64/sn/io/invent.c delete mode 100644 arch/ia64/sn/io/klconflib.c delete mode 100644 arch/ia64/sn/io/klgraph.c delete mode 100644 arch/ia64/sn/io/l1.c delete mode 100644 arch/ia64/sn/io/l1_command.c create mode 100644 arch/ia64/sn/io/machvec/Makefile rename arch/ia64/sn/{kernel/sn2 => io/machvec}/iomv.c (94%) create mode 100644 arch/ia64/sn/io/machvec/pci.c rename arch/ia64/sn/io/{sn2 => machvec}/pci_bus_cvlink.c (66%) rename arch/ia64/sn/io/{ => machvec}/pci_dma.c (72%) delete mode 100644 arch/ia64/sn/io/ml_SN_init.c delete mode 100644 arch/ia64/sn/io/ml_iograph.c delete mode 100644 arch/ia64/sn/io/module.c delete mode 100644 arch/ia64/sn/io/pci.c delete mode 100644 arch/ia64/sn/io/pci_bus_cvlink.c delete mode 100644 arch/ia64/sn/io/pciba.c delete mode 100644 arch/ia64/sn/io/pciio.c create mode 100644 arch/ia64/sn/io/platform_init/Makefile create mode 100644 arch/ia64/sn/io/platform_init/irix_io_init.c create mode 100644 arch/ia64/sn/io/platform_init/sgi_io_init.c delete mode 100644 arch/ia64/sn/io/sgi_io_init.c delete mode 100644 arch/ia64/sn/io/sn1/hub_intr.c delete mode 100644 arch/ia64/sn/io/sn1/hubcounters.c delete mode 100644 arch/ia64/sn/io/sn1/huberror.c delete mode 100644 arch/ia64/sn/io/sn1/ip37.c delete mode 100644 arch/ia64/sn/io/sn1/mem_refcnt.c delete mode 100644 arch/ia64/sn/io/sn1/ml_SN_intr.c delete mode 100644 arch/ia64/sn/io/sn1/pcibr.c rewrite arch/ia64/sn/io/sn2/bte_error.c (85%) create mode 100644 arch/ia64/sn/io/sn2/kdba_io.c delete mode 100644 arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c delete mode 100644 arch/ia64/sn/io/sn2/sgi_io_init.c delete mode 100644 arch/ia64/sn/io/stubs.c delete mode 100644 arch/ia64/sn/io/xbow.c delete mode 100644 arch/ia64/sn/io/xtalk.c create mode 100644 arch/ia64/sn/kernel/idle.c delete mode 100644 arch/ia64/sn/kernel/iomv.c delete mode 100644 arch/ia64/sn/kernel/llsc4.c delete mode 100644 arch/ia64/sn/kernel/llsc4.h rewrite arch/ia64/sn/kernel/mca.c (75%) delete mode 100644 arch/ia64/sn/kernel/misctest.c delete mode 100644 arch/ia64/sn/kernel/sn1/Makefile delete mode 100644 arch/ia64/sn/kernel/sn1/cache.c delete mode 100644 arch/ia64/sn/kernel/sn1/error.c delete mode 100644 arch/ia64/sn/kernel/sn1/iomv.c delete mode 100644 arch/ia64/sn/kernel/sn1/sn1_smp.c delete mode 100644 arch/ia64/sn/kernel/sn1/synergy.c create mode 100644 arch/ia64/sn/kernel/sn2/prominfo_proc.c create mode 100644 arch/ia64/sn/kernel/sn2/timer.c delete mode 100644 arch/ia64/sn/kernel/sn_asm.S delete mode 100644 arch/ia64/tools/Makefile delete mode 100644 arch/ia64/tools/print_offsets.awk delete mode 100644 arch/ia64/tools/print_offsets.c create mode 100644 drivers/acpi/asus_acpi.c create mode 100644 drivers/base/Kconfig create mode 100644 drivers/base/firmware_class.c create mode 100644 drivers/i2c/chips/lm78.c create mode 100644 drivers/input/mouse/logips2pp.c create mode 100644 drivers/input/mouse/logips2pp.h rewrite drivers/isdn/eicon/Makefile (67%) rewrite drivers/isdn/hardware/eicon/Makefile (86%) rewrite drivers/isdn/hisax/Makefile (74%) rewrite drivers/isdn/i4l/Makefile (83%) rename drivers/pcmcia/{yenta.c => yenta_socket.c} (99%) rename drivers/pcmcia/{yenta.h => yenta_socket.h} (100%) rewrite drivers/pnp/base.h (71%) rewrite drivers/pnp/manager.c (74%) delete mode 100644 drivers/scsi/eata.h rewrite drivers/scsi/hosts.c (65%) rewrite drivers/scsi/hosts.h (91%) rewrite drivers/scsi/scsi.h (69%) rewrite drivers/scsi/scsi_module.c (90%) create mode 100644 drivers/scsi/scsi_typedefs.h delete mode 100644 drivers/scsi/u14-34f.h create mode 100644 drivers/usb/net/ax8817x.c create mode 100644 fs/Kconfig.binfmt rewrite fs/partitions/acorn.h (98%) create mode 100644 include/asm-arm/hardware/amba.h create mode 100644 include/asm-arm/hardware/icst525.h create mode 100644 include/asm-generic/statfs.h rewrite include/asm-ia64/ia32.h (96%) create mode 100644 include/asm-ia64/ioctl32.h create mode 100644 include/asm-ia64/patch.h rewrite include/asm-ia64/perfmon.h (69%) create mode 100644 include/asm-ia64/perfmon_default_smpl.h delete mode 100644 include/asm-ia64/sn/bte_copy.h rewrite include/asm-ia64/sn/cdl.h (87%) delete mode 100644 include/asm-ia64/sn/eeprom.h delete mode 100644 include/asm-ia64/sn/gda.h delete mode 100644 include/asm-ia64/sn/hack.h rewrite include/asm-ia64/sn/hcl.h (62%) delete mode 100644 include/asm-ia64/sn/hires_clock.h create mode 100644 include/asm-ia64/sn/hwgfs.h delete mode 100644 include/asm-ia64/sn/idle.h delete mode 100644 include/asm-ia64/sn/intr_public.h create mode 100644 include/asm-ia64/sn/ioc4.h delete mode 100644 include/asm-ia64/sn/mca.h delete mode 100644 include/asm-ia64/sn/nic.h delete mode 100644 include/asm-ia64/sn/pci/pciba.h delete mode 100644 include/asm-ia64/sn/pio_flush.h delete mode 100644 include/asm-ia64/sn/sn1/addrs.h delete mode 100644 include/asm-ia64/sn/sn1/arch.h delete mode 100644 include/asm-ia64/sn/sn1/bedrock.h delete mode 100644 include/asm-ia64/sn/sn1/hubdev.h delete mode 100644 include/asm-ia64/sn/sn1/hubio.h delete mode 100644 include/asm-ia64/sn/sn1/hubio_next.h delete mode 100644 include/asm-ia64/sn/sn1/hublb.h delete mode 100644 include/asm-ia64/sn/sn1/hublb_next.h delete mode 100644 include/asm-ia64/sn/sn1/hubmd.h delete mode 100644 include/asm-ia64/sn/sn1/hubmd_next.h delete mode 100644 include/asm-ia64/sn/sn1/hubni.h delete mode 100644 include/asm-ia64/sn/sn1/hubni_next.h delete mode 100644 include/asm-ia64/sn/sn1/hubpi.h delete mode 100644 include/asm-ia64/sn/sn1/hubpi_next.h delete mode 100644 include/asm-ia64/sn/sn1/hubspc.h delete mode 100644 include/asm-ia64/sn/sn1/hubstat.h delete mode 100644 include/asm-ia64/sn/sn1/hubxb.h delete mode 100644 include/asm-ia64/sn/sn1/hubxb_next.h delete mode 100644 include/asm-ia64/sn/sn1/hwcntrs.h delete mode 100644 include/asm-ia64/sn/sn1/intr.h delete mode 100644 include/asm-ia64/sn/sn1/intr_public.h delete mode 100644 include/asm-ia64/sn/sn1/ip27config.h delete mode 100644 include/asm-ia64/sn/sn1/mem_refcnt.h delete mode 100644 include/asm-ia64/sn/sn1/mmzone_sn1.h delete mode 100644 include/asm-ia64/sn/sn1/slotnum.h delete mode 100644 include/asm-ia64/sn/sn1/sn_private.h delete mode 100644 include/asm-ia64/sn/sn1/synergy.h delete mode 100644 include/asm-ia64/sn/sn2/mmzone_sn2.h delete mode 100644 include/asm-ia64/sn/sn_pio_sync.h delete mode 100644 include/asm-ia64/sn/snconfig.h copy arch/ia64/sn/kernel/probe.c => include/asm-ia64/sn/sndrv.h (50%) create mode 100644 include/asm-ia64/ustack.h rewrite include/asm-ia64/xor.h (77%) rewrite include/asm-sparc/statfs.h (73%) create mode 100644 include/linux/firmware.h rewrite include/linux/journal-head.h (62%) rewrite include/linux/rmap-locking.h (60%) create mode 100644 include/linux/statfs.h create mode 100644 include/scsi/scsi_cmnd.h create mode 100644 include/scsi/scsi_device.h create mode 100644 include/scsi/scsi_eh.h create mode 100644 include/scsi/scsi_host.h create mode 100644 include/scsi/scsi_request.h create mode 100644 include/scsi/scsi_tcq.h diff --git a/Documentation/firmware_class/README b/Documentation/firmware_class/README new file mode 100644 index 00000000000..4b2c74fd73d --- /dev/null +++ b/Documentation/firmware_class/README @@ -0,0 +1,58 @@ + + request_firmware() hotplug interface: + ------------------------------------ + Copyright (C) 2003 Manuel Estrada Sainz + + Why: + --- + + Today, the most extended way to use firmware in the Linux kernel is linking + it statically in a header file. Which has political and technical issues: + + 1) Some firmware is not legal to redistribute. + 2) The firmware occupies memory permanently, even though it often is just + used once. + 3) Some people, like the Debian crowd, don't consider some firmware free + enough and remove entire drivers (e.g.: keyspan). + + about in-kernel persistence: + --------------------------- + Under some circumstances, as explained below, it would be interesting to keep + firmware images in non-swappable kernel memory or even in the kernel image + (probably within initramfs). + + Note that this functionality has not been implemented. + + - Why OPTIONAL in-kernel persistence may be a good idea sometimes: + + - If the device that needs the firmware is needed to access the + filesystem. When upon some error the device has to be reset and the + firmware reloaded, it won't be possible to get it from userspace. + e.g.: + - A diskless client with a network card that needs firmware. + - The filesystem is stored in a disk behind an scsi device + that needs firmware. + - Replacing buggy DSDT/SSDT ACPI tables on boot. + Note: this would require the persistent objects to be included + within the kernel image, probably within initramfs. + + And the same device can be needed to access the filesystem or not depending + on the setup, so I think that the choice on what firmware to make + persistent should be left to userspace. + + - Why register_firmware()+__init can be useful: + - For boot devices needing firmware. + - To make the transition easier: + The firmware can be declared __init and register_firmware() + called on module_init. Then the firmware is warranted to be + there even if "firmware hotplug userspace" is not there yet or + it doesn't yet provide the needed firmware. + Once the firmware is widely available in userspace, it can be + removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE). + + In either case, if firmware hotplug support is there, it can move the + firmware out of kernel memory into the real filesystem for later + usage. + + Note: If persistence is implemented on top of initramfs, + register_firmware() may not be appropriate. diff --git a/Documentation/firmware_class/firmware_sample_driver.c b/Documentation/firmware_class/firmware_sample_driver.c new file mode 100644 index 00000000000..e1c56a7e658 --- /dev/null +++ b/Documentation/firmware_class/firmware_sample_driver.c @@ -0,0 +1,126 @@ +/* + * firmware_sample_driver.c - + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Sample code on how to use request_firmware() from drivers. + * + * Note that register_firmware() is currently useless. + * + */ + +#include +#include +#include +#include + +#include "linux/firmware.h" + +#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE +#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE +char __init inkernel_firmware[] = "let's say that this is firmware\n"; +#endif + +static struct device ghost_device = { + .name = "Ghost Device", + .bus_id = "ghost0", +}; + + +static void sample_firmware_load(char *firmware, int size) +{ + u8 buf[size+1]; + memcpy(buf, firmware, size); + buf[size] = '\0'; + printk("firmware_sample_driver: firmware: %s\n", buf); +} + +static void sample_probe_default(void) +{ + /* uses the default method to get the firmware */ + const struct firmware *fw_entry; + printk("firmware_sample_driver: a ghost device got inserted :)\n"); + + if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0) + { + printk(KERN_ERR + "firmware_sample_driver: Firmware not available\n"); + return; + } + + sample_firmware_load(fw_entry->data, fw_entry->size); + + release_firmware(fw_entry); + + /* finish setting up the device */ +} +static void sample_probe_specific(void) +{ + /* Uses some specific hotplug support to get the firmware from + * userspace directly into the hardware, or via some sysfs file */ + + /* NOTE: This currently doesn't work */ + + printk("firmware_sample_driver: a ghost device got inserted :)\n"); + + if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0) + { + printk(KERN_ERR + "firmware_sample_driver: Firmware load failed\n"); + return; + } + + /* request_firmware blocks until userspace finished, so at + * this point the firmware should be already in the device */ + + /* finish setting up the device */ +} +static void sample_probe_async_cont(const struct firmware *fw, void *context) +{ + if(!fw){ + printk(KERN_ERR + "firmware_sample_driver: firmware load failed\n"); + return; + } + + printk("firmware_sample_driver: device pointer \"%s\"\n", + (char *)context); + sample_firmware_load(fw->data, fw->size); +} +static void sample_probe_async(void) +{ + /* Let's say that I can't sleep */ + int error; + error = request_firmware_nowait (THIS_MODULE, + "sample_driver_fw", &ghost_device, + "my device pointer", + sample_probe_async_cont); + if(error){ + printk(KERN_ERR + "firmware_sample_driver:" + " request_firmware_nowait failed\n"); + } +} + +static int sample_init(void) +{ +#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE + register_firmware("sample_driver_fw", inkernel_firmware, + sizeof(inkernel_firmware)); +#endif + device_initialize(&ghost_device); + /* since there is no real hardware insertion I just call the + * sample probe functions here */ + sample_probe_specific(); + sample_probe_default(); + sample_probe_async(); + return 0; +} +static void __exit sample_exit(void) +{ +} + +module_init (sample_init); +module_exit (sample_exit); + +MODULE_LICENSE("GPL"); diff --git a/Documentation/firmware_class/firmware_sample_firmware_class.c b/Documentation/firmware_class/firmware_sample_firmware_class.c new file mode 100644 index 00000000000..037c0bed9eb --- /dev/null +++ b/Documentation/firmware_class/firmware_sample_firmware_class.c @@ -0,0 +1,205 @@ +/* + * firmware_sample_firmware_class.c - + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * NOTE: This is just a probe of concept, if you think that your driver would + * be well served by this mechanism please contact me first. + * + * DON'T USE THIS CODE AS IS + * + */ + +#include +#include +#include +#include +#include + +#include "linux/firmware.h" + +MODULE_AUTHOR("Manuel Estrada Sainz "); +MODULE_DESCRIPTION("Hackish sample for using firmware class directly"); +MODULE_LICENSE("GPL"); + +static inline struct class_device *to_class_dev(struct kobject *obj) +{ + return container_of(obj,struct class_device,kobj); +} +static inline +struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) +{ + return container_of(_attr,struct class_device_attribute,attr); +} + +int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); +int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); + +struct firmware_priv { + char fw_id[FIRMWARE_NAME_MAX]; + s32 loading:2; + u32 abort:1; +}; + +extern struct class firmware_class; + +static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + return sprintf(buf, "%d\n", fw_priv->loading); +} +static ssize_t firmware_loading_store(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int prev_loading = fw_priv->loading; + + fw_priv->loading = simple_strtol(buf, NULL, 10); + + switch(fw_priv->loading){ + case -1: + /* abort load an panic */ + break; + case 1: + /* setup load */ + break; + case 0: + if(prev_loading==1){ + /* finish load and get the device back to working + * state */ + } + break; + } + + return count; +} +static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + +static ssize_t firmware_data_read(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + /* read from the devices firmware memory */ + + return count; +} +static ssize_t firmware_data_write(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + /* write to the devices firmware memory */ + + return count; +} +static struct bin_attribute firmware_attr_data = { + .attr = {.name = "data", .mode = 0644}, + .size = 0, + .read = firmware_data_read, + .write = firmware_data_write, +}; +static int fw_setup_class_device(struct class_device *class_dev, + const char *fw_name, + struct device *device) +{ + int retval = 0; + struct firmware_priv *fw_priv = kmalloc(sizeof(struct firmware_priv), + GFP_KERNEL); + + if(!fw_priv){ + retval = -ENOMEM; + goto out; + } + memset(fw_priv, 0, sizeof(*fw_priv)); + memset(class_dev, 0, sizeof(*class_dev)); + + strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0'; + + strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE); + class_dev->class_id[BUS_ID_SIZE-1] = '\0'; + class_dev->dev = device; + + class_dev->class = &firmware_class, + class_set_devdata(class_dev, fw_priv); + retval = class_device_register(class_dev); + if (retval){ + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + goto error_free_fw_priv; + } + + retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data); + if (retval){ + printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", + __FUNCTION__); + goto error_unreg_class_dev; + } + + retval = class_device_create_file(class_dev, + &class_device_attr_loading); + if (retval){ + printk(KERN_ERR "%s: class_device_create_file failed\n", + __FUNCTION__); + goto error_remove_data; + } + + goto out; + +error_remove_data: + sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); +error_unreg_class_dev: + class_device_unregister(class_dev); +error_free_fw_priv: + kfree(fw_priv); +out: + return retval; +} +static void fw_remove_class_device(struct class_device *class_dev) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + class_device_remove_file(class_dev, &class_device_attr_loading); + sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); + class_device_unregister(class_dev); +} + +static struct class_device *class_dev; + +static struct device my_device = { + .name = "Sample Device", + .bus_id = "my_dev0", +}; + +static int __init firmware_sample_init(void) +{ + int error; + + device_initialize(&my_device); + class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); + if(!class_dev) + return -ENOMEM; + + error = fw_setup_class_device(class_dev, "my_firmware_image", + &my_device); + if(error){ + kfree(class_dev); + return error; + } + return 0; + +} +static void __exit firmware_sample_exit(void) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + fw_remove_class_device(class_dev); + kfree(fw_priv); + kfree(class_dev); +} +module_init(firmware_sample_init); +module_exit(firmware_sample_exit); + diff --git a/Documentation/firmware_class/hotplug-script b/Documentation/firmware_class/hotplug-script new file mode 100644 index 00000000000..0a31bcd6fa9 --- /dev/null +++ b/Documentation/firmware_class/hotplug-script @@ -0,0 +1,16 @@ +#!/bin/sh + +# Simple hotplug script sample: +# +# Both $DEVPATH and $FIRMWARE are already provided in the environment. + +HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ + +echo 1 > /sysfs/$DEVPATH/loading +cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data +echo 0 > /sysfs/$DEVPATH/loading + +# To cancel the load in case of error: +# +# echo -1 > /sysfs/$DEVPATH/loading +# diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index d05ead30ee1..79967127795 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -5,15 +5,8 @@ Patrick Mochel Updated: 3 June 2003 -Copyright (c) Patrick Mochel -Copyright (c) Open Source Development Labs -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.2 -or any later version published by the Free Software Foundation; -with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -A copy of the license is included in the section entitled "GNU -Free Documentation License". - +Copyright (c) 2003 Patrick Mochel +Copyright (c) 2003 Open Source Development Labs 0. Introduction diff --git a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt index 585b302beb9..385f9eff653 100644 --- a/Documentation/sched-coding.txt +++ b/Documentation/sched-coding.txt @@ -103,7 +103,7 @@ void set_user_nice(task_t *p, long nice) Sets the "nice" value of task p to the given value. int setscheduler(pid_t pid, int policy, struct sched_param *param) Sets the scheduling policy and parameters for the given pid. -void set_cpus_allowed(task_t *p, unsigned long new_mask) +int set_cpus_allowed(task_t *p, unsigned long new_mask) Sets a given task's CPU affinity and migrates it to a proper cpu. Callers must have a valid reference to the task and assure the task not exit prematurely. No locks can be held during the call. diff --git a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt index fae53718657..62844aeba69 100644 --- a/Documentation/usb/dma.txt +++ b/Documentation/usb/dma.txt @@ -15,10 +15,12 @@ OR: they can now be DMA-aware. manage dma mappings for existing dma-ready buffers (see below). - URBs have an additional "transfer_dma" field, as well as a transfer_flags - bit saying if it's valid. (Control requests also needed "setup_dma".) + bit saying if it's valid. (Control requests also have "setup_dma" and a + corresponding transfer_flags bit.) -- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do it - first and set URB_NO_DMA_MAP. HCDs don't manage dma mappings for urbs. +- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do + it first and set URB_NO_TRANSFER_DMA_MAP or URB_NO_SETUP_DMA_MAP. HCDs + don't manage dma mappings for URBs. - There's a new "generic DMA API", parts of which are usable by USB device drivers. Never use dma_set_mask() on any USB interface or device; that @@ -33,8 +35,9 @@ and effects like cache-trashing can impose subtle penalties. - When you're allocating a buffer for DMA purposes anyway, use the buffer primitives. Think of them as kmalloc and kfree that give you the right kind of addresses to store in urb->transfer_buffer and urb->transfer_dma, - while guaranteeing that hidden copies through DMA "bounce" buffers won't - slow things down. You'd also set URB_NO_DMA_MAP in urb->transfer_flags: + while guaranteeing that no hidden copies through DMA "bounce" buffers will + slow things down. You'd also set URB_NO_TRANSFER_DMA_MAP in + urb->transfer_flags: void *usb_buffer_alloc (struct usb_device *dev, size_t size, int mem_flags, dma_addr_t *dma); @@ -42,10 +45,18 @@ and effects like cache-trashing can impose subtle penalties. void usb_buffer_free (struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); + For control transfers you can use the buffer primitives or not for each + of the transfer buffer and setup buffer independently. Set the flag bits + URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which + buffers you have prepared. For non-control transfers URB_NO_SETUP_DMA_MAP + is ignored. + The memory buffer returned is "dma-coherent"; sometimes you might need to force a consistent memory access ordering by using memory barriers. It's not using a streaming DMA mapping, so it's good for small transfers on - systems where the I/O would otherwise tie up an IOMMU mapping. + systems where the I/O would otherwise tie up an IOMMU mapping. (See + Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming" + DMA mappings.) Asking for 1/Nth of a page (as well as asking for N pages) is reasonably space-efficient. @@ -91,7 +102,8 @@ DMA address space of the device. These calls all work with initialized urbs: urb->dev, urb->pipe, urb->transfer_buffer, and urb->transfer_buffer_length must all be - valid when these calls are used: + valid when these calls are used (urb->setup_packet must be valid too + if urb is a control request): struct urb *usb_buffer_map (struct urb *urb); @@ -99,6 +111,6 @@ DMA address space of the device. void usb_buffer_unmap (struct urb *urb); - The calls manage urb->transfer_dma for you, and set URB_NO_DMA_MAP so that - usbcore won't map or unmap the buffer. - + The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP + so that usbcore won't map or unmap the buffer. The same goes for + urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests. diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index f39e2bb310c..55b3cc0efda 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -68,14 +68,21 @@ call, then it is required that system administrator mount a file system of type hugetlbfs: mount none /mnt/huge -t hugetlbfs + This command mounts a (pseudo) filesystem of type hugetlbfs on the directory /mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid options sets the owner and group of the root of the file system. By default the uid and gid of the current process are taken. The mode option sets the mode of root of file system to value & 0777. This value is given in octal. -By default the value 0755 is picked. An example is given at the end of this -document. +By default the value 0755 is picked. The size option sets the maximum value of +memory (huge pages) allowed for that filesystem (/mnt/huge). The size is +rounded down to HPAGE_SIZE. The option nr_inode sets the maximum number of +inodes that /mnt/huge can use. If the size or nr_inode options are not +provided on command line then no limits are set. For size and nr_inodes +options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For +example, size=2K has the same meaning as size=2048. An example is given at +the end of this document. read and write system calls are not supported on files that reside on hugetlb file systems. diff --git a/MAINTAINERS b/MAINTAINERS index 6e6fd71df97..d6376e9771f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1429,10 +1429,10 @@ W: http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html S: Maintained PCI SUBSYSTEM -P: Martin Mares -M: mj@ucw.cz +P: Greg Kroah-Hartman +M: greg@kroah.com L: linux-kernel@vger.kernel.org -S: Odd Fixes +S: Supported PCI HOTPLUG CORE P: Greg Kroah-Hartman diff --git a/Makefile b/Makefile index a7a773eb874..37c6e443911 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 72 +SUBLEVEL = 73 EXTRAVERSION = # *DOCUMENTATION* diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 7fd5f8fff52..920e9e840a0 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -647,108 +647,14 @@ config SRM_ENV This driver is also available as a module and will be called srm_env then. -config BINFMT_AOUT - tristate "Kernel support for a.out (ECOFF) binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config OSF4_COMPAT - bool "OSF/1 v4 readv/writev compatibility" - depends on BINFMT_AOUT - help - Say Y if you are using OSF/1 binaries (like Netscape and Acrobat) - with v4 shared libraries freely available from Compaq. If you're - going to use shared libraries from Tru64 version 5.0 or later, say N. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. - -config BINFMT_EM86 - tristate "Kernel support for Linux/Intel ELF binaries" - ---help--- - Say Y here if you want to be able to execute Linux/Intel ELF - binaries just like native Alpha binaries on your Alpha machine. For - this to work, you need to have the emulator /usr/bin/em86 in place. - - You can get the same functionality by saying N here and saying Y to - "Kernel support for MISC binaries". - - You may answer M to compile the emulation support as a module and - later load the module when you want to use a Linux/Intel binary. The - module will be called binfmt_em86. If unsure, say Y. +source "fs/Kconfig.binfmt" source "drivers/parport/Kconfig" endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/pnp/Kconfig" diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index c9a1d55d0db..890bee0f1aa 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -156,7 +156,7 @@ EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_write); EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(__kernel_execve); +EXPORT_SYMBOL(execve); EXPORT_SYMBOL(sys_setsid); EXPORT_SYMBOL(sys_wait4); diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 0d8be8cca89..be173110444 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -606,7 +606,8 @@ ret_from_fork: .globl kernel_thread .ent kernel_thread kernel_thread: - ldgp $gp, 0($27) /* we can be called from a module */ + /* We can be called from a module. */ + ldgp $gp, 0($27) .prologue 1 subq $sp, SP_OFF+6*8, $sp br $1, 2f /* load start address */ @@ -654,26 +655,56 @@ kernel_thread: .end kernel_thread /* - * __kernel_execve(path, argv, envp, regs) + * execve(path, argv, envp) */ .align 4 - .globl __kernel_execve - .ent __kernel_execve -__kernel_execve: - ldgp $gp, 0($27) /* we can be called from modules. */ - subq $sp, 16, $sp - .frame $sp, 16, $26, 0 + .globl execve + .ent execve +execve: + /* We can be called from a module. */ + ldgp $gp, 0($27) + lda $sp, -(32+SIZEOF_PT_REGS+8)($sp) + .frame $sp, 32+SIZEOF_PT_REGS+8, $26, 0 stq $26, 0($sp) - stq $19, 8($sp) + stq $16, 8($sp) + stq $17, 16($sp) + stq $18, 24($sp) .prologue 1 - jsr $26, do_execve - bne $0, 1f /* error! */ - ldq $sp, 8($sp) + + lda $16, 32($sp) + lda $17, 0 + lda $18, SIZEOF_PT_REGS + bsr $26, memset !samegp + + /* Avoid the HAE being gratuitously wrong, which would cause us + to do the whole turn off interrupts thing and restore it. */ + ldq $2, alpha_mv+HAE_CACHE + stq $2, 152+32($sp) + + ldq $16, 8($sp) + ldq $17, 16($sp) + ldq $18, 24($sp) + lda $19, 32($sp) + bsr $26, do_execve !samegp + + ldq $26, 0($sp) + bne $0, 1f /* error! */ + + /* Move the temporary pt_regs struct from its current location + to the top of the kernel stack frame. See copy_thread for + details for a normal process. */ + lda $16, 0x4000 - SIZEOF_PT_REGS($8) + lda $17, 32($sp) + lda $18, SIZEOF_PT_REGS + bsr $26, memmove !samegp + + /* Take that over as our new stack frame and visit userland! */ + lda $sp, 0x4000 - SIZEOF_PT_REGS($8) br $31, ret_from_sys_call -1: ldq $26, 0($sp) - addq $sp, 16, $sp + +1: lda $sp, 32+SIZEOF_PT_REGS+8($sp) ret -.end __kernel_execve +.end execve /* diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index c42a9d7b84b..cce7e0d0725 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -218,15 +218,14 @@ struct osf_statfs { } *osf_stat; static int -linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, +linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz) { struct osf_statfs tmp_stat; tmp_stat.f_type = linux_stat->f_type; tmp_stat.f_flags = 0; /* mount flags */ - /* Linux doesn't provide a "fundamental filesystem block size": */ - tmp_stat.f_fsize = linux_stat->f_bsize; + tmp_stat.f_fsize = linux_stat->f_frsize; tmp_stat.f_bsize = linux_stat->f_bsize; tmp_stat.f_blocks = linux_stat->f_blocks; tmp_stat.f_bfree = linux_stat->f_bfree; @@ -243,7 +242,7 @@ static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz) { - struct statfs linux_stat; + struct kstatfs linux_stat; int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat); if (!error) error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 9fc63ee500f..1a9b4c64593 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -291,6 +291,7 @@ srmcons_init(void) driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_SYSCONS; driver->init_termios = tty_std_termios; + tty_set_operations(driver, &srmcons_ops); err = tty_register_driver(driver); if (err) { put_tty_driver(driver); diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index ddea651cb87..412cd367257 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -148,7 +148,7 @@ void show_trace_task(struct task_struct * tsk) static int kstack_depth_to_print = 24; -void show_stack(unsigned long *sp) +void show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack; int i; @@ -174,7 +174,7 @@ void show_stack(unsigned long *sp) void dump_stack(void) { - show_stack(NULL); + show_stack(NULL, NULL); } void diff --git a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S index a09e1d13bc6..2f06e460392 100644 --- a/arch/alpha/lib/memmove.S +++ b/arch/alpha/lib/memmove.S @@ -15,15 +15,23 @@ .globl bcopy .ent bcopy bcopy: + ldgp $29, 0($27) + .prologue 1 mov $16,$0 mov $17,$16 mov $0,$17 + br $31, memmove !samegp .end bcopy .align 4 .globl memmove .ent memmove memmove: + ldgp $29, 0($27) + unop + nop + .prologue 1 + addq $16,$18,$4 addq $17,$18,$5 cmpule $4,$17,$1 /* dest + n <= src */ @@ -32,7 +40,7 @@ memmove: bis $1,$2,$1 mov $16,$0 xor $16,$17,$2 - bne $1,memcpy + bne $1,memcpy !samegp and $2,7,$2 /* Test for src/dest co-alignment. */ and $16,7,$1 diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index 0976ff84e33..3ce73d57794 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -188,7 +188,7 @@ oprofile_arch_init(struct oprofile_operations **ops) } -void __exit +void oprofile_arch_exit(void) { } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c359c0799ba..594d94c5889 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -483,6 +483,16 @@ config PCI_HOST_VIA82C505 depends on PCI && ARCH_SHARK default y +config ICST525 + bool + depends on ARCH_INTEGRATOR + default y + +config ARM_AMBA + bool + depends on ARCH_INTEGRATOR + default y + config ISA bool depends on FOOTBRIDGE_HOST || ARCH_SHARK || ARCH_CLPS7500 || ARCH_EBSA110 || ARCH_CDB89712 || ARCH_EDB7211 || ARCH_SA1100 @@ -582,7 +592,7 @@ endif config CPU_FREQ_INTEGRATOR tristate "CPUfreq driver for ARM Integrator CPUs" - depends on ARCH_INTEGRATOR && CPU_FREQ + depends on ARCH_INTEGRATOR && ICST525 && CPU_FREQ default y help This enables the CPUfreq driver for ARM Integrator CPUs. @@ -691,81 +701,9 @@ config KCORE_AOUT endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . +source "fs/Kconfig.binfmt" - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "drivers/base/Kconfig" config PM bool "Power Management support" diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 0a3495af6bb..247621c53e4 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -3,6 +3,8 @@ # obj-y += platform.o +obj-$(CONFIG_ARM_AMBA) += amba.o +obj-$(CONFIG_ICST525) += icst525.o obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff --git a/arch/arm/common/amba.c b/arch/arm/common/amba.c new file mode 100644 index 00000000000..fad2d82e225 --- /dev/null +++ b/arch/arm/common/amba.c @@ -0,0 +1,243 @@ +/* + * linux/arch/arm/common/amba.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + +#define to_amba_device(d) container_of(d, struct amba_device, dev) +#define to_amba_driver(d) container_of(d, struct amba_driver, drv) + +static struct amba_id * +amba_lookup(struct amba_id *table, struct amba_device *dev) +{ + int ret = 0; + + while (table->mask) { + ret = (dev->periphid & table->mask) == table->id; + if (ret) + break; + table++; + } + + return ret ? table : NULL; +} + +static int amba_match(struct device *dev, struct device_driver *drv) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(drv); + + return amba_lookup(pcdrv->id_table, pcdev) != NULL; +} + +/* + * Primecells are part of the Advanced Microcontroller Bus Architecture, + * so we call the bus "amba". + */ +struct bus_type amba_bustype = { + .name = "amba", + .match = amba_match, +}; + +static int __init amba_init(void) +{ + return bus_register(&amba_bustype); +} + +postcore_initcall(amba_init); + +/* + * These are the device model conversion veneers; they convert the + * device model structures to our more specific structures. + */ +static int amba_probe(struct device *dev) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(dev->driver); + struct amba_id *id; + + id = amba_lookup(pcdrv->id_table, pcdev); + + return pcdrv->probe(pcdev, id); +} + +static int amba_remove(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->remove(to_amba_device(dev)); +} + +static void amba_shutdown(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + drv->shutdown(to_amba_device(dev)); +} + +static int amba_suspend(struct device *dev, u32 state, u32 level) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->suspend(to_amba_device(dev), state, level); +} + +static int amba_resume(struct device *dev, u32 level) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->resume(to_amba_device(dev), level); +} + +/** + * amba_driver_register - register an AMBA device driver + * @drv: amba device driver structure + * + * Register an AMBA device driver with the Linux device model + * core. If devices pre-exist, the drivers probe function will + * be called. + */ +int amba_driver_register(struct amba_driver *drv) +{ + drv->drv.bus = &amba_bustype; + +#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn + SETFN(probe); + SETFN(remove); + SETFN(shutdown); + SETFN(suspend); + SETFN(resume); + + return driver_register(&drv->drv); +} + +/** + * amba_driver_unregister - remove an AMBA device driver + * @drv: AMBA device driver structure to remove + * + * Unregister an AMBA device driver from the Linux device + * model. The device model will call the drivers remove function + * for each device the device driver is currently handling. + */ +void amba_driver_unregister(struct amba_driver *drv) +{ + driver_unregister(&drv->drv); +} + + +static void amba_device_release(struct device *dev) +{ + struct amba_device *d = to_amba_device(dev); + + if (d->res.parent) + release_resource(&d->res); + kfree(d); +} + +static ssize_t show_id(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "%08x\n", dev->periphid); +} +static DEVICE_ATTR(id, S_IRUGO, show_id, NULL); + +static ssize_t show_irq(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "%u\n", dev->irq); +} +static DEVICE_ATTR(irq, S_IRUGO, show_irq, NULL); + +static ssize_t show_res(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "\t%08lx\t%08lx\t%08lx\n", + dev->res.start, dev->res.end, dev->res.flags); +} +static DEVICE_ATTR(resource, S_IRUGO, show_res, NULL); + +/** + * amba_device_register - register an AMBA device + * @dev: AMBA device to register + * @parent: parent memory resource + * + * Setup the AMBA device, reading the cell ID if present. + * Claim the resource, and register the AMBA device with + * the Linux device manager. + */ +int amba_device_register(struct amba_device *dev, struct resource *parent) +{ + u32 pid, cid; + void *tmp; + int i, ret; + + dev->dev.release = amba_device_release; + dev->dev.bus = &amba_bustype; + dev->res.name = dev->dev.name; + + ret = request_resource(parent, &dev->res); + if (ret == 0) { + tmp = ioremap(dev->res.start, SZ_4K); + if (!tmp) { + ret = -ENOMEM; + goto out; + } + + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); + + iounmap(tmp); + + if (cid == 0xb105f00d) + dev->periphid = pid; + + if (dev->periphid) + snprintf(dev->dev.name, sizeof(dev->dev.name), + "AMBA PL%03X", + dev->periphid & 0xfff); + else + strlcpy(dev->dev.name, "AMBA unknown", + sizeof(dev->dev.name)); + + ret = device_register(&dev->dev); + if (ret == 0) { + device_create_file(&dev->dev, &dev_attr_id); + device_create_file(&dev->dev, &dev_attr_irq); + device_create_file(&dev->dev, &dev_attr_resource); + } else { + out: + release_resource(&dev->res); + } + } + return ret; +} + +/** + * amba_device_unregister - unregister an AMBA device + * @dev: AMBA device to remove + * + * Remove the specified AMBA device from the Linux device + * manager. All files associated with this object will be + * destroyed, and device drivers notified that the device has + * been removed. The AMBA device's resources including + * the amba_device structure will be freed once all + * references to it have been dropped. + */ +void amba_device_unregister(struct amba_device *dev) +{ + device_unregister(&dev->dev); +} + +EXPORT_SYMBOL(amba_driver_register); +EXPORT_SYMBOL(amba_driver_unregister); +EXPORT_SYMBOL(amba_device_register); +EXPORT_SYMBOL(amba_device_unregister); diff --git a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c new file mode 100644 index 00000000000..943ef88c037 --- /dev/null +++ b/arch/arm/common/icst525.c @@ -0,0 +1,160 @@ +/* + * linux/arch/arm/common/icst525.c + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST525 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + */ +#include +#include + +#include + +/* + * Divisors for each OD setting. + */ +static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; + +unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco) +{ + return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); +} + +EXPORT_SYMBOL(icst525_khz); + +/* + * Ascending divisor S values. + */ +static unsigned char idx2s[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; + +struct icst525_vco +icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq) +{ + struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f; + unsigned int i = 0, rd, best = (unsigned int)-1; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = freq * s2div[idx2s[i]]; + + /* + * f must be between 10MHz and + * 320MHz (5V) or 200MHz (3V) + */ + if (f > 10000 && f <= p->vco_max) + break; + } while (i < ARRAY_SIZE(idx2s)); + + if (i > ARRAY_SIZE(idx2s)) + return vco; + + vco.s = idx2s[i]; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long fref_div, f_pll; + unsigned int vd; + int f_diff; + + fref_div = (2 * p->ref) / rd; + + vd = (f + fref_div / 2) / fref_div; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = fref_div * vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst525_khz_to_vco); + +struct icst525_vco +icst525_ps_to_vco(const struct icst525_params *p, unsigned long period) +{ + struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f, ps; + unsigned int i = 0, rd, best = (unsigned int)-1; + + ps = 1000000000UL / p->vco_max; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = period / s2div[idx2s[i]]; + + /* + * f must be between 10MHz and + * 320MHz (5V) or 200MHz (3V) + */ + if (f >= ps && f < 100000) + break; + } while (i < ARRAY_SIZE(idx2s)); + + if (i > ARRAY_SIZE(idx2s)) + return vco; + + vco.s = idx2s[i]; + + ps = 500000000UL / p->ref; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long f_in_div, f_pll; + unsigned int vd; + int f_diff; + + f_in_div = ps * rd; + + vd = (f_in_div + f / 2) / f; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = (f_in_div + vd / 2) / vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst525_ps_to_vco); diff --git a/arch/arm/kernel/pm.c b/arch/arm/kernel/pm.c index e80142d9304..f28e2ba66f5 100644 --- a/arch/arm/kernel/pm.c +++ b/arch/arm/kernel/pm.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S index 815db7c8ee6..e6aab5ceec1 100644 --- a/arch/arm/lib/lib1funcs.S +++ b/arch/arm/lib/lib1funcs.S @@ -52,10 +52,6 @@ divisor .req r1 result .req r2 overdone .req r2 curbit .req r3 -ip .req r12 -sp .req r13 -lr .req r14 -pc .req r15 ENTRY(__udivsi3) cmp divisor, #0 diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 88dd84ad01d..c7e7eb4a9c4 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -104,7 +106,7 @@ static struct irqchip sc_chip = { .mask = sc_mask_irq, .unmask = sc_unmask_irq, }; - + static void __init integrator_init_irq(void) { unsigned int i; @@ -126,6 +128,52 @@ static void __init integrator_init_irq(void) } } +static struct amba_device kmi0_device = { + .dev = { + .bus_id = "mb:18", + }, + .res = { + .start = KMI0_BASE, + .end = KMI0_BASE + KMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = IRQ_KMIINT0, + .periphid = 0x00041050, +}; + +static struct amba_device kmi1_device = { + .dev = { + .bus_id = "mb:19", + }, + .res = { + .start = KMI1_BASE, + .end = KMI1_BASE + KMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = IRQ_KMIINT1, + .periphid = 0x00041050, +}; + +static struct amba_device *amba_devs[] __initdata = { + &kmi0_device, + &kmi1_device, +}; + +static int __init register_devices(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + + amba_device_register(d, &iomem_resource); + } + + return 0; +} + +arch_initcall(register_devices); + MACHINE_START(INTEGRATOR, "ARM-Integrator") MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c index 991a37e170f..c1494386428 100644 --- a/arch/arm/mach-integrator/cpu.c +++ b/arch/arm/mach-integrator/cpu.c @@ -23,6 +23,7 @@ #include #include +#include static struct cpufreq_driver integrator_driver; @@ -31,75 +32,40 @@ static struct cpufreq_driver integrator_driver; #define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) -struct vco { - unsigned char vdw; - unsigned char od; +static const struct icst525_params lclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 8, + .vd_max = 132, + .rd_min = 24, + .rd_max = 24, }; -/* - * Divisors for each OD setting. - */ -static unsigned char cc_divisor[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; - -static unsigned int vco_to_freq(struct vco vco, int factor) -{ - return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor; -} - -/* - * Divisor indexes in ascending divisor order - */ -static unsigned char s2od[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; - -static struct vco freq_to_vco(unsigned int freq_khz, int factor) -{ - struct vco vco = {0, 0}; - unsigned int i, f; - - freq_khz *= factor; - - for (i = 0; i < 8; i++) { - f = freq_khz * cc_divisor[s2od[i]]; - /* f must be between 10MHz and 320MHz */ - if (f > 10000 && f <= 320000) - break; - } - - vco.od = s2od[i]; - vco.vdw = f / 2000 - 8; - - return vco; -} - +static const struct icst525_params cclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 12, + .vd_max = 160, + .rd_min = 24, + .rd_max = 24, +}; /* * Validate the speed policy. */ static int integrator_verify_policy(struct cpufreq_policy *policy) { - struct vco vco; + struct icst525_vco vco; cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - vco = freq_to_vco(policy->max, 1); - - if (vco.vdw < 4) - vco.vdw = 4; - if (vco.vdw > 152) - vco.vdw = 152; - - policy->max = vco_to_freq(vco, 1); - - vco = freq_to_vco(policy->min, 1); - - if (vco.vdw < 4) - vco.vdw = 4; - if (vco.vdw > 152) - vco.vdw = 152; + vco = icst525_khz_to_vco(&cclk_params, policy->max); + policy->max = icst525_khz(&cclk_params, vco); - policy->min = vco_to_freq(vco, 1); + vco = icst525_khz_to_vco(&cclk_params, policy->min); + policy->min = icst525_khz(&cclk_params, vco); cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, @@ -115,7 +81,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, { unsigned long cpus_allowed; int cpu = policy->cpu; - struct vco vco; + struct icst525_vco vco; struct cpufreq_freqs freqs; u_int cm_osc; @@ -133,19 +99,20 @@ static int integrator_set_target(struct cpufreq_policy *policy, /* get current setting */ cm_osc = __raw_readl(CM_OSC); - vco.od = (cm_osc >> 8) & 7; - vco.vdw = cm_osc & 255; - freqs.old = vco_to_freq(vco, 1); + vco.s = (cm_osc >> 8) & 7; + vco.v = cm_osc & 255; + vco.r = 22; + freqs.old = icst525_khz(&cclk_params, vco); - /* freq_to_vco rounds down -- so we need the next larger freq in - * case of CPUFREQ_RELATION_L. + /* icst525_khz_to_vco rounds down -- so we need the next + * larger freq in case of CPUFREQ_RELATION_L. */ if (relation == CPUFREQ_RELATION_L) target_freq += 1999; if (target_freq > policy->max) target_freq = policy->max; - vco = freq_to_vco(target_freq, 1); - freqs.new = vco_to_freq(vco, 1); + vco = icst525_khz_to_vco(&cclk_params, target_freq); + freqs.new = icst525_khz(&cclk_params, vco); freqs.cpu = policy->cpu; @@ -158,7 +125,7 @@ static int integrator_set_target(struct cpufreq_policy *policy, cm_osc = __raw_readl(CM_OSC); cm_osc &= 0xfffff800; - cm_osc |= vco.vdw | vco.od << 8; + cm_osc |= vco.v | vco.s << 8; __raw_writel(0xa05f, CM_LOCK); __raw_writel(cm_osc, CM_OSC); @@ -179,7 +146,7 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) unsigned long cpus_allowed; unsigned int cpu = policy->cpu; u_int cm_osc, cm_stat, mem_freq_khz; - struct vco vco; + struct icst525_vco vco; cpus_allowed = current->cpus_allowed; @@ -189,23 +156,26 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy) /* detect memory etc. */ cm_stat = __raw_readl(CM_STAT); cm_osc = __raw_readl(CM_OSC); - vco.od = (cm_osc >> 20) & 7; - vco.vdw = (cm_osc >> 12) & 255; - mem_freq_khz = vco_to_freq(vco, 2); + vco.s = (cm_osc >> 20) & 7; + vco.v = (cm_osc >> 12) & 255; + vco.r = 22; + mem_freq_khz = icst525_khz(&lclk_params, vco) / 2; printk(KERN_INFO "CPU%d: Module id: %d\n", cpu, cm_stat & 255); printk(KERN_INFO "CPU%d: Memory clock = %d.%03d MHz\n", cpu, mem_freq_khz / 1000, mem_freq_khz % 1000); - vco.od = (cm_osc >> 8) & 7; - vco.vdw = cm_osc & 255; + vco.s = (cm_osc >> 8) & 7; + vco.v = cm_osc & 255; + vco.r = 22; /* set default policy and cpuinfo */ policy->policy = CPUFREQ_POLICY_PERFORMANCE; policy->cpuinfo.max_freq = 160000; policy->cpuinfo.min_freq = 12000; policy->cpuinfo.transition_latency = 1000; /* 1 ms, assumed */ - policy->cur = policy->min = policy->max = vco_to_freq(vco, 1); /* current freq */ + policy->cur = policy->min = policy->max = + icst525_khz(&cclk_params, vco); /* current freq */ set_cpus_allowed(current, cpus_allowed); diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 3b665242763..4a4238d5a10 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -138,11 +138,14 @@ static struct resource sa11x0udc_resources[] = { }, }; +static u64 sa11x0udc_dma_mask = 0xffffffffUL; + static struct platform_device sa11x0udc_device = { .name = "sa11x0-udc", .id = 0, .dev = { .name = "Intel Corporation SA11x0 [UDC]", + .dma_mask = &sa11x0udc_dma_mask, }, .num_resources = ARRAY_SIZE(sa11x0udc_resources), .resource = sa11x0udc_resources, @@ -166,6 +169,27 @@ static struct platform_device sa11x0mcp_device = { .resource = sa11x0mcp_resources, }; +static struct resource sa11x0ssp_resources[] = { + [0] = { + .start = 0x80070000, + .end = 0x8007ffff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 sa11x0ssp_dma_mask = 0xffffffffUL; + +static struct platform_device sa11x0ssp_device = { + .name = "sa11x0-ssp", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [SSP]", + .dma_mask = &sa11x0ssp_dma_mask, + }, + .num_resources = ARRAY_SIZE(sa11x0ssp_resources), + .resource = sa11x0ssp_resources, +}; + static struct resource sa11x0fb_resources[] = { [0] = { .start = 0xb0100000, @@ -200,6 +224,7 @@ static struct platform_device sa11x0pcmcia_device = { static struct platform_device *sa11x0_devices[] __initdata = { &sa11x0udc_device, &sa11x0mcp_device, + &sa11x0ssp_device, &sa11x0pcmcia_device, &sa11x0fb_device, }; diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c index 1a934f83133..026755f8834 100644 --- a/arch/arm/mach-sa1100/irq.c +++ b/arch/arm/mach-sa1100/irq.c @@ -211,14 +211,14 @@ static struct resource irq_resource = { .end = 0x9005ffff, }; -static struct { +static struct sa1100irq_state { unsigned int saved; unsigned int icmr; unsigned int iclr; unsigned int iccr; } sa1100irq_state; -static int sa1100irq_suspend(struct device *dev, u32 state, u32 level) +static int sa1100irq_suspend(struct sys_device *dev, u32 state) { struct sa1100irq_state *st = &sa1100irq_state; diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 8783e805700..7aa0e733b0a 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -213,7 +213,7 @@ void __flush_dcache_page(struct page *page) if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT) continue; - flush_cache_page(mpnt, off); + flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT)); } } diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 3017f7b1481..b2d8278858b 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -309,9 +309,9 @@ static void __init build_mem_type_table(void) const char *policy; /* - * ARMv5 can use ECC memory. + * ARMv5 and higher can use ECC memory. */ - if (cpu_arch == CPU_ARCH_ARMv5) { + if (cpu_arch >= CPU_ARCH_ARMv5) { mem_types[MT_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_MEMORY].prot_sect |= ecc_mask; } else { diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 2749f755370..7ef598839d1 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Wed May 7 23:43:08 2003 +# Last update: Thu Jun 19 18:42:39 2003 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -259,7 +259,7 @@ stork_nest ARCH_STORK_NEST STORK_NEST 247 stork_egg ARCH_STORK_EGG STORK_EGG 248 wismo SA1100_WISMO WISMO 249 ezlinx ARCH_EZLINX EZLINX 250 -at91 ARCH_AT91 AT91 251 +at91rm9200 ARCH_AT91 AT91 251 orion ARCH_ORION ORION 252 neptune ARCH_NEPTUNE NEPTUNE 253 hackkit SA1100_HACKKIT HACKKIT 254 @@ -332,10 +332,26 @@ pxa_pooh ARCH_PXA_POOH PXA_POOH 320 bandon ARCH_BANDON BANDON 321 pcm7210 ARCH_PCM7210 PCM7210 322 nms9200 ARCH_NMS9200 NMS9200 323 -gealog ARCH_GEALOG GEALOG 324 +logodl ARCH_LOGODL LOGODL 324 m7140 SA1100_M7140 M7140 325 korebot ARCH_KOREBOT KOREBOT 326 iq31244 ARCH_IQ31244 IQ31244 327 koan393 SA1100_KOAN393 KOAN393 328 inhandftip3 ARCH_INHANDFTIP3 INHANDFTIP3 329 gonzo ARCH_GONZO GONZO 330 +bast ARCH_BAST BAST 331 +scanpass ARCH_SCANPASS SCANPASS 332 +ep7312_pooh ARCH_EP7312_POOH EP7312_POOH 333 +ta7s ARCH_TA7S TA7S 334 +ta7v ARCH_TA7V TA7V 335 +icarus SA1100_ICARUS ICARUS 336 +h1900 ARCH_H1900 H1900 337 +gemini SA1100_GEMINI GEMINI 338 +axim ARCH_AXIM AXIM 339 +audiotron ARCH_AUDIOTRON AUDIOTRON 340 +h2200 ARCH_H2200 H2200 341 +loox600 ARCH_LOOX600 LOOX600 342 +niop ARCH_NIOP NIOP 343 +dm310 ARCH_DM310 DM310 344 +seedpxa_c2 ARCH_SEEDPXA_C2 SEEDPXA_C2 345 +ixp4xx_mguardpci ARCH_IXP4XX_MGUARD_PCI IXP4XX_MGUARD_PCI 346 diff --git a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in index 0c84ec53264..addbcb88ae0 100644 --- a/arch/arm/vmlinux-armv.lds.in +++ b/arch/arm/vmlinux-armv.lds.in @@ -53,7 +53,9 @@ SECTIONS __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; - SECURITY_INIT + __security_initcall_start = .; + *(.security_initcall.init) + __security_initcall_end = .; . = ALIGN(32); __initramfs_start = .; usr/built-in.o(.init.ramfs) diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig index f071e0c713a..b5dac8d6ba2 100644 --- a/arch/arm26/Kconfig +++ b/arch/arm26/Kconfig @@ -297,6 +297,8 @@ config CMDLINE endmenu +source "drivers/base/Kconfig" + source "drivers/parport/Kconfig" source "drivers/pnp/Kconfig" diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index ab633b6b748..08ad9415907 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -25,34 +25,7 @@ source "init/Kconfig" menu "General setup" -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. +source "fs/Kconfig.binfmt" config ETRAX_KGDB bool "Use kernel gdb debugger" @@ -542,6 +515,8 @@ config ETRAX_POWERBUTTON_BIT endmenu +source "drivers/base/Kconfig" + # bring in Etrax built-in drivers source "arch/cris/drivers/Kconfig" diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index aa8258243eb..0720e0f693e 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -141,13 +141,12 @@ config KCORE_AOUT config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. +source "fs/Kconfig.binfmt" endmenu +source "drivers/base/Kconfig" + source "drivers/block/Kconfig" source "drivers/ide/Kconfig" diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index a1b727c98bd..1da9d947a59 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -1190,84 +1190,12 @@ config KCORE_AOUT endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile index 2cf76a94184..41f9b6fa498 100644 --- a/arch/i386/kernel/acpi/Makefile +++ b/arch/i386/kernel/acpi/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_ACPI_HT_ONLY) := acpitable.o obj-$(CONFIG_ACPI_BOOT) := boot.o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o diff --git a/arch/i386/kernel/acpi/acpitable.c b/arch/i386/kernel/acpi/acpitable.c new file mode 100644 index 00000000000..ebcde5af1b7 --- /dev/null +++ b/arch/i386/kernel/acpi/acpitable.c @@ -0,0 +1,553 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * $Id: acpitable.c,v 1.7 2001/11/04 12:21:18 fenrus Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpitable.h" + +static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT]; + +int acpi_lapic; + +static unsigned char __init +acpi_checksum(void *buffer, int length) +{ + int i; + unsigned char *bytebuffer; + unsigned char sum = 0; + + if (!buffer || length <= 0) + return 0; + + bytebuffer = (unsigned char *) buffer; + + for (i = 0; i < length; i++) + sum += *(bytebuffer++); + + return sum; +} + +static void __init +acpi_print_table_header(acpi_table_header * header) +{ + if (!header) + return; + + printk(KERN_INFO "ACPI table found: %.4s v%d [%.6s %.8s %d.%d]\n", + header->signature, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision >> 16, + header->oem_revision & 0xffff); + + return; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_scan_memory_for_rsdp + * + * PARAMETERS: address - Starting pointer for search + * length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found and valid, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +static void *__init +acpi_tb_scan_memory_for_rsdp(void *address, int length) +{ + u32 offset; + + if (length <= 0) + return NULL; + + /* Search from given start addr for the requested length */ + + offset = 0; + + while (offset < length) { + /* The signature must match and the checksum must be correct */ + if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 && + acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { + /* If so, we have found the RSDP */ + printk(KERN_INFO "ACPI: RSDP located at physical address %p\n", + address); + return address; + } + offset += RSDP_SCAN_STEP; + address += RSDP_SCAN_STEP; + } + + /* Searched entire block, no RSDP was found */ + printk(KERN_INFO "ACPI: Searched entire block, no RSDP was found.\n"); + return NULL; +} + +/******************************************************************************* + * + * FUNCTION: acpi_find_root_pointer + * + * PARAMETERS: none + * + * RETURN: physical address of the RSDP + * + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section + * 5.2.2; assertion #421). + * + ******************************************************************************/ + +static struct acpi_table_rsdp * __init +acpi_find_root_pointer(void) +{ + struct acpi_table_rsdp * rsdp; + + /* + * Physical address is given + */ + /* + * Region 1) Search EBDA (low memory) paragraphs + */ + rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), + LO_RSDP_WINDOW_SIZE); + + if (rsdp) + return rsdp; + + /* + * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + */ + rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), + HI_RSDP_WINDOW_SIZE); + + + + if (rsdp) + return rsdp; + + printk(KERN_ERR "ACPI: System description tables not found\n"); + return NULL; +} + + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. + */ +static __init char * +__va_range(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size; + int idx; + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(FIX_IO_APIC_BASE_END, phys); + base = fix_to_virt(FIX_IO_APIC_BASE_END); + dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size, + FIX_IO_APIC_BASE_END, base); + + /* + * Most cases can be covered by the below. + */ + idx = FIX_IO_APIC_BASE_END; + while (mapped_size < size) { + if (--idx < FIX_IO_APIC_BASE_0) + return 0; /* cannot handle this */ + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } + + return ((unsigned char *) base + offset); +} + +static int __init acpi_tables_init(void) +{ + int result = -ENODEV; + acpi_table_header *header = NULL; + struct acpi_table_rsdp *rsdp = NULL; + struct acpi_table_rsdt *rsdt = NULL; + struct acpi_table_rsdt saved_rsdt; + int tables = 0; + int type = 0; + int i = 0; + + + rsdp = (struct acpi_table_rsdp *) acpi_find_root_pointer(); + + if (!rsdp) + return -ENODEV; + + printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, + rsdp->oem_id); + + if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + printk(KERN_WARNING "RSDP table signature incorrect\n"); + return -EINVAL; + } + + rsdt = (struct acpi_table_rsdt *) + __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + + if (!rsdt) { + printk(KERN_WARNING "ACPI: Invalid root system description tables (RSDT)\n"); + return -ENODEV; + } + + header = & rsdt->header; + acpi_print_table_header(header); + + if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); + return -ENODEV; + } + + /* + * The number of tables is computed by taking the + * size of all entries (header size minus total + * size of RSDT) divided by the size of each entry + * (4-byte table pointers). + */ + tables = (header->length - sizeof(acpi_table_header)) / 4; + + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); + + if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length); + return -ENODEV; + } + + for (i = 0; i < tables; i++) { + /* Map in header, then map in full table length. */ + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], + sizeof(acpi_table_header)); + if (!header) + break; + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], header->length); + if (!header) + break; + + acpi_print_table_header(header); + + if (acpi_checksum(header,header->length)) { + printk(KERN_WARNING "ACPI %s has invalid checksum\n", + acpi_table_signatures[i]); + continue; + } + + for (type = 0; type < ACPI_TABLE_COUNT; type++) + if (!strncmp((char *) &header->signature, + acpi_table_signatures[type],strlen(acpi_table_signatures[type]))) + break; + + if (type >= ACPI_TABLE_COUNT) { + printk(KERN_WARNING "ACPI: Unsupported table %.4s\n", + header->signature); + continue; + } + + + if (!acpi_boot_ops[type]) + continue; + + result = acpi_boot_ops[type] (header, + (unsigned long) saved_rsdt. + entry[i]); + } + + return result; +} + +static int total_cpus __initdata = 0; +int have_acpi_tables; + +extern void __init MP_processor_info(struct mpc_config_processor *); + +static void __init +acpi_parse_lapic(struct acpi_table_lapic *local_apic) +{ + struct mpc_config_processor proc_entry; + int ix = 0; + + if (!local_apic) + return; + + printk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", + local_apic->acpi_id, local_apic->id, local_apic->flags.enabled); + + printk(KERN_INFO "CPU %d (0x%02x00)", total_cpus, local_apic->id); + + if (local_apic->flags.enabled) { + printk(" enabled"); + ix = local_apic->id; + if (ix >= MAX_APICS) { + printk(KERN_WARNING + "Processor #%d INVALID - (Max ID: %d).\n", ix, + MAX_APICS); + return; + } + /* + * Fill in the info we want to save. Not concerned about + * the processor ID. Processor features aren't present in + * the table. + */ + proc_entry.mpc_type = MP_PROCESSOR; + proc_entry.mpc_apicid = local_apic->id; + proc_entry.mpc_cpuflag = CPU_ENABLED; + if (proc_entry.mpc_apicid == boot_cpu_physical_apicid) { + printk(" (BSP)"); + proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR; + } + proc_entry.mpc_cpufeature = + (boot_cpu_data.x86 << 8) | + (boot_cpu_data.x86_model << 4) | + boot_cpu_data.x86_mask; + proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0]; + proc_entry.mpc_reserved[0] = 0; + proc_entry.mpc_reserved[1] = 0; + proc_entry.mpc_apicver = 0x10; /* integrated APIC */ + MP_processor_info(&proc_entry); + } else { + printk(" disabled"); + } + printk("\n"); + + total_cpus++; + return; +} + +static void __init +acpi_parse_ioapic(struct acpi_table_ioapic *ioapic) +{ + + if (!ioapic) + return; + + printk(KERN_INFO + "IOAPIC (id[0x%x] address[0x%x] global_irq_base[0x%x])\n", + ioapic->id, ioapic->address, ioapic->global_irq_base); + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_WARNING + "Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); +/* panic("Recompile kernel with bigger MAX_IO_APICS!\n"); */ + } +} + + +/* Interrupt source overrides inform the machine about exceptions + to the normal "PIC" mode interrupt routing */ + +static void __init +acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc) +{ + if (!intsrc) + return; + + printk(KERN_INFO + "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", + intsrc->bus, intsrc->bus_irq, intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); +} + +/* + * At this point, we look at the interrupt assignment entries in the MPS + * table. + */ + +static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc) +{ + if (!nmisrc) + return; + + printk(KERN_INFO + "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", + nmisrc->flags.polarity, nmisrc->flags.trigger, + nmisrc->global_irq); + +} +static void __init +acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi) +{ + if (!localnmi) + return; + + printk(KERN_INFO + "LAPIC_NMI (acpi_id[0x%04x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", + localnmi->acpi_id, localnmi->flags.polarity, + localnmi->flags.trigger, localnmi->lint); +} +static void __init +acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr) +{ + if (!lapic_addr_ovr) + return; + + printk(KERN_INFO "LAPIC_ADDR_OVR (address[0x%lx])\n", + (unsigned long) lapic_addr_ovr->address); + +} + +static void __init +acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc) +{ + if (!plintsrc) + return; + + printk(KERN_INFO + "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + plintsrc->flags.polarity, plintsrc->flags.trigger, + plintsrc->type, plintsrc->id, plintsrc->eid, + plintsrc->iosapic_vector, plintsrc->global_irq); +} +static int __init +acpi_parse_madt(acpi_table_header * header, unsigned long phys) +{ + + struct acpi_table_madt *madt; + acpi_madt_entry_header *entry_header; + int table_size; + + madt = (struct acpi_table_madt *) __va_range(phys, header->length); + + if (!madt) + return -EINVAL; + + table_size = (int) (header->length - sizeof(*madt)); + entry_header = + (acpi_madt_entry_header *) ((void *) madt + sizeof(*madt)); + + while (entry_header && (table_size > 0)) { + switch (entry_header->type) { + case ACPI_MADT_LAPIC: + acpi_parse_lapic((struct acpi_table_lapic *) + entry_header); + break; + case ACPI_MADT_IOAPIC: + acpi_parse_ioapic((struct acpi_table_ioapic *) + entry_header); + break; + case ACPI_MADT_INT_SRC_OVR: + acpi_parse_int_src_ovr((struct acpi_table_int_src_ovr *) + entry_header); + break; + case ACPI_MADT_NMI_SRC: + acpi_parse_nmi_src((struct acpi_table_nmi_src *) + entry_header); + break; + case ACPI_MADT_LAPIC_NMI: + acpi_parse_lapic_nmi((struct acpi_table_lapic_nmi *) + entry_header); + break; + case ACPI_MADT_LAPIC_ADDR_OVR: + acpi_parse_lapic_addr_ovr((struct + acpi_table_lapic_addr_ovr *) + entry_header); + break; + case ACPI_MADT_PLAT_INT_SRC: + acpi_parse_plat_int_src((struct acpi_table_plat_int_src + *) entry_header); + break; + default: + printk(KERN_WARNING + "Unsupported MADT entry type 0x%x\n", + entry_header->type); + break; + } + table_size -= entry_header->length; + entry_header = + (acpi_madt_entry_header *) ((void *) entry_header + + entry_header->length); + } + + if (!total_cpus) { + printk("ACPI: No Processors found in the APCI table.\n"); + return -EINVAL; + } + + printk(KERN_INFO "%d CPUs total\n", total_cpus); + + if (madt->lapic_address) + mp_lapic_addr = madt->lapic_address; + else + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + printk(KERN_INFO "Local APIC address %x\n", madt->lapic_address); + + return 0; +} + + +/* + * Configure the processor info using MADT in the ACPI tables. If we fail to + * configure that, then we use the MPS tables. + */ +void __init +acpi_boot_init(void) +{ + + memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); + acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; + + /* + * Only do this when requested, either because of CPU/Bios type or from the command line + */ + + if (!acpi_tables_init()) + acpi_lapic = 1; +} + diff --git a/arch/i386/kernel/acpi/acpitable.h b/arch/i386/kernel/acpi/acpitable.h new file mode 100644 index 00000000000..ddf1c84a654 --- /dev/null +++ b/arch/i386/kernel/acpi/acpitable.h @@ -0,0 +1,260 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * $Id: acpitable.h,v 1.3 2001/11/03 22:41:34 fenrus Exp $ + */ + +/* + * The following codes are cut&pasted from drivers/acpi. Part of the code + * there can be not updated or delivered yet. + * To avoid conflicts when CONFIG_ACPI is defined, the following codes are + * modified so that they are self-contained in this file. + * -- jun + */ + +#ifndef _HEADER_ACPITABLE_H_ +#define _HEADER_ACPITABLE_H_ + +#define dprintk printk +typedef unsigned int ACPI_TBLPTR; + +typedef struct { /* ACPI common table header */ + char signature[4]; /* identifies type of table */ + u32 length; /* length of table, + in bytes, * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_table_header __attribute__ ((packed));; + +enum { + ACPI_APIC = 0, + ACPI_BOOT, + ACPI_DBGP, + ACPI_DSDT, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, + ACPI_FACS, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_XSDT, + ACPI_TABLE_COUNT +}; + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + "APIC", + "BOOT", + "DBGP", + "DSDT", + "ECDT", + "ETDT", + "FACP", + "FACS", + "OEM", + "PSDT", + "SBST", + "SLIT", + "SPCR", + "SRAT", + "SSDT", + "SPMI", + "XSDT" +}; + +struct acpi_table_madt { + acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed));; + +enum { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +#define RSDP_SIG "RSD PTR " +#define RSDT_SIG "RSDT" + +#define ACPI_DEBUG_PRINT(pl) + +#define ACPI_MEMORY_MODE 0x01 +#define ACPI_LOGICAL_ADDRESSING 0x00 +#define ACPI_PHYSICAL_ADDRESSING 0x01 + +#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ +#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 +#define RSDP_CHECKSUM_LENGTH 20 + +typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi_table_rsdt { + acpi_table_header header; + u32 entry[ACPI_TABLE_COUNT]; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_madt_entry_header __attribute__ ((packed)); + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_madt_int_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_madt_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_madt_int_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_madt_entry_header header; + u8 acpi_id; + acpi_madt_int_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_madt_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u8 type; + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc { + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + acpi_table_header *pointer; + void *base_pointer; + u8 *aml_pointer; + u64 physical_address; + u32 aml_length; + u32 length; + u32 count; + u16 table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} acpi_table_desc __attribute__ ((packed));; + +#endif diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index ad45189c98c..5aef7a47a38 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -874,6 +874,7 @@ ENTRY(sys_call_table) .long sys_clock_gettime /* 265 */ .long sys_clock_getres .long sys_clock_nanosleep - + .long sys_statfs64 + .long sys_fstatfs64 nr_syscalls=(.-sys_call_table)/4 diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 656eb3bcff5..72362882327 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -23,17 +23,27 @@ #include #include #include +#include #include #include #include #include +#include unsigned int nmi_watchdog = NMI_NONE; static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); +/* nmi_active: + * +1: the lapic NMI watchdog is active, but can be disabled + * 0: the lapic NMI watchdog has not been set up, and cannot + * be enabled + * -1: the lapic NMI watchdog is disabled, but can be enabled + */ +static int nmi_active; + #define K7_EVNTSEL_ENABLE (1 << 22) #define K7_EVNTSEL_INT (1 << 20) #define K7_EVNTSEL_OS (1 << 17) @@ -91,6 +101,7 @@ int __init check_nmi_watchdog (void) continue; if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck!\n", cpu); + nmi_active = 0; return -1; } } @@ -131,21 +142,15 @@ static int __init setup_nmi_watchdog(char *str) * We can enable the IO-APIC watchdog * unconditionally. */ - if (nmi == NMI_IO_APIC) + if (nmi == NMI_IO_APIC) { + nmi_active = 1; nmi_watchdog = nmi; + } return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); -/* nmi_active: - * +1: the lapic NMI watchdog is active, but can be disabled - * 0: the lapic NMI watchdog has not been set up, and cannot - * be enabled - * -1: the lapic NMI watchdog is disabled, but can be enabled - */ -static int nmi_active; - void disable_lapic_nmi_watchdog(void) { if (nmi_active <= 0) @@ -179,6 +184,27 @@ void enable_lapic_nmi_watchdog(void) } } +void disable_timer_nmi_watchdog(void) +{ + if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0)) + return; + + disable_irq(0); + unset_nmi_callback(); + nmi_active = -1; + nmi_watchdog = NMI_NONE; +} + +void enable_timer_nmi_watchdog(void) +{ + if (nmi_active < 0) { + nmi_watchdog = NMI_IO_APIC; + touch_nmi_watchdog(); + nmi_active = 1; + enable_irq(0); + } +} + #ifdef CONFIG_PM static int nmi_pm_active; /* nmi_active before suspend */ @@ -429,3 +455,5 @@ void nmi_watchdog_tick (struct pt_regs * regs) EXPORT_SYMBOL(nmi_watchdog); EXPORT_SYMBOL(disable_lapic_nmi_watchdog); EXPORT_SYMBOL(enable_lapic_nmi_watchdog); +EXPORT_SYMBOL(disable_timer_nmi_watchdog); +EXPORT_SYMBOL(enable_timer_nmi_watchdog); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 8cb6adb50b8..61bc3326e28 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -190,7 +190,7 @@ void show_regs(struct pt_regs * regs) ".previous \n" : "=r" (cr4): "0" (0)); printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); - show_trace(®s->esp); + show_trace(NULL, ®s->esp); } /* diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index ed5db84a1b2..8eda5c87e8e 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -61,7 +61,12 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; unsigned long mmu_cr4_features; EXPORT_SYMBOL_GPL(mmu_cr4_features); -int acpi_disabled __initdata = 0; +#ifdef CONFIG_ACPI_HT_ONLY +int acpi_disabled = 1; +#else +int acpi_disabled = 0; +#endif +EXPORT_SYMBOL(acpi_disabled); int MCA_bus; /* for MCA, but anyone else can use it if they want */ @@ -96,7 +101,6 @@ extern void dmi_scan_machine(void); extern void generic_apic_probe(char *); extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern int blk_nohighio; unsigned long saved_videomode; @@ -515,6 +519,10 @@ static void __init parse_cmdline_early (char ** cmdline_p) if (c == ' ' && !memcmp(from, "acpi=off", 8)) acpi_disabled = 1; + /* "acpismp=force" turns on ACPI again */ + else if (!memcmp(from, "acpismp=force", 14)) + acpi_disabled = 0; + /* * highmem=size forces highmem to be exactly 'size' bytes. * This works even on boxes that have no highmem otherwise. @@ -995,15 +1003,6 @@ void __init setup_arch(char **cmdline_p) #endif } -static int __init highio_setup(char *str) -{ - printk("i386: disabling HIGHMEM block I/O\n"); - blk_nohighio = 1; - return 1; -} -__setup("nohighio", highio_setup); - - #include "setup_arch_post.h" /* * Local Variables: diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 02f8e251271..db98194645c 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -281,19 +281,19 @@ unsigned long get_cmos_time(void) return retval; } -static struct sysdev_class rtc_sysclass = { - set_kset_name("rtc"), +static struct sysdev_class pit_sysclass = { + set_kset_name("pit"), }; /* XXX this driverfs stuff should probably go elsewhere later -john */ static struct sys_device device_i8253 = { - .id = 0, - .cls = &rtc_sysclass, + .id = 0, + .cls = &pit_sysclass, }; static int time_init_device(void) { - int error = sysdev_class_register(&rtc_sysclass); + int error = sysdev_class_register(&pit_sysclass); if (!error) error = sys_device_register(&device_i8253); return error; diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index c6bc1936f45..5a7a28deb04 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -32,9 +32,9 @@ #ifdef CONFIG_MCA #include -#include #endif +#include #include #include #include @@ -92,9 +92,8 @@ asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -void show_trace(unsigned long * stack) +void show_trace(struct task_struct *task, unsigned long * stack) { - int i; unsigned long addr; if (!stack) @@ -104,7 +103,6 @@ void show_trace(unsigned long * stack) #ifdef CONFIG_KALLSYMS printk("\n"); #endif - i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { @@ -122,10 +120,10 @@ void show_trace_task(struct task_struct *tsk) /* User space on another CPU? */ if ((esp ^ (unsigned long)tsk->thread_info) & (PAGE_MASK<<1)) return; - show_trace((unsigned long *)esp); + show_trace(tsk, (unsigned long *)esp); } -void show_stack(unsigned long * esp) +void show_stack(struct task_struct *task, unsigned long * esp) { unsigned long *stack; int i; @@ -145,7 +143,7 @@ void show_stack(unsigned long * esp) printk("%08lx ", *stack++); } printk("\n"); - show_trace(esp); + show_trace(task, esp); } /* @@ -155,7 +153,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } void show_registers(struct pt_regs *regs) @@ -192,7 +190,7 @@ void show_registers(struct pt_regs *regs) if (in_kernel) { printk("\nStack: "); - show_stack((unsigned long*)esp); + show_stack(NULL, (unsigned long*)esp); printk("Code: "); if(regs->eip < PAGE_OFFSET) diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 78c81583dd1..f4e07347195 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -24,9 +24,41 @@ static long htlbpagemem; int htlbpage_max; static long htlbzone_pages; -static LIST_HEAD(htlbpage_freelist); +static struct list_head hugepage_freelists[MAX_NUMNODES]; static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; +static void enqueue_huge_page(struct page *page) +{ + list_add(&page->list, + &hugepage_freelists[page_zone(page)->zone_pgdat->node_id]); +} + +static struct page *dequeue_huge_page(void) +{ + int nid = numa_node_id(); + struct page *page = NULL; + + if (list_empty(&hugepage_freelists[nid])) { + for (nid = 0; nid < MAX_NUMNODES; ++nid) + if (!list_empty(&hugepage_freelists[nid])) + break; + } + if (nid >= 0 && nid < MAX_NUMNODES && !list_empty(&hugepage_freelists[nid])) { + page = list_entry(hugepage_freelists[nid].next, struct page, list); + list_del(&page->list); + } + return page; +} + +static struct page *alloc_fresh_huge_page(void) +{ + static int nid = 0; + struct page *page; + page = alloc_pages_node(nid, GFP_HIGHUSER, HUGETLB_PAGE_ORDER); + nid = (nid + 1) % numnodes; + return page; +} + void free_huge_page(struct page *page); static struct page *alloc_hugetlb_page(void) @@ -35,13 +67,11 @@ static struct page *alloc_hugetlb_page(void) struct page *page; spin_lock(&htlbpage_lock); - if (list_empty(&htlbpage_freelist)) { + page = dequeue_huge_page(); + if (!page) { spin_unlock(&htlbpage_lock); return NULL; } - - page = list_entry(htlbpage_freelist.next, struct page, list); - list_del(&page->list); htlbpagemem--; spin_unlock(&htlbpage_lock); set_page_count(page, 1); @@ -253,7 +283,7 @@ void free_huge_page(struct page *page) INIT_LIST_HEAD(&page->list); spin_lock(&htlbpage_lock); - list_add(&page->list, &htlbpage_freelist); + enqueue_huge_page(page); htlbpagemem++; spin_unlock(&htlbpage_lock); } @@ -369,7 +399,8 @@ int try_to_free_low(int count) map = NULL; spin_lock(&htlbpage_lock); - list_for_each(p, &htlbpage_freelist) { + /* all lowmem is on node 0 */ + list_for_each(p, &hugepage_freelists[0]) { if (map) { list_del(&map->list); update_and_free_page(map); @@ -406,11 +437,11 @@ int set_hugetlb_mem_size(int count) return (int)htlbzone_pages; if (lcount > 0) { /* Increase the mem size. */ while (lcount--) { - page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); + page = alloc_fresh_huge_page(); if (page == NULL) break; spin_lock(&htlbpage_lock); - list_add(&page->list, &htlbpage_freelist); + enqueue_huge_page(page); htlbpagemem++; htlbzone_pages++; spin_unlock(&htlbpage_lock); @@ -451,12 +482,15 @@ static int __init hugetlb_init(void) int i; struct page *page; + for (i = 0; i < MAX_NUMNODES; ++i) + INIT_LIST_HEAD(&hugepage_freelists[i]); + for (i = 0; i < htlbpage_max; ++i) { - page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); + page = alloc_fresh_huge_page(); if (!page) break; spin_lock(&htlbpage_lock); - list_add(&page->list, &htlbpage_freelist); + enqueue_huge_page(page); spin_unlock(&htlbpage_lock); } htlbpage_max = htlbpagemem = htlbzone_pages = i; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index d1ac5318f2d..19321ca5540 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -425,6 +426,8 @@ static void __init set_max_mapnr_init(void) extern void set_max_mapnr_init(void); #endif /* !CONFIG_DISCONTIGMEM */ +static struct kcore_list kcore_mem, kcore_vmalloc; + void __init mem_init(void) { extern int ppro_with_ram_bug(void); @@ -477,6 +480,10 @@ void __init mem_init(void) datasize = (unsigned long) &_edata - (unsigned long) &_etext; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); + kclist_add(&kcore_vmalloc, (void *)VMALLOC_START, + VMALLOC_END-VMALLOC_START); + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), num_physpages << (PAGE_SHIFT-10), diff --git a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile index 79d7e0d1217..a6945077e80 100644 --- a/arch/i386/oprofile/Makefile +++ b/arch/i386/oprofile/Makefile @@ -9,3 +9,4 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofile-y := $(DRIVER_OBJS) init.o oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ op_model_ppro.o op_model_p4.o +oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o diff --git a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c index b87e0f2e3eb..7cb2029ca85 100644 --- a/arch/i386/oprofile/init.c +++ b/arch/i386/oprofile/init.c @@ -16,15 +16,21 @@ */ extern int nmi_init(struct oprofile_operations ** ops); +extern int nmi_timer_init(struct oprofile_operations **ops); extern void nmi_exit(void); int __init oprofile_arch_init(struct oprofile_operations ** ops) { + int ret = -ENODEV; #ifdef CONFIG_X86_LOCAL_APIC - return nmi_init(ops); -#else - return -ENODEV; + ret = nmi_init(ops); #endif + +#ifdef CONFIG_X86_IO_APIC + if (ret < 0) + ret = nmi_timer_init(ops); +#endif + return ret; } diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index 030f0fa8c45..18655f44b88 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -182,8 +182,8 @@ static void nmi_cpu_shutdown(void * dummy) static void nmi_shutdown(void) { nmi_enabled = 0; - unset_nmi_callback(); on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); + unset_nmi_callback(); enable_lapic_nmi_watchdog(); } diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c new file mode 100644 index 00000000000..5c1a9347dbb --- /dev/null +++ b/arch/i386/oprofile/nmi_timer_int.c @@ -0,0 +1,57 @@ +/** + * @file nmi_timer_int.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + */ + +#include +#include +#include +#include +#include + + +#include +#include +#include + +static int nmi_timer_callback(struct pt_regs * regs, int cpu) +{ + unsigned long eip = instruction_pointer(regs); + + oprofile_add_sample(eip, !user_mode(regs), 0, cpu); + return 1; +} + +static int timer_start(void) +{ + disable_timer_nmi_watchdog(); + set_nmi_callback(nmi_timer_callback); + return 0; +} + + +static void timer_stop(void) +{ + enable_timer_nmi_watchdog(); + unset_nmi_callback(); + synchronize_kernel(); +} + + +static struct oprofile_operations nmi_timer_ops = { + .start = timer_start, + .stop = timer_stop, + .cpu_type = "timer" +}; + + +int __init nmi_timer_init(struct oprofile_operations ** ops) +{ + *ops = &nmi_timer_ops; + printk(KERN_INFO "oprofile: using NMI timer interrupt.\n"); + return 0; +} diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 6c9fa8f376f..3e9ed569c3a 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -23,7 +23,24 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; int pcibios_last_bus = -1; struct pci_bus *pci_root_bus = NULL; -struct pci_ops *pci_root_ops = NULL; +struct pci_raw_ops *raw_pci_ops; + +static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +{ + return raw_pci_ops->read(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + return raw_pci_ops->write(0, bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, size, value); +} + +struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, +}; /* * legacy, numa, and acpi all want to call pcibios_scan_root @@ -115,7 +132,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) printk("PCI: Probing PCI hardware (bus %02x)\n", busnum); - return pci_scan_bus(busnum, pci_root_ops, NULL); + return pci_scan_bus(busnum, &pci_root_ops, NULL); } extern u8 pci_cache_line_size; @@ -124,7 +141,7 @@ static int __init pcibios_init(void) { struct cpuinfo_x86 *c = &boot_cpu_data; - if (!pci_root_ops) { + if (!raw_pci_ops) { printk("PCI: System does not support PCI\n"); return 0; } diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 039448ab26b..b61223fe843 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -13,7 +13,7 @@ #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ static int __pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len return 0; } -static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -71,19 +71,7 @@ static int __pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int le #undef PCI_CONF1_ADDRESS -static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf1_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf1_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -struct pci_ops pci_direct_conf1 = { +struct pci_raw_ops pci_direct_conf1 = { .read = pci_conf1_read, .write = pci_conf1_write, }; @@ -95,7 +83,7 @@ struct pci_ops pci_direct_conf1 = { #define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg) -static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -129,7 +117,7 @@ static int __pci_conf2_read (int seg, int bus, int dev, int fn, int reg, int len return 0; } -static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -165,19 +153,7 @@ static int __pci_conf2_write (int seg, int bus, int dev, int fn, int reg, int le #undef PCI_CONF2_ADDRESS -static int pci_conf2_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf2_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf2_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf2_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static struct pci_ops pci_direct_conf2 = { +static struct pci_raw_ops pci_direct_conf2 = { .read = pci_conf2_read, .write = pci_conf2_write, }; @@ -193,38 +169,30 @@ static struct pci_ops pci_direct_conf2 = { * This should be close to trivial, but it isn't, because there are buggy * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ -static int __devinit pci_sanity_check(struct pci_ops *o) +static int __devinit pci_sanity_check(struct pci_raw_ops *o) { u32 x = 0; - int retval = 0; - struct pci_bus *bus; /* Fake bus and device */ - struct pci_dev *dev; + int devfn; if (pci_probe & PCI_NO_CHECKS) return 1; - bus = kmalloc(sizeof(*bus), GFP_ATOMIC); - dev = kmalloc(sizeof(*dev), GFP_ATOMIC); - if (!bus || !dev) { - printk(KERN_ERR "Out of memory in %s\n", __FUNCTION__); - goto exit; + for (devfn = 0; devfn < 0x100; devfn++) { + if (o->read(0, 0, PCI_SLOT(devfn), PCI_FUNC(devfn), + PCI_CLASS_DEVICE, 2, &x)) + continue; + if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA) + return 1; + + if (o->read(0, 0, PCI_SLOT(devfn), PCI_FUNC(devfn), + PCI_VENDOR_ID, 2, &x)) + continue; + if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ) + return 1; } - bus->number = 0; - dev->bus = bus; - for(dev->devfn=0; dev->devfn < 0x100; dev->devfn++) - if ((!o->read(bus, dev->devfn, PCI_CLASS_DEVICE, 2, &x) && - (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || - (!o->read(bus, dev->devfn, PCI_VENDOR_ID, 2, &x) && - (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) { - retval = 1; - goto exit; - } DBG("PCI: Sanity check failed\n"); -exit: - kfree(dev); - kfree(bus); - return retval; + return 0; } static int __init pci_direct_init(void) @@ -247,9 +215,9 @@ static int __init pci_direct_init(void) local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) - pci_root_ops = NULL; + raw_pci_ops = NULL; else - pci_root_ops = &pci_direct_conf1; + raw_pci_ops = &pci_direct_conf1; return 0; } outl (tmp, 0xCF8); @@ -267,9 +235,9 @@ static int __init pci_direct_init(void) local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) - pci_root_ops = NULL; + raw_pci_ops = NULL; else - pci_root_ops = &pci_direct_conf2; + raw_pci_ops = &pci_direct_conf2; return 0; } } diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index 7f47b5a5f00..8247ee72149 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -23,9 +23,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(busno, &pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(suba+1, &pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -39,7 +39,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d) u8 busno; pci_read_config_byte(d, 0x4a, &busno); printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", d->slot_name, busno); - pci_scan_bus(busno, pci_root_ops, NULL); + pci_scan_bus(busno, &pci_root_ops, NULL); pcibios_last_bus = -1; } diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index e35674679df..53db10c42fe 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -107,7 +107,7 @@ static void __init pirq_peer_trick(void) * It might be a secondary bus, but in this case its parent is already * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ - if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) + if (busmap[i] && pci_scan_bus(i, &pci_root_ops, NULL)) printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i); pcibios_last_bus = -1; } diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c index 7e7f9120df8..29fea7d6ad6 100644 --- a/arch/i386/pci/legacy.c +++ b/arch/i386/pci/legacy.c @@ -31,14 +31,14 @@ static void __devinit pcibios_fixup_peer_bridges(void) if (pci_bus_exists(&pci_root_buses, n)) continue; bus->number = n; - bus->ops = pci_root_ops; + bus->ops = &pci_root_ops; dev->bus = bus; for (dev->devfn=0; dev->devfn<256; dev->devfn += 8) if (!pci_read_config_word(dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { DBG("Found device at %02x:%02x [%04x]\n", n, dev->devfn, l); printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n); - pci_scan_bus(n, pci_root_ops, NULL); + pci_scan_bus(n, &pci_root_ops, NULL); break; } } @@ -49,7 +49,7 @@ exit: static int __init pci_legacy_init(void) { - if (!pci_root_ops) { + if (!raw_pci_ops) { printk("PCI: System does not support PCI\n"); return 0; } diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index 0a184f2c7b5..80a093f06a8 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -13,7 +13,7 @@ #define PCI_CONF1_MQ_ADDRESS(bus, dev, fn, reg) \ (0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3)) -static int __pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long flags; @@ -41,7 +41,7 @@ static int __pci_conf1_mq_read (int seg, int bus, int dev, int fn, int reg, int return 0; } -static int __pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long flags; @@ -71,19 +71,7 @@ static int __pci_conf1_mq_write (int seg, int bus, int dev, int fn, int reg, int #undef PCI_CONF1_MQ_ADDRESS -static int pci_conf1_mq_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_conf1_mq_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_conf1_mq_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_conf1_mq_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static struct pci_ops pci_direct_conf1_mq = { +static struct pci_raw_ops pci_direct_conf1_mq = { .read = pci_conf1_mq_read, .write = pci_conf1_mq_write }; @@ -106,9 +94,9 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL); /* Bus A */ + pci_scan_bus(QUADLOCAL2BUS(quad,busno), &pci_root_ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL); /* Bus B */ + pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), &pci_root_ops, NULL); /* Bus B */ } pcibios_last_bus = -1; } @@ -121,7 +109,7 @@ static int __init pci_numa_init(void) { int quad; - pci_root_ops = &pci_direct_conf1_mq; + raw_pci_ops = &pci_direct_conf1_mq; if (pcibios_scanned++) return 0; @@ -132,7 +120,7 @@ static int __init pci_numa_init(void) printk("Scanning PCI bus %d for quad %d\n", QUADLOCAL2BUS(quad,0), quad); pci_scan_bus(QUADLOCAL2BUS(quad,0), - pci_root_ops, NULL); + &pci_root_ops, NULL); } } return 0; diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c index 1a21e260096..06557dd705e 100644 --- a/arch/i386/pci/pcbios.c +++ b/arch/i386/pci/pcbios.c @@ -172,7 +172,7 @@ static int __devinit pci_bios_find_device (unsigned short vendor, unsigned short return (int) (ret & 0xff00) >> 8; } -static int __pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +static int pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { unsigned long result = 0; unsigned long flags; @@ -227,7 +227,7 @@ static int __pci_bios_read (int seg, int bus, int dev, int fn, int reg, int len, return (int)((result & 0xff00) >> 8); } -static int __pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +static int pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { unsigned long result = 0; unsigned long flags; @@ -282,24 +282,12 @@ static int __pci_bios_write (int seg, int bus, int dev, int fn, int reg, int len return (int)((result & 0xff00) >> 8); } -static int pci_bios_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) -{ - return __pci_bios_read(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - -static int pci_bios_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) -{ - return __pci_bios_write(0, bus->number, PCI_SLOT(devfn), - PCI_FUNC(devfn), where, size, value); -} - /* * Function table for BIOS32 access */ -static struct pci_ops pci_bios_access = { +static struct pci_raw_ops pci_bios_access = { .read = pci_bios_read, .write = pci_bios_write }; @@ -308,7 +296,7 @@ static struct pci_ops pci_bios_access = { * Try to find PCI BIOS. */ -static struct pci_ops * __devinit pci_find_bios(void) +static struct pci_raw_ops * __devinit pci_find_bios(void) { union bios32 *check; unsigned char sum; @@ -484,7 +472,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) static int __init pci_pcbios_init(void) { if ((pci_probe & PCI_PROBE_BIOS) - && ((pci_root_ops = pci_find_bios()))) { + && ((raw_pci_ops = pci_find_bios()))) { pci_probe |= PCI_BIOS_SORT; pci_bios_present = 1; } diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 68100f53ecb..6f3786334bf 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -37,7 +37,7 @@ int pcibios_enable_resources(struct pci_dev *, int); extern int pcibios_last_bus; extern struct pci_bus *pci_root_bus; -extern struct pci_ops *pci_root_ops; +extern struct pci_ops pci_root_ops; /* pci-irq.c */ diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 207b0cd309a..a3a0c31dd1b 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -26,6 +26,10 @@ config RWSEM_XCHGADD_ALGORITHM bool default y +config TIME_INTERPOLATION + bool + default y + choice prompt "IA-64 processor type" default ITANIUM @@ -63,7 +67,7 @@ config IA64_GENERIC HP-simulator For the HP simulator (). HP-zx1 For HP zx1-based systems. - SN1-simulator For the SGI SN1 simulator. + SGI-SN2 For SGI Altix systems DIG-compliant For DIG ("Developer's Interface Guide") compliant systems. @@ -82,9 +86,6 @@ config IA64_HP_ZX1 for the zx1 I/O MMU and makes root bus bridges appear in PCI config space (required for zx1 agpgart support). -config IA64_SGI_SN1 - bool "SGI-SN1" - config IA64_SGI_SN2 bool "SGI-SN2" @@ -190,8 +191,8 @@ config ITANIUM_BSTEP_SPECIFIC # align cache-sensitive data to 128 bytes config IA64_L1_CACHE_SHIFT int - default "7" if MCKINLEY || ITANIUM && IA64_SGI_SN1 - default "6" if ITANIUM && !IA64_SGI_SN1 + default "7" if MCKINLEY + default "6" if ITANIUM # align cache-sensitive data to 64 bytes config MCKINLEY_ASTEP_SPECIFIC @@ -210,7 +211,7 @@ config MCKINLEY_A0_SPECIFIC config NUMA bool "Enable NUMA support" if IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y if IA64_SGI_SN1 || IA64_SGI_SN2 + default y if IA64_SGI_SN2 help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor @@ -234,7 +235,7 @@ endchoice config DISCONTIGMEM bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 || (IA64_GENERIC || IA64_DIG || IA64_HP_ZX1) && NUMA + depends on IA64_SGI_SN2 || (IA64_GENERIC || IA64_DIG || IA64_HP_ZX1) && NUMA default y help Say Y to support efficient handling of discontiguous physical memory, @@ -259,7 +260,7 @@ config VIRTUAL_MEM_MAP config IA64_MCA bool "Enable IA-64 Machine Check Abort" if IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y if IA64_SGI_SN1 || IA64_SGI_SN2 + default y if IA64_SGI_SN2 help Say Y here to enable machine check support for IA-64. If you're unsure, answer Y. @@ -288,17 +289,12 @@ config PM config IOSAPIC bool - depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y - -config IA64_SGI_SN - bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 || IA64_SGI_SN2 default y config IA64_SGI_SN_DEBUG bool "Enable extra debugging code" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Turns on extra debugging code in the SGI SN (Scalable NUMA) platform for IA-64. Unless you are debugging problems on an SGI SN IA-64 box, @@ -306,14 +302,14 @@ config IA64_SGI_SN_DEBUG config IA64_SGI_SN_SIM bool "Enable SGI Medusa Simulator Support" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help If you are compiling a kernel that will run under SGI's IA-64 simulator (Medusa) then say Y, otherwise say N. config IA64_SGI_AUTOTEST bool "Enable autotest (llsc). Option to run cache test instead of booting" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Build a kernel used for hardware validation. If you include the keyword "autotest" on the boot command line, the kernel does NOT boot. @@ -323,7 +319,7 @@ config IA64_SGI_AUTOTEST config SERIAL_SGI_L1_PROTOCOL bool "Enable protocol mode for the L1 console" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Uses protocol mode instead of raw mode for the level 1 console on the SGI SN (Scalable NUMA) platform for IA-64. If you are compiling for @@ -331,17 +327,9 @@ config SERIAL_SGI_L1_PROTOCOL config PERCPU_IRQ bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 default y -config PCIBA - tristate "PCIBA support" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 - help - IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable - NUMA) platform for IA-64. Unless you are compiling a kernel for an - SGI SN IA-64 box, say N. - # On IA-64, we always want an ELF /proc/kcore. config KCORE_ELF bool @@ -493,38 +481,7 @@ config NR_CPUS depends on SMP default "64" -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries. - - Information about ELF is contained in the ELF HOWTO available from - . - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. Once you have registered such a binary class with the - kernel, you can start one of those programs simply by typing in its - name at a shell prompt; Linux will automatically feed it to the - correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" if !IA64_HP_SIM @@ -577,6 +534,8 @@ endif endmenu +source "drivers/base/Kconfig" + if !IA64_HP_SIM source "drivers/mtd/Kconfig" @@ -729,20 +688,18 @@ endmenu source "drivers/usb/Kconfig" -source "lib/Kconfig" source "net/bluetooth/Kconfig" endif +source "lib/Kconfig" + source "arch/ia64/hp/sim/Kconfig" menu "Kernel hacking" -config FSYS - bool "Light-weight system-call support (via epc)" - choice prompt "Physical memory granularity" default IA64_GRANULE_64MB @@ -809,7 +766,7 @@ config MAGIC_SYSRQ config IA64_EARLY_PRINTK bool "Early printk support" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && !IA64_GENERIC help Selecting this option uses the VGA screen or serial console for printk() output before the consoles are initialised. It is useful diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index dd86e79af59..8149bbab35a 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -18,8 +18,8 @@ LDFLAGS_MODULE += -T arch/ia64/module.lds AFLAGS_KERNEL := -mconstant-gp EXTRA := -cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ - -falign-functions=32 +cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \ + -falign-functions=32 -frename-registers CFLAGS_KERNEL := -mconstant-gp GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') @@ -27,6 +27,10 @@ GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP)) +arch-cppflags := $(shell arch/ia64/scripts/toolchain-flags $(CC) $(LD) $(OBJDUMP)) +cflags-y += $(arch-cppflags) +AFLAGS += $(arch-cppflags) + ifeq ($(GAS_STATUS),buggy) $(error Sorry, you need a newer version of the assember, one that is built from \ a source-tree that post-dates 18-Dec-2002. You can find a pre-compiled \ @@ -35,19 +39,18 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifneq ($(GCC_VERSION),2) - cflags-$(CONFIG_ITANIUM) += -frename-registers +ifeq ($(GCC_VERSION),2) +$(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) endif ifeq ($(GCC_VERSION),3) ifeq ($(GCC_MINOR_VERSION),4) - cflags-$(CONFIG_ITANIUM) += -mtune=merced - cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley + cflags-$(CONFIG_ITANIUM) += -mtune=merced + cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley endif endif cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC) += -mb-step -cflags-$(CONFIG_IA64_SGI_SN) += -DBRINGUP CFLAGS += $(cflags-y) head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o @@ -58,7 +61,7 @@ core-$(CONFIG_IA32_SUPPORT) += arch/ia64/ia32/ core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ -core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/ +core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ drivers-$(CONFIG_PCI) += arch/ia64/pci/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ @@ -66,33 +69,37 @@ drivers-$(CONFIG_IA64_HP_ZX1) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ boot := arch/ia64/boot -tools := arch/ia64/tools - -.PHONY: boot compressed include/asm-ia64/offsets.h -all: prepare vmlinux +.PHONY: boot compressed check compressed: vmlinux.gz vmlinux.gz: vmlinux - $(Q)$(MAKE) $(build)=$(boot) vmlinux.gz + $(Q)$(MAKE) $(build)=$(boot) $@ check: vmlinux - arch/ia64/scripts/unwcheck.sh vmlinux + arch/ia64/scripts/unwcheck.sh $< archclean: $(Q)$(MAKE) $(clean)=$(boot) - $(Q)$(MAKE) $(clean)=$(tools) -CLEAN_FILES += include/asm-ia64/offsets.h vmlinux.gz bootloader +CLEAN_FILES += include/asm-ia64/.offsets.h.stamp include/asm-ia64/offsets.h vmlinux.gz bootloader prepare: include/asm-ia64/offsets.h +include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s + $(call filechk,gen-asm-offsets) + +arch/ia64/kernel/asm-offsets.s: include/asm-ia64/.offsets.h.stamp + +include/asm-ia64/.offsets.h.stamp: + [ -s include/asm-ia64/offsets.h ] \ + || echo "#define IA64_TASK_SIZE 0" > include/asm-ia64/offsets.h + touch $@ + boot: lib/lib.a vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -include/asm-ia64/offsets.h: include/asm include/linux/version.h include/config/MARKER - $(Q)$(MAKE) $(build)=$(tools) $@ define archhelp echo ' compressed - Build compressed kernel image' diff --git a/arch/ia64/boot/bootloader.c b/arch/ia64/boot/bootloader.c index 090f25b8b9c..593667cbb74 100644 --- a/arch/ia64/boot/bootloader.c +++ b/arch/ia64/boot/bootloader.c @@ -55,6 +55,9 @@ struct disk_stat { #include "../kernel/fw-emu.c" +/* This needs to be defined because lib/string.c:strlcat() calls it in case of error... */ +asm (".global printk; printk = 0"); + /* * Set a break point on this function so that symbols are available to set breakpoints in * the kernel being debugged. @@ -181,10 +184,10 @@ _start (void) continue; req.len = elf_phdr->p_filesz; - req.addr = __pa(elf_phdr->p_vaddr); + req.addr = __pa(elf_phdr->p_paddr); ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); - memset((char *)__pa(elf_phdr->p_vaddr) + elf_phdr->p_filesz, 0, + memset((char *)__pa(elf_phdr->p_paddr) + elf_phdr->p_filesz, 0, elf_phdr->p_memsz - elf_phdr->p_filesz); } ssc(fd, 0, 0, 0, SSC_CLOSE); diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index a7cd4fddf27..77f7c35cf0c 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1682,6 +1682,10 @@ ioc_init(u64 hpa, void *handle) ioc_resource_init(ioc); ioc_sac_init(ioc); + if ((long) ~IOVP_MASK > (long) ia64_max_iommu_merge_mask) + ia64_max_iommu_merge_mask = ~IOVP_MASK; + MAX_DMA_ADDRESS = ~0UL; + printk(KERN_INFO PFX "%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, @@ -1898,22 +1902,26 @@ acpi_sba_ioc_add(struct acpi_device *device) struct ioc *ioc; acpi_status status; u64 hpa, length; - struct acpi_device_info dev_info; + struct acpi_buffer buffer; + struct acpi_device_info *dev_info; status = hp_acpi_csr_space(device->handle, &hpa, &length); if (ACPI_FAILURE(status)) return 1; - status = acpi_get_object_info(device->handle, &dev_info); + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_get_object_info(device->handle, &buffer); if (ACPI_FAILURE(status)) return 1; + dev_info = buffer.pointer; /* * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI * root bridges, and its CSR space includes the IOC function. */ - if (strncmp("HWP0001", dev_info.hardware_id, 7) == 0) + if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) hpa += ZX1_IOC_OFFSET; + ACPI_MEM_FREE(dev_info); ioc = ioc_init(hpa, device->handle); if (!ioc) @@ -1933,8 +1941,6 @@ static struct acpi_driver acpi_sba_ioc_driver = { static int __init sba_init(void) { - MAX_DMA_ADDRESS = ~0UL; - acpi_bus_register_driver(&acpi_sba_ioc_driver); #ifdef CONFIG_PCI diff --git a/arch/ia64/hp/sim/Kconfig b/arch/ia64/hp/sim/Kconfig index 78448ed8214..c2cdd2f353e 100644 --- a/arch/ia64/hp/sim/Kconfig +++ b/arch/ia64/hp/sim/Kconfig @@ -8,6 +8,10 @@ config HP_SIMETH config HP_SIMSERIAL bool "Simulated serial driver support" +config HP_SIMSERIAL_CONSOLE + bool "Console for HP simulator" + depends on HP_SIMSERIAL + config HP_SIMSCSI bool "Simulated SCSI disk" depends on SCSI diff --git a/arch/ia64/hp/sim/Makefile b/arch/ia64/hp/sim/Makefile index 6f46d1834aa..e8fba4e6f77 100644 --- a/arch/ia64/hp/sim/Makefile +++ b/arch/ia64/hp/sim/Makefile @@ -7,9 +7,10 @@ # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) # -obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o +obj-y := hpsim_irq.o hpsim_setup.o obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o obj-$(CONFIG_HP_SIMETH) += simeth.o obj-$(CONFIG_HP_SIMSERIAL) += simserial.o +obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o obj-$(CONFIG_HP_SIMSCSI) += simscsi.o diff --git a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c index 13a6f5391d8..64ff3a9c6e3 100644 --- a/arch/ia64/hp/sim/hpsim_setup.c +++ b/arch/ia64/hp/sim/hpsim_setup.c @@ -5,6 +5,7 @@ * David Mosberger-Tang * Copyright (C) 1999 Vijay Chander */ +#include #include #include #include @@ -24,8 +25,6 @@ #include "hpsim_ssc.h" -extern struct console hpsim_cons; - /* * Simulator system call. */ @@ -56,5 +55,11 @@ hpsim_setup (char **cmdline_p) { ROOT_DEV = Root_SDA1; /* default to first SCSI drive */ - register_console(&hpsim_cons); +#ifdef CONFIG_HP_SIMSERIAL_CONSOLE + { + extern struct console hpsim_cons; + if (ia64_platform_is("hpsim")) + register_console(&hpsim_cons); + } +#endif } diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index ba2275f9aaf..52e60143874 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -1031,6 +1031,9 @@ simrs_init (void) int i; struct serial_state *state; + if (!ia64_platform_is("hpsim")) + return -ENODEV; + hp_simserial_driver = alloc_tty_driver(1); if (!hp_simserial_driver) return -ENOMEM; diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index d42137b98b5..dcc4982c2c6 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -16,7 +16,8 @@ #include #include -#include + +#include "ia32priv.h" #define CONFIG_BINFMT_ELF32 diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S index cc0d72ac6d6..17ec2150ffb 100644 --- a/arch/ia64/ia32/ia32_entry.S +++ b/arch/ia64/ia32/ia32_entry.S @@ -44,14 +44,8 @@ ENTRY(ia32_clone) br.call.sptk.many rp=do_fork .ret0: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(ia32_clone) @@ -183,14 +177,8 @@ GLOBAL_ENTRY(sys32_fork) br.call.sptk.few rp=do_fork .ret5: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys32_fork) @@ -439,8 +427,8 @@ ia32_syscall_table: data8 sys_ni_syscall data8 sys_ni_syscall data8 compat_sys_futex /* 240 */ - data8 compat_sys_setaffinity - data8 compat_sys_getaffinity + data8 compat_sys_sched_setaffinity + data8 compat_sys_sched_getaffinity data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall /* 245 */ @@ -448,6 +436,28 @@ ia32_syscall_table: data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall + data8 sys_ni_syscall /* 250 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /*255*/ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 260 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 265 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_statfs64 + data8 sys_fstatfs64 + data8 sys_ni_syscall + /* * CAUTION: If any system calls are added beyond this point * then the check in `arch/ia64/kernel/ivt.S' will have diff --git a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c index e86c863a515..3e7a9fec21f 100644 --- a/arch/ia64/ia32/ia32_ioctl.c +++ b/arch/ia64/ia32/ia32_ioctl.c @@ -11,36 +11,107 @@ #include #include /* argh, msdos_fs.h isn't self-contained... */ #include /* argh, msdos_fs.h isn't self-contained... */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include "ia32priv.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include /* Ugly hack. */ -#undef __KERNEL__ +#undef __KERNEL__ #include -#define __KERNEL__ +#define __KERNEL__ #include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + #include <../drivers/char/drm/drm.h> #include <../drivers/char/drm/mga_drm.h> #include <../drivers/char/drm/i810_drm.h> - #define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define DO_IOCTL(fd, cmd, arg) ({ \ @@ -57,6 +128,9 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); +#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct linux32_dirent[2]) +#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct linux32_dirent[2]) + static long put_dirent32 (struct dirent *d, struct linux32_dirent *d32) { @@ -67,6 +141,23 @@ put_dirent32 (struct dirent *d, struct linux32_dirent *d32) || put_user(d->d_reclen, &d32->d_reclen) || copy_to_user(d32->d_name, d->d_name, namelen + 1)); } + +static int vfat_ioctl32(unsigned fd, unsigned cmd, void *ptr) +{ + int ret; + mm_segment_t oldfs = get_fs(); + struct dirent d[2]; + + set_fs(KERNEL_DS); + ret = sys_ioctl(fd,cmd,(unsigned long)&d); + set_fs(oldfs); + if (!ret) { + ret |= put_dirent32(&d[0], (struct linux32_dirent *)ptr); + ret |= put_dirent32(&d[1], ((struct linux32_dirent *)ptr) + 1); + } + return ret; +} + /* * The transform code for the SG_IO ioctl was brazenly lifted from * the Sparc64 port in the file `arch/sparc64/kernel/ioctl32.c'. @@ -294,3 +385,83 @@ out: } return err; } + +static __inline__ void *alloc_user_space(long len) +{ + struct pt_regs *regs = ((struct pt_regs *)((unsigned long) current + + IA64_STK_OFFSET)) - 1; + return (void *)regs->r12 - len; +} + +struct ifmap32 { + u32 mem_start; + u32 mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + compat_caddr_t ifru_data; + } ifr_ifru; +}; + +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 *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 = (void *) P(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); +} + +typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *); + +#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl) +#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl32_handler_t)(handler), NULL }, +#define IOCTL_TABLE_START \ + struct ioctl_trans ioctl_start[] = { +#define IOCTL_TABLE_END \ + }; struct ioctl_trans ioctl_end[0]; + +IOCTL_TABLE_START +#include +HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) +HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) +HANDLE_IOCTL(SG_IO,sg_ioctl_trans) +IOCTL_TABLE_END diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c index 4b0eb73dd44..515503ae083 100644 --- a/arch/ia64/ia32/ia32_ldt.c +++ b/arch/ia64/ia32/ia32_ldt.c @@ -14,7 +14,8 @@ #include #include -#include + +#include "ia32priv.h" #define P(p) ((void *) (unsigned long) (p)) diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c index e86f432bce9..19de74e1eda 100644 --- a/arch/ia64/ia32/ia32_signal.c +++ b/arch/ia64/ia32/ia32_signal.c @@ -28,7 +28,8 @@ #include #include #include -#include + +#include "ia32priv.h" #include "../kernel/sigframe.h" @@ -179,8 +180,10 @@ copy_siginfo_to_user32 (siginfo_t32 *to, siginfo_t *from) * datasel ar.fdr(32:47) * * _st[(0+TOS)%8] f8 - * _st[(1+TOS)%8] f9 (f8, f9 from ptregs) - * : : : (f10..f15 from live reg) + * _st[(1+TOS)%8] f9 + * _st[(2+TOS)%8] f10 + * _st[(3+TOS)%8] f11 (f8..f11 from ptregs) + * : : : (f12..f15 from live reg) * : : : * _st[(7+TOS)%8] f15 TOS=sw.top(bits11:13) * @@ -262,8 +265,8 @@ save_ia32_fpstate_live (struct _fpstate_ia32 *save) __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC 0x0000 /* - * save f8 and f9 from pt_regs - * save f10..f15 from live register set + * save f8..f11 from pt_regs + * save f12..f15 from live register set */ /* * Find the location where f8 has to go in fp reg stack. This depends on @@ -278,11 +281,11 @@ save_ia32_fpstate_live (struct _fpstate_ia32 *save) copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64f2ia32f(fpregp, &ptp->f9); copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); - - __stfe(fpregp, 10); + ia64f2ia32f(fpregp, &ptp->f10); copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); - __stfe(fpregp, 11); + ia64f2ia32f(fpregp, &ptp->f11); copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 12); copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); __stfe(fpregp, 13); @@ -394,8 +397,8 @@ restore_ia32_fpstate_live (struct _fpstate_ia32 *save) asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr)); /* - * restore f8, f9 onto pt_regs - * restore f10..f15 onto live registers + * restore f8..f11 onto pt_regs + * restore f12..f15 onto live registers */ /* * Find the location where f8 has to go in fp reg stack. This depends on @@ -411,11 +414,11 @@ restore_ia32_fpstate_live (struct _fpstate_ia32 *save) ia32f2ia64f(&ptp->f8, fpregp); copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); ia32f2ia64f(&ptp->f9, fpregp); - copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); - __ldfe(10, fpregp); + ia32f2ia64f(&ptp->f10, fpregp); copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); - __ldfe(11, fpregp); + ia32f2ia64f(&ptp->f11, fpregp); + copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); __ldfe(12, fpregp); copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); @@ -738,11 +741,11 @@ restore_sigcontext_ia32 (struct pt_regs *regs, struct sigcontext_ia32 *sc, int * #define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) -#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) -#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) +#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) (tmp) << 48) +#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) (tmp) << 32) #define copyseg_cs(tmp) (regs->r17 |= tmp) -#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) -#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) +#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) (tmp) << 16) +#define copyseg_es(tmp) (regs->r16 |= (unsigned long) (tmp) << 16) #define copyseg_ds(tmp) (regs->r16 |= tmp) #define COPY_SEG(seg) \ diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c index 8b6db81cf02..df53dcdb72b 100644 --- a/arch/ia64/ia32/ia32_support.c +++ b/arch/ia64/ia32/ia32_support.c @@ -22,7 +22,8 @@ #include #include #include -#include + +#include "ia32priv.h" extern void die_if_kernel (char *str, struct pt_regs *regs, long err); @@ -60,30 +61,26 @@ ia32_load_segment_descriptors (struct task_struct *task) regs->r27 = load_desc(regs->r16 >> 0); /* DSD */ regs->r28 = load_desc(regs->r16 >> 32); /* FSD */ regs->r29 = load_desc(regs->r16 >> 48); /* GSD */ - task->thread.csd = load_desc(regs->r17 >> 0); /* CSD */ - task->thread.ssd = load_desc(regs->r17 >> 16); /* SSD */ + regs->ar_csd = load_desc(regs->r17 >> 0); /* CSD */ + regs->ar_ssd = load_desc(regs->r17 >> 16); /* SSD */ } void ia32_save_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; + unsigned long eflag, fsr, fcr, fir, fdr; asm ("mov %0=ar.eflag;" "mov %1=ar.fsr;" "mov %2=ar.fcr;" "mov %3=ar.fir;" "mov %4=ar.fdr;" - "mov %5=ar.csd;" - "mov %6=ar.ssd;" - : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd)); + : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr)); t->thread.eflag = eflag; t->thread.fsr = fsr; t->thread.fcr = fcr; t->thread.fir = fir; t->thread.fdr = fdr; - t->thread.csd = csd; - t->thread.ssd = ssd; ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob); ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1); } @@ -91,7 +88,7 @@ ia32_save_state (struct task_struct *t) void ia32_load_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, tssd; struct pt_regs *regs = ia64_task_regs(t); int nr = get_cpu(); /* LDT and TSS depend on CPU number: */ @@ -100,8 +97,6 @@ ia32_load_state (struct task_struct *t) fcr = t->thread.fcr; fir = t->thread.fir; fdr = t->thread.fdr; - csd = t->thread.csd; - ssd = t->thread.ssd; tssd = load_desc(_TSS(nr)); /* TSSD */ asm volatile ("mov ar.eflag=%0;" @@ -109,9 +104,7 @@ ia32_load_state (struct task_struct *t) "mov ar.fcr=%2;" "mov ar.fir=%3;" "mov ar.fdr=%4;" - "mov ar.csd=%5;" - "mov ar.ssd=%6;" - :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); + :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr)); current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD); ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); @@ -181,6 +174,13 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) force_sig_info(SIGTRAP, &siginfo, current); } +void +ia32_cpu_init (void) +{ + /* initialize global ia32 state - CR0 and CR4 */ + asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); +} + static int __init ia32_init (void) { diff --git a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c index 30906900f04..fbdb10a580d 100644 --- a/arch/ia64/ia32/ia32_traps.c +++ b/arch/ia64/ia32/ia32_traps.c @@ -12,7 +12,8 @@ #include #include -#include +#include "ia32priv.h" + #include int diff --git a/include/asm-ia64/ia32.h b/arch/ia64/ia32/ia32priv.h similarity index 96% copy from include/asm-ia64/ia32.h copy to arch/ia64/ia32/ia32priv.h index a8b5c44a898..d9537ba7f04 100644 --- a/include/asm-ia64/ia32.h +++ b/arch/ia64/ia32/ia32priv.h @@ -3,6 +3,8 @@ #include +#include + #ifdef CONFIG_IA32_SUPPORT #include @@ -108,7 +110,8 @@ struct ia32_user_i387_struct { int fcs; int foo; int fos; - int st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ + /* 8*10 bytes for each FP-reg = 80 bytes */ + struct _fpreg_ia32 st_space[8]; }; struct ia32_user_fxsr_struct { @@ -452,11 +455,8 @@ struct ia32_modify_ldt_ldt_s { struct linux_binprm; -extern void ia32_gdt_init (void); extern void ia32_init_addr_space (struct pt_regs *regs); extern int ia32_setup_arg_pages (struct linux_binprm *bprm); -extern int ia32_exception (struct pt_regs *regs, unsigned long isr); -extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); extern void ia32_load_segment_descriptors (struct task_struct *task); @@ -474,8 +474,4 @@ extern void ia32_load_segment_descriptors (struct task_struct *task); #endif /* !CONFIG_IA32_SUPPORT */ -/* Declare this uncondiontally, so we don't get warnings for unreachable code. */ -extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs); - #endif /* _ASM_IA64_IA32_H */ diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c index fedff08667a..fd033607bf6 100644 --- a/arch/ia64/ia32/sys_ia32.c +++ b/arch/ia64/ia32/sys_ia32.c @@ -53,7 +53,8 @@ #include #include #include -#include + +#include "ia32priv.h" #include #include @@ -206,9 +207,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *ubuf) static int -get_page_prot (unsigned long addr) +get_page_prot (struct vm_area_struct *vma, unsigned long addr) { - struct vm_area_struct *vma = find_vma(current->mm, addr); int prot = 0; if (!vma || vma->vm_start > addr) @@ -231,14 +231,26 @@ static unsigned long mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags, loff_t off) { - void *page = (void *) get_zeroed_page(GFP_KERNEL); + void *page = NULL; struct inode *inode; - unsigned long ret; - int old_prot = get_page_prot(start); + unsigned long ret = 0; + struct vm_area_struct *vma = find_vma(current->mm, start); + int old_prot = get_page_prot(vma, start); DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n", file, start, end, prot, flags, off); + + /* Optimize the case where the old mmap and the new mmap are both anonymous */ + if ((old_prot & PROT_WRITE) && (flags & MAP_ANONYMOUS) && !vma->vm_file) { + if (clear_user((void *) start, end - start)) { + ret = -EFAULT; + goto out; + } + goto skip_mmap; + } + + page = (void *) get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -263,6 +275,7 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro copy_to_user((void *) end, page + PAGE_OFF(end), PAGE_SIZE - PAGE_OFF(end)); } + if (!(flags & MAP_ANONYMOUS)) { /* read the file contents */ inode = file->f_dentry->d_inode; @@ -273,10 +286,13 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int pro goto out; } } + + skip_mmap: if (!(prot & PROT_WRITE)) ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot); out: - free_page((unsigned long) page); + if (page) + free_page((unsigned long) page); return ret; } @@ -532,11 +548,12 @@ static long mprotect_subpage (unsigned long address, int new_prot) { int old_prot; + struct vm_area_struct *vma; if (new_prot == PROT_NONE) return 0; /* optimize case where nothing changes... */ - - old_prot = get_page_prot(address); + vma = find_vma(current->mm, address); + old_prot = get_page_prot(vma, address); return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot); } @@ -642,7 +659,6 @@ sys32_alarm (unsigned int seconds) sorts of things, like timeval and itimerval. */ extern struct timezone sys_tz; -extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long sys32_gettimeofday (struct compat_timeval *tv, struct timezone *tz) @@ -664,18 +680,21 @@ asmlinkage long sys32_settimeofday (struct compat_timeval *tv, struct timezone *tz) { struct timeval ktv; + struct timespec kts; struct timezone ktz; if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; + kts.tv_sec = ktv.tv_sec; + kts.tv_nsec = ktv.tv_usec * 1000; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } - return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); + return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } struct getdents32_callback { @@ -836,9 +855,8 @@ sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct compat_timev } } - size = FDS_BYTES(n); ret = -EINVAL; - if (n < 0 || size < n) + if (n < 0) goto out_nofds; if (n > current->files->max_fdset) @@ -850,6 +868,7 @@ sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct compat_timev * long-words. */ ret = -ENOMEM; + size = FDS_BYTES(n); bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; @@ -1102,7 +1121,7 @@ struct shmid_ds32 { }; struct shmid64_ds32 { - struct ipc64_perm shm_perm; + struct ipc64_perm32 shm_perm; compat_size_t shm_segsz; compat_time_t shm_atime; unsigned int __unused1; @@ -1320,7 +1339,6 @@ static int msgctl32 (int first, int second, void *uptr) { int err = -EINVAL, err2; - struct msqid_ds m; struct msqid64_ds m64; struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr; struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr; @@ -1336,21 +1354,21 @@ msgctl32 (int first, int second, void *uptr) case IPC_SET: if (version == IPC_64) { - err = get_user(m.msg_perm.uid, &up64->msg_perm.uid); - err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid); - err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode); - err |= get_user(m.msg_qbytes, &up64->msg_qbytes); + err = get_user(m64.msg_perm.uid, &up64->msg_perm.uid); + err |= get_user(m64.msg_perm.gid, &up64->msg_perm.gid); + err |= get_user(m64.msg_perm.mode, &up64->msg_perm.mode); + err |= get_user(m64.msg_qbytes, &up64->msg_qbytes); } else { - err = get_user(m.msg_perm.uid, &up32->msg_perm.uid); - err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid); - err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode); - err |= get_user(m.msg_qbytes, &up32->msg_qbytes); + err = get_user(m64.msg_perm.uid, &up32->msg_perm.uid); + err |= get_user(m64.msg_perm.gid, &up32->msg_perm.gid); + err |= get_user(m64.msg_perm.mode, &up32->msg_perm.mode); + err |= get_user(m64.msg_qbytes, &up32->msg_qbytes); } if (err) break; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_msgctl(first, second, &m); + err = sys_msgctl(first, second, &m64); set_fs(old_fs); break; @@ -1430,7 +1448,7 @@ static int shmctl32 (int first, int second, void *uptr) { int err = -EFAULT, err2; - struct shmid_ds s; + struct shmid64_ds s64; struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr; struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr; @@ -1482,19 +1500,19 @@ shmctl32 (int first, int second, void *uptr) case IPC_SET: if (version == IPC_64) { - err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); + err = get_user(s64.shm_perm.uid, &up64->shm_perm.uid); + err |= get_user(s64.shm_perm.gid, &up64->shm_perm.gid); + err |= get_user(s64.shm_perm.mode, &up64->shm_perm.mode); } else { - err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); + err = get_user(s64.shm_perm.uid, &up32->shm_perm.uid); + err |= get_user(s64.shm_perm.gid, &up32->shm_perm.gid); + err |= get_user(s64.shm_perm.mode, &up32->shm_perm.mode); } if (err) break; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_shmctl(first, second, &s); + err = sys_shmctl(first, second, &s64); set_fs(old_fs); break; @@ -1798,12 +1816,16 @@ put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switc ia64f2ia32f(f, &ptp->f9); break; case 2: + ia64f2ia32f(f, &ptp->f10); + break; case 3: + ia64f2ia32f(f, &ptp->f11); + break; case 4: case 5: case 6: case 7: - ia64f2ia32f(f, &swp->f10 + (regno - 2)); + ia64f2ia32f(f, &swp->f12 + (regno - 4)); break; } copy_to_user(reg, f, sizeof(*reg)); @@ -1824,12 +1846,16 @@ get_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switc copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; case 2: + copy_from_user(&ptp->f10, reg, sizeof(*reg)); + break; case 3: + copy_from_user(&ptp->f11, reg, sizeof(*reg)); + break; case 4: case 5: case 6: case 7: - copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); + copy_from_user(&swp->f12 + (regno - 4), reg, sizeof(*reg)); break; } return; @@ -1860,7 +1886,7 @@ save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + put_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0; } @@ -1893,7 +1919,7 @@ restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *sav ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + get_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0; } diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 0add23aaf71..bac7687f6b3 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -4,12 +4,11 @@ extra-y := head.o init_task.o -obj-y := acpi.o entry.o efi.o efi_stub.o gate.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o \ - ivt.o machvec.o pal.o perfmon.o process.o ptrace.o sal.o semaphore.o setup.o signal.o \ - sys_ia64.o time.o traps.o unaligned.o unwind.o +obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ + irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ + semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o obj-$(CONFIG_EFI_VARS) += efivars.o -obj-$(CONFIG_FSYS) += fsys.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o @@ -18,3 +17,30 @@ obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o + +# The gate DSO image is built using a special linker script. +targets += gate.so gate-syms.o + +AFLAGS_gate.lds.o += -P -C -U$(ARCH) +arch/ia64/kernel/gate.lds.s: %.s: %.S scripts FORCE + $(call if_changed_dep,as_s_S) + +quiet_cmd_gate = GATE $@ + cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@ + +GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 +$(obj)/gate.so: $(src)/gate.lds.s $(obj)/gate.o FORCE + $(call if_changed,gate) + +$(obj)/built-in.o: $(obj)/gate-syms.o +$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o + +GATECFLAGS_gate-syms.o = -r +$(obj)/gate-syms.o: $(src)/gate.lds.s $(obj)/gate.o FORCE + $(call if_changed,gate) + +# gate-data.o contains the gate DSO image as data in section .data.gate. +# We must build gate.so before we can assemble it. +# Note: kbuild does not track this dependency due to usage of .incbin +$(obj)/gate-data.o: $(obj)/gate.so diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index 42d0c1f6c27..b70f6de25ed 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c @@ -84,7 +84,6 @@ hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) acpi_status status; u8 *data; u32 length; - int i; status = acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length); diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 7f888fbffea..a6a4d11fff3 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -96,6 +96,9 @@ acpi_get_sysname (void) if (!strcmp(hdr->oem_id, "HP")) { return "hpzx1"; } + else if (!strcmp(hdr->oem_id, "SGI")) { + return "sn2"; + } return "dig"; #else @@ -103,8 +106,6 @@ acpi_get_sysname (void) return "hpsim"; # elif defined (CONFIG_IA64_HP_ZX1) return "hpzx1"; -# elif defined (CONFIG_IA64_SGI_SN1) - return "sn1"; # elif defined (CONFIG_IA64_SGI_SN2) return "sn2"; # elif defined (CONFIG_IA64_DIG) @@ -191,21 +192,19 @@ acpi_parse_lsapic (acpi_table_entry_header *header) printk(KERN_INFO "CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid); - if (lsapic->flags.enabled) { - available_cpus++; + if (!lsapic->flags.enabled) + printk(" disabled"); + else if (available_cpus >= NR_CPUS) + printk(" ignored (increase NR_CPUS)"); + else { printk(" enabled"); #ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; + smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; if (hard_smp_processor_id() - == (unsigned int) smp_boot_data.cpu_phys_id[total_cpus]) + == (unsigned int) smp_boot_data.cpu_phys_id[available_cpus]) printk(" (BSP)"); #endif - } - else { - printk(" disabled"); -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = -1; -#endif + ++available_cpus; } printk("\n"); @@ -694,11 +693,11 @@ acpi_boot_init (void) #endif #ifdef CONFIG_SMP + smp_boot_data.cpu_count = available_cpus; if (available_cpus == 0) { printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = total_cpus; smp_build_cpu_map(); # ifdef CONFIG_NUMA diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c new file mode 100644 index 00000000000..49c464cd04f --- /dev/null +++ b/arch/ia64/kernel/asm-offsets.c @@ -0,0 +1,189 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + */ + +#include + +#include + +#include +#include +#include +#include + +#include "../kernel/sigframe.h" + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +void foo(void) +{ + DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct)); + DEFINE(IA64_THREAD_INFO_SIZE, sizeof (struct thread_info)); + DEFINE(IA64_PT_REGS_SIZE, sizeof (struct pt_regs)); + DEFINE(IA64_SWITCH_STACK_SIZE, sizeof (struct switch_stack)); + DEFINE(IA64_SIGINFO_SIZE, sizeof (struct siginfo)); + DEFINE(IA64_CPU_SIZE, sizeof (struct cpuinfo_ia64)); + DEFINE(SIGFRAME_SIZE, sizeof (struct sigframe)); + DEFINE(UNW_FRAME_INFO_SIZE, sizeof (struct unw_frame_info)); + + BLANK(); + + DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); + DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); + DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid)); + DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent)); + DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); + DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp)); + DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack)); + + BLANK(); + + DEFINE(IA64_PT_REGS_B6_OFFSET, offsetof (struct pt_regs, b6)); + DEFINE(IA64_PT_REGS_B7_OFFSET, offsetof (struct pt_regs, b7)); + DEFINE(IA64_PT_REGS_AR_CSD_OFFSET, offsetof (struct pt_regs, ar_csd)); + DEFINE(IA64_PT_REGS_AR_SSD_OFFSET, offsetof (struct pt_regs, ar_ssd)); + DEFINE(IA64_PT_REGS_R8_OFFSET, offsetof (struct pt_regs, r8)); + DEFINE(IA64_PT_REGS_R9_OFFSET, offsetof (struct pt_regs, r9)); + DEFINE(IA64_PT_REGS_R10_OFFSET, offsetof (struct pt_regs, r10)); + DEFINE(IA64_PT_REGS_R11_OFFSET, offsetof (struct pt_regs, r11)); + DEFINE(IA64_PT_REGS_CR_IPSR_OFFSET, offsetof (struct pt_regs, cr_ipsr)); + DEFINE(IA64_PT_REGS_CR_IIP_OFFSET, offsetof (struct pt_regs, cr_iip)); + DEFINE(IA64_PT_REGS_CR_IFS_OFFSET, offsetof (struct pt_regs, cr_ifs)); + DEFINE(IA64_PT_REGS_AR_UNAT_OFFSET, offsetof (struct pt_regs, ar_unat)); + DEFINE(IA64_PT_REGS_AR_PFS_OFFSET, offsetof (struct pt_regs, ar_pfs)); + DEFINE(IA64_PT_REGS_AR_RSC_OFFSET, offsetof (struct pt_regs, ar_rsc)); + DEFINE(IA64_PT_REGS_AR_RNAT_OFFSET, offsetof (struct pt_regs, ar_rnat)); + + DEFINE(IA64_PT_REGS_AR_BSPSTORE_OFFSET, offsetof (struct pt_regs, ar_bspstore)); + DEFINE(IA64_PT_REGS_PR_OFFSET, offsetof (struct pt_regs, pr)); + DEFINE(IA64_PT_REGS_B0_OFFSET, offsetof (struct pt_regs, b0)); + DEFINE(IA64_PT_REGS_LOADRS_OFFSET, offsetof (struct pt_regs, loadrs)); + DEFINE(IA64_PT_REGS_R1_OFFSET, offsetof (struct pt_regs, r1)); + DEFINE(IA64_PT_REGS_R12_OFFSET, offsetof (struct pt_regs, r12)); + DEFINE(IA64_PT_REGS_R13_OFFSET, offsetof (struct pt_regs, r13)); + DEFINE(IA64_PT_REGS_AR_FPSR_OFFSET, offsetof (struct pt_regs, ar_fpsr)); + DEFINE(IA64_PT_REGS_R15_OFFSET, offsetof (struct pt_regs, r15)); + DEFINE(IA64_PT_REGS_R14_OFFSET, offsetof (struct pt_regs, r14)); + DEFINE(IA64_PT_REGS_R2_OFFSET, offsetof (struct pt_regs, r2)); + DEFINE(IA64_PT_REGS_R3_OFFSET, offsetof (struct pt_regs, r3)); + DEFINE(IA64_PT_REGS_R16_OFFSET, offsetof (struct pt_regs, r16)); + DEFINE(IA64_PT_REGS_R17_OFFSET, offsetof (struct pt_regs, r17)); + DEFINE(IA64_PT_REGS_R18_OFFSET, offsetof (struct pt_regs, r18)); + DEFINE(IA64_PT_REGS_R19_OFFSET, offsetof (struct pt_regs, r19)); + DEFINE(IA64_PT_REGS_R20_OFFSET, offsetof (struct pt_regs, r20)); + DEFINE(IA64_PT_REGS_R21_OFFSET, offsetof (struct pt_regs, r21)); + DEFINE(IA64_PT_REGS_R22_OFFSET, offsetof (struct pt_regs, r22)); + DEFINE(IA64_PT_REGS_R23_OFFSET, offsetof (struct pt_regs, r23)); + DEFINE(IA64_PT_REGS_R24_OFFSET, offsetof (struct pt_regs, r24)); + DEFINE(IA64_PT_REGS_R25_OFFSET, offsetof (struct pt_regs, r25)); + DEFINE(IA64_PT_REGS_R26_OFFSET, offsetof (struct pt_regs, r26)); + DEFINE(IA64_PT_REGS_R27_OFFSET, offsetof (struct pt_regs, r27)); + DEFINE(IA64_PT_REGS_R28_OFFSET, offsetof (struct pt_regs, r28)); + DEFINE(IA64_PT_REGS_R29_OFFSET, offsetof (struct pt_regs, r29)); + DEFINE(IA64_PT_REGS_R30_OFFSET, offsetof (struct pt_regs, r30)); + DEFINE(IA64_PT_REGS_R31_OFFSET, offsetof (struct pt_regs, r31)); + DEFINE(IA64_PT_REGS_AR_CCV_OFFSET, offsetof (struct pt_regs, ar_ccv)); + DEFINE(IA64_PT_REGS_F6_OFFSET, offsetof (struct pt_regs, f6)); + DEFINE(IA64_PT_REGS_F7_OFFSET, offsetof (struct pt_regs, f7)); + DEFINE(IA64_PT_REGS_F8_OFFSET, offsetof (struct pt_regs, f8)); + DEFINE(IA64_PT_REGS_F9_OFFSET, offsetof (struct pt_regs, f9)); + DEFINE(IA64_PT_REGS_F10_OFFSET, offsetof (struct pt_regs, f10)); + DEFINE(IA64_PT_REGS_F11_OFFSET, offsetof (struct pt_regs, f11)); + + BLANK(); + + DEFINE(IA64_SWITCH_STACK_CALLER_UNAT_OFFSET, offsetof (struct switch_stack, caller_unat)); + DEFINE(IA64_SWITCH_STACK_AR_FPSR_OFFSET, offsetof (struct switch_stack, ar_fpsr)); + DEFINE(IA64_SWITCH_STACK_F2_OFFSET, offsetof (struct switch_stack, f2)); + DEFINE(IA64_SWITCH_STACK_F3_OFFSET, offsetof (struct switch_stack, f3)); + DEFINE(IA64_SWITCH_STACK_F4_OFFSET, offsetof (struct switch_stack, f4)); + DEFINE(IA64_SWITCH_STACK_F5_OFFSET, offsetof (struct switch_stack, f5)); + DEFINE(IA64_SWITCH_STACK_F12_OFFSET, offsetof (struct switch_stack, f12)); + DEFINE(IA64_SWITCH_STACK_F13_OFFSET, offsetof (struct switch_stack, f13)); + DEFINE(IA64_SWITCH_STACK_F14_OFFSET, offsetof (struct switch_stack, f14)); + DEFINE(IA64_SWITCH_STACK_F15_OFFSET, offsetof (struct switch_stack, f15)); + DEFINE(IA64_SWITCH_STACK_F16_OFFSET, offsetof (struct switch_stack, f16)); + DEFINE(IA64_SWITCH_STACK_F17_OFFSET, offsetof (struct switch_stack, f17)); + DEFINE(IA64_SWITCH_STACK_F18_OFFSET, offsetof (struct switch_stack, f18)); + DEFINE(IA64_SWITCH_STACK_F19_OFFSET, offsetof (struct switch_stack, f19)); + DEFINE(IA64_SWITCH_STACK_F20_OFFSET, offsetof (struct switch_stack, f20)); + DEFINE(IA64_SWITCH_STACK_F21_OFFSET, offsetof (struct switch_stack, f21)); + DEFINE(IA64_SWITCH_STACK_F22_OFFSET, offsetof (struct switch_stack, f22)); + DEFINE(IA64_SWITCH_STACK_F23_OFFSET, offsetof (struct switch_stack, f23)); + DEFINE(IA64_SWITCH_STACK_F24_OFFSET, offsetof (struct switch_stack, f24)); + DEFINE(IA64_SWITCH_STACK_F25_OFFSET, offsetof (struct switch_stack, f25)); + DEFINE(IA64_SWITCH_STACK_F26_OFFSET, offsetof (struct switch_stack, f26)); + DEFINE(IA64_SWITCH_STACK_F27_OFFSET, offsetof (struct switch_stack, f27)); + DEFINE(IA64_SWITCH_STACK_F28_OFFSET, offsetof (struct switch_stack, f28)); + DEFINE(IA64_SWITCH_STACK_F29_OFFSET, offsetof (struct switch_stack, f29)); + DEFINE(IA64_SWITCH_STACK_F30_OFFSET, offsetof (struct switch_stack, f30)); + DEFINE(IA64_SWITCH_STACK_F31_OFFSET, offsetof (struct switch_stack, f31)); + DEFINE(IA64_SWITCH_STACK_R4_OFFSET, offsetof (struct switch_stack, r4)); + DEFINE(IA64_SWITCH_STACK_R5_OFFSET, offsetof (struct switch_stack, r5)); + DEFINE(IA64_SWITCH_STACK_R6_OFFSET, offsetof (struct switch_stack, r6)); + DEFINE(IA64_SWITCH_STACK_R7_OFFSET, offsetof (struct switch_stack, r7)); + DEFINE(IA64_SWITCH_STACK_B0_OFFSET, offsetof (struct switch_stack, b0)); + DEFINE(IA64_SWITCH_STACK_B1_OFFSET, offsetof (struct switch_stack, b1)); + DEFINE(IA64_SWITCH_STACK_B2_OFFSET, offsetof (struct switch_stack, b2)); + DEFINE(IA64_SWITCH_STACK_B3_OFFSET, offsetof (struct switch_stack, b3)); + DEFINE(IA64_SWITCH_STACK_B4_OFFSET, offsetof (struct switch_stack, b4)); + DEFINE(IA64_SWITCH_STACK_B5_OFFSET, offsetof (struct switch_stack, b5)); + DEFINE(IA64_SWITCH_STACK_AR_PFS_OFFSET, offsetof (struct switch_stack, ar_pfs)); + DEFINE(IA64_SWITCH_STACK_AR_LC_OFFSET, offsetof (struct switch_stack, ar_lc)); + DEFINE(IA64_SWITCH_STACK_AR_UNAT_OFFSET, offsetof (struct switch_stack, ar_unat)); + DEFINE(IA64_SWITCH_STACK_AR_RNAT_OFFSET, offsetof (struct switch_stack, ar_rnat)); + DEFINE(IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET, offsetof (struct switch_stack, ar_bspstore)); + DEFINE(IA64_SWITCH_STACK_PR_OFFSET, offsetof (struct switch_stack, pr)); + + BLANK(); + + DEFINE(IA64_SIGCONTEXT_IP_OFFSET, offsetof (struct sigcontext, sc_ip)); + DEFINE(IA64_SIGCONTEXT_AR_BSP_OFFSET, offsetof (struct sigcontext, sc_ar_bsp)); + DEFINE(IA64_SIGCONTEXT_AR_FPSR_OFFSET, offsetof (struct sigcontext, sc_ar_fpsr)); + DEFINE(IA64_SIGCONTEXT_AR_RNAT_OFFSET, offsetof (struct sigcontext, sc_ar_rnat)); + DEFINE(IA64_SIGCONTEXT_AR_UNAT_OFFSET, offsetof (struct sigcontext, sc_ar_unat)); + DEFINE(IA64_SIGCONTEXT_B0_OFFSET, offsetof (struct sigcontext, sc_br[0])); + DEFINE(IA64_SIGCONTEXT_CFM_OFFSET, offsetof (struct sigcontext, sc_cfm)); + DEFINE(IA64_SIGCONTEXT_FLAGS_OFFSET, offsetof (struct sigcontext, sc_flags)); + DEFINE(IA64_SIGCONTEXT_FR6_OFFSET, offsetof (struct sigcontext, sc_fr[6])); + DEFINE(IA64_SIGCONTEXT_PR_OFFSET, offsetof (struct sigcontext, sc_pr)); + DEFINE(IA64_SIGCONTEXT_R12_OFFSET, offsetof (struct sigcontext, sc_gr[12])); + DEFINE(IA64_SIGCONTEXT_RBS_BASE_OFFSET,offsetof (struct sigcontext, sc_rbs_base)); + DEFINE(IA64_SIGCONTEXT_LOADRS_OFFSET, offsetof (struct sigcontext, sc_loadrs)); + + BLANK(); + + DEFINE(IA64_SIGFRAME_ARG0_OFFSET, offsetof (struct sigframe, arg0)); + DEFINE(IA64_SIGFRAME_ARG1_OFFSET, offsetof (struct sigframe, arg1)); + DEFINE(IA64_SIGFRAME_ARG2_OFFSET, offsetof (struct sigframe, arg2)); + DEFINE(IA64_SIGFRAME_HANDLER_OFFSET, offsetof (struct sigframe, handler)); + DEFINE(IA64_SIGFRAME_SIGCONTEXT_OFFSET, offsetof (struct sigframe, sc)); + BLANK(); + /* for assembly files which can't include sched.h: */ + DEFINE(IA64_CLONE_VFORK, CLONE_VFORK); + DEFINE(IA64_CLONE_VM, CLONE_VM); + + BLANK(); + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ + DEFINE(IA64_CPUINFO_ITM_DELTA_OFFSET, offsetof (struct cpuinfo_ia64, itm_delta)); + DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); + DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); + DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); + + + DEFINE(CLONE_IDLETASK_BIT, 12); +#if CLONE_IDLETASK != (1 << 12) +# error "CLONE_IDLETASK_BIT incorrect, please fix" +#endif + + DEFINE(CLONE_SETTLS_BIT, 19); +#if CLONE_SETTLS != (1<<19) +# error "CLONE_SETTLS_BIT incorrect, please fix" +#endif + +} diff --git a/arch/ia64/kernel/efi_stub.S b/arch/ia64/kernel/efi_stub.S index 8c59ed452ce..6e8a8c1b934 100644 --- a/arch/ia64/kernel/efi_stub.S +++ b/arch/ia64/kernel/efi_stub.S @@ -62,7 +62,7 @@ GLOBAL_ENTRY(efi_call_phys) mov b6=r2 ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret0: mov out4=in5 mov out0=in1 mov out1=in2 @@ -73,7 +73,7 @@ GLOBAL_ENTRY(efi_call_phys) br.call.sptk.many rp=b6 // call the EFI function .ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index eac7eca31e7..ba2bcfc717b 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -5,10 +5,13 @@ * * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 1999, 2002-2003 + * Asit Mallick + * Don Dugger + * Suresh Siddha + * Fenghua Yu * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 Asit Mallick - * Copyright (C) 1999 Don Dugger */ /* * ia64_switch_to now places correct virtual mapping in in TR2 for @@ -74,19 +77,18 @@ ENTRY(ia64_execve) * this executes in less than 20 cycles even on Itanium, so it's not worth * optimizing for...). */ + mov ar.unat=0; mov ar.lc=0 mov r4=0; mov f2=f0; mov b1=r0 mov r5=0; mov f3=f0; mov b2=r0 mov r6=0; mov f4=f0; mov b3=r0 mov r7=0; mov f5=f0; mov b4=r0 - mov ar.unat=0; mov f10=f0; mov b5=r0 - ldf.fill f11=[sp]; ldf.fill f12=[sp]; mov f13=f0 + ldf.fill f12=[sp]; mov f13=f0; mov b5=r0 ldf.fill f14=[sp]; ldf.fill f15=[sp]; mov f16=f0 ldf.fill f17=[sp]; ldf.fill f18=[sp]; mov f19=f0 ldf.fill f20=[sp]; ldf.fill f21=[sp]; mov f22=f0 ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 - mov ar.lc=0 br.ret.sptk.many rp END(ia64_execve) @@ -114,14 +116,8 @@ GLOBAL_ENTRY(sys_clone2) br.call.sptk.many rp=do_fork .ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys_clone2) @@ -149,14 +145,8 @@ GLOBAL_ENTRY(sys_clone) br.call.sptk.many rp=do_fork .ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys_clone) @@ -178,15 +168,12 @@ GLOBAL_ENTRY(ia64_switch_to) ;; st8 [r22]=sp // save kernel stack pointer of old task shr.u r26=r20,IA64_GRANULE_SHIFT - shr.u r17=r20,KERNEL_TR_PAGE_SHIFT - ;; - cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17 adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* * If we've already mapped this task's page, we can skip doing it again. */ -(p6) cmp.eq p7,p6=r26,r27 + cmp.eq p7,p6=r26,r27 (p6) br.cond.dpnt .map ;; .done: @@ -224,14 +211,12 @@ GLOBAL_ENTRY(ia64_switch_to) END(ia64_switch_to) /* - * Note that interrupts are enabled during save_switch_stack and - * load_switch_stack. This means that we may get an interrupt with - * "sp" pointing to the new kernel stack while ar.bspstore is still - * pointing to the old kernel backing store area. Since ar.rsc, - * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, - * this is not a problem. Also, we don't need to specify unwind - * information for preserved registers that are not modified in - * save_switch_stack as the right unwind information is already + * Note that interrupts are enabled during save_switch_stack and load_switch_stack. This + * means that we may get an interrupt with "sp" pointing to the new kernel stack while + * ar.bspstore is still pointing to the old kernel backing store area. Since ar.rsc, + * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, this is not a + * problem. Also, we don't need to specify unwind information for preserved registers + * that are not modified in save_switch_stack as the right unwind information is already * specified at the call-site of save_switch_stack. */ @@ -305,8 +290,6 @@ GLOBAL_ENTRY(save_switch_stack) st8 [r14]=r21,SW(B1)-SW(B0) // save b0 st8 [r15]=r23,SW(B3)-SW(B2) // save b2 mov r25=b4 - stf.spill [r2]=f10,32 - stf.spill [r3]=f11,32 mov r26=b5 ;; st8 [r14]=r22,SW(B4)-SW(B1) // save b1 @@ -405,9 +388,6 @@ ENTRY(load_switch_stack) ldf.fill f4=[r14],32 ldf.fill f5=[r15],32 ;; - ldf.fill f10=[r14],32 - ldf.fill f11=[r15],32 - ;; ldf.fill f12=[r14],32 ldf.fill f13=[r15],32 ;; @@ -525,11 +505,11 @@ strace_check_retval: (p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 strace_save_retval: -.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 -.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 +.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 +.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value -.rety: br.cond.sptk ia64_leave_kernel +.rety: br.cond.sptk ia64_leave_syscall strace_error: ld8 r3=[r2] // load pt_regs.r8 @@ -575,129 +555,288 @@ GLOBAL_ENTRY(ia64_ret_from_syscall) adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 ;; - .mem.offset 0,0 -(p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit - .mem.offset 8,0 -(p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit +.mem.offset 0,0; (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit +.mem.offset 8,0; (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit (p7) br.cond.spnt handle_syscall_error // handle potential syscall failure END(ia64_ret_from_syscall) // fall through -GLOBAL_ENTRY(ia64_leave_kernel) +/* + * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't + * need to switch to bank 0 and doesn't restore the scratch registers. + * To avoid leaking kernel bits, the scratch registers are set to + * the following known-to-be-safe values: + * + * r1: restored (global pointer) + * r2: cleared + * r3: 1 (when returning to user-level) + * r8-r11: restored (syscall return value(s)) + * r12: restored (user-level stack pointer) + * r13: restored (user-level thread pointer) + * r14: cleared + * r15: restored (syscall #) + * r16-r19: cleared + * r20: user-level ar.fpsr + * r21: user-level b0 + * r22: user-level b6 + * r23: user-level ar.bspstore + * r24: user-level ar.rnat + * r25: user-level ar.unat + * r26: user-level ar.pfs + * r27: user-level ar.rsc + * r28: user-level ip + * r29: user-level psr + * r30: user-level cfm + * r31: user-level pr + * f6-f11: cleared + * pr: restored (user-level pr) + * b0: restored (user-level rp) + * b6: restored + * b7: cleared + * ar.unat: restored (user-level ar.unat) + * ar.pfs: restored (user-level ar.pfs) + * ar.rsc: restored (user-level ar.rsc) + * ar.rnat: restored (user-level ar.rnat) + * ar.bspstore: restored (user-level ar.bspstore) + * ar.fpsr: restored (user-level ar.fpsr) + * ar.ccv: cleared + * ar.csd: cleared + * ar.ssd: cleared + */ +GLOBAL_ENTRY(ia64_leave_syscall) PT_REGS_UNWIND_INFO(0) - // work.need_resched etc. mustn't get changed by this CPU before it returns to - // user- or fsys-mode: -(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to + * user- or fsys-mode, hence we disable interrupts early on: + */ #ifdef CONFIG_PREEMPT rsm psr.i // disable interrupts - adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 +#else +(pUStk) rsm psr.i +#endif + cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk +.work_processed_syscall: +#ifdef CONFIG_PREEMPT (pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; -(pKStk) ld4 r21=[r20] // preempt_count ->r21 + .pred.rel.mutex pUStk,pKStk +(pKStk) ld4 r21=[r20] // r21 <- preempt_count +(pUStk) mov r21=0 // r21 <- 0 + ;; +(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) +#endif /* CONFIG_PREEMPT */ + adds r16=PT(LOADRS)+16,r12 + adds r17=PT(AR_BSPSTORE)+16,r12 + adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; +(p6) ld4 r31=[r18] // load current_thread_info()->flags + ld8 r19=[r16],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" + nop.i 0 + ;; + ld8 r23=[r17],PT(R9)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) + ld8 r22=[r16],PT(R8)-PT(B6) // load b6 +(p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? + ;; + + mov.m ar.ccv=r0 // clear ar.ccv +(p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending? +(p6) br.cond.spnt .work_pending + ;; + // start restoring the state saved on the kernel stack (struct pt_regs): + ld8.fill r8=[r16],16 + ld8.fill r9=[r17],16 + mov f6=f0 // clear f6 ;; -(pKStk) cmp4.eq p6,p0=r21,r0 // p6 <- preempt_count == 0 + ld8.fill r10=[r16],16 + ld8.fill r11=[r17],16 + mov f7=f0 // clear f7 ;; -#else /* CONFIG_PREEMPT */ + ld8 r29=[r16],16 // load cr.ipsr + ld8 r28=[r17],16 // load cr.iip + mov f8=f0 // clear f8 + ;; + ld8 r30=[r16],16 // load cr.ifs + ld8 r25=[r17],16 // load ar.unat + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs + ;; + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + invala // invalidate ALAT + mov f9=f0 // clear f9 + + mov.m ar.ssd=r0 // clear ar.ssd + mov.m ar.csd=r0 // clear ar.csd + mov f10=f0 // clear f10 + ;; + ld8 r26=[r16],16 // load ar.pfs + ld8 r27=[r17],PT(PR)-PT(AR_RSC) // load ar.rsc + mov f11=f0 // clear f11 + ;; + ld8 r24=[r16],PT(B0)-PT(AR_RNAT) // load ar.rnat (may be garbage) + ld8 r31=[r17],PT(R1)-PT(PR) // load predicates +(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 + ;; + ld8 r21=[r16],PT(R12)-PT(B0) // load b0 + ld8.fill r1=[r17],16 // load r1 +(pUStk) mov r3=1 + ;; + ld8.fill r12=[r16],16 + ld8.fill r13=[r17],16 + mov r2=r0 // clear r2 + ;; + ld8 r20=[r16] // load ar.fpsr + ld8.fill r15=[r17] // load r15 + mov b7=r0 // clear b7 + ;; +(pUStk) st1 [r14]=r3 + movl r17=THIS_CPU(ia64_phys_stacked_size_p8) + ;; + mov r16=ar.bsp // get existing backing store pointer + srlz.i // ensure interruption collection is off + mov r14=r0 // clear r14 + ;; + ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 + mov b6=r22 // restore b6 + shr.u r18=r19,16 // get byte size of existing "dirty" partition +(pKStk) br.cond.dpnt.many skip_rbs_switch + br.cond.sptk.many rbs_switch +END(ia64_leave_syscall) + +GLOBAL_ENTRY(ia64_leave_kernel) + PT_REGS_UNWIND_INFO(0) + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to + * user- or fsys-mode, hence we disable interrupts early on: + */ +#ifdef CONFIG_PREEMPT + rsm psr.i // disable interrupts +#else (pUStk) rsm psr.i +#endif + cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk ;; -(pUStk) adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 +.work_processed_kernel: +#ifdef CONFIG_PREEMPT + adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 + ;; + .pred.rel.mutex pUStk,pKStk +(pKStk) ld4 r21=[r20] // r21 <- preempt_count +(pUStk) mov r21=0 // r21 <- 0 ;; +(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) #endif /* CONFIG_PREEMPT */ -.work_processed: -(p6) ld4 r18=[r17] // load current_thread_info()->flags - adds r2=PT(R8)+16,r12 - adds r3=PT(R9)+16,r12 + adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 ;; - // start restoring the state saved on the kernel stack (struct pt_regs): - ld8.fill r8=[r2],16 - ld8.fill r9=[r3],16 -(p6) and r19=TIF_WORK_MASK,r18 // any work other than TIF_SYSCALL_TRACE? +(p6) ld4 r31=[r17] // load current_thread_info()->flags + adds r21=PT(PR)+16,r12 ;; - ld8.fill r10=[r2],16 - ld8.fill r11=[r3],16 + + lfetch [r21],PT(CR_IPSR)-PT(PR) + adds r2=PT(B6)+16,r12 + adds r3=PT(R16)+16,r12 + ;; + lfetch [r21] + ld8 r28=[r2],8 // load b6 + adds r29=PT(R24)+16,r12 + + ld8.fill r16=[r3],PT(AR_CSD)-PT(R16) + adds r30=PT(AR_CCV)+16,r12 +(p6) and r19=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? + ;; + ld8.fill r24=[r29] + ld8 r15=[r30] // load ar.ccv (p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending? ;; - ld8.fill r16=[r2],16 - ld8.fill r17=[r3],16 + ld8 r29=[r2],16 // load b7 + ld8 r30=[r3],16 // load ar.csd (p6) br.cond.spnt .work_pending ;; + ld8 r31=[r2],16 // load ar.ssd + ld8.fill r8=[r3],16 + ;; + ld8.fill r9=[r2],16 + ld8.fill r10=[r3],PT(R17)-PT(R10) + ;; + ld8.fill r11=[r2],PT(R18)-PT(R11) + ld8.fill r17=[r3],16 + ;; ld8.fill r18=[r2],16 ld8.fill r19=[r3],16 ;; ld8.fill r20=[r2],16 ld8.fill r21=[r3],16 + mov ar.csd=r30 + mov ar.ssd=r31 ;; - ld8.fill r22=[r2],16 - ld8.fill r23=[r3],16 - ;; - ld8.fill r24=[r2],16 - ld8.fill r25=[r3],16 - ;; - ld8.fill r26=[r2],16 - ld8.fill r27=[r3],16 + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + invala // invalidate ALAT ;; - ld8.fill r28=[r2],16 - ld8.fill r29=[r3],16 + ld8.fill r22=[r2],24 + ld8.fill r23=[r3],24 + mov b6=r28 ;; - ld8.fill r30=[r2],16 - ld8.fill r31=[r3],16 + ld8.fill r25=[r2],16 + ld8.fill r26=[r3],16 + mov b7=r29 ;; - rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection - invala // invalidate ALAT + ld8.fill r27=[r2],16 + ld8.fill r28=[r3],16 ;; - ld8 r1=[r2],16 // ar.ccv - ld8 r13=[r3],16 // ar.fpsr + ld8.fill r29=[r2],16 + ld8.fill r30=[r3],24 ;; - ld8 r14=[r2],16 // b0 - ld8 r15=[r3],16+8 // b7 + ld8.fill r31=[r2],PT(F9)-PT(R31) + adds r3=PT(F10)-PT(F6),r3 ;; - ldf.fill f6=[r2],32 - ldf.fill f7=[r3],32 + ldf.fill f9=[r2],PT(F6)-PT(F9) + ldf.fill f10=[r3],PT(F8)-PT(F10) ;; - ldf.fill f8=[r2],32 - ldf.fill f9=[r3],32 + ldf.fill f6=[r2],PT(F7)-PT(F6) ;; - mov ar.ccv=r1 - mov ar.fpsr=r13 - mov b0=r14 + ldf.fill f7=[r2],PT(F11)-PT(F7) + ldf.fill f8=[r3],32 ;; srlz.i // ensure interruption collection is off - mov b7=r15 + mov ar.ccv=r15 + ;; bsw.0 // switch back to bank 0 (no stop bit required beforehand...) ;; + ldf.fill f11=[r2] (pUStk) mov r18=IA64_KR(CURRENT) // Itanium 2: 12 cycle read latency - adds r16=16,r12 - adds r17=24,r12 + adds r16=PT(CR_IPSR)+16,r12 + adds r17=PT(CR_IIP)+16,r12 ;; - ld8 rCRIPSR=[r16],16 // load cr.ipsr - ld8 rCRIIP=[r17],16 // load cr.iip + ld8 r29=[r16],16 // load cr.ipsr + ld8 r28=[r17],16 // load cr.iip ;; - ld8 rCRIFS=[r16],16 // load cr.ifs - ld8 rARUNAT=[r17],16 // load ar.unat - cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs + ld8 r30=[r16],16 // load cr.ifs + ld8 r25=[r17],16 // load ar.unat ;; - ld8 rARPFS=[r16],16 // load ar.pfs - ld8 rARRSC=[r17],16 // load ar.rsc + ld8 r26=[r16],16 // load ar.pfs + ld8 r27=[r17],16 // load ar.rsc + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; - ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage) - ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) + ld8 r24=[r16],16 // load ar.rnat (may be garbage) + ld8 r23=[r17],16// load ar.bspstore (may be garbage) ;; - ld8 rARPR=[r16],16 // load predicates - ld8 rB6=[r17],16 // load b6 + ld8 r31=[r16],16 // load predicates + ld8 r21=[r17],16 // load b0 ;; ld8 r19=[r16],16 // load ar.rsc value for "loadrs" ld8.fill r1=[r17],16 // load r1 ;; - ld8.fill r2=[r16],16 - ld8.fill r3=[r17],16 - ;; ld8.fill r12=[r16],16 ld8.fill r13=[r17],16 (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 ;; - ld8.fill r14=[r16] - ld8.fill r15=[r17] + ld8 r20=[r16],16 // ar.fpsr + ld8.fill r15=[r17],16 + ;; + ld8.fill r14=[r16],16 + ld8.fill r2=[r17] (pUStk) mov r17=1 ;; + ld8.fill r3=[r16] (pUStk) st1 [r18]=r17 // restore current->thread.on_ustack shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; @@ -713,6 +852,8 @@ GLOBAL_ENTRY(ia64_leave_kernel) * NOTE: alloc, loadrs, and cover can't be predicated. */ (pNonSys) br.cond.dpnt dont_preserve_current_frame + +rbs_switch: cover // add current frame into dirty partition and set cr.ifs ;; mov r19=ar.bsp // get new backing store pointer @@ -765,7 +906,7 @@ rse_clear_invalid: }{ .mib mov loc3=0 mov loc4=0 -(pRecurse) br.call.sptk.many b6=rse_clear_invalid +(pRecurse) br.call.sptk.many b0=rse_clear_invalid }{ .mfi // cycle 2 mov loc5=0 @@ -774,7 +915,7 @@ rse_clear_invalid: }{ .mib mov loc6=0 mov loc7=0 -(pReturn) br.ret.sptk.many b6 +(pReturn) br.ret.sptk.many b0 } #else /* !CONFIG_ITANIUM */ alloc loc0=ar.pfs,2,Nregs-2,2,0 @@ -789,14 +930,14 @@ rse_clear_invalid: mov loc5=0 mov loc6=0 mov loc7=0 -(pRecurse) br.call.sptk.many b6=rse_clear_invalid +(pRecurse) br.call.sptk.few b0=rse_clear_invalid ;; mov loc8=0 mov loc9=0 cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret mov loc10=0 mov loc11=0 -(pReturn) br.ret.sptk.many b6 +(pReturn) br.ret.sptk.many b0 #endif /* !CONFIG_ITANIUM */ # undef pRecurse # undef pReturn @@ -806,59 +947,65 @@ rse_clear_invalid: loadrs ;; skip_rbs_switch: - mov b6=rB6 - mov ar.pfs=rARPFS -(pUStk) mov ar.bspstore=rARBSPSTORE -(p9) mov cr.ifs=rCRIFS - mov cr.ipsr=rCRIPSR - mov cr.iip=rCRIIP - ;; -(pUStk) mov ar.rnat=rARRNAT // must happen with RSE in lazy mode - mov ar.rsc=rARRSC - mov ar.unat=rARUNAT - mov pr=rARPR,-1 +(pLvSys) mov r19=r0 // clear r19 for leave_syscall, no-op otherwise + mov b0=r21 + mov ar.pfs=r26 +(pUStk) mov ar.bspstore=r23 +(p9) mov cr.ifs=r30 +(pLvSys)mov r16=r0 // clear r16 for leave_syscall, no-op otherwise + mov cr.ipsr=r29 + mov ar.fpsr=r20 +(pLvSys)mov r17=r0 // clear r17 for leave_syscall, no-op otherwise + mov cr.iip=r28 + ;; +(pUStk) mov ar.rnat=r24 // must happen with RSE in lazy mode +(pLvSys)mov r18=r0 // clear r18 for leave_syscall, no-op otherwise + mov ar.rsc=r27 + mov ar.unat=r25 + mov pr=r31,-1 rfi + /* + * On entry: + * r20 = ¤t->thread_info->pre_count (if CONFIG_PREEMPT) + * r31 = current->thread_info->flags + * On exit: + * p6 = TRUE if work-pending-check needs to be redone + */ .work_pending: - tbit.z p6,p0=r18,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? + tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? (p6) br.cond.sptk.few .notify #ifdef CONFIG_PREEMPT -(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 +(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 ;; (pKStk) st4 [r20]=r21 - ssm psr.i // enable interrupts + ssm psr.i // enable interrupts #endif - -#if __GNUC__ < 3 - br.call.spnt.many rp=invoke_schedule -#else br.call.spnt.many rp=schedule -#endif .ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 rsm psr.i // disable interrupts ;; - adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 #ifdef CONFIG_PREEMPT (pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; (pKStk) st4 [r20]=r0 // preempt_count() <- 0 #endif - br.cond.sptk.many .work_processed // re-check +(pLvSys)br.cond.sptk.many .work_processed_syscall // re-check + br.cond.sptk.many .work_processed_kernel // re-check .notify: br.call.spnt.many rp=notify_resume_user .ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 - br.cond.sptk.many .work_processed // don't re-check +(pLvSys)br.cond.sptk.many .work_processed_syscall // don't re-check + br.cond.sptk.many .work_processed_kernel // don't re-check END(ia64_leave_kernel) ENTRY(handle_syscall_error) /* - * Some system calls (e.g., ptrace, mmap) can return arbitrary - * values which could lead us to mistake a negative return - * value as a failed syscall. Those syscall must deposit - * a non-zero value in pt_regs.r8 to indicate an error. - * If pt_regs.r8 is zero, we assume that the call completed - * successfully. + * Some system calls (e.g., ptrace, mmap) can return arbitrary values which could + * lead us to mistake a negative return value as a failed syscall. Those syscall + * must deposit a non-zero value in pt_regs.r8 to indicate an error. If + * pt_regs.r8 is zero, we assume that the call completed successfully. */ PT_REGS_UNWIND_INFO(0) ld8 r3=[r2] // load pt_regs.r8 @@ -873,7 +1020,7 @@ ENTRY(handle_syscall_error) ;; .mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit .mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit - br.cond.sptk ia64_leave_kernel + br.cond.sptk ia64_leave_syscall END(handle_syscall_error) /* @@ -892,31 +1039,6 @@ GLOBAL_ENTRY(ia64_invoke_schedule_tail) br.ret.sptk.many rp END(ia64_invoke_schedule_tail) -#if __GNUC__ < 3 - - /* - * Invoke schedule() while preserving in0-in7, which may be needed - * in case a system call gets restarted. Note that declaring schedule() - * with asmlinkage() is NOT enough because that will only preserve as many - * registers as there are formal arguments. - * - * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage - * renders all eight input registers (in0-in7) as "untouchable". - */ -ENTRY(invoke_schedule) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,2,0,0 - mov loc0=rp - ;; - .body - br.call.sptk.many rp=schedule -.ret14: mov ar.pfs=loc1 - mov rp=loc0 - br.ret.sptk.many rp -END(invoke_schedule) - -#endif /* __GNUC__ < 3 */ - /* * Setup stack and call do_notify_resume_user(). Note that pSys and pNonSys need to * be set up by the caller. We declare 8 input registers so the system call @@ -984,6 +1106,23 @@ ENTRY(sys_rt_sigreturn) .body cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; + /* + * leave_kernel() restores f6-f11 from pt_regs, but since the streamlined + * syscall-entry path does not save them we save them here instead. Note: we + * don't need to save any other registers that are not saved by the stream-lined + * syscall path, because restore_sigcontext() restores them. + */ + adds r16=PT(F6)+32,sp + adds r17=PT(F7)+32,sp + ;; + stf.spill [r16]=f6,32 + stf.spill [r17]=f7,32 + ;; + stf.spill [r16]=f8,32 + stf.spill [r17]=f9,32 + ;; + stf.spill [r16]=f10 + stf.spill [r17]=f11 adds out0=16,sp // out0 = &sigscratch br.call.sptk.many rp=ia64_rt_sigreturn .ret19: .restore sp 0 @@ -1291,8 +1430,8 @@ sys_call_table: data8 sys_clock_gettime data8 sys_clock_getres // 1255 data8 sys_clock_nanosleep - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_fstatfs64 + data8 sys_statfs64 data8 ia64_ni_syscall data8 ia64_ni_syscall // 1260 data8 ia64_ni_syscall @@ -1313,3 +1452,6 @@ sys_call_table: data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall + data8 ia64_ni_syscall + + .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h index b7db2253311..32ecc497b47 100644 --- a/arch/ia64/kernel/entry.h +++ b/arch/ia64/kernel/entry.h @@ -4,8 +4,9 @@ * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ -#define pKStk p2 /* will leave_kernel return to kernel-stacks? */ -#define pUStk p3 /* will leave_kernel return to user-stacks? */ +#define pLvSys p1 /* set 1 if leave from syscall; otherwise, set 0*/ +#define pKStk p2 /* will leave_{kernel,syscall} return to kernel-stacks? */ +#define pUStk p3 /* will leave_{kernel,syscall} return to user-stacks? */ #define pSys p4 /* are we processing a (synchronous) system call? */ #define pNonSys p5 /* complement of pSys */ @@ -13,6 +14,7 @@ #define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) #define PT_REGS_SAVES(off) \ + .unwabi 3, 'i'; \ .unwabi @svr4, 'i'; \ .fframe IA64_PT_REGS_SIZE+16+(off); \ .spillsp rp, PT(CR_IIP)+16+(off); \ diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 1023d095dd3..ff4f2b38f97 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -14,6 +14,11 @@ #include #include #include +#include +#include +#include + +#include "entry.h" /* * See Documentation/ia64/fsys.txt for details on fsyscalls. @@ -38,6 +43,9 @@ */ ENTRY(fsys_ni_syscall) + .prologue + .altrp b6 + .body mov r8=ENOSYS mov r10=-1 MCKINLEY_E9_WORKAROUND @@ -45,6 +53,9 @@ ENTRY(fsys_ni_syscall) END(fsys_ni_syscall) ENTRY(fsys_getpid) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 ;; ld4 r9=[r9] @@ -60,6 +71,9 @@ ENTRY(fsys_getpid) END(fsys_getpid) ENTRY(fsys_getppid) + .prologue + .altrp b6 + .body add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16 ;; ld8 r17=[r17] // r17 = current->group_leader @@ -105,6 +119,9 @@ ENTRY(fsys_getppid) END(fsys_getppid) ENTRY(fsys_set_tid_address) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 ;; ld4 r9=[r9] @@ -142,23 +159,33 @@ END(fsys_set_tid_address) * we ought to either skip the ITC-based interpolation or run an ntp-like * daemon to keep the ITCs from drifting too far apart. */ + ENTRY(fsys_gettimeofday) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 movl r3=THIS_CPU(cpu_info) mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc) - movl r19=xtime // xtime is a timespec struct - ;; - #ifdef CONFIG_SMP movl r10=__per_cpu_offset + movl r2=sal_platform_features ;; + + ld8 r2=[r2] + movl r19=xtime // xtime is a timespec struct + ld8 r10=[r10] // r10 <- __per_cpu_offset[0] - movl r21=cpu_info__per_cpu + movl r21=THIS_CPU(cpu_info) ;; add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id) + tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT +(p8) br.spnt.many fsys_fallback_syscall #else + ;; mov r10=r3 + movl r19=xtime // xtime is a timespec struct #endif ld4 r9=[r9] movl r17=xtime_lock @@ -305,262 +332,374 @@ EX(.fail, st8 [r9]=r3) // store them in the timeval struct br.ret.spnt.many b6 // return with r8 set to EINVAL END(fsys_gettimeofday) +ENTRY(fsys_fallback_syscall) + .prologue + .altrp b6 + .body + /* + * We only get here from light-weight syscall handlers. Thus, we already + * know that r15 contains a valid syscall number. No need to re-check. + */ + adds r17=-1024,r15 + movl r14=sys_call_table + ;; + shladd r18=r17,3,r14 + ;; + ld8 r18=[r18] // load normal (heavy-weight) syscall entry-point + mov r29=psr // read psr (12 cyc load latency) + mov r27=ar.rsc + mov r21=ar.fpsr + mov r26=ar.pfs +END(fsys_fallback_syscall) + /* FALL THROUGH */ +GLOBAL_ENTRY(fsys_bubble_down) + .prologue + .altrp b6 + .body + /* + * We get here for syscalls that don't have a lightweight handler. For those, we + * need to bubble down into the kernel and that requires setting up a minimal + * pt_regs structure, and initializing the CPU state more or less as if an + * interruption had occurred. To make syscall-restarts work, we setup pt_regs + * such that cr_iip points to the second instruction in syscall_via_break. + * Decrementing the IP hence will restart the syscall via break and not + * decrementing IP will return us to the caller, as usual. Note that we preserve + * the value of psr.pp rather than initializing it from dcr.pp. This makes it + * possible to distinguish fsyscall execution from other privileged execution. + * + * On entry: + * - normal fsyscall handler register usage, except that we also have: + * - r18: address of syscall entry point + * - r21: ar.fpsr + * - r26: ar.pfs + * - r27: ar.rsc + * - r29: psr + */ +# define PSR_PRESERVED_BITS (IA64_PSR_UP | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_PK \ + | IA64_PSR_DT | IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_RT \ + | IA64_PSR_IC) + /* + * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. The rest we have + * to synthesize. + */ +# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \ + | IA64_PSR_BN) + + invala + movl r8=PSR_ONE_BITS + + mov r25=ar.unat // save ar.unat (5 cyc) + movl r9=PSR_PRESERVED_BITS + + mov ar.rsc=0 // set enforced lazy mode, pl 0, little-endian, loadrs=0 + movl r28=__kernel_syscall_via_break + ;; + mov r23=ar.bspstore // save ar.bspstore (12 cyc) + mov r31=pr // save pr (2 cyc) + mov r20=r1 // save caller's gp in r20 + ;; + mov r2=r16 // copy current task addr to addl-addressable register + and r9=r9,r29 + mov r19=b6 // save b6 (2 cyc) + ;; + mov psr.l=r9 // slam the door (17 cyc to srlz.i) + or r29=r8,r29 // construct cr.ipsr value to save + addl r22=IA64_RBS_OFFSET,r2 // compute base of RBS + ;; + mov.m r24=ar.rnat // read ar.rnat (5 cyc lat) + lfetch.fault.excl.nt1 [r22] + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r2 + + // ensure previous insn group is issued before we stall for srlz.i: + ;; + srlz.i // ensure new psr.l has been established + ///////////////////////////////////////////////////////////////////////////// + ////////// from this point on, execution is not interruptible anymore + ///////////////////////////////////////////////////////////////////////////// + addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // compute base of memory stack + cmp.ne pKStk,pUStk=r0,r0 // set pKStk <- 0, pUStk <- 1 + ;; + st1 [r16]=r0 // clear current->thread.on_ustack flag + mov ar.bspstore=r22 // switch to kernel RBS + mov b6=r18 // copy syscall entry-point to b6 (7 cyc) + add r3=TI_FLAGS+IA64_TASK_SIZE,r2 + ;; + ld4 r3=[r3] // r2 = current_thread_info()->flags + mov r18=ar.bsp // save (kernel) ar.bsp (12 cyc) + mov ar.rsc=0x3 // set eager mode, pl 0, little-endian, loadrs=0 + br.call.sptk.many b7=ia64_syscall_setup + ;; + ssm psr.i + movl r2=ia64_ret_from_syscall + ;; + mov rp=r2 // set the real return addr + tbit.z p8,p0=r3,TIF_SYSCALL_TRACE + +(p8) br.call.sptk.many b6=b6 // ignore this return addr + br.cond.sptk ia64_trace_syscall +END(fsys_bubble_down) + .rodata .align 8 .globl fsyscall_table + + data8 fsys_bubble_down fsyscall_table: data8 fsys_ni_syscall - data8 fsys_fallback_syscall // exit // 1025 - data8 fsys_fallback_syscall // read - data8 fsys_fallback_syscall // write - data8 fsys_fallback_syscall // open - data8 fsys_fallback_syscall // close - data8 fsys_fallback_syscall // creat // 1030 - data8 fsys_fallback_syscall // link - data8 fsys_fallback_syscall // unlink - data8 fsys_fallback_syscall // execve - data8 fsys_fallback_syscall // chdir - data8 fsys_fallback_syscall // fchdir // 1035 - data8 fsys_fallback_syscall // utimes - data8 fsys_fallback_syscall // mknod - data8 fsys_fallback_syscall // chmod - data8 fsys_fallback_syscall // chown - data8 fsys_fallback_syscall // lseek // 1040 - data8 fsys_getpid + data8 0 // exit // 1025 + data8 0 // read + data8 0 // write + data8 0 // open + data8 0 // close + data8 0 // creat // 1030 + data8 0 // link + data8 0 // unlink + data8 0 // execve + data8 0 // chdir + data8 0 // fchdir // 1035 + data8 0 // utimes + data8 0 // mknod + data8 0 // chmod + data8 0 // chown + data8 0 // lseek // 1040 + data8 fsys_getpid // getpid data8 fsys_getppid // getppid - data8 fsys_fallback_syscall // mount - data8 fsys_fallback_syscall // umount - data8 fsys_fallback_syscall // setuid // 1045 - data8 fsys_fallback_syscall // getuid - data8 fsys_fallback_syscall // geteuid - data8 fsys_fallback_syscall // ptrace - data8 fsys_fallback_syscall // access - data8 fsys_fallback_syscall // sync // 1050 - data8 fsys_fallback_syscall // fsync - data8 fsys_fallback_syscall // fdatasync - data8 fsys_fallback_syscall // kill - data8 fsys_fallback_syscall // rename - data8 fsys_fallback_syscall // mkdir // 1055 - data8 fsys_fallback_syscall // rmdir - data8 fsys_fallback_syscall // dup - data8 fsys_fallback_syscall // pipe - data8 fsys_fallback_syscall // times - data8 fsys_fallback_syscall // brk // 1060 - data8 fsys_fallback_syscall // setgid - data8 fsys_fallback_syscall // getgid - data8 fsys_fallback_syscall // getegid - data8 fsys_fallback_syscall // acct - data8 fsys_fallback_syscall // ioctl // 1065 - data8 fsys_fallback_syscall // fcntl - data8 fsys_fallback_syscall // umask - data8 fsys_fallback_syscall // chroot - data8 fsys_fallback_syscall // ustat - data8 fsys_fallback_syscall // dup2 // 1070 - data8 fsys_fallback_syscall // setreuid - data8 fsys_fallback_syscall // setregid - data8 fsys_fallback_syscall // getresuid - data8 fsys_fallback_syscall // setresuid - data8 fsys_fallback_syscall // getresgid // 1075 - data8 fsys_fallback_syscall // setresgid - data8 fsys_fallback_syscall // getgroups - data8 fsys_fallback_syscall // setgroups - data8 fsys_fallback_syscall // getpgid - data8 fsys_fallback_syscall // setpgid // 1080 - data8 fsys_fallback_syscall // setsid - data8 fsys_fallback_syscall // getsid - data8 fsys_fallback_syscall // sethostname - data8 fsys_fallback_syscall // setrlimit - data8 fsys_fallback_syscall // getrlimit // 1085 - data8 fsys_fallback_syscall // getrusage + data8 0 // mount + data8 0 // umount + data8 0 // setuid // 1045 + data8 0 // getuid + data8 0 // geteuid + data8 0 // ptrace + data8 0 // access + data8 0 // sync // 1050 + data8 0 // fsync + data8 0 // fdatasync + data8 0 // kill + data8 0 // rename + data8 0 // mkdir // 1055 + data8 0 // rmdir + data8 0 // dup + data8 0 // pipe + data8 0 // times + data8 0 // brk // 1060 + data8 0 // setgid + data8 0 // getgid + data8 0 // getegid + data8 0 // acct + data8 0 // ioctl // 1065 + data8 0 // fcntl + data8 0 // umask + data8 0 // chroot + data8 0 // ustat + data8 0 // dup2 // 1070 + data8 0 // setreuid + data8 0 // setregid + data8 0 // getresuid + data8 0 // setresuid + data8 0 // getresgid // 1075 + data8 0 // setresgid + data8 0 // getgroups + data8 0 // setgroups + data8 0 // getpgid + data8 0 // setpgid // 1080 + data8 0 // setsid + data8 0 // getsid + data8 0 // sethostname + data8 0 // setrlimit + data8 0 // getrlimit // 1085 + data8 0 // getrusage data8 fsys_gettimeofday // gettimeofday - data8 fsys_fallback_syscall // settimeofday - data8 fsys_fallback_syscall // select - data8 fsys_fallback_syscall // poll // 1090 - data8 fsys_fallback_syscall // symlink - data8 fsys_fallback_syscall // readlink - data8 fsys_fallback_syscall // uselib - data8 fsys_fallback_syscall // swapon - data8 fsys_fallback_syscall // swapoff // 1095 - data8 fsys_fallback_syscall // reboot - data8 fsys_fallback_syscall // truncate - data8 fsys_fallback_syscall // ftruncate - data8 fsys_fallback_syscall // fchmod - data8 fsys_fallback_syscall // fchown // 1100 - data8 fsys_fallback_syscall // getpriority - data8 fsys_fallback_syscall // setpriority - data8 fsys_fallback_syscall // statfs - data8 fsys_fallback_syscall // fstatfs - data8 fsys_fallback_syscall // gettid // 1105 - data8 fsys_fallback_syscall // semget - data8 fsys_fallback_syscall // semop - data8 fsys_fallback_syscall // semctl - data8 fsys_fallback_syscall // msgget - data8 fsys_fallback_syscall // msgsnd // 1110 - data8 fsys_fallback_syscall // msgrcv - data8 fsys_fallback_syscall // msgctl - data8 fsys_fallback_syscall // shmget - data8 fsys_fallback_syscall // shmat - data8 fsys_fallback_syscall // shmdt // 1115 - data8 fsys_fallback_syscall // shmctl - data8 fsys_fallback_syscall // syslog - data8 fsys_fallback_syscall // setitimer - data8 fsys_fallback_syscall // getitimer - data8 fsys_fallback_syscall // 1120 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // vhangup - data8 fsys_fallback_syscall // lchown - data8 fsys_fallback_syscall // remap_file_pages // 1125 - data8 fsys_fallback_syscall // wait4 - data8 fsys_fallback_syscall // sysinfo - data8 fsys_fallback_syscall // clone - data8 fsys_fallback_syscall // setdomainname - data8 fsys_fallback_syscall // newuname // 1130 - data8 fsys_fallback_syscall // adjtimex - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // init_module - data8 fsys_fallback_syscall // delete_module - data8 fsys_fallback_syscall // 1135 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // quotactl - data8 fsys_fallback_syscall // bdflush - data8 fsys_fallback_syscall // sysfs - data8 fsys_fallback_syscall // personality // 1140 - data8 fsys_fallback_syscall // afs_syscall - data8 fsys_fallback_syscall // setfsuid - data8 fsys_fallback_syscall // setfsgid - data8 fsys_fallback_syscall // getdents - data8 fsys_fallback_syscall // flock // 1145 - data8 fsys_fallback_syscall // readv - data8 fsys_fallback_syscall // writev - data8 fsys_fallback_syscall // pread64 - data8 fsys_fallback_syscall // pwrite64 - data8 fsys_fallback_syscall // sysctl // 1150 - data8 fsys_fallback_syscall // mmap - data8 fsys_fallback_syscall // munmap - data8 fsys_fallback_syscall // mlock - data8 fsys_fallback_syscall // mlockall - data8 fsys_fallback_syscall // mprotect // 1155 - data8 fsys_fallback_syscall // mremap - data8 fsys_fallback_syscall // msync - data8 fsys_fallback_syscall // munlock - data8 fsys_fallback_syscall // munlockall - data8 fsys_fallback_syscall // sched_getparam // 1160 - data8 fsys_fallback_syscall // sched_setparam - data8 fsys_fallback_syscall // sched_getscheduler - data8 fsys_fallback_syscall // sched_setscheduler - data8 fsys_fallback_syscall // sched_yield - data8 fsys_fallback_syscall // sched_get_priority_max // 1165 - data8 fsys_fallback_syscall // sched_get_priority_min - data8 fsys_fallback_syscall // sched_rr_get_interval - data8 fsys_fallback_syscall // nanosleep - data8 fsys_fallback_syscall // nfsservctl - data8 fsys_fallback_syscall // prctl // 1170 - data8 fsys_fallback_syscall // getpagesize - data8 fsys_fallback_syscall // mmap2 - data8 fsys_fallback_syscall // pciconfig_read - data8 fsys_fallback_syscall // pciconfig_write - data8 fsys_fallback_syscall // perfmonctl // 1175 - data8 fsys_fallback_syscall // sigaltstack - data8 fsys_fallback_syscall // rt_sigaction - data8 fsys_fallback_syscall // rt_sigpending - data8 fsys_fallback_syscall // rt_sigprocmask - data8 fsys_fallback_syscall // rt_sigqueueinfo // 1180 - data8 fsys_fallback_syscall // rt_sigreturn - data8 fsys_fallback_syscall // rt_sigsuspend - data8 fsys_fallback_syscall // rt_sigtimedwait - data8 fsys_fallback_syscall // getcwd - data8 fsys_fallback_syscall // capget // 1185 - data8 fsys_fallback_syscall // capset - data8 fsys_fallback_syscall // sendfile - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // socket // 1190 - data8 fsys_fallback_syscall // bind - data8 fsys_fallback_syscall // connect - data8 fsys_fallback_syscall // listen - data8 fsys_fallback_syscall // accept - data8 fsys_fallback_syscall // getsockname // 1195 - data8 fsys_fallback_syscall // getpeername - data8 fsys_fallback_syscall // socketpair - data8 fsys_fallback_syscall // send - data8 fsys_fallback_syscall // sendto - data8 fsys_fallback_syscall // recv // 1200 - data8 fsys_fallback_syscall // recvfrom - data8 fsys_fallback_syscall // shutdown - data8 fsys_fallback_syscall // setsockopt - data8 fsys_fallback_syscall // getsockopt - data8 fsys_fallback_syscall // sendmsg // 1205 - data8 fsys_fallback_syscall // recvmsg - data8 fsys_fallback_syscall // pivot_root - data8 fsys_fallback_syscall // mincore - data8 fsys_fallback_syscall // madvise - data8 fsys_fallback_syscall // newstat // 1210 - data8 fsys_fallback_syscall // newlstat - data8 fsys_fallback_syscall // newfstat - data8 fsys_fallback_syscall // clone2 - data8 fsys_fallback_syscall // getdents64 - data8 fsys_fallback_syscall // getunwind // 1215 - data8 fsys_fallback_syscall // readahead - data8 fsys_fallback_syscall // setxattr - data8 fsys_fallback_syscall // lsetxattr - data8 fsys_fallback_syscall // fsetxattr - data8 fsys_fallback_syscall // getxattr // 1220 - data8 fsys_fallback_syscall // lgetxattr - data8 fsys_fallback_syscall // fgetxattr - data8 fsys_fallback_syscall // listxattr - data8 fsys_fallback_syscall // llistxattr - data8 fsys_fallback_syscall // flistxattr // 1225 - data8 fsys_fallback_syscall // removexattr - data8 fsys_fallback_syscall // lremovexattr - data8 fsys_fallback_syscall // fremovexattr - data8 fsys_fallback_syscall // tkill - data8 fsys_fallback_syscall // futex // 1230 - data8 fsys_fallback_syscall // sched_setaffinity - data8 fsys_fallback_syscall // sched_getaffinity + data8 0 // settimeofday + data8 0 // select + data8 0 // poll // 1090 + data8 0 // symlink + data8 0 // readlink + data8 0 // uselib + data8 0 // swapon + data8 0 // swapoff // 1095 + data8 0 // reboot + data8 0 // truncate + data8 0 // ftruncate + data8 0 // fchmod + data8 0 // fchown // 1100 + data8 0 // getpriority + data8 0 // setpriority + data8 0 // statfs + data8 0 // fstatfs + data8 0 // gettid // 1105 + data8 0 // semget + data8 0 // semop + data8 0 // semctl + data8 0 // msgget + data8 0 // msgsnd // 1110 + data8 0 // msgrcv + data8 0 // msgctl + data8 0 // shmget + data8 0 // shmat + data8 0 // shmdt // 1115 + data8 0 // shmctl + data8 0 // syslog + data8 0 // setitimer + data8 0 // getitimer + data8 0 // 1120 + data8 0 + data8 0 + data8 0 // vhangup + data8 0 // lchown + data8 0 // remap_file_pages // 1125 + data8 0 // wait4 + data8 0 // sysinfo + data8 0 // clone + data8 0 // setdomainname + data8 0 // newuname // 1130 + data8 0 // adjtimex + data8 0 + data8 0 // init_module + data8 0 // delete_module + data8 0 // 1135 + data8 0 + data8 0 // quotactl + data8 0 // bdflush + data8 0 // sysfs + data8 0 // personality // 1140 + data8 0 // afs_syscall + data8 0 // setfsuid + data8 0 // setfsgid + data8 0 // getdents + data8 0 // flock // 1145 + data8 0 // readv + data8 0 // writev + data8 0 // pread64 + data8 0 // pwrite64 + data8 0 // sysctl // 1150 + data8 0 // mmap + data8 0 // munmap + data8 0 // mlock + data8 0 // mlockall + data8 0 // mprotect // 1155 + data8 0 // mremap + data8 0 // msync + data8 0 // munlock + data8 0 // munlockall + data8 0 // sched_getparam // 1160 + data8 0 // sched_setparam + data8 0 // sched_getscheduler + data8 0 // sched_setscheduler + data8 0 // sched_yield + data8 0 // sched_get_priority_max // 1165 + data8 0 // sched_get_priority_min + data8 0 // sched_rr_get_interval + data8 0 // nanosleep + data8 0 // nfsservctl + data8 0 // prctl // 1170 + data8 0 // getpagesize + data8 0 // mmap2 + data8 0 // pciconfig_read + data8 0 // pciconfig_write + data8 0 // perfmonctl // 1175 + data8 0 // sigaltstack + data8 0 // rt_sigaction + data8 0 // rt_sigpending + data8 0 // rt_sigprocmask + data8 0 // rt_sigqueueinfo // 1180 + data8 0 // rt_sigreturn + data8 0 // rt_sigsuspend + data8 0 // rt_sigtimedwait + data8 0 // getcwd + data8 0 // capget // 1185 + data8 0 // capset + data8 0 // sendfile + data8 0 + data8 0 + data8 0 // socket // 1190 + data8 0 // bind + data8 0 // connect + data8 0 // listen + data8 0 // accept + data8 0 // getsockname // 1195 + data8 0 // getpeername + data8 0 // socketpair + data8 0 // send + data8 0 // sendto + data8 0 // recv // 1200 + data8 0 // recvfrom + data8 0 // shutdown + data8 0 // setsockopt + data8 0 // getsockopt + data8 0 // sendmsg // 1205 + data8 0 // recvmsg + data8 0 // pivot_root + data8 0 // mincore + data8 0 // madvise + data8 0 // newstat // 1210 + data8 0 // newlstat + data8 0 // newfstat + data8 0 // clone2 + data8 0 // getdents64 + data8 0 // getunwind // 1215 + data8 0 // readahead + data8 0 // setxattr + data8 0 // lsetxattr + data8 0 // fsetxattr + data8 0 // getxattr // 1220 + data8 0 // lgetxattr + data8 0 // fgetxattr + data8 0 // listxattr + data8 0 // llistxattr + data8 0 // flistxattr // 1225 + data8 0 // removexattr + data8 0 // lremovexattr + data8 0 // fremovexattr + data8 0 // tkill + data8 0 // futex // 1230 + data8 0 // sched_setaffinity + data8 0 // sched_getaffinity data8 fsys_set_tid_address // set_tid_address - data8 fsys_fallback_syscall // unused - data8 fsys_fallback_syscall // unused // 1235 - data8 fsys_fallback_syscall // exit_group - data8 fsys_fallback_syscall // lookup_dcookie - data8 fsys_fallback_syscall // io_setup - data8 fsys_fallback_syscall // io_destroy - data8 fsys_fallback_syscall // io_getevents // 1240 - data8 fsys_fallback_syscall // io_submit - data8 fsys_fallback_syscall // io_cancel - data8 fsys_fallback_syscall // epoll_create - data8 fsys_fallback_syscall // epoll_ctl - data8 fsys_fallback_syscall // epoll_wait // 1245 - data8 fsys_fallback_syscall // restart_syscall - data8 fsys_fallback_syscall // semtimedop - data8 fsys_fallback_syscall // timer_create - data8 fsys_fallback_syscall // timer_settime - data8 fsys_fallback_syscall // timer_gettime // 1250 - data8 fsys_fallback_syscall // timer_getoverrun - data8 fsys_fallback_syscall // timer_delete - data8 fsys_fallback_syscall // clock_settime - data8 fsys_fallback_syscall // clock_gettime - data8 fsys_fallback_syscall // clock_getres // 1255 - data8 fsys_fallback_syscall // clock_nanosleep - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1260 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1265 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1270 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1275 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall + data8 0 // unused + data8 0 // unused // 1235 + data8 0 // exit_group + data8 0 // lookup_dcookie + data8 0 // io_setup + data8 0 // io_destroy + data8 0 // io_getevents // 1240 + data8 0 // io_submit + data8 0 // io_cancel + data8 0 // epoll_create + data8 0 // epoll_ctl + data8 0 // epoll_wait // 1245 + data8 0 // restart_syscall + data8 0 // semtimedop + data8 0 // timer_create + data8 0 // timer_settime + data8 0 // timer_gettime // 1250 + data8 0 // timer_getoverrun + data8 0 // timer_delete + data8 0 // clock_settime + data8 0 // clock_gettime + data8 0 // clock_getres // 1255 + data8 0 // clock_nanosleep + data8 0 + data8 0 + data8 0 + data8 0 // 1260 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1265 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1270 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1275 + data8 0 + data8 0 + data8 0 + data8 0 + + .org fsyscall_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/gate-data.S b/arch/ia64/kernel/gate-data.S new file mode 100644 index 00000000000..beb5234f792 --- /dev/null +++ b/arch/ia64/kernel/gate-data.S @@ -0,0 +1,3 @@ + .section .data.gate, "ax" + + .incbin "arch/ia64/kernel/gate.so" diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S index 8601b2646ab..9d3ee002d23 100644 --- a/arch/ia64/kernel/gate.S +++ b/arch/ia64/kernel/gate.S @@ -6,20 +6,47 @@ * David Mosberger-Tang */ +#include + #include +#include #include #include #include #include -#include - - .section .text.gate, "ax" -.start_gate: +/* + * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, + * complications with the linker (which likes to create PLT stubs for branches + * to targets outside the shared object) and to avoid multi-phase kernel builds, we + * simply create minimalistic "patch lists" in special ELF sections. + */ + .section ".data.patch.fsyscall_table", "a" + .previous +#define LOAD_FSYSCALL_TABLE(reg) \ +[1:] movl reg=0; \ + .xdata4 ".data.patch.fsyscall_table", 1b-. -#ifdef CONFIG_FSYS + .section ".data.patch.brl_fsys_bubble_down", "a" + .previous +#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ +[1:](pr)brl.cond.sptk 0; \ + .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-. -#include +GLOBAL_ENTRY(__kernel_syscall_via_break) + .prologue + .altrp b6 + .body + /* + * Note: for (fast) syscall restart to work, the break instruction must be + * the first one in the bundle addressed by syscall_via_break. + */ +{ .mib + break 0x100000 + nop.i 0 + br.ret.sptk.many b6 +} +END(__kernel_syscall_via_break) /* * On entry: @@ -34,7 +61,8 @@ * all other "scratch" registers: undefined * all "preserved" registers: same as on entry */ -GLOBAL_ENTRY(syscall_via_epc) + +GLOBAL_ENTRY(__kernel_syscall_via_epc) .prologue .altrp b6 .body @@ -49,52 +77,50 @@ GLOBAL_ENTRY(syscall_via_epc) epc } ;; - rsm psr.be - movl r18=fsyscall_table + rsm psr.be // note: on McKinley "rsm psr.be/srlz.d" is slightly faster than "rum psr.be" + LOAD_FSYSCALL_TABLE(r14) - mov r16=IA64_KR(CURRENT) - mov r19=255 + mov r16=IA64_KR(CURRENT) // 12 cycle read latency + mov r19=NR_syscalls-1 ;; - shladd r18=r17,3,r18 - cmp.geu p6,p0=r19,r17 // (syscall > 0 && syscall <= 1024+255)? + shladd r18=r17,3,r14 + + srlz.d + cmp.ne p8,p0=r0,r0 // p8 <- FALSE + /* Note: if r17 is a NaT, p6 will be set to zero. */ + cmp.geu p6,p7=r19,r17 // (syscall > 0 && syscall < 1024+NR_syscalls)? ;; - srlz.d // ensure little-endian byteorder is in effect (p6) ld8 r18=[r18] + mov r29=psr // read psr (12 cyc load latency) + add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry ;; (p6) mov b7=r18 +(p6) tbit.z p8,p0=r18,0 +(p8) br.dptk.many b7 + + mov r27=ar.rsc + mov r21=ar.fpsr + mov r26=ar.pfs +/* + * brl.cond doesn't work as intended because the linker would convert this branch + * into a branch to a PLT. Perhaps there will be a way to avoid this with some + * future version of the linker. In the meantime, we just use an indirect branch + * instead. + */ +#ifdef CONFIG_ITANIUM +(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down + ;; +(p6) mov b7=r14 (p6) br.sptk.many b7 +#else + BRL_COND_FSYS_BUBBLE_DOWN(p6) +#endif mov r10=-1 mov r8=ENOSYS MCKINLEY_E9_WORKAROUND br.ret.sptk.many b6 -END(syscall_via_epc) - -GLOBAL_ENTRY(syscall_via_break) - .prologue - .altrp b6 - .body - break 0x100000 - br.ret.sptk.many b6 -END(syscall_via_break) - -GLOBAL_ENTRY(fsys_fallback_syscall) - /* - * It would be better/fsyser to do the SAVE_MIN magic directly here, but for now - * we simply fall back on doing a system-call via break. Good enough - * to get started. (Note: we have to do this through the gate page again, since - * the br.ret will switch us back to user-level privilege.) - * - * XXX Move this back to fsys.S after changing it over to avoid break 0x100000. - */ - movl r2=(syscall_via_break - .start_gate) + GATE_ADDR - ;; - MCKINLEY_E9_WORKAROUND - mov b7=r2 - br.ret.sptk.many b7 -END(fsys_fallback_syscall) - -#endif /* CONFIG_FSYS */ +END(__kernel_syscall_via_epc) # define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) # define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) @@ -145,7 +171,8 @@ END(fsys_fallback_syscall) */ #define SIGTRAMP_SAVES \ - .unwabi @svr4, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ + .unwabi 3, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ + .unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */ \ .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \ .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \ .savesp pr, PR_OFF+SIGCONTEXT_OFF; \ @@ -153,7 +180,7 @@ END(fsys_fallback_syscall) .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \ .vframesp SP_OFF+SIGCONTEXT_OFF -GLOBAL_ENTRY(ia64_sigtramp) +GLOBAL_ENTRY(__kernel_sigtramp) // describe the state that is active when we get here: .prologue SIGTRAMP_SAVES @@ -335,4 +362,4 @@ restore_rbs: mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode br.cond.sptk back_from_restore_rbs -END(ia64_sigtramp) +END(__kernel_sigtramp) diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S new file mode 100644 index 00000000000..e1e4aba9ecd --- /dev/null +++ b/arch/ia64/kernel/gate.lds.S @@ -0,0 +1,95 @@ +/* + * Linker script for gate DSO. The gate pages are an ELF shared object prelinked to its + * virtual address, with only one read-only segment and one execute-only segment (both fit + * in one page). This script controls its layout. + */ + +#include + +#include + +SECTIONS +{ + . = GATE_ADDR + SIZEOF_HEADERS; + + .hash : { *(.hash) } :readable + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .dynamic : { *(.dynamic) } :readable :dynamic + + /* + * This linker script is used both with -r and with -shared. For the layouts to match, + * we need to skip more than enough space for the dynamic symbol table et al. If this + * amount is insufficient, ld -shared will barf. Just increase it here. + */ + . = GATE_ADDR + 0x500; + + .data.patch : { + __start_gate_mckinley_e9_patchlist = .; + *(.data.patch.mckinley_e9) + __end_gate_mckinley_e9_patchlist = .; + + __start_gate_vtop_patchlist = .; + *(.data.patch.vtop) + __end_gate_vtop_patchlist = .; + + __start_gate_fsyscall_patchlist = .; + *(.data.patch.fsyscall_table) + __end_gate_fsyscall_patchlist = .; + + __start_gate_brl_fsys_bubble_down_patchlist = .; + *(.data.patch.brl_fsys_bubble_down) + __end_gate_brl_fsys_bubble_down_patchlist = .; + } :readable + .IA_64.unwind_info : { *(.IA_64.unwind_info*) } + .IA_64.unwind : { *(.IA_64.unwind*) } :readable :unwind +#ifdef HAVE_BUGGY_SEGREL + .text (GATE_ADDR + PAGE_SIZE) : { *(.text) *(.text.*) } :readable +#else + . = ALIGN (PERCPU_PAGE_SIZE) + (. & (PERCPU_PAGE_SIZE - 1)); + .text : { *(.text) *(.text.*) } :epc +#endif + + /DISCARD/ : { + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(__ex_table) + } +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + readable PT_LOAD FILEHDR PHDRS FLAGS(4); /* PF_R */ +#ifndef HAVE_BUGGY_SEGREL + epc PT_LOAD FILEHDR PHDRS FLAGS(1); /* PF_X */ +#endif + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.5 { + global: + __kernel_syscall_via_break; + __kernel_syscall_via_epc; + __kernel_sigtramp; + + local: *; + }; +} + +/* The ELF entry point can be used to set the AT_SYSINFO value. */ +ENTRY(__kernel_syscall_via_epc) diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index ff50c198756..f2b03eed66c 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S @@ -60,22 +60,42 @@ start_ap: mov r4=r0 .body - /* - * Initialize the region register for region 7 and install a translation register - * that maps the kernel's text and data: - */ rsm psr.i | psr.ic - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (IA64_GRANULE_SHIFT << 2)) ;; srlz.i + ;; + /* + * Initialize kernel region registers: + * rr[5]: VHPT enabled, page size = PAGE_SHIFT + * rr[6]: VHPT disabled, page size = IA64_GRANULE_SHIFT + * rr[5]: VHPT disabled, page size = IA64_GRANULE_SHIFT + */ + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1) + movl r17=(5<<61) + mov r18=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) + movl r19=(6<<61) + mov r20=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) + movl r21=(7<<61) + ;; + mov rr[r17]=r16 + mov rr[r19]=r18 + mov rr[r21]=r20 + ;; + /* + * Now pin mappings into the TLB for kernel text and data + */ mov r18=KERNEL_TR_PAGE_SHIFT<<2 movl r17=KERNEL_START ;; - mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL) + mov r3=ip + movl r18=PAGE_KERNEL + ;; + dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT + ;; + or r18=r2,r18 ;; srlz.i ;; @@ -113,16 +133,6 @@ start_ap: mov ar.fpsr=r2 ;; -#ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (IA64_GRANULE_SHIFT<<2) - movl r2=6<<61 - ;; - mov rr[r2]=r3 - ;; - srlz.i - ;; -#endif - #define isAP p2 // are we an Application Processor? #define isBP p3 // are we the Bootstrap Processor? @@ -143,12 +153,36 @@ start_ap: movl r2=init_thread_union cmp.eq isBP,isAP=r0,r0 #endif - mov r16=KERNEL_TR_PAGE_NUM ;; + tpa r3=r2 // r3 == phys addr of task struct + // load mapping for stack (virtaddr in r2, physaddr in r3) + rsm psr.ic + movl r17=PAGE_KERNEL + ;; + srlz.d + dep r18=0,r3,0,12 + ;; + or r18=r17,r18 + dep r2=-1,r3,61,3 // IMVA of task + ;; + mov r17=rr[r2] + shr.u r16=r3,IA64_GRANULE_SHIFT + ;; + dep r17=0,r17,8,24 + ;; + mov cr.itir=r17 + mov cr.ifa=r2 + + mov r19=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r19]=r18 + ;; + ssm psr.ic + srlz.d + ;; // load the "current" pointer (r13) and ar.k6 with the current task mov IA64_KR(CURRENT)=r2 // virtual address - // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) mov IA64_KR(CURRENT_STACK)=r16 mov r13=r2 /* @@ -665,14 +699,14 @@ GLOBAL_ENTRY(__ia64_init_fpu) END(__ia64_init_fpu) /* - * Switch execution mode from virtual to physical or vice versa. + * Switch execution mode from virtual to physical * * Inputs: * r16 = new psr to establish * * Note: RSE must already be in enforced lazy mode */ -GLOBAL_ENTRY(ia64_switch_mode) +GLOBAL_ENTRY(ia64_switch_mode_phys) { alloc r2=ar.pfs,0,0,0,0 rsm psr.i | psr.ic // disable interrupts and interrupt collection @@ -682,35 +716,86 @@ GLOBAL_ENTRY(ia64_switch_mode) { flushrs // must be first insn in group srlz.i - shr.u r19=r15,61 // r19 <- top 3 bits of current IP } ;; mov cr.ipsr=r16 // set new PSR - add r3=1f-ia64_switch_mode,r15 - xor r15=0x7,r19 // flip the region bits + add r3=1f-ia64_switch_mode_phys,r15 mov r17=ar.bsp mov r14=rp // get return address into a general register + ;; - // switch RSE backing store: + // going to physical mode, use tpa to translate virt->phys + tpa r17=r17 + tpa r3=r3 + tpa sp=sp + tpa r14=r14 ;; - dep r17=r15,r17,61,3 // make ar.bsp physical or virtual + mov r18=ar.rnat // save ar.rnat - ;; mov ar.bspstore=r17 // this steps on ar.rnat - dep r3=r15,r3,61,3 // make rfi return address physical or virtual + mov cr.iip=r3 + mov cr.ifs=r0 ;; + mov ar.rnat=r18 // restore ar.rnat + rfi // must be last insn in group + ;; +1: mov rp=r14 + br.ret.sptk.many rp +END(ia64_switch_mode_phys) + +/* + * Switch execution mode from physical to virtual + * + * Inputs: + * r16 = new psr to establish + * + * Note: RSE must already be in enforced lazy mode + */ +GLOBAL_ENTRY(ia64_switch_mode_virt) + { + alloc r2=ar.pfs,0,0,0,0 + rsm psr.i | psr.ic // disable interrupts and interrupt collection + mov r15=ip + } + ;; + { + flushrs // must be first insn in group + srlz.i + } + ;; + mov cr.ipsr=r16 // set new PSR + add r3=1f-ia64_switch_mode_virt,r15 + + mov r17=ar.bsp + mov r14=rp // get return address into a general register + ;; + + // going to virtual + // - for code addresses, set upper bits of addr to KERNEL_START + // - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the + // lower bits since we want it to stay identity mapped + movl r18=KERNEL_START + dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r17=-1,r17,61,3 + dep sp=-1,sp,61,3 + ;; + or r3=r3,r18 + or r14=r14,r18 + ;; + + mov r18=ar.rnat // save ar.rnat + mov ar.bspstore=r17 // this steps on ar.rnat mov cr.iip=r3 mov cr.ifs=r0 - dep sp=r15,sp,61,3 // make stack pointer physical or virtual ;; mov ar.rnat=r18 // restore ar.rnat - dep r14=r15,r14,61,3 // make function return address physical or virtual rfi // must be last insn in group ;; 1: mov rp=r14 br.ret.sptk.many rp -END(ia64_switch_mode) +END(ia64_switch_mode_virt) #ifdef CONFIG_IA64_BRL_EMU @@ -753,7 +838,7 @@ SET_REG(b5); * r29 - available for use. * r30 - available for use. * r31 - address of lock, available for use. - * b7 - return address + * b6 - return address * p14 - available for use. * * If you patch this code to use more registers, do not forget to update diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 0818c9f700a..d06ed2f7689 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -65,6 +65,9 @@ EXPORT_SYMBOL(ia64_pfn_valid); #include EXPORT_SYMBOL(cpu_info__per_cpu); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(__per_cpu_offset); +#endif EXPORT_SYMBOL(kernel_thread); #include @@ -88,6 +91,7 @@ EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_single); EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(phys_cpu_present_map); EXPORT_SYMBOL(ia64_cpu_to_sapicid); #else /* !CONFIG_SMP */ @@ -124,6 +128,18 @@ EXPORT_SYMBOL_NOVERS(__udivdi3); EXPORT_SYMBOL_NOVERS(__moddi3); EXPORT_SYMBOL_NOVERS(__umoddi3); +#if defined(CONFIG_MD_RAID5) || defined(CONFIG_MD_RAID5_MODULE) +extern void xor_ia64_2(void); +extern void xor_ia64_3(void); +extern void xor_ia64_4(void); +extern void xor_ia64_5(void); + +EXPORT_SYMBOL_NOVERS(xor_ia64_2); +EXPORT_SYMBOL_NOVERS(xor_ia64_3); +EXPORT_SYMBOL_NOVERS(xor_ia64_4); +EXPORT_SYMBOL_NOVERS(xor_ia64_5); +#endif + extern unsigned long ia64_iobase; EXPORT_SYMBOL(ia64_iobase); @@ -147,10 +163,15 @@ EXPORT_SYMBOL(efi_dir); EXPORT_SYMBOL(ia64_mv); #endif EXPORT_SYMBOL(machvec_noop); +EXPORT_SYMBOL(machvec_memory_fence); +EXPORT_SYMBOL(zero_page_memmap_ptr); #ifdef CONFIG_PERFMON #include -EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem); -EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem); +EXPORT_SYMBOL(pfm_register_buffer_fmt); +EXPORT_SYMBOL(pfm_unregister_buffer_fmt); +EXPORT_SYMBOL(pfm_mod_fast_read_pmds); +EXPORT_SYMBOL(pfm_mod_read_pmds); +EXPORT_SYMBOL(pfm_mod_write_pmcs); #endif #ifdef CONFIG_NUMA @@ -169,10 +190,25 @@ EXPORT_SYMBOL(unw_access_fr); EXPORT_SYMBOL(unw_access_ar); EXPORT_SYMBOL(unw_access_pr); -#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) -extern void ia64_spinlock_contention_pre3_4 (void); +#ifdef CONFIG_SMP +# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +/* + * This is not a normal routine and we don't want a function descriptor for it, so we use + * a fake declaration here. + */ +extern char ia64_spinlock_contention_pre3_4; EXPORT_SYMBOL(ia64_spinlock_contention_pre3_4); -#else -extern void ia64_spinlock_contention (void); +# else +/* + * This is not a normal routine and we don't want a function descriptor for it, so we use + * a fake declaration here. + */ +extern char ia64_spinlock_contention; EXPORT_SYMBOL(ia64_spinlock_contention); +# endif #endif + +EXPORT_SYMBOL(ia64_max_iommu_merge_mask); + +#include +EXPORT_SYMBOL(pm_idle); diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c index b2978cf1f31..0cc7b37af21 100644 --- a/arch/ia64/kernel/init_task.c +++ b/arch/ia64/kernel/init_task.c @@ -36,7 +36,7 @@ union init_thread { unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)]; } init_thread_union __attribute__((section(".data.init_task"))) = {{ .task = INIT_TASK(init_thread_union.s.task), - .thread_info = INIT_THREAD_INFO(init_thread_union.s.thread_info) + .thread_info = INIT_THREAD_INFO(init_thread_union.s.task) }}; asm (".global init_task; init_task = init_thread_union"); diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index e5055a9b972..9505dbea63f 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -65,7 +65,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { +irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .handler = &no_irq_type, @@ -235,7 +235,6 @@ int handle_IRQ_event(unsigned int irq, { int status = 1; /* Force the "do bottom halves" bit */ int retval = 0; - struct irqaction *first_action = action; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -248,30 +247,88 @@ int handle_IRQ_event(unsigned int irq, if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); - if (retval != 1) { - static int count = 100; - if (count) { - count--; - if (retval) { - printk("irq event %d: bogus retval mask %x\n", - irq, retval); - } else { - printk("irq %d: nobody cared!\n", irq); - } - dump_stack(); - printk("handlers:\n"); - action = first_action; - do { - printk("[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; - } while (action); - } + return retval; +} + +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; + + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); } - return status; + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; } /* @@ -380,21 +437,24 @@ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int cpu; irq_desc_t *desc = irq_desc(irq); struct irqaction * action; + irqreturn_t action_ret; unsigned int status; + int cpu; irq_enter(); - cpu = smp_processor_id(); + cpu = smp_processor_id(); /* for CONFIG_PREEMPT, this must come after irq_enter()! */ kstat_cpu(cpu).irqs[irq]++; if (desc->status & IRQ_PER_CPU) { /* no locking required for CPU-local interrupts: */ desc->handler->ack(irq); - handle_IRQ_event(irq, regs, desc->action); + action_ret = handle_IRQ_event(irq, regs, desc->action); desc->handler->end(irq); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); } else { spin_lock(&desc->lock); desc->handler->ack(irq); @@ -438,9 +498,10 @@ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) */ for (;;) { spin_unlock(&desc->lock); - handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, regs, action); spin_lock(&desc->lock); - + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S index 9a79016c046..db9500165ab 100644 --- a/arch/ia64/kernel/ivt.S +++ b/arch/ia64/kernel/ivt.S @@ -1,9 +1,14 @@ /* * arch/ia64/kernel/ivt.S * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * Stephane Eranian * David Mosberger + * Copyright (C) 2000, 2002-2003 Intel Co + * Asit Mallick + * Suresh Siddha + * Kenneth Chen + * Fenghua Yu * * 00/08/23 Asit Mallick TLB handling for SMP * 00/12/20 David Mosberger-Tang DTLB/ITLB handler now uses virtual PT. @@ -122,8 +127,11 @@ ENTRY(vhpt_miss) shr.u r18=r22,PGDIR_SHIFT // get bits 33-63 of the faulting address ;; (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place - srlz.d // ensure "rsm psr.dt" has taken effect -(p6) movl r19=__pa(swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + srlz.d + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ;; @@ -415,8 +423,11 @@ ENTRY(nested_dtlb_miss) shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address ;; (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d -(p6) movl r19=__pa(swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ;; @@ -622,103 +633,95 @@ END(daccess_bit) ///////////////////////////////////////////////////////////////////////////////////////// // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) ENTRY(break_fault) + /* + * The streamlined system call entry/exit paths only save/restore the initial part + * of pt_regs. This implies that the callers of system-calls must adhere to the + * normal procedure calling conventions. + * + * Registers to be saved & restored: + * CR registers: cr.ipsr, cr.iip, cr.ifs + * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr + * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15 + * Registers to be restored only: + * r8-r11: output value from the system call. + * + * During system call exit, scratch registers (including r15) are modified/cleared + * to prevent leaking bits from kernel to user level. + */ DBG_FAULT(11) - mov r16=cr.iim - mov r17=__IA64_BREAK_SYSCALL - mov r31=pr // prepare to save predicates - ;; - cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) + mov r16=IA64_KR(CURRENT) // r16 = current task; 12 cycle read lat. + mov r17=cr.iim + mov r18=__IA64_BREAK_SYSCALL + mov r21=ar.fpsr + mov r29=cr.ipsr + mov r19=b6 + mov r25=ar.unat + mov r27=ar.rsc + mov r26=ar.pfs + mov r28=cr.iip + mov r31=pr // prepare to save predicates + mov r20=r1 + ;; + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 + cmp.eq p0,p7=r18,r17 // is this a system call? (p7 <- false, if so) (p7) br.cond.spnt non_syscall + ;; + ld1 r17=[r16] // load current->thread.on_ustack flag + st1 [r16]=r0 // clear current->thread.on_ustack flag + add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT + ;; + invala - SAVE_MIN // uses r31; defines r2: + /* adjust return address so we skip over the break instruction: */ - ssm psr.ic | PSR_DEFAULT_BITS + extr.u r8=r29,41,2 // extract ei field from cr.ipsr ;; - srlz.i // guarantee that interruption collection is on - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + cmp.eq p6,p7=2,r8 // isr.ei==2? + mov r2=r1 // setup r2 for ia64_syscall_setup ;; -(p15) ssm psr.i // restore psr.i - adds r8=(IA64_PT_REGS_R8_OFFSET-IA64_PT_REGS_R16_OFFSET),r2 +(p6) mov r8=0 // clear ei to 0 +(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped +(p7) adds r8=1,r8 // increment ei to next slot ;; - stf8 [r8]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) - adds r3=8,r2 // set up second base pointer for SAVE_REST + cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already? + dep r29=r8,r29,41,2 // insert new ei into cr.ipsr ;; - SAVE_REST - br.call.sptk.many rp=demine_args // clear NaT bits in (potential) syscall args - mov r3=255 - adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + // switch from user to kernel RBS: + MINSTATE_START_SAVE_MIN_VIRT + br.call.sptk.many b7=ia64_syscall_setup ;; - cmp.geu p6,p7=r3,r15 // (syscall > 0 && syscall <= 1024+255) ? - movl r16=sys_call_table + MINSTATE_END_SAVE_MIN_VIRT // switch to bank 1 + ssm psr.ic | PSR_DEFAULT_BITS ;; -(p6) shladd r16=r15,3,r16 - movl r15=ia64_ret_from_syscall -(p7) adds r16=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall + srlz.i // guarantee that interruption collection is on ;; - ld8 r16=[r16] // load address of syscall entry point - mov rp=r15 // set the real return addr +(p15) ssm psr.i // restore psr.i ;; - mov b6=r16 - - // arrange things so we skip over break instruction when returning: + mov r3=NR_syscalls - 1 + movl r16=sys_call_table - adds r16=16,sp // get pointer to cr_ipsr - adds r17=24,sp // get pointer to cr_iip - add r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld8 r18=[r16] // fetch cr_ipsr - ld4 r2=[r2] // r2 = current_thread_info()->flags + adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + movl r2=ia64_ret_from_syscall ;; - ld8 r19=[r17] // fetch cr_iip - extr.u r20=r18,41,2 // extract ei field + shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) + cmp.geu p0,p7=r3,r15 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? + mov rp=r2 // set the real return addr ;; - cmp.eq p6,p7=2,r20 // isr.ei==2? - adds r19=16,r19 // compute address of next bundle +(p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall + add r2=TI_FLAGS+IA64_TASK_SIZE,r13 ;; -(p6) mov r20=0 // clear ei to 0 -(p7) adds r20=1,r20 // increment ei to next slot + ld8 r20=[r20] // load address of syscall entry point + ld4 r2=[r2] // r2 = current_thread_info()->flags ;; -(p6) st8 [r17]=r19 // store new cr.iip if cr.isr.ei wrapped around - dep r18=r20,r18,41,2 // insert new ei into cr.isr tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + mov b6=r20 ;; - st8 [r16]=r18 // store new value for cr.isr - (p8) br.call.sptk.many b6=b6 // ignore this return addr br.cond.sptk ia64_trace_syscall // NOT REACHED END(break_fault) -ENTRY_MIN_ALIGN(demine_args) - alloc r2=ar.pfs,8,0,0,0 - tnat.nz p8,p0=in0 - tnat.nz p9,p0=in1 - ;; -(p8) mov in0=-1 - tnat.nz p10,p0=in2 - tnat.nz p11,p0=in3 - -(p9) mov in1=-1 - tnat.nz p12,p0=in4 - tnat.nz p13,p0=in5 - ;; -(p10) mov in2=-1 - tnat.nz p14,p0=in6 - tnat.nz p15,p0=in7 - -(p11) mov in3=-1 - tnat.nz p8,p0=r15 // demining r15 is not a must, but it is safer - -(p12) mov in4=-1 -(p13) mov in5=-1 - ;; -(p14) mov in6=-1 -(p15) mov in7=-1 -(p8) mov r15=-1 - br.ret.sptk.many rp -END(demine_args) - .org ia64_ivt+0x3000 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) @@ -726,7 +729,6 @@ ENTRY(interrupt) DBG_FAULT(12) mov r31=pr // prepare to save predicates ;; - SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 ssm psr.ic | PSR_DEFAULT_BITS ;; @@ -739,7 +741,7 @@ ENTRY(interrupt) mov out0=cr.ivr // pass cr.ivr as first arg add out1=16,sp // pass pointer to pt_regs as second arg ;; - srlz.d // make sure we see the effect of cr.ivr + srlz.d // make sure we see the effect of cr.ivr movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -758,6 +760,131 @@ END(interrupt) DBG_FAULT(14) FAULT(14) + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + * + * ia64_syscall_setup() is a separate subroutine so that it can + * allocate stacked registers so it can safely demine any + * potential NaT values from the input registers. + * + * On entry: + * - executing on bank 0 or bank 1 register set (doesn't matter) + * - r1: stack pointer + * - r2: current task pointer + * - r3: preserved + * - r11: original contents (saved ar.pfs to be saved) + * - r12: original contents (sp to be saved) + * - r13: original contents (tp to be saved) + * - r15: original contents (syscall # to be saved) + * - r18: saved bsp (after switching to kernel stack) + * - r19: saved b6 + * - r20: saved r1 (gp) + * - r21: saved ar.fpsr + * - r22: kernel's register backing store base (krbs_base) + * - r23: saved ar.bspstore + * - r24: saved ar.rnat + * - r25: saved ar.unat + * - r26: saved ar.pfs + * - r27: saved ar.rsc + * - r28: saved cr.iip + * - r29: saved cr.ipsr + * - r31: saved pr + * - b0: original contents (to be saved) + * On exit: + * - executing on bank 1 registers + * - psr.ic enabled, interrupts restored + * - r1: kernel's gp + * - r3: preserved (same as on entry) + * - r12: points to kernel stack + * - r13: points to current task + * - p15: TRUE if interrupts need to be re-enabled + * - ar.fpsr: set to kernel settings + */ +GLOBAL_ENTRY(ia64_syscall_setup) +#if PT(B6) != 0 +# error This code assumes that b6 is the first field in pt_regs. +#endif + st8 [r1]=r19 // save b6 + add r16=PT(CR_IPSR),r1 // initialize first base pointer + add r17=PT(R11),r1 // initialize second base pointer + ;; + alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable + st8 [r16]=r29,PT(CR_IFS)-PT(CR_IPSR) // save cr.ipsr + tnat.nz p8,p0=in0 + + st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11 + tnat.nz p9,p0=in1 +(pKStk) mov r18=r0 // make sure r18 isn't NaT + ;; + + st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip + mov r28=b0 // save b0 (2 cyc) +(p8) mov in0=-1 + ;; + + st8 [r16]=r0,PT(AR_PFS)-PT(CR_IFS) // clear cr.ifs + st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat +(p9) mov in1=-1 + ;; + + st8 [r16]=r26,PT(AR_RNAT)-PT(AR_PFS) // save ar.pfs + st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc + tnat.nz p10,p0=in2 + +(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 + tbit.nz p15,p0=r29,IA64_PSR_I_BIT + tnat.nz p11,p0=in3 + ;; +(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field +(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field +(p10) mov in2=-1 + +(p11) mov in3=-1 + tnat.nz p12,p0=in4 + tnat.nz p13,p0=in5 + ;; +(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat +(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore + shl r18=r18,16 // compute ar.rsc to be used for "loadrs" + ;; + st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates + st8 [r17]=r28,PT(R1)-PT(B0) // save b0 +(p12) mov in4=-1 + ;; + st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs" + st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1 +(p13) mov in5=-1 + ;; + +.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12 +.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13 + tnat.nz p14,p0=in6 + ;; + st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr + st8.spill [r17]=r15 // save r15 + tnat.nz p8,p0=in7 + ;; + stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) + adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) +(p14) mov in6=-1 + + mov r13=r2 // establish `current' + movl r1=__gp // establish kernel global pointer + ;; +(p8) mov in7=-1 + tnat.nz p9,p0=r15 + + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + movl r17=FPSR_DEFAULT + ;; + mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value +(p9) mov r15=-1 + br.ret.sptk.many b7 +END(ia64_syscall_setup) + .org ia64_ivt+0x3c00 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3c00 Entry 15 (size 64 bundles) Reserved @@ -809,90 +936,6 @@ END(dispatch_illegal_op_fault) DBG_FAULT(16) FAULT(16) -#ifdef CONFIG_IA32_SUPPORT - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - */ - - // IA32 interrupt entry point - -ENTRY(dispatch_to_ia32_handler) - SAVE_MIN - ;; - mov r14=cr.isr - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i - adds r3=8,r2 // Base pointer for SAVE_REST - ;; - SAVE_REST - ;; - mov r15=0x80 - shr r14=r14,16 // Get interrupt number - ;; - cmp.ne p6,p0=r14,r15 -(p6) br.call.dpnt.many b6=non_ia32_syscall - - adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions - adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp - ;; - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) - ;; - alloc r15=ar.pfs,0,0,6,0 // must first in an insn group - ;; - ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=250 // number of entries in ia32 system call table - ;; - cmp.ltu.unc p6,p7=r8,r15 - ld4 out1=[r14],8 // r9 == ecx - ;; - ld4 out2=[r14],8 // r10 == edx - ;; - ld4 out0=[r14] // r11 == ebx - adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp - ;; - ld4 out5=[r14],8 // r13 == ebp - ;; - ld4 out3=[r14],8 // r14 == esi - adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld4 out4=[r14] // r15 == edi - movl r16=ia32_syscall_table - ;; -(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number - ld4 r2=[r2] // r2 = current_thread_info()->flags - ;; - ld8 r16=[r16] - tbit.z p8,p0=r2,TIF_SYSCALL_TRACE - ;; - mov b6=r16 - movl r15=ia32_ret_from_syscall - ;; - mov rp=r15 -(p8) br.call.sptk.many b6=b6 - br.cond.sptk ia32_trace_syscall - -non_ia32_syscall: - alloc r15=ar.pfs,0,0,2,0 - mov out0=r14 // interrupt # - add out1=16,sp // pointer to pt_regs - ;; // avoid WAW on CFM - br.call.sptk.many rp=ia32_bad_interrupt -.ret1: movl r15=ia64_leave_kernel - ;; - mov rp=r15 - br.ret.sptk.many rp -END(dispatch_to_ia32_handler) - -#endif /* CONFIG_IA32_SUPPORT */ - .org ia64_ivt+0x4400 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4400 Entry 17 (size 64 bundles) Reserved @@ -1428,3 +1471,89 @@ END(ia32_interrupt) // 0x7f00 Entry 67 (size 16 bundles) Reserved DBG_FAULT(67) FAULT(67) + +#ifdef CONFIG_IA32_SUPPORT + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ + + // IA32 interrupt entry point + +ENTRY(dispatch_to_ia32_handler) + SAVE_MIN + ;; + mov r14=cr.isr + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i + adds r3=8,r2 // Base pointer for SAVE_REST + ;; + SAVE_REST + ;; + mov r15=0x80 + shr r14=r14,16 // Get interrupt number + ;; + cmp.ne p6,p0=r14,r15 +(p6) br.call.dpnt.many b6=non_ia32_syscall + + adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions + adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp + ;; + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + ld8 r8=[r14] // get r8 + ;; + st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) + ;; + alloc r15=ar.pfs,0,0,6,0 // must first in an insn group + ;; + ld4 r8=[r14],8 // r8 == eax (syscall number) + mov r15=270 // number of entries in ia32 system call table + ;; + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx + ;; + ld4 out2=[r14],8 // r10 == edx + ;; + ld4 out0=[r14] // r11 == ebx + adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp + ;; + ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp + ;; + ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi + adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 out4=[r14] // r15 == edi + movl r16=ia32_syscall_table + ;; +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ld4 r2=[r2] // r2 = current_thread_info()->flags + ;; + ld8 r16=[r16] + tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + ;; + mov b6=r16 + movl r15=ia32_ret_from_syscall + ;; + mov rp=r15 +(p8) br.call.sptk.many b6=b6 + br.cond.sptk ia32_trace_syscall + +non_ia32_syscall: + alloc r15=ar.pfs,0,0,2,0 + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs + ;; // avoid WAW on CFM + br.call.sptk.many rp=ia32_bad_interrupt +.ret1: movl r15=ia64_leave_kernel + ;; + mov rp=r15 + br.ret.sptk.many rp +END(dispatch_to_ia32_handler) + +#endif /* CONFIG_IA32_SUPPORT */ diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index b5d0fcd62df..c9aec860c4e 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -322,7 +322,7 @@ fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_sta } void -init_handler_platform (sal_log_processor_info_t *proc_ptr, +init_handler_platform (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) { struct unw_frame_info info; @@ -337,15 +337,18 @@ init_handler_platform (sal_log_processor_info_t *proc_ptr, */ printk("Delaying for 5 seconds...\n"); udelay(5*1000000); - show_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area); + show_min_state(ms); printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm); - fetch_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area, pt, sw); + fetch_min_state(ms, pt, sw); unw_init_from_interruption(&info, current, pt, sw); ia64_do_show_stack(&info, NULL); +#ifdef CONFIG_SMP + /* read_trylock() would be handy... */ if (!tasklist_lock.write_lock) read_lock(&tasklist_lock); +#endif { struct task_struct *g, *t; do_each_thread (g, t) { @@ -353,11 +356,13 @@ init_handler_platform (sal_log_processor_info_t *proc_ptr, continue; printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); - show_stack(t); + show_stack(t, NULL); } while_each_thread (g, t); } +#ifdef CONFIG_SMP if (!tasklist_lock.write_lock) read_unlock(&tasklist_lock); +#endif printk("\nINIT dump complete. Please reboot now.\n"); while (1); /* hang city if no debugger */ @@ -657,17 +662,17 @@ ia64_mca_init(void) IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); + ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be - * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, - mca_hldlr_ptr->gp, + ia64_tpa(mca_hldlr_ptr->gp), ia64_mc_info.imi_mca_handler_size, 0, 0, 0))) { @@ -677,15 +682,15 @@ ia64_mca_init(void) } IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", - ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); + ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); /* * XXX - disable SAL checksum by setting size to 0, should be * IA64_INIT_HANDLER_SIZE */ - ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", @@ -694,10 +699,10 @@ ia64_mca_init(void) /* Register the os init handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, ia64_mc_info.imi_monarch_init_handler, - __pa(ia64_get_gp()), + ia64_tpa(ia64_get_gp()), ia64_mc_info.imi_monarch_init_handler_size, ia64_mc_info.imi_slave_init_handler, - __pa(ia64_get_gp()), + ia64_tpa(ia64_get_gp()), ia64_mc_info.imi_slave_init_handler_size))) { printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. " @@ -1235,32 +1240,19 @@ device_initcall(ia64_mca_late_init); void ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) { - sal_log_processor_info_t *proc_ptr; - ia64_err_rec_t *plog_ptr; + pal_min_state_area_t *ms; - printk(KERN_INFO "Entered OS INIT handler\n"); - - /* Get the INIT processor log */ - if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) - return; // no record retrieved - -#ifdef IA64_DUMP_ALL_PROC_INFO - ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk); -#endif + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", + ia64_sal_to_os_handoff_state.proc_state_param); /* - * get pointer to min state save area - * + * Address of minstate area provided by PAL is physical, + * uncacheable (bit 63 set). Convert to Linux virtual + * address in region 6. */ - plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT); - proc_ptr = &plog_ptr->proc_err; - - ia64_process_min_state_save(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area); - - /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); + ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61)); - init_handler_platform(proc_ptr, pt, sw); /* call platform specific routines */ + init_handler_platform(ms, pt, sw); /* call platform specific routines */ } /* diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index f4ccd0c1810..0318d81ea61 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -50,14 +50,15 @@ * 6. GR12 = Return address to location within SAL_CHECK */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ + LOAD_PHYSICAL(p0, _tmp, ia64_sal_to_os_handoff_state);; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ st8 [_tmp]=r9,0x08;; \ st8 [_tmp]=r10,0x08;; \ st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08 + st8 [_tmp]=r12,0x08;; \ + st8 [_tmp]=r17,0x08;; \ + st8 [_tmp]=r18,0x08 /* * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) @@ -70,9 +71,8 @@ * returns ptr to SAL rtn save loc in _tmp */ #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ -(p6) movl _tmp=ia64_sal_to_os_handoff_state;; \ -(p7) movl _tmp=ia64_os_to_sal_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ + LOAD_PHYSICAL(p6, _tmp, ia64_sal_to_os_handoff_state);; \ + LOAD_PHYSICAL(p7, _tmp, ia64_os_to_sal_handoff_state);; \ (p6) movl r8=IA64_MCA_COLD_BOOT; \ (p6) movl r10=IA64_MCA_SAME_CONTEXT; \ (p6) add _tmp=0x18,_tmp;; \ diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h dissimilarity index 63% index 800c929e93d..540301f6efa 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -1,251 +1,250 @@ -#include - -#include - -#include "entry.h" - -/* - * A couple of convenience macros that make writing and reading - * SAVE_MIN and SAVE_REST easier. - */ -#define rARPR r31 -#define rCRIFS r30 -#define rCRIPSR r29 -#define rCRIIP r28 -#define rARRSC r27 -#define rARPFS r26 -#define rARUNAT r25 -#define rARRNAT r24 -#define rARBSPSTORE r23 -#define rKRBS r22 -#define rB6 r21 -#define rR1 r20 - -/* - * Here start the source dependent macros. - */ - -/* - * For ivt.s we want to access the stack virtually so we don't have to disable translation - * on interrupts. - */ -#define MINSTATE_START_SAVE_MIN_VIRT \ -(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ - ;; \ -(pUStk) mov.m rARRNAT=ar.rnat; \ -(pUStk) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ -(pKStk) mov r1=sp; /* get sp */ \ - ;; \ -(pUStk) lfetch.fault.excl.nt1 [rKRBS]; \ -(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ - ;; \ -(pUStk) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ -(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ - ;; \ -(pUStk) mov r18=ar.bsp; \ -(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ - -#define MINSTATE_END_SAVE_MIN_VIRT \ - bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ - ;; - -/* - * For mca_asm.S we want to access the stack physically since the state is saved before we - * go virtual and don't want to destroy the iip or ipsr. - */ -#define MINSTATE_START_SAVE_MIN_PHYS \ -(pKStk) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ -(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(pUStk) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ - ;; \ -(pUStk) mov rARRNAT=ar.rnat; \ -(pKStk) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ -(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ -(pUStk) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ - ;; \ -(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(pUStk) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ - ;; \ -(pUStk) mov r18=ar.bsp; \ -(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ - -#define MINSTATE_END_SAVE_MIN_PHYS \ - or r12=r12,r14; /* make sp a kernel virtual address */ \ - or r13=r13,r14; /* make `current' a kernel virtual address */ \ - ;; - -#ifdef MINSTATE_VIRT -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT) -# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_VIRT -# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_VIRT -#endif - -#ifdef MINSTATE_PHYS -# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; dep reg=0,reg,61,3 -# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS -# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS -#endif - -/* - * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves - * the minimum state necessary that allows us to turn psr.ic back - * on. - * - * Assumed state upon entry: - * psr.ic: off - * r31: contains saved predicates (pr) - * - * Upon exit, the state is as follows: - * psr.ic: off - * r2 = points to &pt_regs.r16 - * r12 = kernel sp (kernel virtual address) - * r13 = points to current task_struct (kernel virtual address) - * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p2, p3, and p15), b6, r3, r8, r9, r10, r11, r14, r15: - * preserved - * - * Note that psr.ic is NOT turned on by this macro. This is so that - * we can pass interruption state as arguments to a handler. - */ -#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ - mov rARRSC=ar.rsc; /* M */ \ - mov rARUNAT=ar.unat; /* M */ \ - mov rR1=r1; /* A */ \ - MINSTATE_GET_CURRENT(r1); /* M (or M;;I) */ \ - mov rCRIPSR=cr.ipsr; /* M */ \ - mov rARPFS=ar.pfs; /* I */ \ - mov rCRIIP=cr.iip; /* M */ \ - mov rB6=b6; /* I */ /* rB6 = branch reg 6 */ \ - COVER; /* B;; (or nothing) */ \ - ;; \ - adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r1; \ - ;; \ - ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ - st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ - /* switch from user to kernel RBS: */ \ - ;; \ - invala; /* M */ \ - SAVE_IFS; \ - cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? (psr.cpl==0) */ \ - ;; \ - MINSTATE_START_SAVE_MIN \ - add r17=L1_CACHE_BYTES,r1 /* really: biggest cache-line size */ \ - ;; \ - st8 [r1]=rCRIPSR; /* save cr.ipsr */ \ - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ - add r16=16,r1; /* initialize first base pointer */ \ - ;; \ - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ - ;; \ - lfetch.fault.excl.nt1 [r17]; \ - adds r17=8,r1; /* initialize second base pointer */ \ -(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ - ;; \ - st8 [r17]=rCRIIP,16; /* save cr.iip */ \ - st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ -(pUStk) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ - ;; \ - st8 [r17]=rARUNAT,16; /* save ar.unat */ \ - st8 [r16]=rARPFS,16; /* save ar.pfs */ \ - shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ - ;; \ - st8 [r17]=rARRSC,16; /* save ar.rsc */ \ -(pUStk) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ -(pKStk) adds r16=16,r16; /* skip over ar_rnat field */ \ - ;; /* avoid RAW on r16 & r17 */ \ -(pUStk) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ - st8 [r16]=rARPR,16; /* save predicates */ \ -(pKStk) adds r17=16,r17; /* skip over ar_bspstore field */ \ - ;; \ - st8 [r17]=rB6,16; /* save b6 */ \ - st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ - tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=rR1,16; /* save original r1 */ \ -.mem.offset 0,0; st8.spill [r16]=r2,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r3,16; \ -.mem.offset 0,0; st8.spill [r16]=r12,16; \ - adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r13,16; \ -.mem.offset 0,0; st8.spill [r16]=r14,16; \ - cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r15,16; \ -.mem.offset 0,0; st8.spill [r16]=r8,16; \ - dep r14=-1,r0,61,3; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r9,16; \ -.mem.offset 0,0; st8.spill [r16]=r10,16; \ - adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r11,16; \ - mov r13=IA64_KR(CURRENT); /* establish `current' */ \ - ;; \ - EXTRA; \ - movl r1=__gp; /* establish kernel global pointer */ \ - ;; \ - MINSTATE_END_SAVE_MIN - -/* - * SAVE_REST saves the remainder of pt_regs (with psr.ic on). This - * macro guarantees to preserve all predicate registers, r8, r9, r10, - * r11, r14, and r15. - * - * Assumed state upon entry: - * psr.ic: on - * r2: points to &pt_regs.r16 - * r3: points to &pt_regs.r17 - */ -#define SAVE_REST \ -.mem.offset 0,0; st8.spill [r2]=r16,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r17,16; \ -.mem.offset 0,0; st8.spill [r2]=r18,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r19,16; \ -.mem.offset 0,0; st8.spill [r2]=r20,16; \ - ;; \ - mov r16=ar.ccv; /* M-unit */ \ - movl r18=FPSR_DEFAULT /* L-unit */ \ - ;; \ - mov r17=ar.fpsr; /* M-unit */ \ - mov ar.fpsr=r18; /* M-unit */ \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r21,16; \ -.mem.offset 0,0; st8.spill [r2]=r22,16; \ - mov r18=b0; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r23,16; \ -.mem.offset 0,0; st8.spill [r2]=r24,16; \ - mov r19=b7; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r25,16; \ -.mem.offset 0,0; st8.spill [r2]=r26,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r27,16; \ -.mem.offset 0,0; st8.spill [r2]=r28,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r29,16; \ -.mem.offset 0,0; st8.spill [r2]=r30,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r31,16; \ - st8 [r2]=r16,16; /* ar.ccv */ \ - ;; \ - st8 [r3]=r17,16; /* ar.fpsr */ \ - st8 [r2]=r18,16; /* b0 */ \ - ;; \ - st8 [r3]=r19,16+8; /* b7 */ \ - ;; \ - stf.spill [r2]=f6,32; \ - stf.spill [r3]=f7,32; \ - ;; \ - stf.spill [r2]=f8,32; \ - stf.spill [r3]=f9,32 - -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) -#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) +#include + +#include + +#include "entry.h" + +/* + * For ivt.s we want to access the stack virtually so we don't have to disable translation + * on interrupts. + * + * On entry: + * r1: pointer to current task (ar.k6) + */ +#define MINSTATE_START_SAVE_MIN_VIRT \ +(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ + ;; \ +(pUStk) mov.m r24=ar.rnat; \ +(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ +(pKStk) mov r1=sp; /* get sp */ \ + ;; \ +(pUStk) lfetch.fault.excl.nt1 [r22]; \ +(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ + ;; \ +(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ +(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ + ;; \ +(pUStk) mov r18=ar.bsp; \ +(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ + +#define MINSTATE_END_SAVE_MIN_VIRT \ + bsw.1; /* switch back to bank 1 (must be last in insn group) */ \ + ;; + +/* + * For mca_asm.S we want to access the stack physically since the state is saved before we + * go virtual and don't want to destroy the iip or ipsr. + */ +#define MINSTATE_START_SAVE_MIN_PHYS \ +(pKStk) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ +(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ + ;; \ +(pUStk) mov r24=ar.rnat; \ +(pKStk) tpa r1=sp; /* compute physical addr of sp */ \ +(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ +(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ + ;; \ +(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ +(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ + ;; \ +(pUStk) mov r18=ar.bsp; \ +(pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ + +#define MINSTATE_END_SAVE_MIN_PHYS \ + or r12=r12,r14; /* make sp a kernel virtual address */ \ + or r13=r13,r14; /* make `current' a kernel virtual address */ \ + ;; + +#ifdef MINSTATE_VIRT +# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT) +# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_VIRT +# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_VIRT +#endif + +#ifdef MINSTATE_PHYS +# define MINSTATE_GET_CURRENT(reg) mov reg=IA64_KR(CURRENT);; dep reg=0,reg,61,3 +# define MINSTATE_START_SAVE_MIN MINSTATE_START_SAVE_MIN_PHYS +# define MINSTATE_END_SAVE_MIN MINSTATE_END_SAVE_MIN_PHYS +#endif + +/* + * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves + * the minimum state necessary that allows us to turn psr.ic back + * on. + * + * Assumed state upon entry: + * psr.ic: off + * r31: contains saved predicates (pr) + * + * Upon exit, the state is as follows: + * psr.ic: off + * r2 = points to &pt_regs.r16 + * r8 = contents of ar.ccv + * r9 = contents of ar.csd + * r10 = contents of ar.ssd + * r11 = FPSR_DEFAULT + * r12 = kernel sp (kernel virtual address) + * r13 = points to current task_struct (kernel virtual address) + * p15 = TRUE if psr.i is set in cr.ipsr + * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: + * preserved + * + * Note that psr.ic is NOT turned on by this macro. This is so that + * we can pass interruption state as arguments to a handler. + */ +#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ + MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ + mov r27=ar.rsc; /* M */ \ + mov r20=r1; /* A */ \ + mov r25=ar.unat; /* M */ \ + mov r29=cr.ipsr; /* M */ \ + mov r26=ar.pfs; /* I */ \ + mov r28=cr.iip; /* M */ \ + mov r21=ar.fpsr; /* M */ \ + COVER; /* B;; (or nothing) */ \ + ;; \ + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \ + ;; \ + ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ + st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ + adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \ + /* switch from user to kernel RBS: */ \ + ;; \ + invala; /* M */ \ + SAVE_IFS; \ + cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \ + ;; \ + MINSTATE_START_SAVE_MIN \ + adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ + adds r16=PT(CR_IPSR),r1; \ + ;; \ + lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ + st8 [r16]=r29; /* save cr.ipsr */ \ + ;; \ + lfetch.fault.excl.nt1 [r17]; \ + tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ + mov r29=b0 \ + ;; \ + adds r16=PT(R8),r1; /* initialize first base pointer */ \ + adds r17=PT(R9),r1; /* initialize second base pointer */ \ +(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r8,16; \ +.mem.offset 8,0; st8.spill [r17]=r9,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r10,24; \ +.mem.offset 8,0; st8.spill [r17]=r11,24; \ + ;; \ + st8 [r16]=r28,16; /* save cr.iip */ \ + st8 [r17]=r30,16; /* save cr.ifs */ \ +(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ + mov r8=ar.ccv; \ + mov r9=ar.csd; \ + mov r10=ar.ssd; \ + movl r11=FPSR_DEFAULT; /* L-unit */ \ + ;; \ + st8 [r16]=r25,16; /* save ar.unat */ \ + st8 [r17]=r26,16; /* save ar.pfs */ \ + shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ + ;; \ + st8 [r16]=r27,16; /* save ar.rsc */ \ +(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \ +(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \ + ;; /* avoid RAW on r16 & r17 */ \ +(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \ + st8 [r17]=r31,16; /* save predicates */ \ +(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \ + ;; \ + st8 [r16]=r29,16; /* save b0 */ \ + st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ + cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ +.mem.offset 8,0; st8.spill [r17]=r12,16; \ + adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r13,16; \ +.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \ + mov r13=IA64_KR(CURRENT); /* establish `current' */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r15,16; \ +.mem.offset 8,0; st8.spill [r17]=r14,16; \ + dep r14=-1,r0,61,3; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r2,16; \ +.mem.offset 8,0; st8.spill [r17]=r3,16; \ + adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ + ;; \ + EXTRA; \ + movl r1=__gp; /* establish kernel global pointer */ \ + ;; \ + MINSTATE_END_SAVE_MIN + +/* + * SAVE_REST saves the remainder of pt_regs (with psr.ic on). + * + * Assumed state upon entry: + * psr.ic: on + * r2: points to &pt_regs.r16 + * r3: points to &pt_regs.r17 + * r8: contents of ar.ccv + * r9: contents of ar.csd + * r10: contents of ar.ssd + * r11: FPSR_DEFAULT + * + * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. + */ +#define SAVE_REST \ +.mem.offset 0,0; st8.spill [r2]=r16,16; \ +.mem.offset 8,0; st8.spill [r3]=r17,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r18,16; \ +.mem.offset 8,0; st8.spill [r3]=r19,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r20,16; \ +.mem.offset 8,0; st8.spill [r3]=r21,16; \ + mov r18=b6; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r22,16; \ +.mem.offset 8,0; st8.spill [r3]=r23,16; \ + mov r19=b7; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r24,16; \ +.mem.offset 8,0; st8.spill [r3]=r25,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r26,16; \ +.mem.offset 8,0; st8.spill [r3]=r27,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r28,16; \ +.mem.offset 8,0; st8.spill [r3]=r29,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r2]=r30,16; \ +.mem.offset 8,0; st8.spill [r3]=r31,32; \ + ;; \ + mov ar.fpsr=r11; /* M-unit */ \ + st8 [r2]=r8,8; /* ar.ccv */ \ + adds r24=PT(B6)-PT(F7),r3; \ + ;; \ + stf.spill [r2]=f6,32; \ + stf.spill [r3]=f7,32; \ + ;; \ + stf.spill [r2]=f8,32; \ + stf.spill [r3]=f9,32; \ + ;; \ + stf.spill [r2]=f10; \ + stf.spill [r3]=f11; \ + adds r25=PT(B7)-PT(F11),r3; \ + ;; \ + st8 [r24]=r18,16; /* b6 */ \ + st8 [r25]=r19,16; /* b7 */ \ + ;; \ + st8 [r24]=r9; /* ar.csd */ \ + st8 [r25]=r10; /* ar.ssd */ \ + ;; + +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov r30=cr.ifs,) +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19) +#define SAVE_MIN DO_SAVE_MIN( , mov r30=r0, ) diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 3bd5e519241..48fee66990f 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -18,7 +18,8 @@ LTOFF22X LTOFF22X LTOFF_FPTR22 - PCREL21B + PCREL21B (for br.call only; br.cond is not supported out of modules!) + PCREL60B (for brl.cond only; brl.call is not supported for modules!) PCREL64LSB SECREL32LSB SEGREL64LSB @@ -33,6 +34,7 @@ #include #include +#include #include #define ARCH_MODULE_DEBUG 0 @@ -158,27 +160,6 @@ slot (const struct insn *insn) return (uint64_t) insn & 0x3; } -/* Patch instruction with "val" where "mask" has 1 bits. */ -static void -apply (struct insn *insn, uint64_t mask, uint64_t val) -{ - uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) bundle(insn); -# define insn_mask ((1UL << 41) - 1) - unsigned long shift; - - b0 = b[0]; b1 = b[1]; - shift = 5 + 41 * slot(insn); /* 5 bits of template, then 3 x 41-bit instructions */ - if (shift >= 64) { - m1 = mask << (shift - 64); - v1 = val << (shift - 64); - } else { - m0 = mask << shift; m1 = mask >> (64 - shift); - v0 = val << shift; v1 = val >> (64 - shift); - b[0] = (b0 & ~m0) | (v0 & m0); - } - b[1] = (b1 & ~m1) | (v1 & m1); -} - static int apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) { @@ -187,12 +168,7 @@ apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) mod->name, slot(insn)); return 0; } - apply(insn, 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ - | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ - | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); - apply((void *) insn - 1, 0x1ffffffffff, val >> 22); + ia64_patch_imm64((u64) insn, val); return 1; } @@ -208,9 +184,7 @@ apply_imm60 (struct module *mod, struct insn *insn, uint64_t val) printk(KERN_ERR "%s: value %ld out of IMM60 range\n", mod->name, (int64_t) val); return 0; } - apply(insn, 0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */ - | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); - apply((void *) insn - 1, 0x1fffffffffc, val >> 18); + ia64_patch_imm60((u64) insn, val); return 1; } @@ -221,10 +195,10 @@ apply_imm22 (struct module *mod, struct insn *insn, uint64_t val) printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val); return 0; } - apply(insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); return 1; } @@ -235,8 +209,8 @@ apply_imm21b (struct module *mod, struct insn *insn, uint64_t val) printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val); return 0; } - apply(insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ - | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); return 1; } @@ -281,7 +255,7 @@ plt_target (struct plt_entry *plt) b0 = b[0]; b1 = b[1]; off = ( ((b1 & 0x00fffff000000000) >> 36) /* imm20b -> bit 0 */ | ((b0 >> 48) << 20) | ((b1 & 0x7fffff) << 36) /* imm39 -> bit 20 */ - | ((b1 & 0x0800000000000000) << 1)); /* i -> bit 60 */ + | ((b1 & 0x0800000000000000) << 0)); /* i -> bit 59 */ return (long) plt->bundle[1] + 16*off; } @@ -751,7 +725,7 @@ do_reloc (struct module *mod, uint8_t r_type, Elf64_Sym *sym, uint64_t addend, if (gp_addressable(mod, val)) { /* turn "ld8" into "mov": */ DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location); - apply(location, 0x1fff80fe000, 0x10000000000); + ia64_patch((u64) location, 0x1fff80fe000, 0x10000000000); } return 0; @@ -889,7 +863,8 @@ module_arch_cleanup (struct module *mod) } #ifdef CONFIG_SMP -void percpu_modcopy(void *pcpudst, const void *src, unsigned long size) +void +percpu_modcopy (void *pcpudst, const void *src, unsigned long size) { unsigned int i; for (i = 0; i < NR_CPUS; i++) diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S index d44041380e8..530d63d4916 100644 --- a/arch/ia64/kernel/pal.S +++ b/arch/ia64/kernel/pal.S @@ -164,7 +164,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) ;; mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical - dep.z r8=r8,0,61 // convert rp to physical + tpa r8=r8 // convert rp to physical ;; mov b7 = loc2 // install target to branch reg mov ar.rsc=0 // put RSE in enforced lazy, LE mode @@ -174,13 +174,13 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static) or loc3=loc3,r17 // add in psr the bits to set ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret1: mov rp = r8 // install return address (physical) br.cond.sptk.many b7 1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov psr.l = loc3 // restore init PSR @@ -228,13 +228,13 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked) mov b7 = loc2 // install target to branch reg ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret8: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c new file mode 100644 index 00000000000..02436c8a7f6 --- /dev/null +++ b/arch/ia64/kernel/patch.c @@ -0,0 +1,194 @@ +/* + * Instruction-patching support. + * + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + */ +#include +#include + +#include +#include +#include +#include + +/* + * This was adapted from code written by Tony Luck: + * + * The 64-bit value in a "movl reg=value" is scattered between the two words of the bundle + * like this: + * + * 6 6 5 4 3 2 1 + * 3210987654321098765432109876543210987654321098765432109876543210 + * ABBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCDEEEEEFFFFFFFFFGGGGGGG + * + * CCCCCCCCCCCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + * xxxxAFFFFFFFFFEEEEEDxGGGGGGGxxxxxxxxxxxxxBBBBBBBBBBBBBBBBBBBBBBB + */ +static u64 +get_imm64 (u64 insn_addr) +{ + u64 *p = (u64 *) (insn_addr & -16); /* mask out slot number */ + + return ( (p[1] & 0x0800000000000000UL) << 4) | /*A*/ + ((p[1] & 0x00000000007fffffUL) << 40) | /*B*/ + ((p[0] & 0xffffc00000000000UL) >> 24) | /*C*/ + ((p[1] & 0x0000100000000000UL) >> 23) | /*D*/ + ((p[1] & 0x0003e00000000000UL) >> 29) | /*E*/ + ((p[1] & 0x07fc000000000000UL) >> 43) | /*F*/ + ((p[1] & 0x000007f000000000UL) >> 36); /*G*/ +} + +/* Patch instruction with "val" where "mask" has 1 bits. */ +void +ia64_patch (u64 insn_addr, u64 mask, u64 val) +{ + u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16); +# define insn_mask ((1UL << 41) - 1) + unsigned long shift; + + b0 = b[0]; b1 = b[1]; + shift = 5 + 41 * (insn_addr % 16); /* 5 bits of template, then 3 x 41-bit instructions */ + if (shift >= 64) { + m1 = mask << (shift - 64); + v1 = val << (shift - 64); + } else { + m0 = mask << shift; m1 = mask >> (64 - shift); + v0 = val << shift; v1 = val >> (64 - shift); + b[0] = (b0 & ~m0) | (v0 & m0); + } + b[1] = (b1 & ~m1) | (v1 & m1); +} + +void +ia64_patch_imm64 (u64 insn_addr, u64 val) +{ + ia64_patch(insn_addr, + 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1ffffffffff, val >> 22); +} + +void +ia64_patch_imm60 (u64 insn_addr, u64 val) +{ + ia64_patch(insn_addr, + 0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */ + | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18); +} + +/* + * We need sometimes to load the physical address of a kernel + * object. Often we can convert the virtual address to physical + * at execution time, but sometimes (either for performance reasons + * or during error recovery) we cannot to this. Patch the marked + * bundles to load the physical address. + */ +void __init +ia64_patch_vtop (unsigned long start, unsigned long end) +{ + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) offp + *offp; + + /* replace virtual address with corresponding physical address: */ + ia64_patch_imm64(ip, ia64_tpa(get_imm64(ip))); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +void +ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) +{ + static int first_time = 1; + int need_workaround; + s32 *offp = (s32 *) start; + u64 *wp; + + need_workaround = (local_cpu_data->family == 0x1f && local_cpu_data->model == 0); + + if (first_time) { + first_time = 0; + if (need_workaround) + printk(KERN_INFO "Leaving McKinley Errata 9 workaround enabled\n"); + else + printk(KERN_INFO "McKinley Errata 9 workaround not needed; " + "disabling it\n"); + } + if (need_workaround) + return; + + while (offp < (s32 *) end) { + wp = (u64 *) ia64_imva((char *) offp + *offp); + wp[0] = 0x0000000100000000; + wp[1] = 0x0004000000000200; + ia64_fc(wp); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +static void +patch_fsyscall_table (unsigned long start, unsigned long end) +{ + extern unsigned long fsyscall_table[NR_syscalls]; + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) ia64_imva((char *) offp + *offp); + ia64_patch_imm64(ip, (u64) fsyscall_table); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +static void +patch_brl_fsys_bubble_down (unsigned long start, unsigned long end) +{ + extern char fsys_bubble_down[]; + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) offp + *offp; + ia64_patch_imm60((u64) ia64_imva((void *) ip), + (u64) (fsys_bubble_down - (ip & -16)) / 16); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +void +ia64_patch_gate (void) +{ + extern char __start_gate_mckinley_e9_patchlist; + extern char __end_gate_mckinley_e9_patchlist; + extern char __start_gate_vtop_patchlist; + extern char __end_gate_vtop_patchlist; + extern char __start_gate_fsyscall_patchlist; + extern char __end_gate_fsyscall_patchlist; + extern char __start_gate_brl_fsys_bubble_down_patchlist; + extern char __end_gate_brl_fsys_bubble_down_patchlist; +# define START(name) ((unsigned long) &__start_gate_##name##_patchlist) +# define END(name) ((unsigned long)&__end_gate_##name##_patchlist) + + patch_fsyscall_table(START(fsyscall), END(fsyscall)); + patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down)); + ia64_patch_vtop(START(vtop), END(vtop)); + ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9)); +} diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c dissimilarity index 68% index fd0f90ae5d5..3bd6c4ff707 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -1,4453 +1,6514 @@ -/* - * This file implements the perfmon subsystem which is used - * to program the IA-64 Performance Monitoring Unit (PMU). - * - * Originally Written by Ganesh Venkitachalam, IBM Corp. - * Copyright (C) 1999 Ganesh Venkitachalam - * - * Modifications by Stephane Eranian, Hewlett-Packard Co. - * Modifications by David Mosberger-Tang, Hewlett-Packard Co. - * - * Copyright (C) 1999-2003 Hewlett Packard Co - * Stephane Eranian - * David Mosberger-Tang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for ia64_get_itc() */ - -#ifdef CONFIG_PERFMON - -/* - * For PMUs which rely on the debug registers for some features, you must - * you must enable the following flag to activate the support for - * accessing the registers via the perfmonctl() interface. - */ -#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY) -#define PFM_PMU_USES_DBR 1 -#endif - -/* - * perfmon context states - */ -#define PFM_CTX_DISABLED 0 -#define PFM_CTX_ENABLED 1 - -/* - * Reset register flags - */ -#define PFM_PMD_LONG_RESET 1 -#define PFM_PMD_SHORT_RESET 2 - -/* - * Misc macros and definitions - */ -#define PMU_FIRST_COUNTER 4 -#define PMU_MAX_PMCS 256 -#define PMU_MAX_PMDS 256 - -/* - * type of a PMU register (bitmask). - * bitmask structure: - * bit0 : register implemented - * bit1 : end marker - * bit2-3 : reserved - * bit4-7 : register type - * bit8-31: reserved - */ -#define PFM_REG_IMPL 0x1 /* register implemented */ -#define PFM_REG_END 0x2 /* end marker */ -#define PFM_REG_MONITOR (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */ -#define PFM_REG_COUNTING (0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */ -#define PFM_REG_CONTROL (0x3<<4|PFM_REG_IMPL) /* PMU control register */ -#define PFM_REG_CONFIG (0x4<<4|PFM_REG_IMPL) /* refine configuration */ -#define PFM_REG_BUFFER (0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */ - -#define PMC_IS_LAST(i) (pmu_conf.pmc_desc[i].type & PFM_REG_END) -#define PMD_IS_LAST(i) (pmu_conf.pmd_desc[i].type & PFM_REG_END) - -#define PFM_IS_DISABLED() pmu_conf.disabled - -#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_soft_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) -#define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) - -/* i assume unsigned */ -#define PMC_IS_IMPL(i) (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL)) -#define PMD_IS_IMPL(i) (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL)) - -/* XXX: these three assume that register i is implemented */ -#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) -#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING) -#define PMC_IS_MONITOR(i) (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR) -#define PMC_DFL_VAL(i) pmu_conf.pmc_desc[i].default_value -#define PMC_RSVD_MASK(i) pmu_conf.pmc_desc[i].reserved_mask -#define PMD_PMD_DEP(i) pmu_conf.pmd_desc[i].dep_pmd[0] -#define PMC_PMD_DEP(i) pmu_conf.pmc_desc[i].dep_pmd[0] - -/* k assume unsigned */ -#define IBR_IS_IMPL(k) (kctx_flags.state == PFM_CTX_ENABLED) -#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) -#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) -#define CTX_HAS_SMPL(c) ((c)->ctx_psb != NULL) -/* XXX: does not support more than 64 PMDs */ -#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) -#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) - - -#define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) -#define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) -#define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) - -#define LOCK_CTX(ctx) spin_lock(&(ctx)->ctx_lock) -#define UNLOCK_CTX(ctx) spin_unlock(&(ctx)->ctx_lock) - -#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0) -#define PMU_OWNER() pmu_owners[smp_processor_id()].owner - -#define LOCK_PFS() spin_lock(&pfm_sessions.pfs_lock) -#define UNLOCK_PFS() spin_unlock(&pfm_sessions.pfs_lock) - -#define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) - -#define PFM_CPUINFO_CLEAR(v) __get_cpu_var(pfm_syst_info) &= ~(v) -#define PFM_CPUINFO_SET(v) __get_cpu_var(pfm_syst_info) |= (v) - -/* - * debugging - */ -#define DBprintk(a) \ - do { \ - if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ - } while (0) - -#define DBprintk_ovfl(a) \ - do { \ - if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ - } while (0) - - - -/* - * Architected PMC structure - */ -typedef struct { - unsigned long pmc_plm:4; /* privilege level mask */ - unsigned long pmc_ev:1; /* external visibility */ - unsigned long pmc_oi:1; /* overflow interrupt */ - unsigned long pmc_pm:1; /* privileged monitor */ - unsigned long pmc_ig1:1; /* reserved */ - unsigned long pmc_es:8; /* event select */ - unsigned long pmc_ig2:48; /* reserved */ -} pfm_monitor_t; - -/* - * There is one such data structure per perfmon context. It is used to describe the - * sampling buffer. It is to be shared among siblings whereas the pfm_context - * is not. - * Therefore we maintain a refcnt which is incremented on fork(). - * This buffer is private to the kernel only the actual sampling buffer - * including its header are exposed to the user. This construct allows us to - * export the buffer read-write, if needed, without worrying about security - * problems. - */ -typedef struct _pfm_smpl_buffer_desc { - spinlock_t psb_lock; /* protection lock */ - unsigned long psb_refcnt; /* how many users for the buffer */ - int psb_flags; /* bitvector of flags (not yet used) */ - - void *psb_addr; /* points to location of first entry */ - unsigned long psb_entries; /* maximum number of entries */ - unsigned long psb_size; /* aligned size of buffer */ - unsigned long psb_index; /* next free entry slot XXX: must use the one in buffer */ - unsigned long psb_entry_size; /* size of each entry including entry header */ - - perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ - - struct _pfm_smpl_buffer_desc *psb_next; /* next psb, used for rvfreeing of psb_hdr */ - -} pfm_smpl_buffer_desc_t; - -/* - * psb_flags - */ -#define PSB_HAS_VMA 0x1 /* a virtual mapping for the buffer exists */ - -#define LOCK_PSB(p) spin_lock(&(p)->psb_lock) -#define UNLOCK_PSB(p) spin_unlock(&(p)->psb_lock) - -/* - * 64-bit software counter structure - */ -typedef struct { - u64 val; /* virtual 64bit counter value */ - u64 lval; /* last value */ - u64 long_reset; /* reset value on sampling overflow */ - u64 short_reset;/* reset value on overflow */ - u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */ - u64 seed; /* seed for random-number generator */ - u64 mask; /* mask for random-number generator */ - unsigned int flags; /* notify/do not notify */ -} pfm_counter_t; - -/* - * perfmon context. One per process, is cloned on fork() depending on - * inheritance flags - */ -typedef struct { - unsigned int state:1; /* 0=disabled, 1=enabled */ - unsigned int inherit:2; /* inherit mode */ - unsigned int block:1; /* when 1, task will blocked on user notifications */ - unsigned int system:1; /* do system wide monitoring */ - unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ - unsigned int protected:1; /* allow access to creator of context only */ - unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ - unsigned int excl_idle:1; /* exclude idle task in system wide session */ - unsigned int unsecure:1; /* sp = 0 for non self-monitored task */ - unsigned int trap_reason:2; /* reason for going into pfm_block_ovfl_reset() */ - unsigned int reserved:20; -} pfm_context_flags_t; - -#define PFM_TRAP_REASON_NONE 0x0 /* default value */ -#define PFM_TRAP_REASON_BLOCKSIG 0x1 /* we need to block on overflow and signal user */ -#define PFM_TRAP_REASON_SIG 0x2 /* we simply need to signal user */ -#define PFM_TRAP_REASON_RESET 0x3 /* we need to reset PMDs */ - -/* - * perfmon context: encapsulates all the state of a monitoring session - * XXX: probably need to change layout - */ -typedef struct pfm_context { - pfm_smpl_buffer_desc_t *ctx_psb; /* sampling buffer, if any */ - unsigned long ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ - - spinlock_t ctx_lock; - pfm_context_flags_t ctx_flags; /* block/noblock */ - - struct task_struct *ctx_notify_task; /* who to notify on overflow */ - struct task_struct *ctx_owner; /* pid of creator (debug) */ - - unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ - unsigned long ctx_smpl_regs[4]; /* which registers to record on overflow */ - - struct semaphore ctx_restart_sem; /* use for blocking notification mode */ - - unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ - unsigned long ctx_reload_pmds[4]; /* bitmask of PMD to reload on ctxsw */ - - unsigned long ctx_used_pmcs[4]; /* bitmask PMC used by context */ - unsigned long ctx_reload_pmcs[4]; /* bitmask of PMC to reload on ctxsw */ - - unsigned long ctx_used_ibrs[4]; /* bitmask of used IBR (speedup ctxsw) */ - unsigned long ctx_used_dbrs[4]; /* bitmask of used DBR (speedup ctxsw) */ - - pfm_counter_t ctx_soft_pmds[IA64_NUM_PMD_REGS]; /* XXX: size should be dynamic */ - - u64 ctx_saved_psr; /* copy of psr used for lazy ctxsw */ - unsigned long ctx_saved_cpus_allowed; /* copy of the task cpus_allowed (system wide) */ - unsigned int ctx_cpu; /* CPU used by system wide session */ - - atomic_t ctx_last_cpu; /* CPU id of current or last CPU used */ -} pfm_context_t; - -#define ctx_fl_inherit ctx_flags.inherit -#define ctx_fl_block ctx_flags.block -#define ctx_fl_system ctx_flags.system -#define ctx_fl_frozen ctx_flags.frozen -#define ctx_fl_protected ctx_flags.protected -#define ctx_fl_using_dbreg ctx_flags.using_dbreg -#define ctx_fl_excl_idle ctx_flags.excl_idle -#define ctx_fl_trap_reason ctx_flags.trap_reason -#define ctx_fl_unsecure ctx_flags.unsecure - -/* - * global information about all sessions - * mostly used to synchronize between system wide and per-process - */ -typedef struct { - spinlock_t pfs_lock; /* lock the structure */ - - unsigned int pfs_task_sessions; /* number of per task sessions */ - unsigned int pfs_sys_sessions; /* number of per system wide sessions */ - unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ - unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ - struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ -} pfm_session_t; - -/* - * information about a PMC or PMD. - * dep_pmd[]: a bitmask of dependent PMD registers - * dep_pmc[]: a bitmask of dependent PMC registers - */ -typedef struct { - unsigned int type; - int pm_pos; - unsigned long default_value; /* power-on default value */ - unsigned long reserved_mask; /* bitmask of reserved bits */ - int (*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); - int (*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); - unsigned long dep_pmd[4]; - unsigned long dep_pmc[4]; -} pfm_reg_desc_t; - -/* assume cnum is a valid monitor */ -#define PMC_PM(cnum, val) (((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1) -#define PMC_WR_FUNC(cnum) (pmu_conf.pmc_desc[cnum].write_check) -#define PMD_WR_FUNC(cnum) (pmu_conf.pmd_desc[cnum].write_check) -#define PMD_RD_FUNC(cnum) (pmu_conf.pmd_desc[cnum].read_check) - -/* - * This structure is initialized at boot time and contains - * a description of the PMU main characteristics. - */ -typedef struct { - unsigned int disabled; /* indicates if perfmon is working properly */ - unsigned long ovfl_val; /* overflow value for generic counters */ - unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ - unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ - unsigned int num_pmcs; /* number of implemented PMCS */ - unsigned int num_pmds; /* number of implemented PMDS */ - unsigned int num_ibrs; /* number of implemented IBRS */ - unsigned int num_dbrs; /* number of implemented DBRS */ - unsigned int num_counters; /* number of PMD/PMC counters */ - pfm_reg_desc_t *pmc_desc; /* detailed PMC register dependencies descriptions */ - pfm_reg_desc_t *pmd_desc; /* detailed PMD register dependencies descriptions */ -} pmu_config_t; - -/* - * structure used to pass argument to/from remote CPU - * using IPI to check and possibly save the PMU context on SMP systems. - * - * not used in UP kernels - */ -typedef struct { - struct task_struct *task; /* which task we are interested in */ - int retval; /* return value of the call: 0=you can proceed, 1=need to wait for completion */ -} pfm_smp_ipi_arg_t; - -/* - * perfmon command descriptions - */ -typedef struct { - int (*cmd_func)(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); - int cmd_flags; - unsigned int cmd_narg; - size_t cmd_argsize; -} pfm_cmd_desc_t; - -#define PFM_CMD_PID 0x1 /* command requires pid argument */ -#define PFM_CMD_ARG_READ 0x2 /* command must read argument(s) */ -#define PFM_CMD_ARG_RW 0x4 /* command must read/write argument(s) */ -#define PFM_CMD_CTX 0x8 /* command needs a perfmon context */ -#define PFM_CMD_NOCHK 0x10 /* command does not need to check task's state */ - -#define PFM_CMD_IDX(cmd) (cmd) - -#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) \ - && (PFM_CMD_IDX(cmd) < (int) PFM_CMD_COUNT) \ - && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) - -#define PFM_CMD_USE_PID(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0) -#define PFM_CMD_READ_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0) -#define PFM_CMD_RW_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0) -#define PFM_CMD_USE_CTX(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0) -#define PFM_CMD_CHK(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0) - -#define PFM_CMD_ARG_MANY -1 /* cannot be zero */ -#define PFM_CMD_NARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg) -#define PFM_CMD_ARG_SIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize) - -typedef struct { - int debug; /* turn on/off debugging via syslog */ - int debug_ovfl; /* turn on/off debug printk in overflow handler */ - int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ -} pfm_sysctl_t; - -typedef struct { - unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ - unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ - unsigned long pfm_recorded_samples_count; - unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */ - char pad[SMP_CACHE_BYTES] ____cacheline_aligned; -} pfm_stats_t; - -/* - * perfmon internal variables - */ -static pfm_session_t pfm_sessions; /* global sessions information */ -static struct proc_dir_entry *perfmon_dir; /* for debug only */ -static pfm_stats_t pfm_stats[NR_CPUS]; -static pfm_intr_handler_desc_t *pfm_alternate_intr_handler; - -DEFINE_PER_CPU(unsigned long, pfm_syst_info); - -/* sysctl() controls */ -static pfm_sysctl_t pfm_sysctl; - -static ctl_table pfm_ctl_table[]={ - {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, - {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, - {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, - { 0, }, -}; -static ctl_table pfm_sysctl_dir[] = { - {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, - {0,}, -}; -static ctl_table pfm_sysctl_root[] = { - {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, - {0,}, -}; -static struct ctl_table_header *pfm_sysctl_header; - -static void pfm_vm_close(struct vm_area_struct * area); - -static struct vm_operations_struct pfm_vm_ops={ - .close = pfm_vm_close -}; - -/* - * keep track of task owning the PMU per CPU. - */ -static struct { - struct task_struct *owner; - char pad[SMP_CACHE_BYTES] ____cacheline_aligned; -} pmu_owners[NR_CPUS]; - - - -/* - * forward declarations - */ -static void pfm_reset_pmu(struct task_struct *); -static void pfm_lazy_save_regs (struct task_struct *ta); - -#if defined(CONFIG_ITANIUM) -#include "perfmon_itanium.h" -#elif defined(CONFIG_MCKINLEY) -#include "perfmon_mckinley.h" -#else -#include "perfmon_generic.h" -#endif - -static inline void -pfm_clear_psr_pp(void) -{ - __asm__ __volatile__ ("rsm psr.pp;; srlz.i;;"::: "memory"); -} - -static inline void -pfm_set_psr_pp(void) -{ - __asm__ __volatile__ ("ssm psr.pp;; srlz.i;;"::: "memory"); -} - -static inline void -pfm_clear_psr_up(void) -{ - __asm__ __volatile__ ("rum psr.up;; srlz.i;;"::: "memory"); -} - -static inline void -pfm_set_psr_up(void) -{ - __asm__ __volatile__ ("sum psr.up;; srlz.i;;"::: "memory"); -} - -static inline unsigned long -pfm_get_psr(void) -{ - unsigned long tmp; - __asm__ __volatile__ ("mov %0=psr;;": "=r"(tmp) :: "memory"); - return tmp; -} - -static inline void -pfm_set_psr_l(unsigned long val) -{ - __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(val): "memory"); -} - -static inline void -pfm_freeze_pmu(void) -{ - ia64_set_pmc(0,1UL); - ia64_srlz_d(); -} - -static inline void -pfm_unfreeze_pmu(void) -{ - ia64_set_pmc(0,0UL); - ia64_srlz_d(); -} - -static inline unsigned long -pfm_read_soft_counter(pfm_context_t *ctx, int i) -{ - return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val); -} - -static inline void -pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) -{ - ctx->ctx_soft_pmds[i].val = val & ~pmu_conf.ovfl_val; - /* - * writing to unimplemented part is ignore, so we do not need to - * mask off top part - */ - ia64_set_pmd(i, val & pmu_conf.ovfl_val); -} - -/* - * Generates a unique (per CPU) timestamp - */ -static inline unsigned long -pfm_get_stamp(void) -{ - /* - * XXX: must find something more efficient - */ - return ia64_get_itc(); -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long -pfm_kvirt_to_pa(unsigned long adr) -{ - __u64 pa = ia64_tpa(adr); - //DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); - return pa; -} - -static void * -pfm_rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size=PAGE_ALIGN(size); - mem=vmalloc(size); - if (mem) { - //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void -pfm_rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (mem) { - adr=(unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void*)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } - return; -} - -/* - * This function gets called from mm/mmap.c:exit_mmap() only when there is a sampling buffer - * attached to the context AND the current task has a mapping for it, i.e., it is the original - * creator of the context. - * - * This function is used to remember the fact that the vma describing the sampling buffer - * has now been removed. It can only be called when no other tasks share the same mm context. - * - */ -static void -pfm_vm_close(struct vm_area_struct *vma) -{ - pfm_smpl_buffer_desc_t *psb = (pfm_smpl_buffer_desc_t *)vma->vm_private_data; - - if (psb == NULL) { - printk(KERN_DEBUG "perfmon: psb is null in [%d]\n", current->pid); - return; - } - /* - * Add PSB to list of buffers to free on release_thread() when no more users - * - * This call is safe because, once the count is zero is cannot be modified anymore. - * This is not because there is no more user of the mm context, that the sampling - * buffer is not being used anymore outside of this task. In fact, it can still - * be accessed from within the kernel by another task (such as the monitored task). - * - * Therefore, we only move the psb into the list of buffers to free when we know - * nobody else is using it. - * The linked list if independent of the perfmon context, because in the case of - * multi-threaded processes, the last thread may not have been involved with - * monitoring however it will be the one removing the vma and it should therefore - * also remove the sampling buffer. This buffer cannot be removed until the vma - * is removed. - * - * This function cannot remove the buffer from here, because exit_mmap() must first - * complete. Given that there is no other vma related callback in the generic code, - * we have created our own with the linked list of sampling buffers to free. The list - * is part of the thread structure. In release_thread() we check if the list is - * empty. If not we call into perfmon to free the buffer and psb. That is the only - * way to ensure a safe deallocation of the sampling buffer which works when - * the buffer is shared between distinct processes or with multi-threaded programs. - * - * We need to lock the psb because the refcnt test and flag manipulation must - * looked like an atomic operation vis a vis pfm_context_exit() - */ - LOCK_PSB(psb); - - if (psb->psb_refcnt == 0) { - - psb->psb_next = current->thread.pfm_smpl_buf_list; - current->thread.pfm_smpl_buf_list = psb; - - DBprintk(("[%d] add smpl @%p size %lu to smpl_buf_list psb_flags=0x%x\n", - current->pid, psb->psb_hdr, psb->psb_size, psb->psb_flags)); - } - DBprintk(("[%d] clearing psb_flags=0x%x smpl @%p size %lu\n", - current->pid, psb->psb_flags, psb->psb_hdr, psb->psb_size)); - /* - * decrement the number vma for the buffer - */ - psb->psb_flags &= ~PSB_HAS_VMA; - - UNLOCK_PSB(psb); -} - -/* - * This function is called from pfm_destroy_context() and also from pfm_inherit() - * to explicitly remove the sampling buffer mapping from the user level address space. - */ -static int -pfm_remove_smpl_mapping(struct task_struct *task) -{ - pfm_context_t *ctx = task->thread.pfm_context; - pfm_smpl_buffer_desc_t *psb; - int r; - - /* - * some sanity checks first - */ - if (ctx == NULL || task->mm == NULL || ctx->ctx_smpl_vaddr == 0 || ctx->ctx_psb == NULL) { - printk(KERN_DEBUG "perfmon: invalid context mm=%p\n", task->mm); - return -1; - } - psb = ctx->ctx_psb; - - down_write(&task->mm->mmap_sem); - - r = do_munmap(task->mm, ctx->ctx_smpl_vaddr, psb->psb_size); - - up_write(&task->mm->mmap_sem); - if (r !=0) { - printk(KERN_DEBUG "perfmon: pid %d unable to unmap sampling buffer " - "@0x%lx size=%ld\n", task->pid, ctx->ctx_smpl_vaddr, psb->psb_size); - } - - DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d refcnt=%lu psb_flags=0x%x\n", - task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r, psb->psb_refcnt, psb->psb_flags)); - - return 0; -} - -static pfm_context_t * -pfm_context_alloc(void) -{ - pfm_context_t *ctx; - - /* allocate context descriptor */ - ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); - if (ctx) memset(ctx, 0, sizeof(pfm_context_t)); - - return ctx; -} - -static void -pfm_context_free(pfm_context_t *ctx) -{ - if (ctx) kfree(ctx); -} - -static int -pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) -{ - unsigned long page; - - DBprintk(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); - - while (size > 0) { - page = pfm_kvirt_to_pa(buf); - - if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM; - - addr += PAGE_SIZE; - buf += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - -/* - * counts the number of PMDS to save per entry. - * This code is generic enough to accommodate more than 64 PMDS when they become available - */ -static unsigned long -pfm_smpl_entry_size(unsigned long *which, unsigned long size) -{ - unsigned long i, res = 0; - - for (i=0; i < size; i++, which++) res += hweight64(*which); - - DBprintk(("weight=%ld\n", res)); - - return res; -} - -/* - * Allocates the sampling buffer and remaps it into caller's address space - */ -static int -pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long *which_pmds, unsigned long entries, - void **user_vaddr) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = NULL; - unsigned long size, regcount; - void *smpl_buf; - pfm_smpl_buffer_desc_t *psb; - - - /* note that regcount might be 0, in this case only the header for each - * entry will be recorded. - */ - regcount = pfm_smpl_entry_size(which_pmds, 1); - - if ((sizeof(perfmon_smpl_hdr_t)+ entries*sizeof(perfmon_smpl_entry_t)) <= entries) { - DBprintk(("requested entries %lu is too big\n", entries)); - return -EINVAL; - } - - /* - * 1 buffer hdr and for each entry a header + regcount PMDs to save - */ - size = PAGE_ALIGN( sizeof(perfmon_smpl_hdr_t) - + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); - - DBprintk(("sampling buffer size=%lu bytes\n", size)); - - /* - * check requested size to avoid Denial-of-service attacks - * XXX: may have to refine this test - * Check against address space limit. - * - * if ((mm->total_vm << PAGE_SHIFT) + len> current->rlim[RLIMIT_AS].rlim_cur) - * return -ENOMEM; - */ - if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; - - /* - * We do the easy to undo allocations first. - * - * pfm_rvmalloc(), clears the buffer, so there is no leak - */ - smpl_buf = pfm_rvmalloc(size); - if (smpl_buf == NULL) { - DBprintk(("Can't allocate sampling buffer\n")); - return -ENOMEM; - } - - DBprintk(("smpl_buf @%p\n", smpl_buf)); - - /* allocate sampling buffer descriptor now */ - psb = kmalloc(sizeof(*psb), GFP_KERNEL); - if (psb == NULL) { - DBprintk(("Can't allocate sampling buffer descriptor\n")); - goto error_kmalloc; - } - - /* allocate vma */ - vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); - if (!vma) { - DBprintk(("Cannot allocate vma\n")); - goto error_kmem; - } - /* - * partially initialize the vma for the sampling buffer - * - * The VM_DONTCOPY flag is very important as it ensures that the mapping - * will never be inherited for any child process (via fork()) which is always - * what we want. - */ - vma->vm_mm = mm; - vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY; - vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ - vma->vm_ops = &pfm_vm_ops; /* necesarry to get the close() callback */ - vma->vm_pgoff = 0; - vma->vm_file = NULL; - vma->vm_private_data = psb; /* information needed by the pfm_vm_close() function */ - - /* - * Now we have everything we need and we can initialize - * and connect all the data structures - */ - - psb->psb_hdr = smpl_buf; - psb->psb_addr = ((char *)smpl_buf)+sizeof(perfmon_smpl_hdr_t); /* first entry */ - psb->psb_size = size; /* aligned size */ - psb->psb_index = 0; - psb->psb_entries = entries; - psb->psb_refcnt = 1; - psb->psb_flags = PSB_HAS_VMA; - - spin_lock_init(&psb->psb_lock); - - /* - * XXX: will need to do cacheline alignment to avoid false sharing in SMP mode and - * multitask monitoring. - */ - psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); - - DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p refcnt=%lu psb_flags=0x%x\n", - (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, - (void *)psb->psb_addr, psb->psb_refcnt, psb->psb_flags)); - - /* initialize some of the fields of user visible buffer header */ - psb->psb_hdr->hdr_version = PFM_SMPL_VERSION; - psb->psb_hdr->hdr_entry_size = psb->psb_entry_size; - psb->psb_hdr->hdr_pmds[0] = which_pmds[0]; - - /* - * Let's do the difficult operations next. - * - * now we atomically find some area in the address space and - * remap the buffer in it. - */ - down_write(¤t->mm->mmap_sem); - - - /* find some free area in address space, must have mmap sem held */ - vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS); - if (vma->vm_start == 0UL) { - DBprintk(("Cannot find unmapped area for size %ld\n", size)); - up_write(¤t->mm->mmap_sem); - goto error; - } - vma->vm_end = vma->vm_start + size; - - DBprintk(("entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, vma->vm_start)); - - /* can only be applied to current, need to have the mm semaphore held when called */ - if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { - DBprintk(("Can't remap buffer\n")); - up_write(¤t->mm->mmap_sem); - goto error; - } - - /* - * now insert the vma in the vm list for the process, must be - * done with mmap lock held - */ - insert_vm_struct(mm, vma); - - mm->total_vm += size >> PAGE_SHIFT; - - up_write(¤t->mm->mmap_sem); - - /* store which PMDS to record */ - ctx->ctx_smpl_regs[0] = which_pmds[0]; - - - /* link to perfmon context */ - ctx->ctx_psb = psb; - - /* - * keep track of user level virtual address - */ - ctx->ctx_smpl_vaddr = *(unsigned long *)user_vaddr = vma->vm_start; - - return 0; - -error: - kmem_cache_free(vm_area_cachep, vma); -error_kmem: - kfree(psb); -error_kmalloc: - pfm_rvfree(smpl_buf, size); - return -ENOMEM; -} - -static int -pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask) -{ - unsigned long m, undo_mask; - unsigned int n, i; - - /* - * validy checks on cpu_mask have been done upstream - */ - LOCK_PFS(); - - if (is_syswide) { - /* - * cannot mix system wide and per-task sessions - */ - if (pfm_sessions.pfs_task_sessions > 0UL) { - DBprintk(("system wide not possible, %u conflicting task_sessions\n", - pfm_sessions.pfs_task_sessions)); - goto abort; - } - - m = cpu_mask; undo_mask = 0UL; n = 0; - DBprintk(("cpu_mask=0x%lx\n", cpu_mask)); - for(i=0; m; i++, m>>=1) { - - if ((m & 0x1) == 0UL) continue; - - if (pfm_sessions.pfs_sys_session[i]) goto undo; - - DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id())); - - pfm_sessions.pfs_sys_session[i] = task; - undo_mask |= 1UL << i; - n++; - } - pfm_sessions.pfs_sys_sessions += n; - } else { - if (pfm_sessions.pfs_sys_sessions) goto abort; - pfm_sessions.pfs_task_sessions++; - } - DBprintk(("task_sessions=%u sys_session[%d]=%d", - pfm_sessions.pfs_task_sessions, - smp_processor_id(), pfm_sessions.pfs_sys_session[smp_processor_id()] ? 1 : 0)); - UNLOCK_PFS(); - return 0; -undo: - DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n", - pfm_sessions.pfs_sys_session[i]->pid, i)); - - for(i=0; undo_mask; i++, undo_mask >>=1) { - pfm_sessions.pfs_sys_session[i] = NULL; - } -abort: - UNLOCK_PFS(); - - return -EBUSY; - -} - -static int -pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask) -{ - pfm_context_t *ctx; - unsigned long m; - unsigned int n, i; - - ctx = task ? task->thread.pfm_context : NULL; - - /* - * validy checks on cpu_mask have been done upstream - */ - LOCK_PFS(); - - DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n", - task->pid, - pfm_sessions.pfs_sys_sessions, - pfm_sessions.pfs_task_sessions, - pfm_sessions.pfs_sys_use_dbregs, - is_syswide, - cpu_mask)); - - - if (is_syswide) { - m = cpu_mask; n = 0; - for(i=0; m; i++, m>>=1) { - if ((m & 0x1) == 0UL) continue; - pfm_sessions.pfs_sys_session[i] = NULL; - n++; - } - /* - * would not work with perfmon+more than one bit in cpu_mask - */ - if (ctx && ctx->ctx_fl_using_dbreg) { - if (pfm_sessions.pfs_sys_use_dbregs == 0) { - printk(KERN_DEBUG "perfmon: invalid release for [%d] " - "sys_use_dbregs=0\n", task->pid); - } else { - pfm_sessions.pfs_sys_use_dbregs--; - } - } - pfm_sessions.pfs_sys_sessions -= n; - - DBprintk(("CPU%d sys_sessions=%u\n", - smp_processor_id(), pfm_sessions.pfs_sys_sessions)); - } else { - pfm_sessions.pfs_task_sessions--; - DBprintk(("[%d] task_sessions=%u\n", - task->pid, pfm_sessions.pfs_task_sessions)); - } - - UNLOCK_PFS(); - - return 0; -} - -/* - * XXX: do something better here - */ -static int -pfm_bad_permissions(struct task_struct *task) -{ - /* stolen from bad_signal() */ - return (current->session != task->session) - && (current->euid ^ task->suid) && (current->euid ^ task->uid) - && (current->uid ^ task->suid) && (current->uid ^ task->uid); -} - - -static int -pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx) -{ - unsigned long smpl_pmds = pfx->ctx_smpl_regs[0]; - int ctx_flags; - int cpu; - - /* valid signal */ - - /* cannot send to process 1, 0 means do not notify */ - if (pfx->ctx_notify_pid == 1) { - DBprintk(("invalid notify_pid %d\n", pfx->ctx_notify_pid)); - return -EINVAL; - } - ctx_flags = pfx->ctx_flags; - - if ((ctx_flags & PFM_FL_INHERIT_MASK) == (PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)) { - DBprintk(("invalid inherit mask 0x%x\n",ctx_flags & PFM_FL_INHERIT_MASK)); - return -EINVAL; - } - - if (ctx_flags & PFM_FL_SYSTEM_WIDE) { - DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask)); - /* - * cannot block in this mode - */ - if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { - DBprintk(("cannot use blocking mode when in system wide monitoring\n")); - return -EINVAL; - } - /* - * must only have one bit set in the CPU mask - */ - if (hweight64(pfx->ctx_cpu_mask) != 1UL) { - DBprintk(("invalid CPU mask specified\n")); - return -EINVAL; - } - /* - * and it must be a valid CPU - */ - cpu = ffz(~pfx->ctx_cpu_mask); -#ifdef CONFIG_SMP - if (cpu_online(cpu) == 0) { -#else - if (cpu != 0) { -#endif - DBprintk(("CPU%d is not online\n", cpu)); - return -EINVAL; - } - - /* - * check for pre-existing pinning, if conflicting reject - */ - if (task->cpus_allowed != ~0UL && (task->cpus_allowed & (1UL<pid, - task->cpus_allowed, cpu)); - return -EINVAL; - } - - } else { - /* - * must provide a target for the signal in blocking mode even when - * no counter is configured with PFM_FL_REG_OVFL_NOTIFY - */ - if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) { - DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid)); - return -EINVAL; - } -#if 0 - if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) { - DBprintk(("cannot notify self when blocking for [%d]\n", task->pid)); - return -EINVAL; - } -#endif - } - /* verify validity of smpl_regs */ - if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) { - DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds)); - return -EINVAL; - } - /* probably more to add here */ - - return 0; -} - -static int -pfm_context_create(struct task_struct *task, pfm_context_t *ctx, void *req, int count, - struct pt_regs *regs) -{ - pfarg_context_t tmp; - void *uaddr = NULL; - int ret; - int ctx_flags; - pid_t notify_pid; - - /* a context has already been defined */ - if (ctx) return -EBUSY; - - /* - * not yet supported - */ - if (task != current) return -EINVAL; - - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - ret = pfx_is_sane(task, &tmp); - if (ret < 0) return ret; - - ctx_flags = tmp.ctx_flags; - - ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask); - if (ret) goto abort; - - ret = -ENOMEM; - - ctx = pfm_context_alloc(); - if (!ctx) goto error; - - /* record the creator (important for inheritance) */ - ctx->ctx_owner = current; - - notify_pid = tmp.ctx_notify_pid; - - spin_lock_init(&ctx->ctx_lock); - - if (notify_pid == current->pid) { - - ctx->ctx_notify_task = current; - task->thread.pfm_context = ctx; - - } else if (notify_pid!=0) { - struct task_struct *notify_task; - - read_lock(&tasklist_lock); - - notify_task = find_task_by_pid(notify_pid); - - if (notify_task) { - - ret = -EPERM; - - /* - * check if we can send this task a signal - */ - if (pfm_bad_permissions(notify_task)) { - read_unlock(&tasklist_lock); - goto buffer_error; - } - - /* - * make visible - * must be done inside critical section - * - * if the initialization does not go through it is still - * okay because child will do the scan for nothing which - * won't hurt. - */ - task->thread.pfm_context = ctx; - - /* - * will cause task to check on exit for monitored - * processes that would notify it. see release_thread() - * Note: the scan MUST be done in release thread, once the - * task has been detached from the tasklist otherwise you are - * exposed to race conditions. - */ - atomic_add(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); - - ctx->ctx_notify_task = notify_task; - } - read_unlock(&tasklist_lock); - } - - /* - * notification process does not exist - */ - if (notify_pid != 0 && ctx->ctx_notify_task == NULL) { - ret = -EINVAL; - goto buffer_error; - } - - if (tmp.ctx_smpl_entries) { - DBprintk(("sampling entries=%lu\n",tmp.ctx_smpl_entries)); - - ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, - tmp.ctx_smpl_entries, &uaddr); - if (ret<0) goto buffer_error; - - tmp.ctx_smpl_vaddr = uaddr; - } - /* initialization of context's flags */ - ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; - ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; - ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; - ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; - ctx->ctx_fl_frozen = 0; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - - /* - * setting this flag to 0 here means, that the creator or the task that the - * context is being attached are granted access. Given that a context can only - * be created for the calling process this, in effect only allows the creator - * to access the context. See pfm_protect() for more. - */ - ctx->ctx_fl_protected = 0; - - /* for system wide mode only (only 1 bit set) */ - ctx->ctx_cpu = ffz(~tmp.ctx_cpu_mask); - - atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */ - - sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ - - if (__copy_to_user(req, &tmp, sizeof(tmp))) { - ret = -EFAULT; - goto buffer_error; - } - - DBprintk(("context=%p, pid=%d notify_task=%p\n", - (void *)ctx, task->pid, ctx->ctx_notify_task)); - - DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d unsecure=%d\n", - (void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, - ctx->ctx_fl_block, ctx->ctx_fl_system, - ctx->ctx_fl_excl_idle, - ctx->ctx_fl_unsecure)); - - /* - * when no notification is required, we can make this visible at the last moment - */ - if (notify_pid == 0) task->thread.pfm_context = ctx; - /* - * pin task to CPU and force reschedule on exit to ensure - * that when back to user level the task runs on the designated - * CPU. - */ - if (ctx->ctx_fl_system) { - ctx->ctx_saved_cpus_allowed = task->cpus_allowed; - set_cpus_allowed(task, tmp.ctx_cpu_mask); - DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid, task->cpus_allowed)); - } - - return 0; - -buffer_error: - pfm_context_free(ctx); -error: - pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask); -abort: - /* make sure we don't leave anything behind */ - task->thread.pfm_context = NULL; - - return ret; -} - -static inline unsigned long -pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset) -{ - unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset; - unsigned long new_seed, old_seed = reg->seed, mask = reg->mask; - extern unsigned long carta_random32 (unsigned long seed); - - if (reg->flags & PFM_REGFL_RANDOM) { - new_seed = carta_random32(old_seed); - val -= (old_seed & mask); /* counter values are negative numbers! */ - if ((mask >> 32) != 0) - /* construct a full 64-bit random value: */ - new_seed |= carta_random32(old_seed >> 32) << 32; - reg->seed = new_seed; - } - reg->lval = val; - return val; -} - -static void -pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) -{ - unsigned long mask = ovfl_regs[0]; - unsigned long reset_others = 0UL; - unsigned long val; - int i, is_long_reset = (flag == PFM_PMD_LONG_RESET); - - /* - * now restore reset value on sampling overflowed counters - */ - mask >>= PMU_FIRST_COUNTER; - for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { - if (mask & 0x1) { - val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset); - reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0]; - - DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid, - is_long_reset ? "long" : "short", i, val)); - - /* upper part is ignored on rval */ - pfm_write_soft_counter(ctx, i, val); - } - } - - /* - * Now take care of resetting the other registers - */ - for(i = 0; reset_others; i++, reset_others >>= 1) { - - if ((reset_others & 0x1) == 0) continue; - - val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset); - - if (PMD_IS_COUNTING(i)) { - pfm_write_soft_counter(ctx, i, val); - } else { - ia64_set_pmd(i, val); - } - DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid, - is_long_reset ? "long" : "short", i, val)); - } - ia64_srlz_d(); -} - -static int -pfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ - struct thread_struct *th = &task->thread; - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; - unsigned long value, reset_pmds; - unsigned int cnum, reg_flags, flags; - int i; - int ret = -EINVAL; - - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - /* XXX: ctx locking may be required here */ - - for (i = 0; i < count; i++, req++) { - - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; - reg_flags = tmp.reg_flags; - value = tmp.reg_value; - reset_pmds = tmp.reg_reset_pmds[0]; - flags = 0; - - /* - * we reject all non implemented PMC as well - * as attempts to modify PMC[0-3] which are used - * as status registers by the PMU - */ - if (!PMC_IS_IMPL(cnum) || cnum < 4) { - DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum)); - goto error; - } - /* - * A PMC used to configure monitors must be: - * - system-wide session: privileged monitor - * - per-task : user monitor - * any other configuration is rejected. - */ - if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) { - DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); - - if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) { - DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system)); - goto error; - } - } - - if (PMC_IS_COUNTING(cnum)) { - pfm_monitor_t *p = (pfm_monitor_t *)&value; - /* - * enforce generation of overflow interrupt. Necessary on all - * CPUs. - */ - p->pmc_oi = 1; - - if (reg_flags & PFM_REGFL_OVFL_NOTIFY) { - /* - * must have a target for the signal - */ - if (ctx->ctx_notify_task == NULL) { - DBprintk(("cannot set ovfl_notify: no notify_task\n")); - goto error; - } - flags |= PFM_REGFL_OVFL_NOTIFY; - } - - if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM; - - /* verify validity of reset_pmds */ - if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) { - DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); - goto error; - } - } else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { - DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum)); - goto error; - } - - /* - * execute write checker, if any - */ - if (PMC_WR_FUNC(cnum)) { - ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs); - if (ret) goto error; - ret = -EINVAL; - } - - /* - * no error on this register - */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); - - /* - * update register return value, abort all if problem during copy. - * we only modify the reg_flags field. no check mode is fine because - * access has been verified upfront in sys_perfmonctl(). - * - * If this fails, then the software state is not modified - */ - if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT; - - /* - * Now we commit the changes to the software state - */ - - /* - * full flag update each time a register is programmed - */ - ctx->ctx_soft_pmds[cnum].flags = flags; - - if (PMC_IS_COUNTING(cnum)) { - ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds; - - /* mark all PMDS to be accessed as used */ - CTX_USED_PMD(ctx, reset_pmds); - } - - /* - * Needed in case the user does not initialize the equivalent - * PMD. Clearing is done in reset_pmu() so there is no possible - * leak here. - */ - CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]); - - /* - * keep copy the pmc, used for register reload - */ - th->pmc[cnum] = value; - - ia64_set_pmc(cnum, value); - - DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", - task->pid, cnum, value, - ctx->ctx_soft_pmds[cnum].flags, - ctx->ctx_used_pmds[0])); - - } - - return 0; - -error: - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); - - if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT; - - DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret)); - - return ret; -} - -static int -pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; - unsigned long value, hw_value; - unsigned int cnum; - int i; - int ret = -EINVAL; - - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - preempt_disable(); - - /* XXX: ctx locking may be required here */ - - - for (i = 0; i < count; i++, req++) { - - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; - value = tmp.reg_value; - - if (!PMD_IS_IMPL(cnum)) { - DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum)); - goto abort_mission; - } - - /* - * execute write checker, if any - */ - if (PMD_WR_FUNC(cnum)) { - unsigned long v = value; - ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs); - if (ret) goto abort_mission; - value = v; - ret = -EINVAL; - } - hw_value = value; - /* - * no error on this register - */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); - - if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT; - - /* - * now commit changes to software state - */ - - /* update virtualized (64bits) counter */ - if (PMD_IS_COUNTING(cnum)) { - ctx->ctx_soft_pmds[cnum].lval = value; - ctx->ctx_soft_pmds[cnum].val = value & ~pmu_conf.ovfl_val; - - hw_value = value & pmu_conf.ovfl_val; - - ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset; - ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset; - - ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed; - ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask; - } - - /* keep track of what we use */ - CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]); - - /* mark this register as used as well */ - CTX_USED_PMD(ctx, RDEP(cnum)); - - /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(cnum, hw_value); - - /* to go away */ - ia64_srlz_d(); - - DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx short_reset=0x%lx " - "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n", - task->pid, cnum, - value, hw_value, - ctx->ctx_soft_pmds[cnum].val, - ctx->ctx_soft_pmds[cnum].short_reset, - ctx->ctx_soft_pmds[cnum].long_reset, - ia64_get_pmd(cnum) & pmu_conf.ovfl_val, - PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', - ctx->ctx_used_pmds[0], - ctx->ctx_soft_pmds[cnum].reset_pmds[0])); - } - preempt_enable(); - return 0; - -abort_mission: - preempt_enable(); - - /* - * for now, we have only one possibility for error - */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); - - /* - * we change the return value to EFAULT in case we cannot write register return code. - * The caller first must correct this error, then a resubmission of the request will - * eventually yield the EINVAL. - */ - if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT; - - DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret)); - - return ret; -} - -static int -pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ - struct thread_struct *th = &task->thread; - unsigned long val, lval; - pfarg_reg_t *req = (pfarg_reg_t *)arg; - unsigned int cnum, reg_flags = 0; - int i, ret = 0; - -#if __GNUC__ < 3 - int foo; -#endif - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - /* - * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING - * This is required when the monitoring has been stoppped by user or kernel. - * If it is still going on, then that's fine because we a re not guaranteed - * to return an accurate value in this case. - */ - - /* XXX: ctx locking may be required here */ - - DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid)); - - for (i = 0; i < count; i++, req++) { - int me; -#if __GNUC__ < 3 - foo = __get_user(cnum, &req->reg_num); - if (foo) return -EFAULT; - foo = __get_user(reg_flags, &req->reg_flags); - if (foo) return -EFAULT; -#else - if (__get_user(cnum, &req->reg_num)) return -EFAULT; - if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT; -#endif - lval = 0UL; - - if (!PMD_IS_IMPL(cnum)) goto abort_mission; - /* - * we can only read the register that we use. That includes - * the one we explicitly initialize AND the one we want included - * in the sampling buffer (smpl_regs). - * - * Having this restriction allows optimization in the ctxsw routine - * without compromising security (leaks) - */ - if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission; - - /* - * If the task is not the current one, then we check if the - * PMU state is still in the local live register due to lazy ctxsw. - * If true, then we read directly from the registers. - */ - me = get_cpu(); - if (atomic_read(&ctx->ctx_last_cpu) == me){ - ia64_srlz_d(); - val = ia64_get_pmd(cnum); - DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val)); - } else { - val = th->pmd[cnum]; - } - - - if (PMD_IS_COUNTING(cnum)) { - /* - * XXX: need to check for overflow - */ - val &= pmu_conf.ovfl_val; - val += ctx->ctx_soft_pmds[cnum].val; - - lval = ctx->ctx_soft_pmds[cnum].lval; - } - - /* - * execute read checker, if any - */ - if (PMD_RD_FUNC(cnum)) { - unsigned long v = val; - ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs); - val = v; - } - - PFM_REG_RETFLAG_SET(reg_flags, ret); - - put_cpu(); - - DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", - cnum, ret, val, ia64_get_pmc(cnum))); - - /* - * update register return value, abort all if problem during copy. - * we only modify the reg_flags field. no check mode is fine because - * access has been verified upfront in sys_perfmonctl(). - */ - if (__put_user(cnum, &req->reg_num)) return -EFAULT; - if (__put_user(val, &req->reg_value)) return -EFAULT; - if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT; - if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT; - } - - return 0; - -abort_mission: - PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL); - /* - * XXX: if this fails, we stick with the original failure, flag not updated! - */ - __put_user(reg_flags, &req->reg_flags); - - return -EINVAL; -} - -#ifdef PFM_PMU_USES_DBR -/* - * Only call this function when a process it trying to - * write the debug registers (reading is always allowed) - */ -int -pfm_use_debug_registers(struct task_struct *task) -{ - pfm_context_t *ctx = task->thread.pfm_context; - int ret = 0; - - DBprintk(("called for [%d]\n", task->pid)); - - /* - * do it only once - */ - if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0; - - /* - * Even on SMP, we do not need to use an atomic here because - * the only way in is via ptrace() and this is possible only when the - * process is stopped. Even in the case where the ctxsw out is not totally - * completed by the time we come here, there is no way the 'stopped' process - * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine. - * So this is always safe. - */ - if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; - - LOCK_PFS(); - - /* - * We cannot allow setting breakpoints when system wide monitoring - * sessions are using the debug registers. - */ - if (pfm_sessions.pfs_sys_use_dbregs> 0) - ret = -1; - else - pfm_sessions.pfs_ptrace_use_dbregs++; - - DBprintk(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", - pfm_sessions.pfs_ptrace_use_dbregs, - pfm_sessions.pfs_sys_use_dbregs, - task->pid, ret)); - - UNLOCK_PFS(); - - return ret; -} - -/* - * This function is called for every task that exits with the - * IA64_THREAD_DBG_VALID set. This indicates a task which was - * able to use the debug registers for debugging purposes via - * ptrace(). Therefore we know it was not using them for - * perfmormance monitoring, so we only decrement the number - * of "ptraced" debug register users to keep the count up to date - */ -int -pfm_release_debug_registers(struct task_struct *task) -{ - int ret; - - LOCK_PFS(); - if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { - printk(KERN_DEBUG "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", - task->pid); - ret = -1; - } else { - pfm_sessions.pfs_ptrace_use_dbregs--; - ret = 0; - } - UNLOCK_PFS(); - - return ret; -} -#else /* PFM_PMU_USES_DBR is true */ -/* - * in case, the PMU does not use the debug registers, these two functions are nops. - * The first function is called from arch/ia64/kernel/ptrace.c. - * The second function is called from arch/ia64/kernel/process.c. - */ -int -pfm_use_debug_registers(struct task_struct *task) -{ - return 0; -} - -int -pfm_release_debug_registers(struct task_struct *task) -{ - return 0; -} -#endif /* PFM_PMU_USES_DBR */ - -static int -pfm_restart(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - void *sem = &ctx->ctx_restart_sem; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - if (task == current) { - DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", - task->pid, - ctx->ctx_fl_frozen, - ctx->ctx_ovfl_regs[0])); - - preempt_disable(); - pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); - - ctx->ctx_ovfl_regs[0] = 0UL; - - /* - * We ignore block/don't block because we never block - * for a self-monitoring process. - */ - ctx->ctx_fl_frozen = 0; - - if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; - } - - /* simply unfreeze */ - pfm_unfreeze_pmu(); - - preempt_enable(); - - return 0; - } - /* restart on another task */ - - /* - * if blocking, then post the semaphore. - * if non-blocking, then we ensure that the task will go into - * pfm_overflow_must_block() before returning to user mode. - * We cannot explicitly reset another task, it MUST always - * be done by the task itself. This works for system wide because - * the tool that is controlling the session is doing "self-monitoring". - * - * XXX: what if the task never goes back to user? - * - */ - if (CTX_OVFL_NOBLOCK(ctx) == 0) { - DBprintk(("unblocking %d \n", task->pid)); - up(sem); - } else { - struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); - task->thread.pfm_ovfl_block_reset = 1; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; - set_bit(TIF_NOTIFY_RESUME, &info->flags); - } -#if 0 - /* - * in case of non blocking mode, then it's just a matter of - * of reseting the sampling buffer (if any) index. The PMU - * is already active. - */ - - /* - * must reset the header count first - */ - if (CTX_HAS_SMPL(ctx)) { - DBprintk(("resetting sampling indexes for %d \n", task->pid)); - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; - } -#endif - return 0; -} - -static int -pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", - current->pid, - ctx->ctx_fl_system, PMU_OWNER(), - current)); - - preempt_disable(); - /* simply stop monitoring but not the PMU */ - if (ctx->ctx_fl_system) { - - /* disable dcr pp */ - ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); - - /* stop monitoring */ - pfm_clear_psr_pp(); - - ia64_srlz_i(); - - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - - ia64_psr(regs)->pp = 0; - - } else { - - /* stop monitoring */ - pfm_clear_psr_up(); - - ia64_srlz_i(); - - /* - * clear user level psr.up - */ - ia64_psr(regs)->up = 0; - } - preempt_enable(); - return 0; -} - -static int -pfm_disable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - preempt_disable(); - /* - * stop monitoring, freeze PMU, and save state in context - * this call will clear IA64_THREAD_PM_VALID for per-task sessions. - */ - pfm_flush_regs(task); - - if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; - } else { - ia64_psr(regs)->up = 0; - } - /* - * goes back to default behavior: no user level control - * no need to change live psr.sp because useless at the kernel level - */ - ia64_psr(regs)->sp = 1; - - DBprintk(("enabling psr.sp for [%d]\n", current->pid)); - - ctx->ctx_flags.state = PFM_CTX_DISABLED; - preempt_enable(); - - return 0; -} - -static int -pfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* - * if context was never enabled, then there is not much - * to do - */ - if (!CTX_IS_ENABLED(ctx)) goto skipped_stop; - - /* - * Disable context: stop monitoring, flush regs to software state (useless here), - * and freeze PMU - * - * The IA64_THREAD_PM_VALID is cleared by pfm_flush_regs() called from pfm_disable() - */ - pfm_disable(task, ctx, arg, count, regs); - - if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; - } else { - ia64_psr(regs)->up = 0; - } - -skipped_stop: - /* - * remove sampling buffer mapping, if any - */ - if (ctx->ctx_smpl_vaddr) { - pfm_remove_smpl_mapping(task); - ctx->ctx_smpl_vaddr = 0UL; - } - /* now free context and related state */ - pfm_context_exit(task); - - return 0; -} - -/* - * does nothing at the moment - */ -static int -pfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - return 0; -} - -static int -pfm_protect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - DBprintk(("context from [%d] is protected\n", task->pid)); - /* - * from now on, only the creator of the context has access to it - */ - ctx->ctx_fl_protected = 1; - - /* - * reinforce secure monitoring: cannot toggle psr.up - */ - if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1; - - return 0; -} - -static int -pfm_debug(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - unsigned int mode = *(unsigned int *)arg; - - pfm_sysctl.debug = mode == 0 ? 0 : 1; - - printk(KERN_INFO "perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off"); - - return 0; -} - -#ifdef PFM_PMU_USES_DBR - -typedef struct { - unsigned long ibr_mask:56; - unsigned long ibr_plm:4; - unsigned long ibr_ig:3; - unsigned long ibr_x:1; -} ibr_mask_reg_t; - -typedef struct { - unsigned long dbr_mask:56; - unsigned long dbr_plm:4; - unsigned long dbr_ig:2; - unsigned long dbr_w:1; - unsigned long dbr_r:1; -} dbr_mask_reg_t; - -typedef union { - unsigned long val; - ibr_mask_reg_t ibr; - dbr_mask_reg_t dbr; -} dbreg_t; - -static int -pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs) -{ - struct thread_struct *thread = &task->thread; - pfm_context_t *ctx = task->thread.pfm_context; - pfarg_dbreg_t tmp, *req = (pfarg_dbreg_t *)arg; - dbreg_t dbreg; - unsigned int rnum; - int first_time; - int i, ret = 0; - - /* - * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w - * ensuring that no real breakpoint can be installed via this call. - */ - - first_time = ctx->ctx_fl_using_dbreg == 0; - - /* - * check for debug registers in system wide mode - * - */ - LOCK_PFS(); - if (ctx->ctx_fl_system && first_time) { - if (pfm_sessions.pfs_ptrace_use_dbregs) - ret = -EBUSY; - else - pfm_sessions.pfs_sys_use_dbregs++; - } - UNLOCK_PFS(); - - if (ret != 0) return ret; - - if (ctx->ctx_fl_system) { - /* we mark ourselves as owner of the debug registers */ - ctx->ctx_fl_using_dbreg = 1; - DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid)); - } else if (first_time) { - ret= -EBUSY; - if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) { - DBprintk(("debug registers already in use for [%d]\n", task->pid)); - goto abort_mission; - } - /* we mark ourselves as owner of the debug registers */ - ctx->ctx_fl_using_dbreg = 1; - - DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid)); - /* - * Given debug registers cannot be used for both debugging - * and performance monitoring at the same time, we reuse - * the storage area to save and restore the registers on ctxsw. - */ - memset(task->thread.dbr, 0, sizeof(task->thread.dbr)); - memset(task->thread.ibr, 0, sizeof(task->thread.ibr)); - } - - if (first_time) { - DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid)); - /* - * clear hardware registers to make sure we don't - * pick up stale state. - * - * for a system wide session, we do not use - * thread.dbr, thread.ibr because this process - * never leaves the current CPU and the state - * is shared by all processes running on it - */ - for (i=0; i < (int) pmu_conf.num_ibrs; i++) { - ia64_set_ibr(i, 0UL); - } - ia64_srlz_i(); - for (i=0; i < (int) pmu_conf.num_dbrs; i++) { - ia64_set_dbr(i, 0UL); - } - ia64_srlz_d(); - } - - ret = -EFAULT; - - /* - * Now install the values into the registers - */ - for (i = 0; i < count; i++, req++) { - - if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission; - - rnum = tmp.dbreg_num; - dbreg.val = tmp.dbreg_value; - - ret = -EINVAL; - - if ((mode == 0 && !IBR_IS_IMPL(rnum)) || ((mode == 1) && !DBR_IS_IMPL(rnum))) { - DBprintk(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", - rnum, dbreg.val, mode, i, count)); - - goto abort_mission; - } - - /* - * make sure we do not install enabled breakpoint - */ - if (rnum & 0x1) { - if (mode == 0) - dbreg.ibr.ibr_x = 0; - else - dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; - } - - /* - * clear return flags and copy back to user - * - * XXX: fix once EAGAIN is implemented - */ - ret = -EFAULT; - - PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0); - - if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission; - - /* - * Debug registers, just like PMC, can only be modified - * by a kernel call. Moreover, perfmon() access to those - * registers are centralized in this routine. The hardware - * does not modify the value of these registers, therefore, - * if we save them as they are written, we can avoid having - * to save them on context switch out. This is made possible - * by the fact that when perfmon uses debug registers, ptrace() - * won't be able to modify them concurrently. - */ - if (mode == 0) { - CTX_USED_IBR(ctx, rnum); - - ia64_set_ibr(rnum, dbreg.val); - ia64_srlz_i(); - - thread->ibr[rnum] = dbreg.val; - - DBprintk(("write ibr%u=0x%lx used_ibrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_ibrs[0])); - } else { - CTX_USED_DBR(ctx, rnum); - - ia64_set_dbr(rnum, dbreg.val); - ia64_srlz_d(); - - thread->dbr[rnum] = dbreg.val; - - DBprintk(("write dbr%u=0x%lx used_dbrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_dbrs[0])); - } - } - - return 0; - -abort_mission: - /* - * in case it was our first attempt, we undo the global modifications - */ - if (first_time) { - LOCK_PFS(); - if (ctx->ctx_fl_system) { - pfm_sessions.pfs_sys_use_dbregs--; - } - UNLOCK_PFS(); - ctx->ctx_fl_using_dbreg = 0; - } - /* - * install error return flag - */ - if (ret != -EFAULT) { - /* - * XXX: for now we can only come here on EINVAL - */ - PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL); - if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT; - } - return ret; -} - -static int -pfm_write_ibrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - return pfm_write_ibr_dbr(0, task, arg, count, regs); -} - -static int -pfm_write_dbrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - return pfm_write_ibr_dbr(1, task, arg, count, regs); -} - -#endif /* PFM_PMU_USES_DBR */ - -static int -pfm_get_features(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ - pfarg_features_t tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.ft_version = PFM_VERSION; - tmp.ft_smpl_version = PFM_SMPL_VERSION; - - if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT; - - return 0; -} - -static int -pfm_start(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", - current->pid, - ctx->ctx_fl_system, PMU_OWNER(), - current)); - - if (PMU_OWNER() != task) { - printk(KERN_DEBUG "perfmon: pfm_start task [%d] not pmu owner\n", task->pid); - return -EINVAL; - } - - preempt_disable(); - if (ctx->ctx_fl_system) { - - PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); - - /* set user level psr.pp */ - ia64_psr(regs)->pp = 1; - - /* start monitoring at kernel level */ - pfm_set_psr_pp(); - - /* enable dcr pp */ - ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); - - ia64_srlz_i(); - - } else { - if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) { - preempt_enable(); - printk(KERN_DEBUG "perfmon: pfm_start task flag not set for [%d]\n", - task->pid); - return -EINVAL; - } - /* set user level psr.up */ - ia64_psr(regs)->up = 1; - - /* start monitoring at kernel level */ - pfm_set_psr_up(); - - ia64_srlz_i(); - } - - preempt_enable(); - return 0; -} - -static int -pfm_enable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - int me; - - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - me = get_cpu(); /* make sure we're not migrated or preempted */ - - if (ctx->ctx_fl_system == 0 && PMU_OWNER() && PMU_OWNER() != current) - pfm_lazy_save_regs(PMU_OWNER()); - - /* reset all registers to stable quiet state */ - pfm_reset_pmu(task); - - /* make sure nothing starts */ - if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; - ia64_psr(regs)->up = 0; /* just to make sure! */ - - /* make sure monitoring is stopped */ - pfm_clear_psr_pp(); - ia64_srlz_i(); - - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); - if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); - } else { - /* - * needed in case the task was a passive task during - * a system wide session and now wants to have its own - * session - */ - ia64_psr(regs)->pp = 0; /* just to make sure! */ - ia64_psr(regs)->up = 0; - - /* make sure monitoring is stopped */ - pfm_clear_psr_up(); - ia64_srlz_i(); - - DBprintk(("clearing psr.sp for [%d]\n", current->pid)); - - /* allow user level control */ - ia64_psr(regs)->sp = 0; - - /* PMU state will be saved/restored on ctxsw */ - task->thread.flags |= IA64_THREAD_PM_VALID; - } - - SET_PMU_OWNER(task); - - ctx->ctx_flags.state = PFM_CTX_ENABLED; - atomic_set(&ctx->ctx_last_cpu, me); - - /* simply unfreeze */ - pfm_unfreeze_pmu(); - - put_cpu(); - - return 0; -} - -static int -pfm_get_pmc_reset(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; - unsigned int cnum; - int i, ret = -EINVAL; - - for (i = 0; i < count; i++, req++) { - - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; - - if (!PMC_IS_IMPL(cnum)) goto abort_mission; - - tmp.reg_value = PMC_DFL_VAL(cnum); - - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); - - DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); - - if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; - } - return 0; -abort_mission: - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); - if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT; - - return ret; -} - -/* - * functions MUST be listed in the increasing order of their index (see permfon.h) - */ -static pfm_cmd_desc_t pfm_cmd_tab[]={ -/* 0 */{ NULL, 0, 0, 0}, /* not used */ -/* 1 */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 2 */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 3 */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 4 */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 5 */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 6 */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 7 */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 8 */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)}, -/* 9 */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0}, -/* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0}, -/* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)}, -/* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 16 */{ NULL, 0, 0, 0}, /* not used */ -/* 17 */{ NULL, 0, 0, 0}, /* not used */ -/* 18 */{ NULL, 0, 0, 0}, /* not used */ -/* 19 */{ NULL, 0, 0, 0}, /* not used */ -/* 20 */{ NULL, 0, 0, 0}, /* not used */ -/* 21 */{ NULL, 0, 0, 0}, /* not used */ -/* 22 */{ NULL, 0, 0, 0}, /* not used */ -/* 23 */{ NULL, 0, 0, 0}, /* not used */ -/* 24 */{ NULL, 0, 0, 0}, /* not used */ -/* 25 */{ NULL, 0, 0, 0}, /* not used */ -/* 26 */{ NULL, 0, 0, 0}, /* not used */ -/* 27 */{ NULL, 0, 0, 0}, /* not used */ -/* 28 */{ NULL, 0, 0, 0}, /* not used */ -/* 29 */{ NULL, 0, 0, 0}, /* not used */ -/* 30 */{ NULL, 0, 0, 0}, /* not used */ -/* 31 */{ NULL, 0, 0, 0}, /* not used */ -#ifdef PFM_PMU_USES_DBR -/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}, -/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)} -#endif -}; -#define PFM_CMD_COUNT ARRAY_SIZE(pfm_cmd_tab) - -static int -check_task_state(struct task_struct *task) -{ - int ret = 0; -#ifdef CONFIG_SMP - /* We must wait until the state has been completely - * saved. There can be situations where the reader arrives before - * after the task is marked as STOPPED but before pfm_save_regs() - * is completed. - */ - if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY; - DBprintk(("before wait_task_inactive [%d] state %ld\n", task->pid, task->state)); - wait_task_inactive(task); - DBprintk(("after wait_task_inactive [%d] state %ld\n", task->pid, task->state)); -#else - if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) { - DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state)); - ret = -EBUSY; - } -#endif - return ret; -} - -asmlinkage long -sys_perfmonctl (pid_t pid, int cmd, void *arg, int count, long arg5, long arg6, long arg7, - long arg8, long stack) -{ - struct pt_regs *regs = (struct pt_regs *)&stack; - struct task_struct *task = current; - pfm_context_t *ctx; - size_t sz; - int ret, narg; - - /* - * reject any call if perfmon was disabled at initialization time - */ - if (PFM_IS_DISABLED()) return -ENOSYS; - - DBprintk(("cmd=%d idx=%d valid=%d narg=0x%x\n", cmd, PFM_CMD_IDX(cmd), - PFM_CMD_IS_VALID(cmd), PFM_CMD_NARG(cmd))); - - if (PFM_CMD_IS_VALID(cmd) == 0) return -EINVAL; - - /* ingore arguments when command has none */ - narg = PFM_CMD_NARG(cmd); - if ((narg == PFM_CMD_ARG_MANY && count == 0) || (narg > 0 && narg != count)) return -EINVAL; - - sz = PFM_CMD_ARG_SIZE(cmd); - - if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT; - - if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT; - - if (PFM_CMD_USE_PID(cmd)) { - /* - * XXX: may need to fine tune this one - */ - if (pid < 2) return -EPERM; - - if (pid != current->pid) { - - ret = -ESRCH; - - read_lock(&tasklist_lock); - - task = find_task_by_pid(pid); - - if (task) get_task_struct(task); - - read_unlock(&tasklist_lock); - - if (!task) goto abort_call; - - ret = -EPERM; - - if (pfm_bad_permissions(task)) goto abort_call; - - if (PFM_CMD_CHK(cmd)) { - ret = check_task_state(task); - if (ret != 0) goto abort_call; - } - } - } - - ctx = task->thread.pfm_context; - - if (PFM_CMD_USE_CTX(cmd)) { - ret = -EINVAL; - if (ctx == NULL) { - DBprintk(("no context for task %d\n", task->pid)); - goto abort_call; - } - ret = -EPERM; - /* - * we only grant access to the context if: - * - the caller is the creator of the context (ctx_owner) - * OR - the context is attached to the caller AND The context IS NOT - * in protected mode - */ - if (ctx->ctx_owner != current && (ctx->ctx_fl_protected || task != current)) { - DBprintk(("context protected, no access for [%d]\n", task->pid)); - goto abort_call; - } - } - - ret = (*pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func)(task, ctx, arg, count, regs); - -abort_call: - if (task && task != current) put_task_struct(task); - - return ret; -} - -/* - * send SIGPROF to register task, must be invoked when it - * is safe to send a signal, e.g., not holding any runqueue - * related locks. - */ -static int -pfm_notify_user(pfm_context_t *ctx) -{ - struct siginfo si; - int ret; - - if (ctx->ctx_notify_task == NULL) { - DBprintk(("[%d] no notifier\n", current->pid)); - return -EINVAL; - } - - si.si_errno = 0; - si.si_addr = NULL; - si.si_pid = current->pid; /* who is sending */ - si.si_signo = SIGPROF; - si.si_code = PROF_OVFL; - - si.si_pfm_ovfl[0] = ctx->ctx_ovfl_regs[0]; - - /* - * when the target of the signal is not ourself, we have to be more - * careful. The notify_task may being cleared by the target task itself - * in release_thread(). We must ensure mutual exclusion here such that - * the signal is delivered (even to a dying task) safely. - */ - - if (ctx->ctx_notify_task != current) { - /* - * grab the notification lock for this task - * This guarantees that the sequence: test + send_signal - * is atomic with regards to the ctx_notify_task field. - * - * We need a spinlock and not just an atomic variable for this. - * - */ - spin_lock(&ctx->ctx_lock); - - /* - * now notify_task cannot be modified until we're done - * if NULL, they it got modified while we were in the handler - */ - if (ctx->ctx_notify_task == NULL) { - - spin_unlock(&ctx->ctx_lock); - - /* - * If we've lost the notified task, then we will run - * to completion wbut keep the PMU frozen. Results - * will be incorrect anyway. We do not kill task - * to leave it possible to attach perfmon context - * to already running task. - */ - printk("perfmon: pfm_notify_user() lost notify_task\n"); - DBprintk_ovfl(("notification task has disappeared !\n")); - - /* we cannot afford to block now */ - ctx->ctx_fl_block = 0; - - return -EINVAL; - } - - /* - * required by send_sig_info() to make sure the target - * task does not disappear on us. - */ - read_lock(&tasklist_lock); - } - /* - * in this case, we don't stop the task, we let it go on. It will - * necessarily go to the signal handler (if any) when it goes back to - * user mode. - */ - DBprintk_ovfl(("[%d] sending notification to [%d]\n", - current->pid, ctx->ctx_notify_task->pid)); - - /* - * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock - */ - ret = send_sig_info(SIGPROF, &si, ctx->ctx_notify_task); - if (ret) { - printk("perfmon: send_sig_info(process %d, SIGPROF)=%d\n", - ctx->ctx_notify_task->pid, ret); - } - - /* - * now undo the protections in order - */ - if (ctx->ctx_notify_task != current) { - read_unlock(&tasklist_lock); - spin_unlock(&ctx->ctx_lock); - } - return ret; -} - -void -pfm_ovfl_block_reset(void) -{ - struct thread_struct *th = ¤t->thread; - pfm_context_t *ctx = current->thread.pfm_context; - unsigned int reason; - int ret; - - /* - * clear the flag, to make sure we won't get here - * again - */ - th->pfm_ovfl_block_reset = 0; - clear_thread_flag(TIF_NOTIFY_RESUME); - - /* - * do some sanity checks first - */ - if (!ctx) { - printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); - return; - } - /* - * extract reason for being here and clear - */ - reason = ctx->ctx_fl_trap_reason; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - - DBprintk(("[%d] reason=%d\n", current->pid, reason)); - - /* - * just here for a reset (non-blocking context only) - */ - if (reason == PFM_TRAP_REASON_RESET) goto non_blocking; - - /* - * first notify user. This can fail if notify_task has disappeared. - */ - if (reason == PFM_TRAP_REASON_SIG || reason == PFM_TRAP_REASON_BLOCKSIG) { - ret = pfm_notify_user(ctx); - if (ret) return; - } - - /* - * came here just to signal (non-blocking) - */ - if (reason == PFM_TRAP_REASON_SIG) return; - - DBprintk(("[%d] before sleeping\n", current->pid)); - - /* - * may go through without blocking on SMP systems - * if restart has been received already by the time we call down() - */ - ret = down_interruptible(&ctx->ctx_restart_sem); - - DBprintk(("[%d] after sleeping ret=%d\n", current->pid, ret)); - - /* - * in case of interruption of down() we don't restart anything - */ - if (ret >= 0) { - -non_blocking: - /* we reactivate on context switch */ - ctx->ctx_fl_frozen = 0; - /* - * the ovfl_sem is cleared by the restart task and this is safe because we always - * use the local reference - */ - - pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); - - ctx->ctx_ovfl_regs[0] = 0UL; - - /* - * Unlock sampling buffer and reset index atomically - * XXX: not really needed when blocking - */ - if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; - } - - pfm_unfreeze_pmu(); - - /* state restored, can go back to work (user mode) */ - } -} - -/* - * This function will record an entry in the sampling if it is not full already. - * Return: - * 0 : buffer is not full (did not BECOME full: still space or was already full) - * 1 : buffer is full (recorded the last entry) - */ -static int -pfm_record_sample(struct task_struct *task, pfm_context_t *ctx, unsigned long ovfl_mask, struct pt_regs *regs) -{ - pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; - unsigned long *e, m, idx; - perfmon_smpl_entry_t *h; - int j; - - - idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries)); - - /* - * XXX: there is a small chance that we could run out on index before resetting - * but index is unsigned long, so it will take some time..... - * We use > instead of == because fetch_and_add() is off by one (see below) - * - * This case can happen in non-blocking mode or with multiple processes. - * For non-blocking, we need to reload and continue. - */ - if (idx > psb->psb_entries) return 0; - - /* first entry is really entry 0, not 1 caused by fetch_and_add */ - idx--; - - h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); - - /* - * initialize entry header - */ - h->pid = current->pid; - h->cpu = get_cpu(); - h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL; - h->ip = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL; - h->regs = ovfl_mask; /* which registers overflowed */ - - /* guaranteed to monotonically increase on each cpu */ - h->stamp = pfm_get_stamp(); - - /* position for first pmd */ - e = (unsigned long *)(h+1); - - /* - * selectively store PMDs in increasing index number - */ - m = ctx->ctx_smpl_regs[0]; - for (j=0; m; m >>=1, j++) { - - if ((m & 0x1) == 0) continue; - - if (PMD_IS_COUNTING(j)) { - *e = pfm_read_soft_counter(ctx, j); - } else { - *e = ia64_get_pmd(j); /* slow */ - } - DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); - e++; - } - pfm_stats[h->cpu].pfm_recorded_samples_count++; - - /* - * make the new entry visible to user, needs to be atomic - */ - ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); - - DBprintk_ovfl(("index=%ld entries=%ld hdr_count=%ld\n", - idx, psb->psb_entries, psb->psb_hdr->hdr_count)); - /* - * sampling buffer full ? - */ - if (idx == (psb->psb_entries-1)) { - DBprintk_ovfl(("sampling buffer full\n")); - /* - * XXX: must reset buffer in blocking mode and lost notified - */ - pfm_stats[h->cpu].pfm_full_smpl_buffer_count++; - put_cpu(); - return 1; - } - put_cpu(); - return 0; -} - -/* - * main overflow processing routine. - * it can be called from the interrupt path or explicitly during the context switch code - * Arguments: - * mode: 0=coming from PMU interrupt, 1=coming from ctxsw - * - * Return: - * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen - */ -static unsigned long -pfm_overflow_handler(int mode, struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) -{ - struct thread_struct *t; - unsigned long mask; - unsigned long old_val; - unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; - int i; - int ret = 1; - /* - * It is never safe to access the task for which the overflow interrupt is destinated - * using the current variable as the interrupt may occur in the middle of a context switch - * where current does not hold the task that is running yet. - * - * For monitoring, however, we do need to get access to the task which caused the overflow - * to account for overflow on the counters. - * - * We accomplish this by maintaining a current owner of the PMU per CPU. During context - * switch the ownership is changed in a way such that the reflected owner is always the - * valid one, i.e. the one that caused the interrupt. - */ - - preempt_disable(); - - t = &task->thread; - - /* - * XXX: debug test - * Don't think this could happen given upfront tests - */ - if ((t->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { - printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d not " - "using perfmon\n", task->pid); - preempt_enable_no_resched(); - return 0x1; - } - /* - * sanity test. Should never happen - */ - if ((pmc0 & 0x1) == 0) { - printk(KERN_DEBUG "perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", - task->pid, pmc0); - preempt_enable_no_resched(); - return 0x0; - } - - mask = pmc0 >> PMU_FIRST_COUNTER; - - DBprintk_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s" - " mode used_pmds=0x%lx used_pmcs=0x%lx reload_pmcs=0x%lx\n", - pmc0, task->pid, (regs ? regs->cr_iip : 0), - CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", - ctx->ctx_used_pmds[0], - ctx->ctx_used_pmcs[0], - ctx->ctx_reload_pmcs[0])); - - /* - * First we update the virtual counters - */ - for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { - - /* skip pmd which did not overflow */ - if ((mask & 0x1) == 0) continue; - - DBprintk_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", - i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val)); - - /* - * Note that the pmd is not necessarily 0 at this point as qualified events - * may have happened before the PMU was frozen. The residual count is not - * taken into consideration here but will be with any read of the pmd via - * pfm_read_pmds(). - */ - old_val = ctx->ctx_soft_pmds[i].val; - ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val; - - /* - * check for overflow condition - */ - if (old_val > ctx->ctx_soft_pmds[i].val) { - - ovfl_pmds |= 1UL << i; - - if (PMC_OVFL_NOTIFY(ctx, i)) { - ovfl_notify |= 1UL << i; - } - } - DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", - i, ctx->ctx_soft_pmds[i].val, old_val, - ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify)); - } - - /* - * check for sampling buffer - * - * if present, record sample only when a 64-bit counter has overflowed. - * We propagate notification ONLY when buffer becomes full. - */ - if(CTX_HAS_SMPL(ctx) && ovfl_pmds) { - ret = pfm_record_sample(task, ctx, ovfl_pmds, regs); - if (ret == 1) { - /* - * Sampling buffer became full - * If no notication was requested, then we reset buffer index - * and reset registers (done below) and resume. - * If notification requested, then defer reset until pfm_restart() - */ - if (ovfl_notify == 0UL) { - ctx->ctx_psb->psb_hdr->hdr_count = 0UL; - ctx->ctx_psb->psb_index = 0UL; - } - } else { - /* - * sample recorded in buffer, no need to notify user - */ - ovfl_notify = 0UL; - } - } - - /* - * No overflow requiring a user level notification - */ - if (ovfl_notify == 0UL) { - if (ovfl_pmds) - pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET); - preempt_enable_no_resched(); - return 0x0UL; - } - - /* - * keep track of what to reset when unblocking - */ - ctx->ctx_ovfl_regs[0] = ovfl_pmds; - - DBprintk_ovfl(("block=%d notify [%d] current [%d]\n", - ctx->ctx_fl_block, - ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, - current->pid )); - - /* - * ctx_notify_task could already be NULL, checked in pfm_notify_user() - */ - if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_notify_task != task) { - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCKSIG; - } else { - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG; - } - /* - * we cannot block in system wide mode and we do not go - * through the PMU ctxsw code. Therefore we can generate - * the notification here. In system wide mode, the current - * task maybe different from the task controlling the session - * on this CPU, therefore owner can be different from current. - * - * In per-process mode, this function gets called from - * the interrupt handler or pfm_load_regs(). The mode argument - * tells where we are coming from. When coming from the interrupt - * handler, it is safe to notify (send signal) right here because - * we do not hold any runqueue locks needed by send_sig_info(). - * - * However when coming from ctxsw, we cannot send the signal here. - * It must be deferred until we are sure we do not hold any runqueue - * related locks. The current task maybe different from the owner - * only in UP mode. The deferral is implemented using the - * TIF_NOTIFY_RESUME mechanism. In this case, the pending work - * is checked when the task is about to leave the kernel (see - * entry.S). As of this version of perfmon, a kernel only - * task cannot be monitored in per-process mode. Therefore, - * when this function gets called from pfm_load_regs(), we know - * we have a user level task which will eventually either exit - * or leave the kernel, and thereby go through the checkpoint - * for TIF_*. - */ - if (ctx->ctx_fl_system || mode == 0) { - pfm_notify_user(ctx); - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - } else { - struct thread_info *info; - - /* - * given that TIF_NOTIFY_RESUME is not specific to - * perfmon, we need to have a second level check to - * verify the source of the notification. - */ - task->thread.pfm_ovfl_block_reset = 1; - /* - * when coming from ctxsw, current still points to the - * previous task, therefore we must work with task and not current. - */ - info = ((struct thread_info *) ((char *) task + IA64_TASK_SIZE)); - set_bit(TIF_NOTIFY_RESUME, &info->flags); - } - - /* - * keep the PMU frozen until either pfm_restart() or - * task completes (non-blocking or notify_task gone). - */ - ctx->ctx_fl_frozen = 1; - - DBprintk_ovfl(("current [%d] owner [%d] mode=%d return pmc0=0x%x must_block=%ld reason=%d\n", - current->pid, - PMU_OWNER() ? PMU_OWNER()->pid : -1, - mode, - ctx->ctx_fl_frozen ? 0x1 : 0x0, - t->pfm_ovfl_block_reset, - ctx->ctx_fl_trap_reason)); - - preempt_enable_no_resched(); - return 0x1UL; -} - -static irqreturn_t -pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) -{ - u64 pmc0; - struct task_struct *task; - pfm_context_t *ctx; - - pfm_stats[get_cpu()].pfm_ovfl_intr_count++; - - /* - * if an alternate handler is registered, just bypass the default one - */ - if (pfm_alternate_intr_handler) { - (*pfm_alternate_intr_handler->handler)(irq, arg, regs); - put_cpu(); - return IRQ_HANDLED; - } - - /* - * srlz.d done before arriving here - * - * This is slow - */ - pmc0 = ia64_get_pmc(0); - - /* - * if we have some pending bits set - * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 - */ - if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) { - /* - * we assume that pmc0.fr is always set here - */ - ctx = task->thread.pfm_context; - - /* sanity check */ - if (!ctx) { - printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d has " - "no PFM context\n", task->pid); - put_cpu(); - return IRQ_HANDLED; - } - - /* - * assume PMC[0].fr = 1 at this point - */ - pmc0 = pfm_overflow_handler(0, task, ctx, pmc0, regs); - /* - * we can only update pmc0 when the overflow - * is for the current context or we are in system - * wide mode. In UP (per-task) the current - * task may not be the one owning the PMU, - * same thing for system-wide. - */ - if (task == current || ctx->ctx_fl_system) { - /* - * We always clear the overflow status bits and either unfreeze - * or keep the PMU frozen. - */ - ia64_set_pmc(0, pmc0); - ia64_srlz_d(); - } else { - task->thread.pmc[0] = pmc0; - } - } else { - pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++; - } - put_cpu_no_resched(); - return IRQ_HANDLED; -} - -/* for debug only */ -static int -pfm_proc_info(char *page) -{ - char *p = page; - int i; - - p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); - p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val); - - for(i=0; i < NR_CPUS; i++) { - if (cpu_online(i) == 0) continue; - p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count); - p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count); - p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count); - p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count); - p += sprintf(p, "CPU%-2d syst_wide : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_SYST_WIDE ? 1 : 0); - p += sprintf(p, "CPU%-2d dcr_pp : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_DCR_PP ? 1 : 0); - p += sprintf(p, "CPU%-2d exclude idle : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0); - p += sprintf(p, "CPU%-2d owner : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); - } - - LOCK_PFS(); - - p += sprintf(p, "proc_sessions : %u\n" - "sys_sessions : %u\n" - "sys_use_dbregs : %u\n" - "ptrace_use_dbregs : %u\n", - pfm_sessions.pfs_task_sessions, - pfm_sessions.pfs_sys_sessions, - pfm_sessions.pfs_sys_use_dbregs, - pfm_sessions.pfs_ptrace_use_dbregs); - - UNLOCK_PFS(); - - return p - page; -} - -/* /proc interface, for debug only */ -static int -perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - int len = pfm_proc_info(page); - - if (len <= off+count) *eof = 1; - - *start = page + off; - len -= off; - - if (len>count) len = count; - if (len<0) len = 0; - - return len; -} - -/* - * we come here as soon as PFM_CPUINFO_SYST_WIDE is set. This happens - * during pfm_enable() hence before pfm_start(). We cannot assume monitoring - * is active or inactive based on mode. We must rely on the value in - * cpu_data(i)->pfm_syst_info - */ -void -pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) -{ - struct pt_regs *regs; - unsigned long dcr; - unsigned long dcr_pp; - - preempt_disable(); - dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0; - - /* - * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 - * on every CPU, so we can rely on the pid to identify the idle task. - */ - if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) { - regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET); - regs--; - ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0; - preempt_enable(); - return; - } - /* - * if monitoring has started - */ - if (dcr_pp) { - dcr = ia64_get_dcr(); - /* - * context switching in? - */ - if (is_ctxswin) { - /* mask monitoring for the idle task */ - ia64_set_dcr(dcr & ~IA64_DCR_PP); - pfm_clear_psr_pp(); - ia64_srlz_i(); - preempt_enable(); - return; - } - /* - * context switching out - * restore monitoring for next task - * - * Due to inlining this odd if-then-else construction generates - * better code. - */ - ia64_set_dcr(dcr |IA64_DCR_PP); - pfm_set_psr_pp(); - ia64_srlz_i(); - } - preempt_enable(); -} - -void -pfm_save_regs (struct task_struct *task) -{ - pfm_context_t *ctx; - unsigned long mask; - u64 psr; - int i; - - preempt_disable(); - - ctx = task->thread.pfm_context; - - - /* - * save current PSR: needed because we modify it - */ - psr = pfm_get_psr(); - - /* - * stop monitoring: - * This is the last instruction which can generate an overflow - * - * We do not need to set psr.sp because, it is irrelevant in kernel. - * It will be restored from ipsr when going back to user level - */ - pfm_clear_psr_up(); - ia64_srlz_i(); - - ctx->ctx_saved_psr = psr; - -#ifdef CONFIG_SMP - /* - * We do not use a lazy scheme in SMP because - * of the new scheduler which masks interrupts - * during low-level context switch. So we save - * all the PMD register we use and restore on - * ctxsw in. - * - * release ownership of this PMU. - * must be done before we save the registers. - */ - SET_PMU_OWNER(NULL); - - /* - * save PMDs - */ - ia64_srlz_d(); - - mask = ctx->ctx_used_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) task->thread.pmd[i] =ia64_get_pmd(i); - } - - /* - * save pmc0 - */ - task->thread.pmc[0] = ia64_get_pmc(0); - - /* - * force a full reload - */ - atomic_set(&ctx->ctx_last_cpu, -1); -#endif - preempt_enable(); -} - -static void -pfm_lazy_save_regs (struct task_struct *task) -{ - pfm_context_t *ctx; - struct thread_struct *t; - unsigned long mask; - int i; - - preempt_disable(); - DBprintk(("on [%d] by [%d]\n", task->pid, current->pid)); - - t = &task->thread; - ctx = task->thread.pfm_context; - - /* - * do not own the PMU - */ - SET_PMU_OWNER(NULL); - - ia64_srlz_d(); - - /* - * XXX needs further optimization. - * Also must take holes into account - */ - mask = ctx->ctx_used_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); - } - - /* save pmc0 */ - t->pmc[0] = ia64_get_pmc(0); - - /* not owned by this CPU */ - atomic_set(&ctx->ctx_last_cpu, -1); - preempt_enable(); -} - -void -pfm_load_regs (struct task_struct *task) -{ - struct thread_struct *t; - pfm_context_t *ctx; - struct task_struct *owner; - unsigned long mask; - u64 psr; - int i; - - preempt_disable(); - - owner = PMU_OWNER(); - ctx = task->thread.pfm_context; - t = &task->thread; - - if (ctx == NULL) { - preempt_enable(); - printk("perfmon: pfm_load_regs: null ctx for [%d]\n", task->pid); - return; - } - - /* - * we restore ALL the debug registers to avoid picking up - * stale state. - * - * This must be done even when the task is still the owner - * as the registers may have been modified via ptrace() - * (not perfmon) by the previous task. - * - * XXX: dealing with this in a lazy fashion requires modifications - * to the way the the debug registers are managed. This is will done - * in the next version of perfmon. - */ - if (ctx->ctx_fl_using_dbreg) { - for (i=0; i < (int) pmu_conf.num_ibrs; i++) { - ia64_set_ibr(i, t->ibr[i]); - } - ia64_srlz_i(); - for (i=0; i < (int) pmu_conf.num_dbrs; i++) { - ia64_set_dbr(i, t->dbr[i]); - } - ia64_srlz_d(); - } - - /* - * if we were the last user, then nothing to do except restore psr - * this path cannot be used in SMP - */ - if (owner == task) { - if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) - DBprintk(("invalid last_cpu=%d for [%d]\n", - atomic_read(&ctx->ctx_last_cpu), task->pid)); - - psr = ctx->ctx_saved_psr; - pfm_set_psr_l(psr); - preempt_enable(); - return; - } - - /* - * someone else is still using the PMU, first push it out and - * then we'll be able to install our stuff ! - * - * not possible in SMP - */ - if (owner) pfm_lazy_save_regs(owner); - - /* - * To avoid leaking information to the user level when psr.sp=0, - * we must reload ALL implemented pmds (even the ones we don't use). - * In the kernel we only allow PFM_READ_PMDS on registers which - * we initialized or requested (sampling) so there is no risk there. - * - * As an optimization, we will only reload the PMD that we use when - * the context is in protected mode, i.e. psr.sp=1 because then there - * is no leak possible. - */ - mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ? ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val); - } - - /* - * PMC0 is never set in the mask because it is always restored - * separately. - * - * ALL PMCs are systematically reloaded, unused registers - * get their default (PAL reset) values to avoid picking up - * stale configuration. - */ - mask = ctx->ctx_reload_pmcs[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); - } - - /* - * manually invoke core interrupt handler - * if the task had a pending overflow when it was ctxsw out. - * Side effect on ctx_fl_frozen is possible. - */ - if (t->pmc[0] & ~0x1) { - t->pmc[0] = pfm_overflow_handler(1, task, ctx, t->pmc[0], NULL); - } - - /* - * unfreeze PMU if possible - */ - if (ctx->ctx_fl_frozen == 0) pfm_unfreeze_pmu(); - - atomic_set(&ctx->ctx_last_cpu, smp_processor_id()); - - SET_PMU_OWNER(task); - - /* - * restore the psr we changed in pfm_save_regs() - */ - psr = ctx->ctx_saved_psr; - preempt_enable(); - pfm_set_psr_l(psr); -} - -/* - * XXX: make this routine able to work with non current context - */ -static void -pfm_reset_pmu(struct task_struct *task) -{ - struct thread_struct *t = &task->thread; - pfm_context_t *ctx = t->pfm_context; - int i; - - if (task != current) { - printk("perfmon: invalid task in pfm_reset_pmu()\n"); - return; - } - preempt_disable(); - - /* Let's make sure the PMU is frozen */ - pfm_freeze_pmu(); - - /* - * install reset values for PMC. We skip PMC0 (done above) - * XX: good up to 64 PMCS - */ - for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) { - if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue; - ia64_set_pmc(i, PMC_DFL_VAL(i)); - /* - * When restoring context, we must restore ALL pmcs, even the ones - * that the task does not use to avoid leaks and possibly corruption - * of the sesion because of configuration conflicts. So here, we - * initialize the entire set used in the context switch restore routine. - */ - t->pmc[i] = PMC_DFL_VAL(i); - DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i])); - } - - /* - * clear reset values for PMD. - * XXX: good up to 64 PMDS. - */ - for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) { - if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue; - ia64_set_pmd(i, 0UL); - t->pmd[i] = 0UL; - } - - /* - * On context switched restore, we must restore ALL pmc and ALL pmd even - * when they are not actively used by the task. In UP, the incoming process - * may otherwise pick up left over PMC, PMD state from the previous process. - * As opposed to PMD, stale PMC can cause harm to the incoming - * process because they may change what is being measured. - * Therefore, we must systematically reinstall the entire - * PMC state. In SMP, the same thing is possible on the - * same CPU but also on between 2 CPUs. - * - * The problem with PMD is information leaking especially - * to user level when psr.sp=0 - * - * There is unfortunately no easy way to avoid this problem - * on either UP or SMP. This definitively slows down the - * pfm_load_regs() function. - */ - - /* - * We must include all the PMC in this mask to make sure we don't - * see any side effect of a stale state, such as opcode matching - * or range restrictions, for instance. - * - * We never directly restore PMC0 so we do not include it in the mask. - */ - ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1; - /* - * We must include all the PMD in this mask to avoid picking - * up stale value and leak information, especially directly - * at the user level when psr.sp=0 - */ - ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0]; - - /* - * Keep track of the pmds we want to sample - * XXX: may be we don't need to save/restore the DEAR/IEAR pmds - * but we do need the BTB for sure. This is because of a hardware - * buffer of 1 only for non-BTB pmds. - * - * We ignore the unimplemented pmds specified by the user - */ - ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0]; - ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ - - /* - * useful in case of re-enable after disable - */ - ctx->ctx_used_ibrs[0] = 0UL; - ctx->ctx_used_dbrs[0] = 0UL; - - ia64_srlz_d(); - preempt_enable(); -} - -/* - * This function is called when a thread exits (from exit_thread()). - * This is a simplified pfm_save_regs() that simply flushes the current - * register state into the save area taking into account any pending - * overflow. This time no notification is sent because the task is dying - * anyway. The inline processing of overflows avoids loosing some counts. - * The PMU is frozen on exit from this call and is to never be reenabled - * again for this task. - * - */ -void -pfm_flush_regs (struct task_struct *task) -{ - pfm_context_t *ctx; - u64 pmc0; - unsigned long mask2, val; - int i; - - ctx = task->thread.pfm_context; - - if (ctx == NULL) return; - - /* - * that's it if context already disabled - */ - if (ctx->ctx_flags.state == PFM_CTX_DISABLED) return; - - preempt_disable(); - /* - * stop monitoring: - * This is the only way to stop monitoring without destroying overflow - * information in PMC[0]. - * This is the last instruction which can cause overflow when monitoring - * in kernel. - * By now, we could still have an overflow interrupt in-flight. - */ - if (ctx->ctx_fl_system) { - - - /* disable dcr pp */ - ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); - - /* stop monitoring */ - pfm_clear_psr_pp(); - - ia64_srlz_i(); - - PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); - } else { - - /* stop monitoring */ - pfm_clear_psr_up(); - - ia64_srlz_i(); - - /* no more save/restore on ctxsw */ - current->thread.flags &= ~IA64_THREAD_PM_VALID; - } - - /* - * Mark the PMU as not owned - * This will cause the interrupt handler to do nothing in case an overflow - * interrupt was in-flight - * This also guarantees that pmc0 will contain the final state - * It virtually gives us full control on overflow processing from that point - * on. - * It must be an atomic operation. - */ - SET_PMU_OWNER(NULL); - - /* - * read current overflow status: - * - * we are guaranteed to read the final stable state - */ - ia64_srlz_d(); - pmc0 = ia64_get_pmc(0); /* slow */ - - /* - * freeze PMU: - * - * This destroys the overflow information. This is required to make sure - * next process does not start with monitoring on if not requested - */ - pfm_freeze_pmu(); - - /* - * We don't need to restore psr, because we are on our way out - */ - - /* - * This loop flushes the PMD into the PFM context. - * It also processes overflow inline. - * - * IMPORTANT: No notification is sent at this point as the process is dying. - * The implicit notification will come from a SIGCHILD or a return from a - * waitpid(). - * - */ - - if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) - printk(KERN_DEBUG "perfmon: [%d] last_cpu=%d\n", - task->pid, atomic_read(&ctx->ctx_last_cpu)); - - /* - * we save all the used pmds - * we take care of overflows for pmds used as counters - */ - mask2 = ctx->ctx_used_pmds[0]; - for (i = 0; mask2; i++, mask2>>=1) { - - /* skip non used pmds */ - if ((mask2 & 0x1) == 0) continue; - - val = ia64_get_pmd(i); - - if (PMD_IS_COUNTING(i)) { - DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", - task->pid, - i, - ctx->ctx_soft_pmds[i].val, - val & pmu_conf.ovfl_val)); - - /* collect latest results */ - ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val; - - /* - * now everything is in ctx_soft_pmds[] and we need - * to clear the saved context from save_regs() such that - * pfm_read_pmds() gets the correct value - */ - task->thread.pmd[i] = 0; - - /* - * take care of overflow inline - */ - if (pmc0 & (1UL << i)) { - ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val; - DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n", - task->pid, i, ctx->ctx_soft_pmds[i].val)); - } - } else { - DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val)); - /* - * not a counter, just save value as is - */ - task->thread.pmd[i] = val; - } - } - /* - * indicates that context has been saved - */ - atomic_set(&ctx->ctx_last_cpu, -1); - preempt_enable(); -} - - -/* - * task is the newly created task, pt_regs for new child - */ -int -pfm_inherit(struct task_struct *task, struct pt_regs *regs) -{ - pfm_context_t *ctx; - pfm_context_t *nctx; - struct thread_struct *thread; - unsigned long m; - int i; - - /* - * the new task was copied from parent and therefore points - * to the parent's context at this point - */ - ctx = task->thread.pfm_context; - thread = &task->thread; - - preempt_disable(); - /* - * for secure sessions, make sure child cannot mess up - * the monitoring session. - */ - if (ctx->ctx_fl_unsecure == 0) { - ia64_psr(regs)->sp = 1; - DBprintk(("enabling psr.sp for [%d]\n", task->pid)); - } else { - DBprintk(("psr.sp=%d [%d]\n", ia64_psr(regs)->sp, task->pid)); - } - - /* - * if there was a virtual mapping for the sampling buffer - * the mapping is NOT inherited across fork() (see VM_DONTCOPY), - * so we don't have to explicitly remove it here. - * - * - * Part of the clearing of fields is also done in - * copy_thread() because the fiels are outside the - * pfm_context structure and can affect tasks not - * using perfmon. - */ - - /* clear pending notification */ - task->thread.pfm_ovfl_block_reset = 0; - - /* - * clear cpu pinning restriction for child - */ - if (ctx->ctx_fl_system) { - set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); - - DBprintk(("setting cpus_allowed for [%d] to 0x%lx from 0x%lx\n", - task->pid, - ctx->ctx_saved_cpus_allowed, - current->cpus_allowed)); - } - - /* - * takes care of easiest case first - */ - if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { - - DBprintk(("removing PFM context for [%d]\n", task->pid)); - - task->thread.pfm_context = NULL; - - /* - * we must clear psr.up because the new child does - * not have a context and the PM_VALID flag is cleared - * in copy_thread(). - * - * we do not clear psr.pp because it is always - * controlled by the system wide logic and we should - * never be here when system wide is running anyway - */ - ia64_psr(regs)->up = 0; - - preempt_enable(); - - /* copy_thread() clears IA64_THREAD_PM_VALID */ - return 0; - } - nctx = pfm_context_alloc(); - if (nctx == NULL) return -ENOMEM; - - /* copy content */ - *nctx = *ctx; - - - if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { - nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; - DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid)); - } - /* - * task is not yet visible in the tasklist, so we do - * not need to lock the newly created context. - * However, we must grab the tasklist_lock to ensure - * that the ctx_owner or ctx_notify_task do not disappear - * while we increment their check counters. - */ - read_lock(&tasklist_lock); - - if (nctx->ctx_notify_task) - atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check); - - if (nctx->ctx_owner) - atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check); - - read_unlock(&tasklist_lock); - - - LOCK_PFS(); - pfm_sessions.pfs_task_sessions++; - UNLOCK_PFS(); - - /* initialize counters in new context */ - m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER; - for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) { - if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) { - nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val; - thread->pmd[i] = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val; - } else { - thread->pmd[i] = 0UL; /* reset to initial state */ - } - } - - nctx->ctx_fl_frozen = 0; - nctx->ctx_ovfl_regs[0] = 0UL; - nctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - atomic_set(&nctx->ctx_last_cpu, -1); - - /* - * here nctx->ctx_psb == ctx->ctx_psb - * - * increment reference count to sampling - * buffer, if any. Note that this is independent - * from the virtual mapping. The latter is never - * inherited while the former will be if context - * is setup to something different from PFM_FL_INHERIT_NONE - */ - if (nctx->ctx_psb) { - LOCK_PSB(nctx->ctx_psb); - - nctx->ctx_psb->psb_refcnt++; - - DBprintk(("updated smpl @ %p refcnt=%lu psb_flags=0x%x\n", - ctx->ctx_psb->psb_hdr, - ctx->ctx_psb->psb_refcnt, - ctx->ctx_psb->psb_flags)); - - UNLOCK_PSB(nctx->ctx_psb); - - /* - * remove any pointer to sampling buffer mapping - */ - nctx->ctx_smpl_vaddr = 0; - } - - sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ - - /* - * propagate kernel psr in new context (used for first ctxsw in - */ - nctx->ctx_saved_psr = pfm_get_psr(); - - /* - * propagate kernel psr in new context (used for first ctxsw in - */ - nctx->ctx_saved_psr = pfm_get_psr(); - - /* link with new task */ - thread->pfm_context = nctx; - - DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid)); - - /* - * the copy_thread routine automatically clears - * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller - */ - if (current->thread.flags & IA64_THREAD_PM_VALID) { - DBprintk(("setting PM_VALID for [%d]\n", task->pid)); - thread->flags |= IA64_THREAD_PM_VALID; - } - - preempt_enable(); - - return 0; -} - -/* - * - * We cannot touch any of the PMU registers at this point as we may - * not be running on the same CPU the task was last run on. Therefore - * it is assumed that the PMU has been stopped appropriately in - * pfm_flush_regs() called from exit_thread(). - * - * The function is called in the context of the parent via a release_thread() - * and wait4(). The task is not in the tasklist anymore. - */ -void -pfm_context_exit(struct task_struct *task) -{ - pfm_context_t *ctx = task->thread.pfm_context; - - /* - * check sampling buffer - */ - preempt_disable(); - if (ctx->ctx_psb) { - pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; - - LOCK_PSB(psb); - - DBprintk(("sampling buffer from [%d] @%p size %ld refcnt=%lu psb_flags=0x%x\n", - task->pid, - psb->psb_hdr, psb->psb_size, psb->psb_refcnt, psb->psb_flags)); - - /* - * in the case where we are the last user, we may be able to free - * the buffer - */ - psb->psb_refcnt--; - - if (psb->psb_refcnt == 0) { - - /* - * The flag is cleared in pfm_vm_close(). which gets - * called from do_exit() via exit_mm(). - * By the time we come here, the task has no more mm context. - * - * We can only free the psb and buffer here after the vm area - * describing the buffer has been removed. This normally happens - * as part of do_exit() but the entire mm context is ONLY removed - * once its reference counts goes to zero. This is typically - * the case except for multi-threaded (several tasks) processes. - * - * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details. - */ - if ((psb->psb_flags & PSB_HAS_VMA) == 0) { - - DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n", - task->pid, - psb->psb_hdr, psb->psb_size)); - - /* - * free the buffer and psb - */ - pfm_rvfree(psb->psb_hdr, psb->psb_size); - kfree(psb); - psb = NULL; - } - } - /* psb may have been deleted */ - if (psb) UNLOCK_PSB(psb); - } - - DBprintk(("cleaning [%d] pfm_context @%p notify_task=%p check=%d mm=%p\n", - task->pid, ctx, - ctx->ctx_notify_task, - atomic_read(&task->thread.pfm_notifiers_check), task->mm)); - - /* - * To avoid getting the notified task or owner task scan the entire process - * list when they exit, we decrement notifiers_check and owners_check respectively. - * - * Of course, there is race condition between decreasing the value and the - * task exiting. The danger comes from the fact that, in both cases, we have a - * direct pointer to a task structure thereby bypassing the tasklist. - * We must make sure that, if we have task!= NULL, the target task is still - * present and is identical to the initial task specified - * during pfm_context_create(). It may already be detached from the tasklist but - * that's okay. Note that it is okay if we miss the deadline and the task scans - * the list for nothing, it will affect performance but not correctness. - * The correctness is ensured by using the ctx_lock which prevents the - * notify_task from changing the fields in our context. - * Once holdhing this lock, if we see task!= NULL, then it will stay like - * that until we release the lock. If it is NULL already then we came too late. - */ - LOCK_CTX(ctx); - - if (ctx->ctx_notify_task != NULL) { - DBprintk(("[%d], [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, - task->pid, - ctx->ctx_notify_task->pid, - atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); - - atomic_dec(&ctx->ctx_notify_task->thread.pfm_notifiers_check); - } - - if (ctx->ctx_owner != NULL) { - DBprintk(("[%d], [%d] atomic_sub on [%d] owners=%u\n", - current->pid, - task->pid, - ctx->ctx_owner->pid, - atomic_read(&ctx->ctx_owner->thread.pfm_owners_check))); - - atomic_dec(&ctx->ctx_owner->thread.pfm_owners_check); - } - - UNLOCK_CTX(ctx); - preempt_enable(); - - pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu); - - if (ctx->ctx_fl_system) { - /* - * remove any CPU pinning - */ - set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); - } - - pfm_context_free(ctx); - /* - * clean pfm state in thread structure, - */ - task->thread.pfm_context = NULL; - task->thread.pfm_ovfl_block_reset = 0; - - /* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */ -} - -/* - * function invoked from release_thread when pfm_smpl_buf_list is not NULL - */ -int -pfm_cleanup_smpl_buf(struct task_struct *task) -{ - pfm_smpl_buffer_desc_t *tmp, *psb = task->thread.pfm_smpl_buf_list; - - if (psb == NULL) { - printk(KERN_DEBUG "perfmon: psb is null in [%d]\n", current->pid); - return -1; - } - /* - * Walk through the list and free the sampling buffer and psb - */ - while (psb) { - DBprintk(("[%d] freeing smpl @%p size %ld\n", current->pid, psb->psb_hdr, psb->psb_size)); - - pfm_rvfree(psb->psb_hdr, psb->psb_size); - tmp = psb->psb_next; - kfree(psb); - psb = tmp; - } - - /* just in case */ - task->thread.pfm_smpl_buf_list = NULL; - - return 0; -} - -/* - * function invoked from release_thread to make sure that the ctx_owner field does not - * point to an unexisting task. - */ -void -pfm_cleanup_owners(struct task_struct *task) -{ - struct task_struct *g, *p; - pfm_context_t *ctx; - - DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); - - read_lock(&tasklist_lock); - - do_each_thread(g, p) { - /* - * It is safe to do the 2-step test here, because thread.ctx - * is cleaned up only in release_thread() and at that point - * the task has been detached from the tasklist which is an - * operation which uses the write_lock() on the tasklist_lock - * so it cannot run concurrently to this loop. So we have the - * guarantee that if we find p and it has a perfmon ctx then - * it is going to stay like this for the entire execution of this - * loop. - */ - ctx = p->thread.pfm_context; - - //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); - - if (ctx && ctx->ctx_owner == task) { - DBprintk(("trying for owner [%d] in [%d]\n", task->pid, p->pid)); - /* - * the spinlock is required to take care of a race condition - * with the send_sig_info() call. We must make sure that - * either the send_sig_info() completes using a valid task, - * or the notify_task is cleared before the send_sig_info() - * can pick up a stale value. Note that by the time this - * function is executed the 'task' is already detached from the - * tasklist. The problem is that the notifiers have a direct - * pointer to it. It is okay to send a signal to a task in this - * stage, it simply will have no effect. But it is better than sending - * to a completely destroyed task or worse to a new task using the same - * task_struct address. - */ - LOCK_CTX(ctx); - - ctx->ctx_owner = NULL; - - UNLOCK_CTX(ctx); - - DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); - } - } while_each_thread(g, p); - - read_unlock(&tasklist_lock); - - atomic_set(&task->thread.pfm_owners_check, 0); -} - - -/* - * function called from release_thread to make sure that the ctx_notify_task is not pointing - * to an unexisting task - */ -void -pfm_cleanup_notifiers(struct task_struct *task) -{ - struct task_struct *g, *p; - pfm_context_t *ctx; - - DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); - - read_lock(&tasklist_lock); - - do_each_thread(g, p) { - /* - * It is safe to do the 2-step test here, because thread.ctx is cleaned up - * only in release_thread() and at that point the task has been detached - * from the tasklist which is an operation which uses the write_lock() on - * the tasklist_lock so it cannot run concurrently to this loop. So we - * have the guarantee that if we find p and it has a perfmon ctx then it - * is going to stay like this for the entire execution of this loop. - */ - ctx = p->thread.pfm_context; - - //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); - - if (ctx && ctx->ctx_notify_task == task) { - DBprintk(("trying for notifier [%d] in [%d]\n", task->pid, p->pid)); - /* - * the spinlock is required to take care of a race condition - * with the send_sig_info() call. We must make sure that - * either the send_sig_info() completes using a valid task, - * or the notify_task is cleared before the send_sig_info() - * can pick up a stale value. Note that by the time this - * function is executed the 'task' is already detached from the - * tasklist. The problem is that the notifiers have a direct - * pointer to it. It is okay to send a signal to a task in this - * stage, it simply will have no effect. But it is better than sending - * to a completely destroyed task or worse to a new task using the same - * task_struct address. - */ - LOCK_CTX(ctx); - - ctx->ctx_notify_task = NULL; - - UNLOCK_CTX(ctx); - - DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); - } - } while_each_thread(g, p); - - read_unlock(&tasklist_lock); - - atomic_set(&task->thread.pfm_notifiers_check, 0); -} - -static struct irqaction perfmon_irqaction = { - .handler = pfm_interrupt_handler, - .flags = SA_INTERRUPT, - .name = "perfmon" -}; - -int -pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl) -{ - int ret; - - - /* some sanity checks */ - if (hdl == NULL || hdl->handler == NULL) { - return -EINVAL; - } - - /* do the easy test first */ - if (pfm_alternate_intr_handler) { - return -EBUSY; - } - - preempt_disable(); - /* reserve our session */ - ret = pfm_reserve_session(NULL, 1, cpu_online_map); - if (ret) { - preempt_enable(); - return ret; - } - - if (pfm_alternate_intr_handler) { - preempt_enable(); - printk(KERN_DEBUG "perfmon: install_alternate, intr_handler not NULL " - "after reserve\n"); - return -EINVAL; - } - - pfm_alternate_intr_handler = hdl; - - preempt_enable(); - return 0; -} - -int -pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl) -{ - if (hdl == NULL) - return -EINVAL; - - /* cannot remove someone else's handler! */ - if (pfm_alternate_intr_handler != hdl) - return -EINVAL; - - preempt_disable(); - pfm_alternate_intr_handler = NULL; - - /* - * XXX: assume cpu_online_map has not changed since reservation - */ - pfm_unreserve_session(NULL, 1, cpu_online_map); - - preempt_enable(); - - return 0; -} - -/* - * perfmon initialization routine, called from the initcall() table - */ -int __init -pfm_init(void) -{ - unsigned int n, n_counters, i; - - pmu_conf.disabled = 1; - - printk(KERN_INFO "perfmon: version %u.%u IRQ %u\n", PFM_VERSION_MAJ, PFM_VERSION_MIN, - IA64_PERFMON_VECTOR); - - /* - * compute the number of implemented PMD/PMC from the - * description tables - */ - n = 0; - for (i=0; PMC_IS_LAST(i) == 0; i++) { - if (PMC_IS_IMPL(i) == 0) continue; - pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63); - n++; - } - pmu_conf.num_pmcs = n; - - n = 0; n_counters = 0; - for (i=0; PMD_IS_LAST(i) == 0; i++) { - if (PMD_IS_IMPL(i) == 0) continue; - pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63); - n++; - if (PMD_IS_COUNTING(i)) n_counters++; - } - pmu_conf.num_pmds = n; - pmu_conf.num_counters = n_counters; - - printk(KERN_INFO "perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", - pmu_conf.num_pmcs, - pmu_conf.num_pmds, - pmu_conf.num_counters, - ffz(pmu_conf.ovfl_val)); - - /* sanity check */ - if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { - printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n"); - return -1; - } - - /* - * for now here for debug purposes - */ - perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); - if (perfmon_dir == NULL) { - printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); - return -1; - } - - /* - * create /proc/perfmon - */ - pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); - - /* - * initialize all our spinlocks - */ - spin_lock_init(&pfm_sessions.pfs_lock); - - /* we are all set */ - pmu_conf.disabled = 0; - - return 0; -} -__initcall(pfm_init); - -void -pfm_init_percpu(void) -{ - int i; - int me = get_cpu(); - - if (me == 0) - register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); - - ia64_set_pmv(IA64_PERFMON_VECTOR); - ia64_srlz_d(); - - /* - * we first initialize the PMU to a stable state. - * the values may have been changed from their power-up - * values by software executed before the kernel took over. - * - * At this point, pmu_conf has not yet been initialized - * - * On McKinley, this code is ineffective until PMC4 is initialized. - */ - for (i=1; PMC_IS_LAST(i) == 0; i++) { - if (PMC_IS_IMPL(i) == 0) continue; - ia64_set_pmc(i, PMC_DFL_VAL(i)); - } - - for (i=0; PMD_IS_LAST(i); i++) { - if (PMD_IS_IMPL(i) == 0) continue; - ia64_set_pmd(i, 0UL); - } - put_cpu(); - pfm_freeze_pmu(); -} - -#else /* !CONFIG_PERFMON */ - -asmlinkage long -sys_perfmonctl (int pid, int cmd, void *req, int count, long arg5, long arg6, - long arg7, long arg8, long stack) -{ - return -ENOSYS; -} - -#endif /* !CONFIG_PERFMON */ +/* + * This file implements the perfmon-2 subsystem which is used + * to program the IA-64 Performance Monitoring Unit (PMU). + * + * The initial version of perfmon.c was written by + * Ganesh Venkitachalam, IBM Corp. + * + * Then it was modified for perfmon-1.x by Stephane Eranian and + * David Mosberger, Hewlett Packard Co. + * + * Version Perfmon-2.x is a rewrite of perfmon-1.x + * by Stephane Eranian, Hewlett Packard Co. + * + * Copyright (C) 1999-2003 Hewlett Packard Co + * Stephane Eranian + * David Mosberger-Tang + * + * More information about perfmon available at: + * http://www.hpl.hp.com/research/linux/perfmon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PERFMON +/* + * perfmon context state + */ +#define PFM_CTX_UNLOADED 1 /* context is not loaded onto any task */ +#define PFM_CTX_LOADED 2 /* context is loaded onto a task */ +#define PFM_CTX_MASKED 3 /* context is loaded but monitoring is masked due to overflow */ +#define PFM_CTX_ZOMBIE 4 /* owner of the context is closing it */ +#define PFM_CTX_TERMINATED 5 /* the task the context was loaded onto is gone */ + +#define CTX_LOADED(c) (c)->ctx_state = PFM_CTX_LOADED +#define CTX_UNLOADED(c) (c)->ctx_state = PFM_CTX_UNLOADED +#define CTX_ZOMBIE(c) (c)->ctx_state = PFM_CTX_ZOMBIE +#define CTX_DESTROYED(c) (c)->ctx_state = PFM_CTX_DESTROYED +#define CTX_MASKED(c) (c)->ctx_state = PFM_CTX_MASKED +#define CTX_TERMINATED(c) (c)->ctx_state = PFM_CTX_TERMINATED + +#define CTX_IS_UNLOADED(c) ((c)->ctx_state == PFM_CTX_UNLOADED) +#define CTX_IS_LOADED(c) ((c)->ctx_state == PFM_CTX_LOADED) +#define CTX_IS_ZOMBIE(c) ((c)->ctx_state == PFM_CTX_ZOMBIE) +#define CTX_IS_MASKED(c) ((c)->ctx_state == PFM_CTX_MASKED) +#define CTX_IS_TERMINATED(c) ((c)->ctx_state == PFM_CTX_TERMINATED) +#define CTX_IS_DEAD(c) ((c)->ctx_state == PFM_CTX_TERMINATED || (c)->ctx_state == PFM_CTX_ZOMBIE) + +#define PFM_INVALID_ACTIVATION (~0UL) + + +/* + * depth of message queue + */ +#define PFM_MAX_MSGS 32 +#define PFM_CTXQ_EMPTY(g) ((g)->ctx_msgq_head == (g)->ctx_msgq_tail) + +/* + * type of a PMU register (bitmask). + * bitmask structure: + * bit0 : register implemented + * bit1 : end marker + * bit2-3 : reserved + * bit4 : pmc has pmc.pm + * bit5 : pmc controls a counter (has pmc.oi), pmd is used as counter + * bit6-7 : register type + * bit8-31: reserved + */ +#define PFM_REG_NOTIMPL 0x0 /* not implemented at all */ +#define PFM_REG_IMPL 0x1 /* register implemented */ +#define PFM_REG_END 0x2 /* end marker */ +#define PFM_REG_MONITOR (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */ +#define PFM_REG_COUNTING (0x2<<4|PFM_REG_MONITOR|PFM_REG_IMPL) /* a monitor + pmc.oi+ PMD used as a counter */ +#define PFM_REG_CONTROL (0x4<<4|PFM_REG_IMPL) /* PMU control register */ +#define PFM_REG_CONFIG (0x8<<4|PFM_REG_IMPL) /* configuration register */ +#define PFM_REG_BUFFER (0xc<<4|PFM_REG_IMPL) /* PMD used as buffer */ + +#define PMC_IS_LAST(i) (pmu_conf.pmc_desc[i].type & PFM_REG_END) +#define PMD_IS_LAST(i) (pmu_conf.pmd_desc[i].type & PFM_REG_END) + +#define PFM_IS_DISABLED() (pmu_conf.enabled == 0) + +#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) + +/* i assumed unsigned */ +#define PMC_IS_IMPL(i) (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL)) +#define PMD_IS_IMPL(i) (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL)) + +/* XXX: these assume that register i is implemented */ +#define PMD_IS_COUNTING(i) ((pmu_conf.pmd_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_COUNTING(i) ((pmu_conf.pmc_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_MONITOR(i) ((pmu_conf.pmc_desc[i].type & PFM_REG_MONITOR) == PFM_REG_MONITOR) +#define PMC_DFL_VAL(i) pmu_conf.pmc_desc[i].default_value +#define PMC_RSVD_MASK(i) pmu_conf.pmc_desc[i].reserved_mask +#define PMD_PMD_DEP(i) pmu_conf.pmd_desc[i].dep_pmd[0] +#define PMC_PMD_DEP(i) pmu_conf.pmc_desc[i].dep_pmd[0] + +/* k assumed unsigned (up to 64 registers) */ +#define IBR_IS_IMPL(k) (k< IA64_NUM_DBG_REGS) +#define DBR_IS_IMPL(k) (k< IA64_NUM_DBG_REGS) + +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) +#define CTX_HAS_SMPL(c) ((c)->ctx_fl_is_sampling) +#define PFM_CTX_TASK(h) (h)->ctx_task + +/* XXX: does not support more than 64 PMDs */ +#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) +#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) + +#define CTX_USED_MONITOR(ctx, mask) (ctx)->ctx_used_monitors[0] |= (mask) + +#define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) +#define PFM_CODE_RR 0 /* requesting code range restriction */ +#define PFM_DATA_RR 1 /* requestion data range restriction */ + +#define PFM_CPUINFO_CLEAR(v) pfm_get_cpu_var(pfm_syst_info) &= ~(v) +#define PFM_CPUINFO_SET(v) pfm_get_cpu_var(pfm_syst_info) |= (v) +#define PFM_CPUINFO_GET() pfm_get_cpu_var(pfm_syst_info) + +/* + * context protection macros + * in SMP: + * - we need to protect against CPU concurrency (spin_lock) + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * in UP: + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * + * spin_lock_irqsave()/spin_lock_irqrestore(): + * in SMP: local_irq_disable + spin_lock + * in UP : local_irq_disable + * + * spin_lock()/spin_lock(): + * in UP : removed automatically + * in SMP: protect against context accesses from other CPU. interrupts + * are not masked. This is useful for the PMU interrupt handler + * because we know we will not get PMU concurrency in that code. + */ +#define PROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_save ctx %p by [%d]\n", c, current->pid)); \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + DPRINT(("spinlocked ctx %p by [%d]\n", c, current->pid)); \ + } while(0) + +#define UNPROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_restore ctx %p by [%d]\n", c, current->pid)); \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + +#define PROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + } while(0) + + +#define UNPROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + + +#define PROTECT_CTX_NOIRQ(c) \ + do { \ + spin_lock(&(c)->ctx_lock); \ + } while(0) + +#define UNPROTECT_CTX_NOIRQ(c) \ + do { \ + spin_unlock(&(c)->ctx_lock); \ + } while(0) + + +#ifdef CONFIG_SMP + +#define GET_ACTIVATION() pfm_get_cpu_var(pmu_activation_number) +#define INC_ACTIVATION() pfm_get_cpu_var(pmu_activation_number)++ +#define SET_ACTIVATION(c) (c)->ctx_last_activation = GET_ACTIVATION() + +#else /* !CONFIG_SMP */ +#define SET_ACTIVATION(t) do {} while(0) +#define GET_ACTIVATION(t) do {} while(0) +#define INC_ACTIVATION(t) do {} while(0) +#endif /* CONFIG_SMP */ + +#define SET_PMU_OWNER(t, c) do { pfm_get_cpu_var(pmu_owner) = (t); pfm_get_cpu_var(pmu_ctx) = (c); } while(0) +#define GET_PMU_OWNER() pfm_get_cpu_var(pmu_owner) +#define GET_PMU_CTX() pfm_get_cpu_var(pmu_ctx) + +#define LOCK_PFS() spin_lock(&pfm_sessions.pfs_lock) +#define UNLOCK_PFS() spin_unlock(&pfm_sessions.pfs_lock) + +#define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) + +#ifdef CONFIG_SMP +#define PFM_CPU_ONLINE_MAP cpu_online_map +#define cpu_is_online(i) (PFM_CPU_ONLINE_MAP & (1UL << i)) +#else +#define PFM_CPU_ONLINE_MAP 1UL +#define cpu_is_online(i) (i==0) +#endif + +/* + * cmp0 must be the value of pmc0 + */ +#define PMC0_HAS_OVFL(cmp0) (cmp0 & ~0x1UL) + +/* + * debugging + */ +#define DPRINT(a) \ + do { \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) +/* + * Architected PMC structure + */ +typedef struct { + unsigned long pmc_plm:4; /* privilege level mask */ + unsigned long pmc_ev:1; /* external visibility */ + unsigned long pmc_oi:1; /* overflow interrupt */ + unsigned long pmc_pm:1; /* privileged monitor */ + unsigned long pmc_ig1:1; /* reserved */ + unsigned long pmc_es:8; /* event select */ + unsigned long pmc_ig2:48; /* reserved */ +} pfm_monitor_t; + +/* + * 64-bit software counter structure + */ +typedef struct { + unsigned long val; /* virtual 64bit counter value */ + unsigned long lval; /* last reset value */ + unsigned long long_reset; /* reset value on sampling overflow */ + unsigned long short_reset; /* reset value on overflow */ + unsigned long reset_pmds[4]; /* which other pmds to reset when this counter overflows */ + unsigned long smpl_pmds[4]; /* which pmds are accessed when counter overflow */ + unsigned long seed; /* seed for random-number generator */ + unsigned long mask; /* mask for random-number generator */ + unsigned int flags; /* notify/do not notify */ + unsigned int reserved; /* for future use */ + unsigned long eventid; /* overflow event identifier */ +} pfm_counter_t; + +/* + * context flags + */ +typedef struct { + unsigned int block:1; /* when 1, task will blocked on user notifications */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ + unsigned int is_sampling:1; /* true if using a custom format */ + unsigned int excl_idle:1; /* exclude idle task in system wide session */ + unsigned int unsecure:1; /* exclude idle task in system wide session */ + unsigned int going_zombie:1; /* context is zombie (MASKED+blocking) */ + unsigned int trap_reason:2; /* reason for going into pfm_handle_work() */ + unsigned int no_msg:1; /* no message sent on overflow */ + unsigned int reserved:22; +} pfm_context_flags_t; + +#define PFM_TRAP_REASON_NONE 0x0 /* default value */ +#define PFM_TRAP_REASON_BLOCK 0x1 /* we need to block on overflow */ +#define PFM_TRAP_REASON_RESET 0x2 /* we need to reset PMDs */ + + +/* + * perfmon context: encapsulates all the state of a monitoring session + */ + +typedef struct pfm_context { + spinlock_t ctx_lock; /* context protection */ + + pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ + unsigned int ctx_state; /* state: active/inactive (no bitfield) */ + + struct task_struct *ctx_task; /* task to which context is attached */ + + unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ + + struct semaphore ctx_restart_sem; /* use for blocking notification mode */ + + unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ + unsigned long ctx_all_pmds[4]; /* bitmask of all accessible PMDs */ + unsigned long ctx_reload_pmds[4]; /* bitmask of force reload PMD on ctxsw in */ + + unsigned long ctx_all_pmcs[4]; /* bitmask of all accessible PMCs */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */ + unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */ + + unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */ + + unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */ + unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */ + unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */ + unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */ + + pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */ + + u64 ctx_saved_psr; /* copy of psr used for ctxsw */ + + unsigned long ctx_last_activation; /* context last activation number for last_cpu */ + unsigned int ctx_last_cpu; /* CPU id of current or last CPU used (SMP only) */ + unsigned int ctx_cpu; /* cpu to which perfmon is applied (system wide) */ + + int ctx_fd; /* file descriptor used my this context */ + + pfm_buffer_fmt_t *ctx_buf_fmt; /* buffer format callbacks */ + void *ctx_smpl_hdr; /* points to sampling buffer header kernel vaddr */ + unsigned long ctx_smpl_size; /* size of sampling buffer */ + void *ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ + + wait_queue_head_t ctx_msgq_wait; + pfm_msg_t ctx_msgq[PFM_MAX_MSGS]; + int ctx_msgq_head; + int ctx_msgq_tail; + struct fasync_struct *ctx_async_queue; + + wait_queue_head_t ctx_zombieq; /* termination cleanup wait queue */ +} pfm_context_t; + +/* + * magic number used to verify that structure is really + * a perfmon context + */ +#define PFM_IS_FILE(f) ((f)->f_op == &pfm_file_ops) + +#define PFM_GET_CTX(t) ((pfm_context_t *)(t)->thread.pfm_context) + +#ifdef CONFIG_SMP +#define SET_LAST_CPU(ctx, v) (ctx)->ctx_last_cpu = (v) +#define GET_LAST_CPU(ctx) (ctx)->ctx_last_cpu +#else +#define SET_LAST_CPU(ctx, v) do {} while(0) +#define GET_LAST_CPU(ctx) do {} while(0) +#endif + + +#define ctx_fl_block ctx_flags.block +#define ctx_fl_system ctx_flags.system +#define ctx_fl_using_dbreg ctx_flags.using_dbreg +#define ctx_fl_is_sampling ctx_flags.is_sampling +#define ctx_fl_excl_idle ctx_flags.excl_idle +#define ctx_fl_unsecure ctx_flags.unsecure +#define ctx_fl_going_zombie ctx_flags.going_zombie +#define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_no_msg ctx_flags.no_msg + +#define PFM_SET_WORK_PENDING(t, v) do { (t)->thread.pfm_needs_checking = v; } while(0); +#define PFM_GET_WORK_PENDING(t) (t)->thread.pfm_needs_checking + +/* + * global information about all sessions + * mostly used to synchronize between system wide and per-process + */ +typedef struct { + spinlock_t pfs_lock; /* lock the structure */ + + unsigned int pfs_task_sessions; /* number of per task sessions */ + unsigned int pfs_sys_sessions; /* number of per system wide sessions */ + unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ + unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ + struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ +} pfm_session_t; + +/* + * information about a PMC or PMD. + * dep_pmd[]: a bitmask of dependent PMD registers + * dep_pmc[]: a bitmask of dependent PMC registers + */ +typedef struct { + unsigned int type; + int pm_pos; + unsigned long default_value; /* power-on default value */ + unsigned long reserved_mask; /* bitmask of reserved bits */ + int (*read_check)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + int (*write_check)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + unsigned long dep_pmd[4]; + unsigned long dep_pmc[4]; +} pfm_reg_desc_t; + +/* assume cnum is a valid monitor */ +#define PMC_PM(cnum, val) (((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1) +#define PMC_WR_FUNC(cnum) (pmu_conf.pmc_desc[cnum].write_check) +#define PMD_WR_FUNC(cnum) (pmu_conf.pmd_desc[cnum].write_check) +#define PMD_RD_FUNC(cnum) (pmu_conf.pmd_desc[cnum].read_check) + +/* + * This structure is initialized at boot time and contains + * a description of the PMU main characteristics. + */ +typedef struct { + unsigned long ovfl_val; /* overflow value for counters */ + + pfm_reg_desc_t *pmc_desc; /* detailed PMC register dependencies descriptions */ + pfm_reg_desc_t *pmd_desc; /* detailed PMD register dependencies descriptions */ + + unsigned int num_pmcs; /* number of PMCS: computed at init time */ + unsigned int num_pmds; /* number of PMDS: computed at init time */ + unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ + unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ + + char *pmu_name; /* PMU family name */ + unsigned int enabled; /* indicates if perfmon initialized properly */ + unsigned int pmu_family; /* cpuid family pattern used to identify pmu */ + + unsigned int num_ibrs; /* number of IBRS: computed at init time */ + unsigned int num_dbrs; /* number of DBRS: computed at init time */ + unsigned int num_counters; /* PMC/PMD counting pairs : computed at init time */ + + unsigned int use_rr_dbregs:1; /* set if debug registers used for range restriction */ +} pmu_config_t; + +/* + * debug register related type definitions + */ +typedef struct { + unsigned long ibr_mask:56; + unsigned long ibr_plm:4; + unsigned long ibr_ig:3; + unsigned long ibr_x:1; +} ibr_mask_reg_t; + +typedef struct { + unsigned long dbr_mask:56; + unsigned long dbr_plm:4; + unsigned long dbr_ig:2; + unsigned long dbr_w:1; + unsigned long dbr_r:1; +} dbr_mask_reg_t; + +typedef union { + unsigned long val; + ibr_mask_reg_t ibr; + dbr_mask_reg_t dbr; +} dbreg_t; + + +/* + * perfmon command descriptions + */ +typedef struct { + int (*cmd_func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + char *cmd_name; + int cmd_flags; + unsigned int cmd_narg; + size_t cmd_argsize; + int (*cmd_getsize)(void *arg, size_t *sz); +} pfm_cmd_desc_t; + +#define PFM_CMD_FD 0x01 /* command requires a file descriptor */ +#define PFM_CMD_ARG_READ 0x02 /* command must read argument(s) */ +#define PFM_CMD_ARG_RW 0x04 /* command must read/write argument(s) */ +#define PFM_CMD_STOP 0x08 /* command does not work on zombie context */ + + +#define PFM_CMD_IDX(cmd) (cmd) +#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \ + && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) + +#define PFM_CMD_NAME(cmd) pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_name +#define PFM_CMD_READ_ARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) +#define PFM_CMD_RW_ARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) +#define PFM_CMD_USE_FD(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_FD) +#define PFM_CMD_STOPPED(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_STOP) + +#define PFM_CMD_ARG_MANY -1 /* cannot be zero */ +#define PFM_CMD_NARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg) +#define PFM_CMD_ARG_SIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize) +#define PFM_CMD_GETSIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_getsize) + +typedef struct { + int debug; /* turn on/off debugging via syslog */ + int debug_ovfl; /* turn on/off debug printk in overflow handler */ + int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ + int debug_pfm_read; +} pfm_sysctl_t; + +typedef struct { + unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ + unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles; /* cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_min; /* min cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_max; /* max cycles spent processing ovfl interrupts */ + unsigned long pfm_sysupdt_count; + unsigned long pfm_sysupdt_cycles; + unsigned long pfm_smpl_handler_calls; + unsigned long pfm_smpl_handler_cycles; + char pad[SMP_CACHE_BYTES] ____cacheline_aligned; +} pfm_stats_t; + +/* + * perfmon internal variables + */ +static pfm_stats_t pfm_stats[NR_CPUS]; +static pfm_session_t pfm_sessions; /* global sessions information */ + +static struct proc_dir_entry *perfmon_dir; +static pfm_uuid_t pfm_null_uuid = {0,}; + +static spinlock_t pfm_smpl_fmt_lock; +static pfm_buffer_fmt_t *pfm_buffer_fmt_list; +#define LOCK_BUF_FMT_LIST() spin_lock(&pfm_smpl_fmt_lock) +#define UNLOCK_BUF_FMT_LIST() spin_unlock(&pfm_smpl_fmt_lock) + +/* sysctl() controls */ +static pfm_sysctl_t pfm_sysctl; +int pfm_debug_var; + +static ctl_table pfm_ctl_table[]={ + {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + { 0, }, +}; +static ctl_table pfm_sysctl_dir[] = { + {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, + {0,}, +}; +static ctl_table pfm_sysctl_root[] = { + {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, + {0,}, +}; +static struct ctl_table_header *pfm_sysctl_header; + +static void pfm_vm_close(struct vm_area_struct * area); + +static struct vm_operations_struct pfm_vm_ops={ + close: pfm_vm_close +}; + +/* + * Linux 2.5 vs. 2.4 helper macros and definitions + * + * if not at least 2.5.69, then assume 2.4.x. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) + +#define PFM_COMPILED_FOR_2_4 1 + +#include + +#define pfm_get_cpu_var(v) local_cpu_data->v +#define pfm_get_cpu_data(a,b) cpu_data((b))->a +typedef void pfm_irq_handler_t; +#define PFM_IRQ_HANDLER_RET(v) + +#define DEFINE_PER_CPU(a,b) + +static inline int +pfm_wait_task_inactive(struct task_struct *task) +{ +#ifdef CONFIG_SMP + /* Make sure the child gets off its CPU.. */ + for (;;) { + task_lock(task); + if (!task_has_cpu(task)) break; + task_unlock(task); + do { + if (task->state != TASK_STOPPED) + return -ESRCH; + barrier(); + cpu_relax(); + } while (task_has_cpu(task)); + } + task_unlock(task); +#endif + return 0; +} + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) free_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ +} + +static inline void +pfm_clear_task_notify(void) +{ +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + unsigned long page; + + page = ia64_tpa(a); + mem_map_reserve(virt_to_page(__va(page))); +} + +static inline void +pfm_unreserve_page(unsigned long a) +{ + unsigned long page; + + page = ia64_tpa(a); + mem_map_unreserve(virt_to_page(__va(page))); +} + +static inline int +pfm_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) +{ + return remap_page_range(from, phys_addr, size, prot); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + unsigned long f; + spin_lock(&(x)->ctx_lock); + return f; +} + +static inline unsigned long +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} + +#else /* 2.5.69 or higher */ + +#define pfm_wait_task_inactive(t) wait_task_inactive(t) +#define pfm_get_cpu_var(v) __get_cpu_var(v) +#define pfm_get_cpu_data(a,b) per_cpu(a, b) +typedef irqreturn_t pfm_irq_handler_t; +#define PFM_IRQ_HANDLER_RET(v) do { \ + put_cpu_no_resched(); \ + return IRQ_HANDLED; \ + } while(0); + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) put_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ + struct thread_info *info; + + info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); + set_bit(TIF_NOTIFY_RESUME, &info->flags); +} + +static inline void +pfm_clear_task_notify(void) +{ + clear_thread_flag(TIF_NOTIFY_RESUME); +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + SetPageReserved(vmalloc_to_page((void *)a)); +} +static inline void +pfm_unreserve_page(unsigned long a) +{ + ClearPageReserved(vmalloc_to_page((void*)a)); +} + +static inline int +pfm_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) +{ + return remap_page_range(vma, from, phys_addr, size, prot); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + spin_lock_irq(&(x)->ctx_lock); + return 0UL; +} + +static inline unsigned long +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} + +#endif /* 2.5 vs. 2.4 */ + +DEFINE_PER_CPU(unsigned long, pfm_syst_info); +DEFINE_PER_CPU(struct task_struct *, pmu_owner); +DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); +DEFINE_PER_CPU(unsigned long, pmu_activation_number); + + +/* forward declaration */ +static struct file_operations pfm_file_ops; + +/* + * forward declarations + */ +#ifndef CONFIG_SMP +static void pfm_lazy_save_regs (struct task_struct *ta); +#endif + +#if defined(CONFIG_ITANIUM) +#include "perfmon_itanium.h" +#elif defined(CONFIG_MCKINLEY) +#include "perfmon_mckinley.h" +#else +#include "perfmon_generic.h" +#endif + +static int pfm_end_notify_user(pfm_context_t *ctx); + +static inline void +pfm_clear_psr_pp(void) +{ + __asm__ __volatile__ ("rsm psr.pp;; srlz.i;;"::: "memory"); +} + +static inline void +pfm_set_psr_pp(void) +{ + __asm__ __volatile__ ("ssm psr.pp;; srlz.i;;"::: "memory"); +} + +static inline void +pfm_clear_psr_up(void) +{ + __asm__ __volatile__ ("rum psr.up;; srlz.i;;"::: "memory"); +} + +static inline void +pfm_set_psr_up(void) +{ + __asm__ __volatile__ ("sum psr.up;; srlz.i;;"::: "memory"); +} + +static inline unsigned long +pfm_get_psr(void) +{ + unsigned long tmp; + __asm__ __volatile__ ("mov %0=psr;;": "=r"(tmp) :: "memory"); + return tmp; +} + +static inline void +pfm_set_psr_l(unsigned long val) +{ + __asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(val): "memory"); +} + +static inline void +pfm_freeze_pmu(void) +{ + ia64_set_pmc(0,1UL); + ia64_srlz_d(); +} + +static inline void +pfm_unfreeze_pmu(void) +{ + ia64_set_pmc(0,0UL); + ia64_srlz_d(); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline unsigned long +pfm_read_soft_counter(pfm_context_t *ctx, int i) +{ + return ctx->ctx_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline void +pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) +{ + ctx->ctx_pmds[i].val = val & ~pmu_conf.ovfl_val; + /* + * writing to unimplemented part is ignore, so we do not need to + * mask off top part + */ + ia64_set_pmd(i, val & pmu_conf.ovfl_val); +} + +static pfm_msg_t * +pfm_get_new_msg(pfm_context_t *ctx) +{ + int idx, next; + + next = (ctx->ctx_msgq_tail+1) % PFM_MAX_MSGS; + + DPRINT(("ctx_fd=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + if (next == ctx->ctx_msgq_head) return NULL; + + idx = ctx->ctx_msgq_tail; + ctx->ctx_msgq_tail = next; + + DPRINT(("ctx=%p head=%d tail=%d msg=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, idx)); + + return ctx->ctx_msgq+idx; +} + +static pfm_msg_t * +pfm_get_next_msg(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + DPRINT(("ctx=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + if (PFM_CTXQ_EMPTY(ctx)) return NULL; + + /* + * get oldest message + */ + msg = ctx->ctx_msgq+ctx->ctx_msgq_head; + + /* + * and move forward + */ + ctx->ctx_msgq_head = (ctx->ctx_msgq_head+1) % PFM_MAX_MSGS; + + DPRINT(("ctx=%p head=%d tail=%d type=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, msg->pfm_gen_msg.msg_type)); + + return msg; +} + +static void +pfm_reset_msgq(pfm_context_t *ctx) +{ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + DPRINT(("ctx=%p msgq reset\n", ctx)); +} + + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long +pfm_kvirt_to_pa(unsigned long adr) +{ + __u64 pa = ia64_tpa(adr); + return pa; +} + +static void * +pfm_rvmalloc(unsigned long size) +{ + void *mem; + unsigned long addr; + + size = PAGE_ALIGN(size); + mem = vmalloc(size); + if (mem) { + //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); + memset(mem, 0, size); + addr = (unsigned long)mem; + while (size > 0) { + pfm_reserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void +pfm_rvfree(void *mem, unsigned long size) +{ + unsigned long addr; + + if (mem) { + DPRINT(("freeing physical buffer @%p size=%lu\n", mem, size)); + addr = (unsigned long) mem; + while ((long) size > 0) { + pfm_unreserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } + return; +} + +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *ctx; + + /* allocate context descriptor */ + ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); + if (ctx) { + memset(ctx, 0, sizeof(pfm_context_t)); + DPRINT(("alloc ctx @%p\n", ctx)); + } + return ctx; +} + +static void +pfm_context_free(pfm_context_t *ctx) +{ + if (ctx) { + DPRINT(("free ctx @%p\n", ctx)); + kfree(ctx); + } +} + +static void +pfm_mask_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, val; + int i; + + DPRINT(("[%d] masking monitoring for [%d]\n", current->pid, task->pid)); + + /* + * monitoring can only be masked as a result of a valid + * counter overflow. In UP, it means that the PMU still + * has an owner. Note that the owner can be different + * from the current task. However the PMU state belongs + * to the owner. + * In SMP, a valid overflow only happens when task is + * current. Therefore if we come here, we know that + * the PMU state belongs to the current task, therefore + * we can access the live registers. + * + * So in both cases, the live register contains the owner's + * state. We can ONLY touch the PMU registers and NOT the PSR. + * + * As a consequence to this call, the thread->pmds[] array + * contains stale information which must be ignored + * when context is reloaded AND monitoring is active (see + * pfm_restart). + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + val = ia64_get_pmd(i); + + if (PMD_IS_COUNTING(i)) { + /* + * we rebuild the full 64 bit value of the counter + */ + ctx->ctx_pmds[i].val += (val & pmu_conf.ovfl_val); + } else { + ctx->ctx_pmds[i].val = val; + } + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val & pmu_conf.ovfl_val)); + } + /* + * mask monitoring by setting the privilege level to 0 + * we cannot use psr.pp/psr.up for this, it is controlled by + * the user + * + * if task is current, modify actual registers, otherwise modify + * thread save state, i.e., what will be restored in pfm_load_regs() + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + ia64_set_pmc(i, th->pmcs[i] & ~0xfUL); + th->pmcs[i] &= ~0xfUL; + } + /* + * make all of this visible + */ + ia64_srlz_d(); +} + +/* + * must always be done with task == current + * + * context must be in MASKED state when calling + */ +static void +pfm_restore_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask; + unsigned long psr, val; + int i; + + if (task != current) { + printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task->pid, current->pid); + return; + } + if (CTX_IS_MASKED(ctx) == 0) { + printk(KERN_ERR "perfmon.%d: task[%d] current[%d] invalid state=%d\n", __LINE__, + task->pid, current->pid, ctx->ctx_state); + return; + } + psr = pfm_get_psr(); + /* + * monitoring is masked via the PMC. + * As we restore their value, we do not want each counter to + * restart right away. We stop monitoring using the PSR, + * restore the PMC (and PMD) and then re-establish the psr + * as it was. Note that there can be no pending overflow at + * this point, because monitoring was MASKED. + * + * system-wide session are pinned and self-monitoring + */ + if (ctx->ctx_fl_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* disable dcr pp */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + } else { + pfm_clear_psr_up(); + } + /* + * first, we restore the PMD + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + + if (PMD_IS_COUNTING(i)) { + /* + * we split the 64bit value according to + * counter width + */ + val = ctx->ctx_pmds[i].val & pmu_conf.ovfl_val; + ctx->ctx_pmds[i].val &= ~pmu_conf.ovfl_val; + } else { + val = ctx->ctx_pmds[i].val; + } + ia64_set_pmd(i, val); + + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val)); + } + /* + * restore the PMCs + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + th->pmcs[i] = ctx->ctx_pmcs[i]; + ia64_set_pmc(i, th->pmcs[i]); + DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i])); + } + ia64_srlz_d(); + + /* + * now restore PSR + */ + if (ctx->ctx_fl_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr() | IA64_DCR_PP); + ia64_srlz_i(); + } + pfm_set_psr_l(psr); +} + +static inline void +pfm_save_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + + ia64_srlz_d(); + + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) pmds[i] = ia64_get_pmd(i); + } +} + +/* + * reload from thread state (used for ctxw only) + */ +static inline void +pfm_restore_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + unsigned long val, ovfl_val = pmu_conf.ovfl_val; + + DPRINT(("mask=0x%lx\n", mask)); + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i]; + ia64_set_pmd(i, val); + DPRINT(("pmd[%d]=0x%lx\n", i, val)); + } + ia64_srlz_d(); +} + +/* + * propagate PMD from context to thread-state + */ +static inline void +pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long ovfl_val = pmu_conf.ovfl_val; + unsigned long mask = ctx->ctx_all_pmds[0]; + unsigned long val; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + + val = ctx->ctx_pmds[i].val; + + /* + * We break up the 64 bit value into 2 pieces + * the lower bits go to the machine state in the + * thread (will be reloaded on ctxsw in). + * The upper part stays in the soft-counter. + */ + if (PMD_IS_COUNTING(i)) { + ctx->ctx_pmds[i].val = val & ~ovfl_val; + val &= ovfl_val; + } + thread->pmds[i] = val; + + DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n", + i, + thread->pmds[i], + ctx->ctx_pmds[i].val)); + } +} + +/* + * propagate PMC from context to thread-state + */ +static inline void +pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long mask = ctx->ctx_all_pmcs[0]; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + /* masking 0 with ovfl_val yields 0 */ + thread->pmcs[i] = ctx->ctx_pmcs[i]; + DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i])); + } +} + + + +static inline void +pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask) +{ + int i; + + DPRINT(("mask=0x%lx\n", mask)); + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + ia64_set_pmc(i, pmcs[i]); + DPRINT(("pmc[%d]=0x%lx\n", i, pmcs[i])); + } + ia64_srlz_d(); +} + +static inline void +pfm_restore_ibrs(unsigned long *ibrs, unsigned int nibrs) +{ + int i; + + for (i=0; i < nibrs; i++) { + ia64_set_ibr(i, ibrs[i]); + } + ia64_srlz_i(); +} + +static inline void +pfm_restore_dbrs(unsigned long *dbrs, unsigned int ndbrs) +{ + int i; + + for (i=0; i < ndbrs; i++) { + ia64_set_dbr(i, dbrs[i]); + } + ia64_srlz_d(); +} + +static inline int +pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b) +{ + return memcmp(a, b, sizeof(pfm_uuid_t)); +} + +static inline int +pfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size) +{ + int ret = 0; + if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size); + return ret; +} + + +static inline int +pfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs); + return ret; +} + + + +int +pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt) +{ + pfm_buffer_fmt_t *p; + int ret = 0; + + /* some sanity checks */ + if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL; + + /* we need at least a handler */ + if (fmt->fmt_handler == NULL) return -EINVAL; + + /* + * XXX: need check validity of fmt_arg_size + */ + + LOCK_BUF_FMT_LIST(); + p = pfm_buffer_fmt_list; + + + while (p) { + if (pfm_uuid_cmp(fmt->fmt_uuid, p->fmt_uuid) == 0) break; + p = p->fmt_next; + } + + if (p) { + printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name); + ret = -EBUSY; + } else { + fmt->fmt_prev = NULL; + fmt->fmt_next = pfm_buffer_fmt_list; + pfm_buffer_fmt_list = fmt; + printk(KERN_ERR "perfmon: added sampling format %s\n", fmt->fmt_name); + } + UNLOCK_BUF_FMT_LIST(); + + return ret; +} + +int +pfm_unregister_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t *p; + int ret = 0; + + LOCK_BUF_FMT_LIST(); + p = pfm_buffer_fmt_list; + while (p) { + if (memcmp(uuid, p->fmt_uuid, sizeof(pfm_uuid_t)) == 0) break; + p = p->fmt_next; + } + if (p) { + if (p->fmt_prev) + p->fmt_prev->fmt_next = p->fmt_next; + else + pfm_buffer_fmt_list = p->fmt_next; + + if (p->fmt_next) + p->fmt_next->fmt_prev = p->fmt_prev; + + printk(KERN_ERR "perfmon: removed sampling format: %s\n", p->fmt_name); + p->fmt_next = p->fmt_prev = NULL; + } else { + printk(KERN_ERR "perfmon: cannot unregister format, not found\n"); + ret = -EINVAL; + } + UNLOCK_BUF_FMT_LIST(); + + return ret; + +} + +/* + * find a buffer format based on its uuid + */ +static pfm_buffer_fmt_t * +pfm_find_buffer_fmt(pfm_uuid_t uuid, int nolock) +{ + pfm_buffer_fmt_t *p; + + LOCK_BUF_FMT_LIST(); + for (p = pfm_buffer_fmt_list; p ; p = p->fmt_next) { + if (pfm_uuid_cmp(uuid, p->fmt_uuid) == 0) break; + } + + UNLOCK_BUF_FMT_LIST(); + + return p; +} + +static int +pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) +{ + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + if (is_syswide) { + /* + * cannot mix system wide and per-task sessions + */ + if (pfm_sessions.pfs_task_sessions > 0UL) { + DPRINT(("system wide not possible, %u conflicting task_sessions\n", + pfm_sessions.pfs_task_sessions)); + goto abort; + } + + if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict; + + DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); + + pfm_sessions.pfs_sys_session[cpu] = task; + + pfm_sessions.pfs_sys_sessions++ ; + + } else { + if (pfm_sessions.pfs_sys_sessions) goto abort; + pfm_sessions.pfs_task_sessions++; + } + + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + UNLOCK_PFS(); + + return 0; + +error_conflict: + DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", + pfm_sessions.pfs_sys_session[cpu]->pid, + smp_processor_id())); +abort: + UNLOCK_PFS(); + + return -EBUSY; + +} + +static int +pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu) +{ + + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + + if (is_syswide) { + pfm_sessions.pfs_sys_session[cpu] = NULL; + /* + * would not work with perfmon+more than one bit in cpu_mask + */ + if (ctx && ctx->ctx_fl_using_dbreg) { + if (pfm_sessions.pfs_sys_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx); + } else { + pfm_sessions.pfs_sys_use_dbregs--; + } + } + pfm_sessions.pfs_sys_sessions--; + } else { + pfm_sessions.pfs_task_sessions--; + } + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + UNLOCK_PFS(); + + return 0; +} + +/* + * removes virtual mapping of the sampling buffer. + * IMPORTANT: cannot be called with interrupts disable, e.g. inside + * a PROTECT_CTX() section. + */ +static int +pfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long size) +{ + int r; + + /* sanity checks */ + if (task->mm == NULL || size == 0UL || vaddr == NULL) { + printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task->pid, task->mm); + return -EINVAL; + } + + DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size)); + + /* + * does the actual unmapping + */ + down_write(&task->mm->mmap_sem); + + DPRINT(("down_write done smpl_vaddr=%p size=%lu\n", vaddr, size)); + + r = do_munmap(task->mm, (unsigned long)vaddr, size); + + up_write(&task->mm->mmap_sem); + if (r !=0) { + printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task->pid, vaddr, size); + } + + DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r)); + + return 0; +} + +/* + * free actual physical storage used by sampling buffer + */ +#if 0 +static int +pfm_free_smpl_buffer(pfm_context_t *ctx) +{ + pfm_buffer_fmt_t *fmt; + + if (ctx->ctx_smpl_hdr == NULL) goto invalid_free; + + /* + * we won't use the buffer format anymore + */ + fmt = ctx->ctx_buf_fmt; + + DPRINT(("sampling buffer @%p size %lu vaddr=%p\n", + ctx->ctx_smpl_hdr, + ctx->ctx_smpl_size, + ctx->ctx_smpl_vaddr)); + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + + /* + * free the buffer + */ + pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size); + + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_smpl_size = 0UL; + + return 0; + +invalid_free: + printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", current->pid); + return -EINVAL; +} +#endif + +static inline void +pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt) +{ + if (fmt == NULL) return; + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + +} + +/* + * pfmfs should _never_ be mounted by userland - too much of security hassle, + * no real gain from having the whole whorehouse mounted. So we don't need + * any operations on the root directory. However, we need a non-trivial + * d_name - pfm: will go nicely and kill the special-casing in procfs. + */ +static struct vfsmount *pfmfs_mnt; +#define PFMFS_MAGIC 0xa0b4d889 + +#ifdef PFM_COMPILED_FOR_2_4 + +static int +pfmfs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = PFMFS_MAGIC; + buf->f_bsize = 1024; + buf->f_namelen = 255; + return 0; +} + +static struct super_operations pfmfs_ops = { + statfs: pfmfs_statfs, +}; + +static struct super_block * +pfmfs_read_super(struct super_block *sb, void *data, int silent) +{ + struct inode *root = new_inode(sb); + if (!root) + return NULL; + root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; + root->i_uid = root->i_gid = 0; + root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = PFMFS_MAGIC; + sb->s_op = &pfmfs_ops; + sb->s_root = d_alloc(NULL, &(const struct qstr) { "pfm:", 4, 0 }); + if (!sb->s_root) { + iput(root); + return NULL; + } + sb->s_root->d_sb = sb; + sb->s_root->d_parent = sb->s_root; + d_instantiate(sb->s_root, root); + return sb; +} + +//static DECLARE_FSTYPE(pfm_fs_type, "pfmfs", pfmfs_read_super, FS_NOMOUNT); +static struct file_system_type pfm_fs_type = { + name: "pfmfs", + read_super: pfmfs_read_super, + fs_flags: FS_NOMOUNT, +}; + +#else /* ! COMPILED_FOR_2_4 */ + +static struct super_block * +pfmfs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); +} + +static struct file_system_type pfm_fs_type = { + .name = "pfmfs", + .get_sb = pfmfs_get_sb, + .kill_sb = kill_anon_super, +}; +#endif /* COMPILED_FOR_2_4 */ + +static int __init +init_pfm_fs(void) +{ + int err = register_filesystem(&pfm_fs_type); + if (!err) { + pfmfs_mnt = kern_mount(&pfm_fs_type); + err = PTR_ERR(pfmfs_mnt); + if (IS_ERR(pfmfs_mnt)) + unregister_filesystem(&pfm_fs_type); + else + err = 0; + } + return err; +} + +static void __exit +exit_pfm_fs(void) +{ + unregister_filesystem(&pfm_fs_type); + mntput(pfmfs_mnt); +} + +static loff_t +pfm_lseek(struct file *file, loff_t offset, int whence) +{ + DPRINT(("pfm_lseek called\n")); + return -ESPIPE; +} + +static ssize_t +pfm_do_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +{ + pfm_context_t *ctx; + pfm_msg_t *msg; + ssize_t ret; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return -EINVAL; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", current->pid); + return -EINVAL; + } + + /* + * check even when there is no message + */ + if (size < sizeof(pfm_msg_t)) { + DPRINT(("message is too small ctx=%p (>=%ld)\n", ctx, sizeof(pfm_msg_t))); + return -EINVAL; + } + /* + * seeks are not allowed on message queues + */ + if (ppos != &filp->f_pos) return -ESPIPE; + + PROTECT_CTX(ctx, flags); + + /* + * put ourselves on the wait queue + */ + add_wait_queue(&ctx->ctx_msgq_wait, &wait); + + + for(;;) { + /* + * check wait queue + */ + + set_current_state(TASK_INTERRUPTIBLE); + + DPRINT(("head=%d tail=%d\n", ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + ret = 0; + if(PFM_CTXQ_EMPTY(ctx) == 0) break; + + UNPROTECT_CTX(ctx, flags); + + /* + * check non-blocking read + */ + ret = -EAGAIN; + if(filp->f_flags & O_NONBLOCK) break; + + /* + * check pending signals + */ + if(signal_pending(current)) { + ret = -EINTR; + break; + } + /* + * no message, so wait + */ + schedule(); + + PROTECT_CTX(ctx, flags); + } + DPRINT(("[%d] back to running ret=%ld\n", current->pid, ret)); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctx->ctx_msgq_wait, &wait); + + if (ret < 0) goto abort; + + ret = -EINVAL; + msg = pfm_get_next_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_read no msg for ctx=%p [%d]\n", ctx, current->pid); + goto abort_locked; + } + + DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); + + ret = -EFAULT; + if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); + +abort_locked: + UNPROTECT_CTX(ctx, flags); +abort: + return ret; +} + +static ssize_t +pfm_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +{ + int oldvar, ret; + + oldvar = pfm_debug_var; + pfm_debug_var = pfm_sysctl.debug_pfm_read; + ret = pfm_do_read(filp, buf, size, ppos); + pfm_debug_var = oldvar; + return ret; +} + +static ssize_t +pfm_write(struct file *file, const char *ubuf, + size_t size, loff_t *ppos) +{ + DPRINT(("pfm_write called\n")); + return -EINVAL; +} + +static unsigned int +pfm_poll(struct file *filp, poll_table * wait) +{ + pfm_context_t *ctx; + unsigned long flags; + unsigned int mask = 0; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return 0; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", current->pid); + return 0; + } + + + DPRINT(("pfm_poll ctx_fd=%d before poll_wait\n", ctx->ctx_fd)); + + poll_wait(filp, &ctx->ctx_msgq_wait, wait); + + PROTECT_CTX(ctx, flags); + + if (PFM_CTXQ_EMPTY(ctx) == 0) + mask = POLLIN | POLLRDNORM; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("pfm_poll ctx_fd=%d mask=0x%x\n", ctx->ctx_fd, mask)); + + return mask; +} + +static int +pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + DPRINT(("pfm_ioctl called\n")); + return -EINVAL; +} + +/* + * context is locked when coming here + */ +static inline int +pfm_do_fasync(int fd, struct file *filp, pfm_context_t *ctx, int on) +{ + int ret; + + ret = fasync_helper (fd, filp, on, &ctx->ctx_async_queue); + + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); + + return ret; +} + +static int +pfm_fasync(int fd, struct file *filp, int on) +{ + pfm_context_t *ctx; + unsigned long flags; + int ret; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_fasync bad magic [%d]\n", current->pid); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + + PROTECT_CTX(ctx, flags); + + ret = pfm_do_fasync(fd, filp, ctx, on); + + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); + + UNPROTECT_CTX(ctx, flags); + + return ret; +} + +#ifdef CONFIG_SMP +/* + * this function is exclusively called from pfm_close(). + * The context is not protected at that time, nor are interrupts + * on the remote CPU. That's necessary to avoid deadlocks. + */ +static void +pfm_syswide_force_stop(void *info) +{ + pfm_context_t *ctx = (pfm_context_t *)info; + struct pt_regs *regs = ia64_task_regs(current); + struct task_struct *owner; + + if (ctx->ctx_cpu != smp_processor_id()) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop for CPU%d but on CPU%d\n", + ctx->ctx_cpu, + smp_processor_id()); + return; + } + owner = GET_PMU_OWNER(); + if (owner != ctx->ctx_task) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected owner [%d] instead of [%d]\n", + smp_processor_id(), + owner->pid, ctx->ctx_task->pid); + return; + } + if (GET_PMU_CTX() != ctx) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected ctx %p instead of %p\n", + smp_processor_id(), + GET_PMU_CTX(), ctx); + return; + } + + DPRINT(("[%d] on CPU%d forcing system wide stop for [%d]\n", current->pid, smp_processor_id(), ctx->ctx_task->pid)); + /* + * Update local PMU + */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + ia64_srlz_i(); + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); + + pfm_clear_psr_pp(); + + /* + * also stop monitoring in the local interrupted task + */ + ia64_psr(regs)->pp = 0; + + SET_PMU_OWNER(NULL, NULL); +} + +static void +pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx) +{ + int ret; + + DPRINT(("[%d] calling CPU%d for cleanup\n", current->pid, ctx->ctx_cpu)); + ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 0, 1); + DPRINT(("[%d] called CPU%d for cleanup ret=%d\n", current->pid, ctx->ctx_cpu, ret)); +} +#endif /* CONFIG_SMP */ + +/* + * called either on explicit close() or from exit_files(). + * + * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero (fput()),i.e, + * last task to access the file. Nobody else can access the file at this point. + * + * When called from exit_files(), the VMA has been freed because exit_mm() + * is executed before exit_files(). + * + * When called from exit_files(), the current task is not yet ZOMBIE but we will + * flush the PMU state to the context. This means * that when we see the context + * state as TERMINATED we are guranteed to have the latest PMU state available, + * even if the task itself is in the middle of being ctxsw out. + */ +static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); +static int +pfm_close(struct inode *inode, struct file *filp) +{ + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_vaddr = NULL; + void *smpl_buf_addr = NULL; + int free_possible = 1; + + { u64 psr = pfm_get_psr(); + BUG_ON((psr & IA64_PSR_I) == 0UL); + } + + DPRINT(("pfm_close called private=%p\n", filp->private_data)); + + if (!inode) { + printk(KERN_ERR "pfm_close: NULL inode\n"); + return 0; + } + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_close: bad magic [%d]\n", current->pid); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + PROTECT_CTX(ctx, flags); + + /* + * remove our file from the async queue, if we use it + */ + if (filp->f_flags & FASYNC) { + DPRINT(("[%d] before async_queue=%p\n", current->pid, ctx->ctx_async_queue)); + pfm_do_fasync (-1, filp, ctx, 0); + DPRINT(("[%d] after async_queue=%p\n", current->pid, ctx->ctx_async_queue)); + } + + task = PFM_CTX_TASK(ctx); + + DPRINT(("[%d] ctx_state=%d\n", current->pid, ctx->ctx_state)); + + if (CTX_IS_UNLOADED(ctx) || CTX_IS_TERMINATED(ctx)) { + goto doit; + } + + regs = ia64_task_regs(task); + + /* + * context still loaded/masked and self monitoring, + * we stop/unload and we destroy right here + * + * We always go here for system-wide sessions + */ + if (task == current) { +#ifdef CONFIG_SMP + /* + * the task IS the owner but it migrated to another CPU: that's bad + * but we must handle this cleanly. Unfortunately, the kernel does + * not provide a mechanism to block migration (while the context is loaded). + * + * We need to release the resource on the ORIGINAL cpu. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + + UNPROTECT_CTX(ctx, flags); + + pfm_syswide_cleanup_other_cpu(ctx); + + PROTECT_CTX(ctx, flags); + + /* + * short circuit pfm_context_unload(); + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + CTX_UNLOADED(ctx); + + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); + } else +#endif /* CONFIG_SMP */ + { + + DPRINT(("forcing unload on [%d]\n", current->pid)); + /* + * stop and unload, returning with state UNLOADED + * and session unreserved. + */ + pfm_context_unload(ctx, NULL, 0, regs); + + CTX_TERMINATED(ctx); + + DPRINT(("[%d] ctx_state=%d\n", current->pid, ctx->ctx_state)); + } + goto doit; + } + + /* + * The task is currently blocked or will block after an overflow. + * we must force it to wakeup to get out of the + * MASKED state and transition to the unloaded state by itself + */ + if (CTX_IS_MASKED(ctx) && CTX_OVFL_NOBLOCK(ctx) == 0) { + + /* + * set a "partial" zombie state to be checked + * upon return from down() in pfm_handle_work(). + * + * We cannot use the ZOMBIE state, because it is checked + * by pfm_load_regs() which is called upon wakeup from down(). + * In such cas, it would free the context and then we would + * return to pfm_handle_work() which would access the + * stale context. Instead, we set a flag invisible to pfm_load_regs() + * but visible to pfm_handle_work(). + * + * For some window of time, we have a zombie context with + * ctx_state = MASKED and not ZOMBIE + */ + ctx->ctx_fl_going_zombie = 1; + + /* + * force task to wake up from MASKED state + */ + up(&ctx->ctx_restart_sem); + + DPRINT(("waking up ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + + /* + * put ourself to sleep waiting for the other + * task to report completion + * + * the context is protected by mutex, therefore there + * is no risk of being notified of completion before + * begin actually on the waitq. + */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ctx->ctx_zombieq, &wait); + + UNPROTECT_CTX(ctx, flags); + + /* + * XXX: check for signals : + * - ok of explicit close + * - not ok when coming from exit_files() + */ + schedule(); + + DPRINT(("woken up ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + + PROTECT_CTX(ctx, flags); + + remove_wait_queue(&ctx->ctx_zombieq, &wait); + set_current_state(TASK_RUNNING); + + /* + * context is terminated at this point + */ + DPRINT(("after zombie wakeup ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + } + else { +#ifdef CONFIG_SMP + /* + * switch context to zombie state + */ + CTX_ZOMBIE(ctx); + + DPRINT(("zombie ctx for [%d]\n", task->pid)); + /* + * cannot free the context on the spot. deferred until + * the task notices the ZOMBIE state + */ + free_possible = 0; +#else + pfm_context_unload(ctx, NULL, 0, regs); +#endif + } + +doit: /* cannot assume task is defined from now on */ + /* + * the context is still attached to a task (possibly current) + * we cannot destroy it right now + */ + /* + * remove virtual mapping, if any. will be NULL when + * called from exit_files(). + */ + if (ctx->ctx_smpl_vaddr) { + smpl_buf_vaddr = ctx->ctx_smpl_vaddr; + smpl_buf_size = ctx->ctx_smpl_size; + ctx->ctx_smpl_vaddr = NULL; + } + + /* + * we must fre the sampling buffer right here because + * we cannot rely on it being cleaned up later by the + * monitored task. It is not possible to free vmalloc'ed + * memory in pfm_load_regs(). Instead, we remove the buffer + * now. should there be subsequent PMU overflow originally + * meant for sampling, the will be converted to spurious + * and that's fine because the monitoring tools is gone anyway. + */ + if (ctx->ctx_smpl_hdr) { + smpl_buf_addr = ctx->ctx_smpl_hdr; + smpl_buf_size = ctx->ctx_smpl_size; + /* no more sampling */ + ctx->ctx_smpl_hdr = NULL; + } + + + DPRINT(("[%d] ctx_state=%d free_possible=%d vaddr=%p addr=%p size=%lu\n", + current->pid, + ctx->ctx_state, + free_possible, + smpl_buf_vaddr, + smpl_buf_addr, + smpl_buf_size)); + + if (smpl_buf_addr) pfm_exit_smpl_buffer(ctx->ctx_buf_fmt); + + /* + * UNLOADED and TERMINATED mean that the session has already been + * unreserved. + */ + if (CTX_IS_ZOMBIE(ctx)) { + pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu); + } + + /* + * disconnect file descriptor from context must be done + * before we unlock. + */ + filp->private_data = NULL; + + /* + * if we free on the spot, the context is now completely unreacheable + * from the callers side. The monitored task side is also cut, so we + * can freely cut. + * + * If we have a deferred free, only the caller side is disconnected. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * if there was a mapping, then we systematically remove it + * at this point. Cannot be done inside critical section + * because some VM function reenables interrupts. + * + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (smpl_buf_vaddr) pfm_remove_smpl_mapping(current, smpl_buf_vaddr, smpl_buf_size); + if (smpl_buf_addr) pfm_rvfree(smpl_buf_addr, smpl_buf_size); + + /* + * return the memory used by the context + */ + if (free_possible) pfm_context_free(ctx); + + return 0; +} + +static int +pfm_no_open(struct inode *irrelevant, struct file *dontcare) +{ + DPRINT(("pfm_no_open called\n")); + return -ENXIO; +} + +static struct file_operations pfm_file_ops = { + .llseek = pfm_lseek, + .read = pfm_read, + .write = pfm_write, + .poll = pfm_poll, + .ioctl = pfm_ioctl, + .open = pfm_no_open, /* special open code to disallow open via /proc */ + .fasync = pfm_fasync, + .release = pfm_close +}; + +static int +pfmfs_delete_dentry(struct dentry *dentry) +{ + return 1; +} +static struct dentry_operations pfmfs_dentry_operations = { + d_delete: pfmfs_delete_dentry, +}; + + +static int +pfm_alloc_fd(struct file **cfile) +{ + int fd, ret = 0; + struct file *file = NULL; + struct inode * inode; + char name[32]; + struct qstr this; + + fd = get_unused_fd(); + if (fd < 0) return -ENFILE; + + ret = -ENFILE; + + file = get_empty_filp(); + if (!file) goto out; + + /* + * allocate a new inode + */ + inode = new_inode(pfmfs_mnt->mnt_sb); + if (!inode) goto out; + + DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); + + inode->i_sb = pfmfs_mnt->mnt_sb; + inode->i_mode = S_IFCHR|S_IRUGO; + inode->i_sock = 0; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; + + ret = -ENOMEM; + + /* + * allocate a new dcache entry + */ + file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); + if (!file->f_dentry) goto out; + + file->f_dentry->d_op = &pfmfs_dentry_operations; + + d_add(file->f_dentry, inode); + file->f_vfsmnt = mntget(pfmfs_mnt); + + file->f_op = &pfm_file_ops; + file->f_mode = FMODE_READ; + file->f_flags = O_RDONLY; + file->f_pos = 0; + + /* + * may have to delay until context is attached? + */ + fd_install(fd, file); + + /* + * the file structure we will use + */ + *cfile = file; + + return fd; +out: + if (file) put_filp(file); + put_unused_fd(fd); + return ret; +} + +static void +pfm_free_fd(int fd, struct file *file) +{ + if (file) put_filp(file); + put_unused_fd(fd); +} + +/* + * This function gets called from mm/mmap.c:exit_mmap() only when there is a sampling buffer + * attached to the context AND the current task has a mapping for it, i.e., it is the original + * creator of the context. + * + * This function is used to remember the fact that the vma describing the sampling buffer + * has now been removed. It can only be called when no other tasks share the same mm context. + * + */ +static void +pfm_vm_close(struct vm_area_struct *vma) +{ + pfm_context_t *ctx = (pfm_context_t *)vma->vm_private_data; + unsigned long flags; + + PROTECT_CTX(ctx, flags); + ctx->ctx_smpl_vaddr = NULL; + UNPROTECT_CTX(ctx, flags); + DPRINT(("[%d] clearing vaddr for ctx %p\n", current->pid, ctx)); +} + +static int +pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) +{ + unsigned long page; + + DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); + + while (size > 0) { + page = pfm_kvirt_to_pa(buf); + + if (pfm_remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +/* + * allocate a sampling buffer and remaps it into the user address space of the task + */ +static int +pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma = NULL; + unsigned long size; + void *smpl_buf; + + + /* + * the fixed header + requested size and align to page boundary + */ + size = PAGE_ALIGN(rsize); + + DPRINT(("sampling buffer rsize=%lu size=%lu bytes\n", rsize, size)); + + /* + * check requested size to avoid Denial-of-service attacks + * XXX: may have to refine this test + * Check against address space limit. + * + * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) + * return -ENOMEM; + */ + if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + + /* + * We do the easy to undo allocations first. + * + * pfm_rvmalloc(), clears the buffer, so there is no leak + */ + smpl_buf = pfm_rvmalloc(size); + if (smpl_buf == NULL) { + DPRINT(("Can't allocate sampling buffer\n")); + return -ENOMEM; + } + + DPRINT(("[%d] smpl_buf @%p\n", current->pid, smpl_buf)); + + /* allocate vma */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) { + DPRINT(("Cannot allocate vma\n")); + goto error_kmem; + } + /* + * partially initialize the vma for the sampling buffer + * + * The VM_DONTCOPY flag is very important as it ensures that the mapping + * will never be inherited for any child process (via fork()) which is always + * what we want. + */ + vma->vm_mm = mm; + vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + vma->vm_ops = &pfm_vm_ops; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = ctx; /* information needed by the pfm_vm_close() function */ + + /* + * Now we have everything we need and we can initialize + * and connect all the data structures + */ + + ctx->ctx_smpl_hdr = smpl_buf; + ctx->ctx_smpl_size = size; /* aligned size */ + + /* + * Let's do the difficult operations next. + * + * now we atomically find some area in the address space and + * remap the buffer in it. + */ + down_write(&task->mm->mmap_sem); + + /* find some free area in address space, must have mmap sem held */ + vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS); + if (vma->vm_start == 0UL) { + DPRINT(("Cannot find unmapped area for size %ld\n", size)); + up_write(&task->mm->mmap_sem); + goto error; + } + vma->vm_end = vma->vm_start + size; + + DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start)); + + /* can only be applied to current task, need to have the mm semaphore held when called */ + if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { + DPRINT(("Can't remap buffer\n")); + up_write(&task->mm->mmap_sem); + goto error; + } + + /* + * now insert the vma in the vm list for the process, must be + * done with mmap lock held + */ + insert_vm_struct(mm, vma); + + mm->total_vm += size >> PAGE_SHIFT; + + up_write(&task->mm->mmap_sem); + + /* + * keep track of user level virtual address + */ + ctx->ctx_smpl_vaddr = (void *)vma->vm_start; + *(unsigned long *)user_vaddr = vma->vm_start; + + return 0; + +error: + kmem_cache_free(vm_area_cachep, vma); +error_kmem: + pfm_rvfree(smpl_buf, size); + + return -ENOMEM; +} + +/* + * XXX: do something better here + */ +static int +pfm_bad_permissions(struct task_struct *task) +{ + /* stolen from bad_signal() */ + return (current->session != task->session) + && (current->euid ^ task->suid) && (current->euid ^ task->uid) + && (current->uid ^ task->suid) && (current->uid ^ task->uid); +} + +static int +pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) +{ + int ctx_flags; + + /* valid signal */ + + ctx_flags = pfx->ctx_flags; + + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + + /* + * cannot block in this mode + */ + if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { + DPRINT(("cannot use blocking mode when in system wide monitoring\n")); + return -EINVAL; + } + } else { + } + /* probably more to add here */ + + return 0; +} + +static int +pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, + unsigned int cpu, pfarg_context_t *arg) +{ + pfm_buffer_fmt_t *fmt = NULL; + unsigned long size = 0UL; + void *uaddr = NULL; + void *fmt_arg = NULL; + int ret = 0; +#define PFM_CTXARG_BUF_ARG(a) (pfm_buffer_fmt_t *)(a+1) + + /* invoke and lock buffer format, if found */ + fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id, 0); + if (fmt == NULL) { + DPRINT(("[%d] cannot find buffer format\n", task->pid)); + return -EINVAL; + } + + /* + * buffer argument MUST be contiguous to pfarg_context_t + */ + if (fmt->fmt_arg_size) fmt_arg = PFM_CTXARG_BUF_ARG(arg); + + ret = pfm_buf_fmt_validate(fmt, task, ctx_flags, cpu, fmt_arg); + + DPRINT(("[%d] after validate(0x%x,%d,%p)=%d\n", task->pid, ctx_flags, cpu, fmt_arg, ret)); + + if (ret) goto error; + + /* link buffer format and context */ + ctx->ctx_buf_fmt = fmt; + + /* + * check if buffer format wants to use perfmon buffer allocation/mapping service + */ + ret = pfm_buf_fmt_getsize(fmt, task, ctx_flags, cpu, fmt_arg, &size); + if (ret) goto error; + + if (size) { + /* + * buffer is always remapped into the caller's address space + */ + ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); + if (ret) goto error; + + /* keep track of user address of buffer */ + arg->ctx_smpl_vaddr = uaddr; + } + ret = pfm_buf_fmt_init(fmt, task, ctx->ctx_smpl_hdr, ctx_flags, cpu, fmt_arg); + +error: + return ret; +} + +static void +pfm_reset_pmu_state(pfm_context_t *ctx) +{ + int i; + + /* + * install reset values for PMC. + */ + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + ctx->ctx_pmcs[i] = PMC_DFL_VAL(i); + DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i])); + } + /* + * PMD registers are set to 0UL when the context in memset() + */ + + /* + * On context switched restore, we must restore ALL pmc and ALL pmd even + * when they are not actively used by the task. In UP, the incoming process + * may otherwise pick up left over PMC, PMD state from the previous process. + * As opposed to PMD, stale PMC can cause harm to the incoming + * process because they may change what is being measured. + * Therefore, we must systematically reinstall the entire + * PMC state. In SMP, the same thing is possible on the + * same CPU but also on between 2 CPUs. + * + * The problem with PMD is information leaking especially + * to user level when psr.sp=0 + * + * There is unfortunately no easy way to avoid this problem + * on either UP or SMP. This definitively slows down the + * pfm_load_regs() function. + */ + + /* + * bitmask of all PMCs accessible to this context + * + * PMC0 is treated differently. + */ + ctx->ctx_all_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1; + + /* + * bitmask of all PMDs that are accesible to this context + */ + ctx->ctx_all_pmds[0] = pmu_conf.impl_pmds[0]; + + DPRINT(("<%d> all_pmcs=0x%lx all_pmds=0x%lx\n", ctx->ctx_fd, ctx->ctx_all_pmcs[0],ctx->ctx_all_pmds[0])); + + /* + * useful in case of re-enable after disable + */ + ctx->ctx_used_ibrs[0] = 0UL; + ctx->ctx_used_dbrs[0] = 0UL; +} + +static int +pfm_ctx_getsize(void *arg, size_t *sz) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + pfm_buffer_fmt_t *fmt; + + *sz = 0; + + if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0; + + /* no buffer locking here, will be called again */ + fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id, 1); + if (fmt == NULL) { + DPRINT(("cannot find buffer format\n")); + return -EINVAL; + } + /* get just enough to copy in user parameters */ + *sz = fmt->fmt_arg_size; + DPRINT(("arg_size=%lu\n", *sz)); + + return 0; +} + + + +/* + * cannot attach if : + * - kernel task + * - task not owned by caller + * - task incompatible with context mode + */ +static int +pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) +{ + /* + * no kernel task or task not owner by caller + */ + if (task->mm == NULL) { + DPRINT(("[%d] task [%d] has not memory context (kernel thread)\n", current->pid, task->pid)); + return -EPERM; + } + if (pfm_bad_permissions(task)) { + DPRINT(("[%d] no permission to attach to [%d]\n", current->pid, task->pid)); + return -EPERM; + } + /* + * cannot block in self-monitoring mode + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && task == current) { + DPRINT(("cannot load a blocking context on self for [%d]\n", task->pid)); + return -EINVAL; + } + + if (task->state == TASK_ZOMBIE) { + DPRINT(("[%d] cannot attach to zombie task [%d]\n", current->pid, task->pid)); + return -EBUSY; + } + + /* + * always ok for self + */ + if (task == current) return 0; + + if (task->state != TASK_STOPPED) { + DPRINT(("[%d] cannot attach to non-stopped task [%d] state=%ld\n", current->pid, task->pid, task->state)); + return -EBUSY; + } + /* + * make sure the task is off any CPU + */ + pfm_wait_task_inactive(task); + + /* more to come... */ + + return 0; +} + +static int +pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task) +{ + struct task_struct *p = current; + int ret; + + /* XXX: need to add more checks here */ + if (pid < 2) return -EPERM; + + if (pid != current->pid) { + + read_lock(&tasklist_lock); + + p = find_task_by_pid(pid); + + /* make sure task cannot go away while we operate on it */ + if (p) get_task_struct(p); + + read_unlock(&tasklist_lock); + + if (p == NULL) return -ESRCH; + } + + ret = pfm_task_incompatible(ctx, p); + if (ret == 0) { + *task = p; + } else if (p != current) { + pfm_put_task(p); + } + return ret; +} + + + +static int +pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + struct file *filp; + int ctx_flags; + int ret; + + /* let's check the arguments first */ + ret = pfarg_is_sane(current, req); + if (ret < 0) return ret; + + ctx_flags = req->ctx_flags; + + ret = -ENOMEM; + + ctx = pfm_context_alloc(); + if (!ctx) goto error; + + req->ctx_fd = ctx->ctx_fd = pfm_alloc_fd(&filp); + if (req->ctx_fd < 0) goto error_file; + + /* + * attach context to file + */ + filp->private_data = ctx; + + /* + * does the user want to sample? + */ + if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { + ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); + if (ret) goto buffer_error; + } + + /* + * init context protection lock + */ + spin_lock_init(&ctx->ctx_lock); + + /* + * context is unloaded + */ + CTX_UNLOADED(ctx); + + /* + * initialization of context's flags + */ + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; + ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ + ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; + /* + * will move to set properties + * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + */ + + /* + * init restart semaphore to locked + */ + sema_init(&ctx->ctx_restart_sem, 0); + + /* + * activation is used in SMP only + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * initialize notification message queue + */ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + init_waitqueue_head(&ctx->ctx_msgq_wait); + init_waitqueue_head(&ctx->ctx_zombieq); + + DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d unsecure=%d no_msg=%d ctx_fd=%d \n", + ctx, + ctx_flags, + ctx->ctx_fl_system, + ctx->ctx_fl_block, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_unsecure, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + + /* + * initialize soft PMU state + */ + pfm_reset_pmu_state(ctx); + + return 0; + +buffer_error: + pfm_free_fd(ctx->ctx_fd, filp); + + if (ctx->ctx_buf_fmt) { + pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); + } +error_file: + pfm_context_free(ctx); + +error: + return ret; +} + +static inline unsigned long +pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset) +{ + unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset; + unsigned long new_seed, old_seed = reg->seed, mask = reg->mask; + extern unsigned long carta_random32 (unsigned long seed); + + if (reg->flags & PFM_REGFL_RANDOM) { + new_seed = carta_random32(old_seed); + val -= (old_seed & mask); /* counter values are negative numbers! */ + if ((mask >> 32) != 0) + /* construct a full 64-bit random value: */ + new_seed |= carta_random32(old_seed >> 32) << 32; + reg->seed = new_seed; + } + reg->lval = val; + return val; +} + +static void +pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i, is_long_reset = (flag == PFM_PMD_LONG_RESET); + + DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag)); + + if (flag == PFM_PMD_NO_RESET) return; + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + if (mask & 0x1) { + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } +} + +static void +pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i, is_long_reset = (flag == PFM_PMD_LONG_RESET); + + DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag)); + + if (flag == PFM_PMD_NO_RESET) return; + + if (CTX_IS_MASKED(ctx)) { + pfm_reset_regs_masked(ctx, ovfl_regs, flag); + return; + } + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + if (mask & 0x1) { + val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + + pfm_write_soft_counter(ctx, i, val); + } + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + if (PMD_IS_COUNTING(i)) { + pfm_write_soft_counter(ctx, i, val); + } else { + ia64_set_pmd(i, val); + } + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } + ia64_srlz_d(); +} + +static int +pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value; + unsigned long smpl_pmds, reset_pmds; + unsigned int cnum, reg_flags, flags; + int i, can_access_pmu = 0, is_loaded; + int is_monitor, is_counting; + int ret = -EINVAL; +#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) + + if (CTX_IS_DEAD(ctx)) return -EINVAL; + + is_loaded = CTX_IS_LOADED(ctx); + + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + reg_flags = req->reg_flags; + value = req->reg_value; + smpl_pmds = req->reg_smpl_pmds[0]; + reset_pmds = req->reg_reset_pmds[0]; + flags = 0; + + is_counting = PMC_IS_COUNTING(cnum); + is_monitor = PMC_IS_MONITOR(cnum); + + /* + * we reject all non implemented PMC as well + * as attempts to modify PMC[0-3] which are used + * as status registers by the PMU + */ + if (!PMC_IS_IMPL(cnum) || cnum < 4) { + DPRINT(("pmc%u is unimplemented or invalid\n", cnum)); + goto error; + } + /* + * If the PMC is a monitor, then if the value is not the default: + * - system-wide session: PMCx.pm=1 (privileged monitor) + * - per-task : PMCx.pm=0 (user monitor) + */ + if ((is_monitor || is_counting) && value != PMC_DFL_VAL(i) && PFM_CHECK_PMC_PM(ctx, cnum, value)) { + DPRINT(("pmc%u pmc_pm=%ld fl_system=%d\n", + cnum, + PMC_PM(cnum, value), + ctx->ctx_fl_system)); + goto error; + } + + + if (is_counting) { + pfm_monitor_t *p = (pfm_monitor_t *)&value; + /* + * enforce generation of overflow interrupt. Necessary on all + * CPUs. + */ + p->pmc_oi = 1; + + if (reg_flags & PFM_REGFL_OVFL_NOTIFY) { + flags |= PFM_REGFL_OVFL_NOTIFY; + } + + if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM; + + /* verify validity of smpl_pmds */ + if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) { + DPRINT(("invalid smpl_pmds 0x%lx for pmc%u\n", smpl_pmds, cnum)); + goto error; + } + + /* verify validity of reset_pmds */ + if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) { + DPRINT(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); + goto error; + } + } else { + if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { + DPRINT(("cannot set ovfl_notify or random on pmc%u\n", cnum)); + goto error; + } + /* eventid on non-counting monitors are ignored */ + } + + /* + * execute write checker, if any + */ + if (PMC_WR_FUNC(cnum)) { + ret = PMC_WR_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &value, regs); + if (ret) goto error; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * Now we commit the changes to the software state + */ + + /* + * update overflow information + */ + if (is_counting) { + /* + * full flag update each time a register is programmed + */ + ctx->ctx_pmds[cnum].flags = flags; + + ctx->ctx_pmds[cnum].reset_pmds[0] = reset_pmds; + ctx->ctx_pmds[cnum].smpl_pmds[0] = smpl_pmds; + ctx->ctx_pmds[cnum].eventid = req->reg_smpl_eventid; + + /* + * Mark all PMDS to be accessed as used. + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + * + * We do not update the used_monitors mask, because + * if we have not programmed them, then will be in + * a quiescent state, therefore we will not need to + * mask/restore then when context is MASKED. + */ + CTX_USED_PMD(ctx, reset_pmds); + CTX_USED_PMD(ctx, smpl_pmds); + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (CTX_IS_MASKED(ctx)) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + /* + * Needed in case the user does not initialize the equivalent + * PMD. Clearing is done indirectly via pfm_reset_pmu_state() so there is no + * possible leak here. + */ + CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]); + + /* + * keep track of the monitor PMC that we are using. + * we save the value of the pmc in ctx_pmcs[] and if + * the monitoring is not stopped for the context we also + * place it in the saved state area so that it will be + * picked up later by the context switch code. + * + * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs(). + * + * The value in t->pmc[] may be modified on overflow, i.e., when + * monitoring needs to be stopped. + */ + if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum); + + /* + * update context state + */ + ctx->ctx_pmcs[cnum] = value; + + if (is_loaded) { + /* + * write thread state + */ + if (ctx->ctx_fl_system == 0) thread->pmcs[cnum] = value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmc(cnum, value); + } +#ifdef CONFIG_SMP + else { + /* + * per-task SMP only here + * + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmcs[0] |= 1UL << cnum; + } +#endif + } + + DPRINT(("pmc[%u]=0x%lx loaded=%d access_pmu=%d all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + ctx->ctx_all_pmcs[0], + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].eventid, + smpl_pmds, + reset_pmds, + ctx->ctx_reload_pmcs[0], + ctx->ctx_used_monitors[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make sure the changes are visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; +error: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + + req->reg_flags = PFM_REG_RETFL_EINVAL; + + DPRINT(("pmc[%u]=0x%lx error %d\n", cnum, value, ret)); + + return ret; +} + +static int +pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value, hw_value; + unsigned int cnum; + int i, can_access_pmu = 0; + int is_counting, is_loaded; + int ret = -EINVAL; + + if (CTX_IS_DEAD(ctx)) return -EINVAL; + + is_loaded = CTX_IS_LOADED(ctx); + + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task ? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + value = req->reg_value; + + if (!PMD_IS_IMPL(cnum)) { + DPRINT(("pmd[%u] is unimplemented or invalid\n", cnum)); + goto abort_mission; + } + is_counting = PMD_IS_COUNTING(cnum); + + /* + * execute write checker, if any + */ + if (PMD_WR_FUNC(cnum)) { + unsigned long v = value; + + ret = PMD_WR_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &v, regs); + if (ret) goto abort_mission; + + value = v; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * now commit changes to software state + */ + hw_value = value; + + /* + * update virtualized (64bits) counter + */ + if (is_counting) { + /* + * write context state + */ + ctx->ctx_pmds[cnum].lval = value; + + /* + * when context is load we use the split value + */ + if (is_loaded) { + hw_value = value & pmu_conf.ovfl_val; + value = value & ~pmu_conf.ovfl_val; + } + + /* + * update sampling periods + */ + ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset; + ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset; + + /* + * update randomization parameters + */ + ctx->ctx_pmds[cnum].seed = req->reg_random_seed; + ctx->ctx_pmds[cnum].mask = req->reg_random_mask; + } + + /* + * update context value + */ + ctx->ctx_pmds[cnum].val = value; + + /* + * Keep track of what we use + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + */ + CTX_USED_PMD(ctx, PMD_PMD_DEP(cnum)); + + /* + * mark this PMD register used as well + */ + CTX_USED_PMD(ctx, RDEP(cnum)); + + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (is_counting && CTX_IS_MASKED(ctx)) { + ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + + if (is_loaded) { + /* + * write thread state + */ + if (ctx->ctx_fl_system == 0) thread->pmds[cnum] = hw_value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmd(cnum, hw_value); + } else { +#ifdef CONFIG_SMP + /* + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmds[0] |= 1UL << cnum; +#endif + } + } + + DPRINT(("pmd[%u]=0x%lx loaded=%d access_pmu=%d, hw_value=0x%lx ctx_pmd=0x%lx short_reset=0x%lx " + "long_reset=0x%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + hw_value, + ctx->ctx_pmds[cnum].val, + ctx->ctx_pmds[cnum].short_reset, + ctx->ctx_pmds[cnum].long_reset, + PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].reset_pmds[0], + ctx->ctx_reload_pmds[0], + ctx->ctx_all_pmds[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make changes visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; + +abort_mission: + /* + * for now, we have only one possibility for error + */ + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + + /* + * we change the return value to EFAULT in case we cannot write register return code. + * The caller first must correct this error, then a resubmission of the request will + * eventually yield the EINVAL. + */ + req->reg_flags = PFM_REG_RETFL_EINVAL; + + DPRINT(("pmd[%u]=0x%lx ret %d\n", cnum, value, ret)); + + return ret; +} + +/* + * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function. + * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an + * interrupt is delivered during the call, it will be kept pending until we leave, making + * it appears as if it had been generated at the UNPROTECT_CONTEXT(). At least we are + * guaranteed to return consistent data to the user, it may simply be old. It is not + * trivial to treat the overflow while inside the call because you may end up in + * some module sampling buffer code causing deadlocks. + */ +static int +pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + unsigned long val = 0UL, lval ; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum, reg_flags = 0; + int i, is_loaded, can_access_pmu = 0; + int ret = -EINVAL; + + if (CTX_IS_ZOMBIE(ctx)) return -EINVAL; + + /* + * access is possible when loaded only for + * self-monitoring tasks or in UP mode + */ + is_loaded = CTX_IS_LOADED(ctx); + + if (is_loaded) { + thread = &ctx->ctx_task->thread; + /* + * this can be true when not self-monitoring only in UP + */ + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task? 1 : 0; + + if (can_access_pmu) ia64_srlz_d(); + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } + DPRINT(("enter loaded=%d access_pmu=%d ctx_state=%d\n", + is_loaded, + can_access_pmu, + ctx->ctx_state)); + + /* + * on both UP and SMP, we can only read the PMD from the hardware register when + * the task is the owner of the local PMU. + */ + + for (i = 0; i < count; i++, req++) { + + lval = 0UL; + cnum = req->reg_num; + reg_flags = req->reg_flags; + + if (!PMD_IS_IMPL(cnum)) goto error; + /* + * we can only read the register that we use. That includes + * the one we explicitely initialize AND the one we want included + * in the sampling buffer (smpl_regs). + * + * Having this restriction allows optimization in the ctxsw routine + * without compromising security (leaks) + */ + if (!CTX_IS_USED_PMD(ctx, cnum)) goto error; + + /* + * If the task is not the current one, then we check if the + * PMU state is still in the local live register due to lazy ctxsw. + * If true, then we read directly from the registers. + */ + if (can_access_pmu){ + val = ia64_get_pmd(cnum); + } else { + /* + * context has been saved + * if context is zombie, then task does not exist anymore. + * In this case, we use the full value saved in the context (pfm_flush_regs()). + */ + val = CTX_IS_LOADED(ctx) ? thread->pmds[cnum] : 0UL; + } + + if (PMD_IS_COUNTING(cnum)) { + /* + * XXX: need to check for overflow when loaded + */ + val &= pmu_conf.ovfl_val; + val += ctx->ctx_pmds[cnum].val; + + lval = ctx->ctx_pmds[cnum].lval; + } + + /* + * execute read checker, if any + */ + if (PMD_RD_FUNC(cnum)) { + unsigned long v = val; + ret = PMD_RD_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &v, regs); + if (ret) goto error; + val = v; + ret = -EINVAL; + } + + PFM_REG_RETFLAG_SET(reg_flags, 0); + + DPRINT(("pmd[%u]=0x%lx loaded=%d access_pmu=%d ctx_state=%d\n", + cnum, + val, + is_loaded, + can_access_pmu, + ctx->ctx_state)); + + /* + * update register return value, abort all if problem during copy. + * we only modify the reg_flags field. no check mode is fine because + * access has been verified upfront in sys_perfmonctl(). + */ + req->reg_value = val; + req->reg_flags = reg_flags; + req->reg_last_reset_val = lval; + } + + return 0; + +error: + PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL); + + req->reg_flags = PFM_REG_RETFL_EINVAL; + + DPRINT(("error pmd[%u]=0x%lx\n", cnum, val)); + + return ret; +} + +long +pfm_mod_write_pmcs(struct task_struct *task, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (task == NULL || req == NULL) return -EINVAL; + + ctx = task->thread.pfm_context; + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current) return -EBUSY; + + return pfm_write_pmcs(ctx, req, nreq, regs); +} + +long +pfm_mod_read_pmds(struct task_struct *task, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (task == NULL || req == NULL) return -EINVAL; + + //ctx = task->thread.pfm_context; + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_read_pmds(ctx, req, nreq, regs); +} + +long +pfm_mod_fast_read_pmds(struct task_struct *task, unsigned long mask[4], unsigned long *addr, struct pt_regs *regs) +{ + pfm_context_t *ctx; + unsigned long m, val; + unsigned int j; + + if (task == NULL || addr == NULL) return -EINVAL; + + //ctx = task->thread.pfm_context; + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + m = mask[0]; + for (j=0; m; m >>=1, j++) { + + if ((m & 0x1) == 0) continue; + + if (!(PMD_IS_IMPL(j) && CTX_IS_USED_PMD(ctx, j)) ) return -EINVAL; + + if (PMD_IS_COUNTING(j)) { + val = pfm_read_soft_counter(ctx, j); + } else { + val = ia64_get_pmd(j); + } + + *addr++ = val; + + /* XXX: should call read checker routine? */ + DPRINT(("single_read_pmd[%u]=0x%lx\n", j, val)); + } + return 0; +} + +/* + * Only call this function when a process it trying to + * write the debug registers (reading is always allowed) + */ +int +pfm_use_debug_registers(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + int ret = 0; + + if (pmu_conf.use_rr_dbregs == 0) return 0; + + DPRINT(("called for [%d]\n", task->pid)); + + /* + * do it only once + */ + if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0; + + /* + * Even on SMP, we do not need to use an atomic here because + * the only way in is via ptrace() and this is possible only when the + * process is stopped. Even in the case where the ctxsw out is not totally + * completed by the time we come here, there is no way the 'stopped' process + * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine. + * So this is always safe. + */ + if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; + + LOCK_PFS(); + + /* + * We cannot allow setting breakpoints when system wide monitoring + * sessions are using the debug registers. + */ + if (pfm_sessions.pfs_sys_use_dbregs> 0) + ret = -1; + else + pfm_sessions.pfs_ptrace_use_dbregs++; + + DPRINT(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", + pfm_sessions.pfs_ptrace_use_dbregs, + pfm_sessions.pfs_sys_use_dbregs, + task->pid, ret)); + + UNLOCK_PFS(); + + return ret; +} + +/* + * This function is called for every task that exits with the + * IA64_THREAD_DBG_VALID set. This indicates a task which was + * able to use the debug registers for debugging purposes via + * ptrace(). Therefore we know it was not using them for + * perfmormance monitoring, so we only decrement the number + * of "ptraced" debug register users to keep the count up to date + */ +int +pfm_release_debug_registers(struct task_struct *task) +{ + int ret; + + if (pmu_conf.use_rr_dbregs == 0) return 0; + + LOCK_PFS(); + if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task->pid); + ret = -1; + } else { + pfm_sessions.pfs_ptrace_use_dbregs--; + ret = 0; + } + UNLOCK_PFS(); + + return ret; +} + +static int +pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_buffer_fmt_t *fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int is_loaded; + int ret = 0; + + fmt = ctx->ctx_buf_fmt; + is_loaded = CTX_IS_LOADED(ctx); + + if (is_loaded && CTX_HAS_SMPL(ctx) && fmt->fmt_restart_active) goto proceed; + + /* + * restarting a terminated context is a nop + */ + if (unlikely(CTX_IS_TERMINATED(ctx))) { + DPRINT(("context is terminated, nothing to do\n")); + return 0; + } + + + /* + * LOADED, UNLOADED, ZOMBIE + */ + if (CTX_IS_MASKED(ctx) == 0) return -EBUSY; + +proceed: + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + + task = PFM_CTX_TASK(ctx); + + /* sanity check */ + if (unlikely(task == NULL)) { + printk(KERN_ERR "perfmon: [%d] pfm_restart no task\n", current->pid); + return -EINVAL; + } + + /* + * this test is always true in system wide mode + */ + if (task == current) { + + fmt = ctx->ctx_buf_fmt; + + DPRINT(("restarting self %d ovfl=0x%lx\n", + task->pid, + ctx->ctx_ovfl_regs[0])); + + if (CTX_HAS_SMPL(ctx)) { + + prefetch(ctx->ctx_smpl_hdr); + + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_NO_RESET; + + if (is_loaded) + ret = pfm_buf_fmt_restart_active(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + + + } else { + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_LONG_RESET; + } + + if (ret == 0) { + if (rst_ctrl.reset_pmds) + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, rst_ctrl.reset_pmds); + + if (rst_ctrl.stop_monitoring == 0) { + DPRINT(("resuming monitoring for [%d]\n", task->pid)); + + if (CTX_IS_MASKED(ctx)) pfm_restore_monitoring(task); + } else { + DPRINT(("keeping monitoring stopped for [%d]\n", task->pid)); + + // cannot use pfm_stop_monitoring(task, regs); + } + } + /* + * clear overflowed PMD mask to remove any stale information + */ + ctx->ctx_ovfl_regs[0] = 0UL; + + /* + * back to LOADED state + */ + CTX_LOADED(ctx); + + return 0; + } + /* restart another task */ + + /* + * if blocking, then post the semaphore. + * if non-blocking, then we ensure that the task will go into + * pfm_handle_work() before returning to user mode. + * We cannot explicitely reset another task, it MUST always + * be done by the task itself. This works for system wide because + * the tool that is controlling the session is doing "self-monitoring". + * + * XXX: what if the task never goes back to user? + * + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0) { + DPRINT(("unblocking [%d] \n", task->pid)); + up(&ctx->ctx_restart_sem); + } else { + DPRINT(("[%d] armed exit trap\n", task->pid)); + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + + + PFM_SET_WORK_PENDING(task, 1); + + pfm_set_task_notify(task); + + /* + * XXX: send reschedule if task runs on another CPU + */ + } + return 0; +} + +static int +pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + unsigned int m = *(unsigned int *)arg; + + pfm_sysctl.debug = m == 0 ? 0 : 1; + + pfm_debug_var = pfm_sysctl.debug; + + printk(KERN_ERR "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); + + + if (m==0) { + memset(pfm_stats, 0, sizeof(pfm_stats)); + for(m=0; m < NR_CPUS; m++) pfm_stats[m].pfm_ovfl_intr_cycles_min = ~0UL; + } + + return 0; +} + + +static int +pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; + dbreg_t dbreg; + unsigned int rnum; + int first_time; + int ret = 0; + int i, can_access_pmu = 0, is_loaded; + + if (pmu_conf.use_rr_dbregs == 0) return -EINVAL; + + if (CTX_IS_DEAD(ctx)) return -EINVAL; + + is_loaded = CTX_IS_LOADED(ctx); + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task ? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } + + /* + * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w + * ensuring that no real breakpoint can be installed via this call. + * + * IMPORTANT: regs can be NULL in this function + */ + + first_time = ctx->ctx_fl_using_dbreg == 0; + + /* + * don't bother if we are loaded and task is being debugged + */ + if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { + DPRINT(("debug registers already in use for [%d]\n", ctx->ctx_task->pid)); + return -EBUSY; + } + + /* + * check for debug registers in system wide mode + * + * We make the reservation even when context is not loaded + * to make sure we get our slot. Note that the PFM_LOAD_CONTEXT + * may still fail if the task has DBG_VALID set. + */ + LOCK_PFS(); + + if (first_time && ctx->ctx_fl_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) + ret = -EBUSY; + else + pfm_sessions.pfs_sys_use_dbregs++; + } + + UNLOCK_PFS(); + + if (ret != 0) return ret; + + /* + * mark ourself as user of the debug registers for + * perfmon purposes. + */ + ctx->ctx_fl_using_dbreg = 1; + + /* + * clear hardware registers to make sure we don't + * pick up stale state. + * + * for a system wide session, we do not use + * thread.dbr, thread.ibr because this process + * never leaves the current CPU and the state + * is shared by all processes running on it + */ + if (first_time && can_access_pmu) { + DPRINT(("[%d] clearing ibrs, dbrs\n", ctx->ctx_task->pid)); + for (i=0; i < pmu_conf.num_ibrs; i++) { + ia64_set_ibr(i, 0UL); + ia64_srlz_i(); + } + ia64_srlz_i(); + for (i=0; i < pmu_conf.num_dbrs; i++) { + ia64_set_dbr(i, 0UL); + ia64_srlz_d(); + } + ia64_srlz_d(); + } + + /* + * Now install the values into the registers + */ + for (i = 0; i < count; i++, req++) { + + rnum = req->dbreg_num; + dbreg.val = req->dbreg_value; + + ret = -EINVAL; + + if ((mode == PFM_CODE_RR && !IBR_IS_IMPL(rnum)) || ((mode == PFM_DATA_RR) && !DBR_IS_IMPL(rnum))) { + DPRINT(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", + rnum, dbreg.val, mode, i, count)); + + goto abort_mission; + } + + /* + * make sure we do not install enabled breakpoint + */ + if (rnum & 0x1) { + if (mode == PFM_CODE_RR) + dbreg.ibr.ibr_x = 0; + else + dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; + } + + PFM_REG_RETFLAG_SET(req->dbreg_flags, 0); + + /* + * Debug registers, just like PMC, can only be modified + * by a kernel call. Moreover, perfmon() access to those + * registers are centralized in this routine. The hardware + * does not modify the value of these registers, therefore, + * if we save them as they are written, we can avoid having + * to save them on context switch out. This is made possible + * by the fact that when perfmon uses debug registers, ptrace() + * won't be able to modify them concurrently. + */ + if (mode == PFM_CODE_RR) { + CTX_USED_IBR(ctx, rnum); + + if (can_access_pmu) ia64_set_ibr(rnum, dbreg.val); + + ctx->ctx_ibrs[rnum] = dbreg.val; + + DPRINT(("write ibr%u=0x%lx used_ibrs=0x%x is_loaded=%d access_pmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_ibrs[0], is_loaded, can_access_pmu)); + } else { + CTX_USED_DBR(ctx, rnum); + + if (can_access_pmu) ia64_set_dbr(rnum, dbreg.val); + + ctx->ctx_dbrs[rnum] = dbreg.val; + + DPRINT(("write dbr%u=0x%lx used_dbrs=0x%x is_loaded=%d access_pmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_dbrs[0], is_loaded, can_access_pmu)); + } + } + + return 0; + +abort_mission: + /* + * in case it was our first attempt, we undo the global modifications + */ + if (first_time) { + LOCK_PFS(); + if (ctx->ctx_fl_system) { + pfm_sessions.pfs_sys_use_dbregs--; + } + UNLOCK_PFS(); + ctx->ctx_fl_using_dbreg = 0; + } + /* + * install error return flag + */ + PFM_REG_RETFLAG_SET(req->dbreg_flags, PFM_REG_RETFL_EINVAL); + + return ret; +} + +static int +pfm_write_ibrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_CODE_RR, ctx, arg, count, regs); +} + +static int +pfm_write_dbrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_DATA_RR, ctx, arg, count, regs); +} + +static int +pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_features_t *req = (pfarg_features_t *)arg; + + req->ft_version = PFM_VERSION; + return 0; +} + +static int +pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + + + if (CTX_IS_LOADED(ctx) == 0 && CTX_IS_MASKED(ctx) == 0) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (ctx->ctx_fl_system) { + /* + * Update local PMU first + * + * disable dcr pp + */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + ia64_srlz_i(); + + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + /* + * stop monitoring, does srlz.i + */ + pfm_clear_psr_pp(); + + /* + * stop monitoring in the caller + */ + ia64_psr(regs)->pp = 0; + + return 0; + } + /* + * per-task mode + */ + + if (ctx->ctx_task == current) { + /* stop monitoring at kernel level */ + pfm_clear_psr_up(); + + /* + * stop monitoring at the user level + */ + ia64_psr(regs)->up = 0; + } else { + tregs = ia64_task_regs(ctx->ctx_task); + + /* + * stop monitoring at the user level + */ + ia64_psr(tregs)->up = 0; + + /* + * monitoring disabled in kernel at next reschedule + */ + ctx->ctx_saved_psr &= ~IA64_PSR_UP; + printk("pfm_stop: current [%d] task=[%d]\n", current->pid, ctx->ctx_task->pid); + } + return 0; +} + + +static int +pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + + if (CTX_IS_LOADED(ctx) == 0) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (ctx->ctx_fl_system) { + + /* + * set user level psr.pp for the caller + */ + ia64_psr(regs)->pp = 1; + + /* + * now update the local PMU and cpuinfo + */ + PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); + + /* + * start monitoring at kernel level + */ + pfm_set_psr_pp(); + + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); + ia64_srlz_i(); + + return 0; + } + + /* + * per-process mode + */ + + if (ctx->ctx_task == current) { + + /* start monitoring at kernel level */ + pfm_set_psr_up(); + + /* + * activate monitoring at user level + */ + ia64_psr(regs)->up = 1; + + } else { + tregs = ia64_task_regs(ctx->ctx_task); + + /* + * start monitoring at the kernel level the next + * time the task is scheduled + */ + ctx->ctx_saved_psr |= IA64_PSR_UP; + + /* + * activate monitoring at user level + */ + ia64_psr(tregs)->up = 1; + } + + return 0; +} + +static int +pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum; + int i; + int ret = -EINVAL; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + + if (!PMC_IS_IMPL(cnum)) goto abort_mission; + + req->reg_value = PMC_DFL_VAL(cnum); + + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + DPRINT(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, req->reg_value)); + } + return 0; + +abort_mission: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +static int +pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + struct thread_struct *thread; + struct pfm_context_t *old; +#ifndef CONFIG_SMP + struct task_struct *owner_task = NULL; +#endif + pfarg_load_t *req = (pfarg_load_t *)arg; + unsigned long *pmcs_source, *pmds_source; + int the_cpu; + int ret = 0; + + /* + * can only load from unloaded or terminated state + */ + if (CTX_IS_UNLOADED(ctx) == 0 && CTX_IS_TERMINATED(ctx) == 0) { + DPRINT(("[%d] cannot load to [%d], invalid ctx_state=%d\n", + current->pid, + req->load_pid, + ctx->ctx_state)); + return -EINVAL; + } + + DPRINT(("load_pid [%d]\n", req->load_pid)); + + if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) { + DPRINT(("cannot use blocking mode on self for [%d]\n", current->pid)); + return -EINVAL; + } + + ret = pfm_get_task(ctx, req->load_pid, &task); + if (ret) { + DPRINT(("load_pid [%d] get_task=%d\n", req->load_pid, ret)); + return ret; + } + + ret = -EINVAL; + + /* + * system wide is self monitoring only + */ + if (ctx->ctx_fl_system && task != current) { + DPRINT(("system wide is self monitoring only current=%d load_pid=%d\n", + current->pid, + req->load_pid)); + goto error; + } + + thread = &task->thread; + + ret = -EBUSY; + + /* + * cannot load a context which is using range restrictions, + * into a task that is being debugged. + */ + if (ctx->ctx_fl_using_dbreg && (thread->flags & IA64_THREAD_DBG_VALID)) { + DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid)); + goto error; + } + + /* + * SMP system-wide monitoring implies self-monitoring. + * + * The programming model expects the task to + * be pinned on a CPU throughout the session. + * Here we take note of the current CPU at the + * time the context is loaded. No call from + * another CPU will be allowed. + * + * The pinning via shed_setaffinity() + * must be done by the calling task prior + * to this call. + * + * systemwide: keep track of CPU this session is supposed to run on + */ + the_cpu = ctx->ctx_cpu = smp_processor_id(); + + /* + * now reserve the session + */ + ret = pfm_reserve_session(current, ctx->ctx_fl_system, the_cpu); + if (ret) goto error; + + ret = -EBUSY; + /* + * task is necessarily stopped at this point. + * + * If the previous context was zombie, then it got removed in + * pfm_save_regs(). Therefore we should not see it here. + * If we see a context, then this is an active context + * + * XXX: needs to be atomic + */ + DPRINT(("[%d] before cmpxchg() old_ctx=%p new_ctx=%p\n", + current->pid, + thread->pfm_context, ctx)); + + old = ia64_cmpxchg("acq", &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *)); + if (old != NULL) { + DPRINT(("load_pid [%d] already has a context\n", req->load_pid)); + goto error_unres; + } + + pfm_reset_msgq(ctx); + + CTX_LOADED(ctx); + + /* + * link context to task + */ + ctx->ctx_task = task; + + if (ctx->ctx_fl_system) { + + /* + * we load as stopped + */ + PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); + } else { + thread->flags |= IA64_THREAD_PM_VALID; + } + + /* + * propagate into thread-state + */ + pfm_copy_pmds(task, ctx); + pfm_copy_pmcs(task, ctx); + + pmcs_source = thread->pmcs; + pmds_source = thread->pmds; + + /* + * always the case for system-wide + */ + if (task == current) { + + if (ctx->ctx_fl_system == 0) { + + /* allow user level control */ + ia64_psr(regs)->sp = 0; + DPRINT(("clearing psr.sp for [%d]\n", task->pid)); + + SET_LAST_CPU(ctx, smp_processor_id()); + INC_ACTIVATION(); + SET_ACTIVATION(ctx); +#ifndef CONFIG_SMP + /* + * push the other task out, if any + */ + owner_task = GET_PMU_OWNER(); + if (owner_task) pfm_lazy_save_regs(owner_task); +#endif + } + /* + * load all PMD from ctx to PMU (as opposed to thread state) + * restore all PMC from ctx to PMU + */ + pfm_restore_pmds(pmds_source, ctx->ctx_all_pmds[0]); + pfm_restore_pmcs(pmcs_source, ctx->ctx_all_pmcs[0]); + + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + /* + * guaranteed safe by earlier check against DBG_VALID + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } + /* + * set new ownership + */ + SET_PMU_OWNER(task, ctx); + + DPRINT(("context loaded on PMU for [%d]\n", task->pid)); + } else { + /* + * when not current, task MUST be stopped, so this is safe + */ + regs = ia64_task_regs(task); + + /* force a full reload */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* initial saved psr (stopped) */ + ctx->ctx_saved_psr = pfm_get_psr() & ~(IA64_PSR_PP|IA64_PSR_UP); + ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; + + if (ctx->ctx_fl_unsecure) { + ia64_psr(regs)->sp = 0; + DPRINT(("context unsecured for [%d]\n", task->pid)); + } + } + + ret = 0; + +error_unres: + if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu); +error: + /* + * release task, there is now a link with the context + */ + if (ctx->ctx_fl_system == 0 && task != current) pfm_put_task(task); + + return ret; +} + +/* + * in this function, we do not need to increase the use count + * for the task via get_task_struct(), because we hold the + * context lock. If the task were to disappear while having + * a context attached, it would go through pfm_exit_thread() + * which also grabs the context lock and would therefore be blocked + * until we are here. + */ +static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx); + +static int +pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + struct pt_regs *tregs; + + DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); + + /* + * unload only when necessary + */ + if (CTX_IS_TERMINATED(ctx) || CTX_IS_UNLOADED(ctx)) { + DPRINT(("[%d] ctx_state=%d, nothing to do\n", current->pid, ctx->ctx_state)); + return 0; + } + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * clear psr and dcr bits + */ + pfm_stop(ctx, NULL, 0, regs); + + CTX_UNLOADED(ctx); + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (ctx->ctx_fl_system) { + + /* + * Update cpuinfo + * + * local PMU is taken care of in pfm_stop() + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); + + /* + * save PMDs in context + * release ownership + */ + pfm_flush_pmds(current, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + */ + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); + + /* + * disconnect context from task + */ + task->thread.pfm_context = NULL; + /* + * disconnect task from context + */ + ctx->ctx_task = NULL; + + /* + * There is nothing more to cleanup here. + */ + return 0; + } + + /* + * per-task mode + */ + tregs = task == current ? regs : ia64_task_regs(task); + + if (task == current || ctx->ctx_fl_unsecure) { + /* + * cancel user level control + */ + ia64_psr(regs)->sp = 1; + DPRINT(("setting psr.sp for [%d]\n", task->pid)); + + } + /* + * save PMDs to context + * release ownership + */ + pfm_flush_pmds(task, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + */ + pfm_unreserve_session(ctx, 0 , ctx->ctx_cpu); + + /* + * reset activation counter and psr + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * PMU state will not be restored + */ + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + /* + * break links between context and task + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + PFM_SET_WORK_PENDING(task, 0); + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + + DPRINT(("disconnected [%d] from context\n", task->pid)); + + return 0; +} + +static void +pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + if (GET_PMU_OWNER() == task) { + DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); + SET_PMU_OWNER(NULL, NULL); + } + + /* + * disconnect the task from the context and vice-versa + */ + PFM_SET_WORK_PENDING(task, 0); + + task->thread.pfm_context = NULL; + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + DPRINT(("context <%d> force cleanup for [%d] by [%d]\n", ctx->ctx_fd, task->pid, current->pid)); +} + + +/* + * called only from exit_thread(): task == current + */ +void +pfm_exit_thread(struct task_struct *task) +{ + pfm_context_t *ctx; + unsigned long flags; + struct pt_regs *regs = ia64_task_regs(task); + int ret; + int free_ok = 0; + + ctx = PFM_GET_CTX(task); + + PROTECT_CTX(ctx, flags); + + DPRINT(("state=%d task [%d]\n", ctx->ctx_state, task->pid)); + + /* + * come here only if attached + */ + if (unlikely(CTX_IS_UNLOADED(ctx))) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] ctx unloaded\n", task->pid); + goto skip_all; + } + + if (CTX_IS_LOADED(ctx) || CTX_IS_MASKED(ctx)) { + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, ctx->ctx_state, ret); + } + CTX_TERMINATED(ctx); + DPRINT(("ctx terminated by [%d]\n", task->pid)); + + pfm_end_notify_user(ctx); + + } else if (CTX_IS_ZOMBIE(ctx)) { + pfm_clear_psr_up(); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_force_cleanup(ctx, regs); + + free_ok = 1; + } + { u64 psr = pfm_get_psr(); + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + } +skip_all: + UNPROTECT_CTX(ctx, flags); + + /* + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (free_ok) pfm_context_free(ctx); +} + +/* + * functions MUST be listed in the increasing order of their index (see permfon.h) + */ +#define PFM_CMD(name, flags, arg_count, arg_type, getsz) { name, #name, flags, arg_count, sizeof(arg_type), getsz } +#define PFM_CMD_S(name, flags) { name, #name, flags, 0, 0, NULL } +#define PFM_CMD_PCLRWS (PFM_CMD_FD|PFM_CMD_ARG_RW|PFM_CMD_STOP) +#define PFM_CMD_PCLRW (PFM_CMD_FD|PFM_CMD_ARG_RW) +#define PFM_CMD_NONE { NULL, "no-cmd", 0, 0, 0, NULL} + +static pfm_cmd_desc_t pfm_cmd_tab[]={ +/* 0 */PFM_CMD_NONE, +/* 1 */PFM_CMD(pfm_write_pmcs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 2 */PFM_CMD(pfm_write_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 3 */PFM_CMD(pfm_read_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 4 */PFM_CMD_S(pfm_stop, PFM_CMD_PCLRWS), +/* 5 */PFM_CMD_S(pfm_start, PFM_CMD_PCLRWS), +/* 6 */PFM_CMD_NONE, +/* 7 */PFM_CMD_NONE, +/* 8 */PFM_CMD(pfm_context_create, PFM_CMD_ARG_RW, 1, pfarg_context_t, pfm_ctx_getsize), +/* 9 */PFM_CMD_NONE, +/* 10 */PFM_CMD_S(pfm_restart, PFM_CMD_PCLRW), +/* 11 */PFM_CMD_NONE, +/* 12 */PFM_CMD(pfm_get_features, PFM_CMD_ARG_RW, 1, pfarg_features_t, NULL), +/* 13 */PFM_CMD(pfm_debug, 0, 1, unsigned int, NULL), +/* 14 */PFM_CMD_NONE, +/* 15 */PFM_CMD(pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 16 */PFM_CMD(pfm_context_load, PFM_CMD_PCLRWS, 1, pfarg_load_t, NULL), +/* 17 */PFM_CMD_S(pfm_context_unload, PFM_CMD_PCLRWS), +/* 18 */PFM_CMD_NONE, +/* 19 */PFM_CMD_NONE, +/* 20 */PFM_CMD_NONE, +/* 21 */PFM_CMD_NONE, +/* 22 */PFM_CMD_NONE, +/* 23 */PFM_CMD_NONE, +/* 24 */PFM_CMD_NONE, +/* 25 */PFM_CMD_NONE, +/* 26 */PFM_CMD_NONE, +/* 27 */PFM_CMD_NONE, +/* 28 */PFM_CMD_NONE, +/* 29 */PFM_CMD_NONE, +/* 30 */PFM_CMD_NONE, +/* 31 */PFM_CMD_NONE, +/* 32 */PFM_CMD(pfm_write_ibrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL), +/* 33 */PFM_CMD(pfm_write_dbrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL) +}; +#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) + +static int +pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags) +{ + struct task_struct *task; + + task = PFM_CTX_TASK(ctx); + if (task == NULL) { + DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, ctx->ctx_state)); + return 0; + } + + DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n", + ctx->ctx_fd, + ctx->ctx_state, + task->pid, + task->state, PFM_CMD_STOPPED(cmd))); + + /* + * self-monitoring always ok. + * + * for system-wide the caller can either be the creator of the + * context (to one to which the context is attached to) OR + * a task running on the same CPU as the session. + */ + if (task == current || ctx->ctx_fl_system) return 0; + + /* + * context is UNLOADED, MASKED, TERMINATED we are safe to go + */ + if (CTX_IS_LOADED(ctx) == 0) return 0; + + if (CTX_IS_ZOMBIE(ctx)) return -EINVAL; + + /* + * context is loaded, we must make sure the task is stopped + * We could lift this restriction for UP but it would mean that + * the user has no guarantee the task would not run between + * two successive calls to perfmonctl(). That's probably OK. + * If this user wants to ensure the task does not run, then + * the task must be stopped. + */ + if (PFM_CMD_STOPPED(cmd) && task->state != TASK_STOPPED) { + DPRINT(("[%d] task not in stopped state\n", task->pid)); + return -EBUSY; + } + + UNPROTECT_CTX(ctx, flags); + + pfm_wait_task_inactive(task); + + PROTECT_CTX(ctx, flags); + return 0; +} + +/* + * system-call entry point (must return long) + */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, + long arg8, long stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + struct file *file = NULL; + pfm_context_t *ctx = NULL; + unsigned long flags = 0UL; + void *args_k = NULL; + long ret; /* will expand int return types */ + size_t base_sz, sz, xtra_sz = 0; + int narg, completed_args = 0, call_made = 0; +#define PFM_MAX_ARGSIZE 4096 + + /* + * reject any call if perfmon was disabled at initialization time + */ + if (PFM_IS_DISABLED()) return -ENOSYS; + + if (unlikely(PFM_CMD_IS_VALID(cmd) == 0)) { + DPRINT(("[%d] invalid cmd=%d\n", current->pid, cmd)); + return -EINVAL; + } + + DPRINT(("cmd=%s idx=%d valid=%d narg=0x%x argsz=%lu count=%d\n", + PFM_CMD_NAME(cmd), + PFM_CMD_IDX(cmd), + PFM_CMD_IS_VALID(cmd), + PFM_CMD_NARG(cmd), + PFM_CMD_ARG_SIZE(cmd), count)); + + /* + * check if number of arguments matches what the command expects + */ + narg = PFM_CMD_NARG(cmd); + if ((narg == PFM_CMD_ARG_MANY && count <= 0) || (narg > 0 && narg != count)) + return -EINVAL; + + /* get single argument size */ + base_sz = PFM_CMD_ARG_SIZE(cmd); + +restart_args: + sz = xtra_sz + base_sz*count; + /* + * limit abuse to min page size + */ + if (unlikely(sz > PFM_MAX_ARGSIZE)) { + printk(KERN_ERR "perfmon: [%d] argument too big %lu\n", current->pid, sz); + return -E2BIG; + } + + /* + * allocate default-sized argument buffer + */ + if (count && args_k == NULL) { + args_k = kmalloc(PFM_MAX_ARGSIZE, GFP_KERNEL); + if (args_k == NULL) return -ENOMEM; + } + + ret = -EFAULT; + + /* + * copy arguments + * + * assume sz = 0 for command without parameters + */ + if (sz && copy_from_user(args_k, arg, sz)) { + DPRINT(("[%d] cannot copy_from_user %lu bytes @%p\n", current->pid, sz, arg)); + goto error_args; + } + + /* + * check if command supports extra parameters + */ + if (completed_args == 0 && PFM_CMD_GETSIZE(cmd)) { + /* + * get extra parameters size (based on main argument) + */ + ret = PFM_CMD_GETSIZE(cmd)(args_k, &xtra_sz); + if (ret) goto error_args; + + completed_args = 1; + + DPRINT(("[%d] restart_args sz=%lu xtra_sz=%lu\n", current->pid, sz, xtra_sz)); + + /* retry if necessary */ + if (xtra_sz) goto restart_args; + } + + if (PFM_CMD_USE_FD(cmd)) { + + ret = -EBADF; + + file = fget(fd); + if (file == NULL) { + DPRINT(("[%d] invalid fd %d\n", current->pid, fd)); + goto error_args; + } + if (PFM_IS_FILE(file) == 0) { + DPRINT(("[%d] fd %d not related to perfmon\n", current->pid, fd)); + goto error_args; + } + + + ctx = (pfm_context_t *)file->private_data; + if (ctx == NULL) { + DPRINT(("[%d] no context for fd %d\n", current->pid, fd)); + goto error_args; + } + + PROTECT_CTX(ctx, flags); + + /* + * check task is stopped + */ + ret = pfm_check_task_state(ctx, cmd, flags); + if (ret) goto abort_locked; + } + + ret = (*pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func)(ctx, args_k, count, regs); + + call_made = 1; + +abort_locked: + if (ctx) { + DPRINT(("[%d] context unlocked\n", current->pid)); + UNPROTECT_CTX(ctx, flags); + fput(file); + } + + /* copy argument back to user, if needed */ + if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT; + +error_args: + if (args_k) kfree(args_k); + + return ret; +} + +static void +pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_regs *regs) +{ + pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int ret = 0; + + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + + rst_ctrl.stop_monitoring = 1; + rst_ctrl.reset_pmds = PFM_PMD_NO_RESET; + + /* XXX: check return value */ + if (fmt->fmt_restart) + ret = (*fmt->fmt_restart)(current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_LONG_RESET; + } + + if (ret == 0) { + if (rst_ctrl.reset_pmds != PFM_PMD_NO_RESET) + pfm_reset_regs(ctx, &ovfl_regs, rst_ctrl.reset_pmds); + + if (rst_ctrl.stop_monitoring == 0) { + DPRINT(("resuming monitoring\n")); + if (CTX_IS_MASKED(ctx)) pfm_restore_monitoring(current); + } else { + DPRINT(("stopping monitoring\n")); + //pfm_stop_monitoring(current, regs); + } + CTX_LOADED(ctx); + } +} + + +/* + * context MUST BE LOCKED when calling + * can only be called for current + */ +static void +pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) +{ + if (ctx->ctx_fl_system) { + printk(KERN_ERR "perfmon: pfm_context_force_terminate [%d] is system-wide\n", current->pid); + return; + } + /* + * we stop the whole thing, we do no need to flush + * we know we WERE masked + */ + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + /* + * disconnect the task from the context and vice-versa + */ + current->thread.pfm_context = NULL; + current->thread.flags &= ~IA64_THREAD_PM_VALID; + ctx->ctx_task = NULL; + + /* + * switch to terminated state + */ + CTX_TERMINATED(ctx); + + DPRINT(("context <%d> terminated for [%d]\n", ctx->ctx_fd, current->pid)); + + /* + * and wakeup controlling task, indicating we are now disconnected + */ + wake_up_interruptible(&ctx->ctx_zombieq); + + /* + * given that context is still locked, the controlling + * task will only get access when we return from + * pfm_handle_work(). + */ +} + +static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); + +void +pfm_handle_work(void) +{ + pfm_context_t *ctx; + struct pt_regs *regs; + unsigned long flags; + unsigned long ovfl_regs; + unsigned int reason; + int ret; + + ctx = PFM_GET_CTX(current); + if (ctx == NULL) { + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); + return; + } + + PROTECT_CTX(ctx, flags); + + PFM_SET_WORK_PENDING(current, 0); + + pfm_clear_task_notify(); + + regs = ia64_task_regs(current); + + /* + * extract reason for being here and clear + */ + reason = ctx->ctx_fl_trap_reason; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + + DPRINT(("[%d] reason=%d\n", current->pid, reason)); + + /* + * must be done before we check non-blocking mode + */ + if (ctx->ctx_fl_going_zombie || CTX_IS_ZOMBIE(ctx)) goto do_zombie; + + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; + if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("before block sleeping\n")); + + /* + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() + */ + ret = down_interruptible(&ctx->ctx_restart_sem); + + DPRINT(("after block sleeping ret=%d\n", ret)); + + PROTECT_CTX(ctx, flags); + + if (ctx->ctx_fl_going_zombie) { +do_zombie: + DPRINT(("context is zombie, bailing out\n")); + pfm_context_force_terminate(ctx, regs); + goto nothing_to_do; + } + /* + * in case of interruption of down() we don't restart anything + */ + if (ret < 0) goto nothing_to_do; + +skip_blocking: + pfm_resume_after_ovfl(ctx, ovfl_regs, regs); + ctx->ctx_ovfl_regs[0] = 0UL; + +nothing_to_do: + + UNPROTECT_CTX(ctx, flags); +} + +static int +pfm_notify_user(pfm_context_t *ctx, pfm_msg_t *msg) +{ + if (CTX_IS_ZOMBIE(ctx)) { + DPRINT(("ignoring overflow notification, owner is zombie\n")); + return 0; + } + + DPRINT(("[%d] waking up somebody\n", current->pid)); + + if (msg) wake_up_interruptible(&ctx->ctx_msgq_wait); + + /* + * safe, we are not in intr handler, nor in ctxsw when + * we come here + */ + kill_fasync (&ctx->ctx_async_queue, SIGIO, POLL_IN); + + return 0; +} + +static int +pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds) +{ + pfm_msg_t *msg = NULL; + + if (ctx->ctx_fl_no_msg == 0) { + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_ovfl_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_ovfl_msg.msg_type = PFM_MSG_OVFL; + msg->pfm_ovfl_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = ia64_get_itc(); /* relevant on UP only */ + msg->pfm_ovfl_msg.msg_active_set = 0; + msg->pfm_ovfl_msg.msg_ovfl_pmds[0] = ovfl_pmds; + msg->pfm_ovfl_msg.msg_ovfl_pmds[1] = msg->pfm_ovfl_msg.msg_ovfl_pmds[2] = msg->pfm_ovfl_msg.msg_ovfl_pmds[3] = 0UL; + + } + + DPRINT(("ovfl msg: msg=%p no_msg=%d fd=%d pid=%d ovfl_pmds=0x%lx\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, + current->pid, + ovfl_pmds)); + + return pfm_notify_user(ctx, msg); +} + +static int +pfm_end_notify_user(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_end_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_end_msg.msg_type = PFM_MSG_END; + msg->pfm_end_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = ia64_get_itc(); /* relevant on UP only */ + + DPRINT(("end msg: msg=%p no_msg=%d ctx_fd=%d pid=%d\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, current->pid)); + + return pfm_notify_user(ctx, msg); +} + +/* + * main overflow processing routine. + * it can be called from the interrupt path or explicitely during the context switch code + */ +static void +pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +{ + pfm_ovfl_arg_t ovfl_arg; + unsigned long mask; + unsigned long old_val; + unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL; + pfm_ovfl_ctrl_t ovfl_ctrl; + unsigned int i, j, has_smpl, first_pmd = ~0U; + int must_notify = 0; + + if (unlikely(CTX_IS_ZOMBIE(ctx))) goto stop_monitoring; + + /* + * sanity test. Should never happen + */ + if (unlikely((pmc0 & 0x1) == 0)) goto sanity_check; + + mask = pmc0 >> PMU_FIRST_COUNTER; + + DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s" + "used_pmds=0x%lx reload_pmcs=0x%lx\n", + pmc0, + task ? task->pid: -1, + (regs ? regs->cr_iip : 0), + CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", + ctx->ctx_used_pmds[0], + ctx->ctx_reload_pmcs[0])); + + has_smpl = CTX_HAS_SMPL(ctx); + + /* + * first we update the virtual counters + * assume there was a prior ia64_srlz_d() issued + */ + for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { + + /* skip pmd which did not overflow */ + if ((mask & 0x1) == 0) continue; + + DPRINT_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx ctx_pmd=0x%lx\n", + i, ia64_get_pmd(i), ctx->ctx_pmds[i].val)); + + /* + * Note that the pmd is not necessarily 0 at this point as qualified events + * may have happened before the PMU was frozen. The residual count is not + * taken into consideration here but will be with any read of the pmd via + * pfm_read_pmds(). + */ + old_val = ctx->ctx_pmds[i].val; + ctx->ctx_pmds[i].val += 1 + pmu_conf.ovfl_val; + + /* + * check for overflow condition + */ + if (likely(old_val > ctx->ctx_pmds[i].val)) { + + ovfl_pmds |= 1UL << i; + + /* + * keep track of pmds of interest for samples + */ + if (has_smpl) { + if (first_pmd == ~0U) first_pmd = i; + smpl_pmds |= ctx->ctx_pmds[i].smpl_pmds[0]; + } + + if (PMC_OVFL_NOTIFY(ctx, i)) ovfl_notify |= 1UL << i; + } + + DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx first_pmd=%u smpl_pmds=0x%lx\n", + i, ctx->ctx_pmds[i].val, old_val, + ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify, first_pmd, smpl_pmds)); + } + + ovfl_ctrl.notify_user = ovfl_notify ? 1 : 0; + ovfl_ctrl.reset_pmds = ovfl_pmds && ovfl_notify == 0UL ? 1 : 0; + ovfl_ctrl.block = ovfl_notify ? 1 : 0; + ovfl_ctrl.stop_monitoring = ovfl_notify ? 1 : 0; + + /* + * when a overflow is detected, check for sampling buffer, if present, invoke + * record() callback. + */ + if (ovfl_pmds && has_smpl) { + unsigned long start_cycles; + int this_cpu = smp_processor_id(); + + ovfl_arg.ovfl_pmds[0] = ovfl_pmds; + ovfl_arg.ovfl_notify[0] = ovfl_notify; + ovfl_arg.ovfl_ctrl = ovfl_ctrl; + ovfl_arg.smpl_pmds[0] = smpl_pmds; + + prefetch(ctx->ctx_smpl_hdr); + + ovfl_arg.pmd_value = ctx->ctx_pmds[first_pmd].val; + ovfl_arg.pmd_last_reset = ctx->ctx_pmds[first_pmd].lval; + ovfl_arg.pmd_eventid = ctx->ctx_pmds[first_pmd].eventid; + + /* + * copy values of pmds of interest. Sampling format may copy them + * into sampling buffer. + */ + if (smpl_pmds) { + for(i=0, j=0; smpl_pmds; i++, smpl_pmds >>=1) { + if ((smpl_pmds & 0x1) == 0) continue; + ovfl_arg.smpl_pmds_values[j++] = PMD_IS_COUNTING(i) ? pfm_read_soft_counter(ctx, i) : ia64_get_pmd(i); + } + } + + pfm_stats[this_cpu].pfm_smpl_handler_calls++; + start_cycles = ia64_get_itc(); + + /* + * call custom buffer format record (handler) routine + */ + (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, &ovfl_arg, regs); + + pfm_stats[this_cpu].pfm_smpl_handler_cycles += ia64_get_itc() - start_cycles; + + ovfl_pmds = ovfl_arg.ovfl_pmds[0]; + ovfl_notify = ovfl_arg.ovfl_notify[0]; + ovfl_ctrl = ovfl_arg.ovfl_ctrl; + } + + if (ovfl_pmds && ovfl_ctrl.reset_pmds) { + pfm_reset_regs(ctx, &ovfl_pmds, ovfl_ctrl.reset_pmds); + } + + if (ovfl_notify && ovfl_ctrl.notify_user) { + /* + * keep track of what to reset when unblocking + */ + ctx->ctx_ovfl_regs[0] = ovfl_pmds; + + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ovfl_ctrl.block) { + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCK; + + /* + * set the perfmon specific checking pending work + */ + PFM_SET_WORK_PENDING(task, 1); + + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + pfm_set_task_notify(task); + } + /* + * defer until state is changed (shorten spin window). the context is locked + * anyway, so the signal receiver would come spin for nothing. + */ + must_notify = 1; + } + + DPRINT_ovfl(("current [%d] owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx stopped=%d\n", + current->pid, + GET_PMU_OWNER() ? GET_PMU_OWNER()->pid : -1, + PFM_GET_WORK_PENDING(task), + ctx->ctx_fl_trap_reason, + ovfl_pmds, + ovfl_notify, + ovfl_ctrl.stop_monitoring ? 1 : 0)); + /* + * in case monitoring must be stopped, we toggle the psr bits + */ + if (ovfl_ctrl.stop_monitoring) { + pfm_mask_monitoring(task); + CTX_MASKED(ctx); + } + /* + * send notification now + */ + if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify); + + return; + + +sanity_check: + printk(KERN_ERR "perfmon: CPU%d overflow handler [%d] pmc0=0x%lx\n", + smp_processor_id(), + task ? task->pid : -1, + pmc0); + return; + +stop_monitoring: + /* + * in SMP, zombie context is never restored but reclaimed in pfm_load_regs(). + * Moreover, zombies are also reclaimed in pfm_save_regs(). Therefore we can + * come here as zombie only if the task is the current task. In which case, we + * can access the PMU hardware directly. + * + * Note that zombies do have PM_VALID set. So here we do the minimal. + * + * In case the context was zombified it could not be reclaimed at the time + * the monitoring program exited. At this point, the PMU reservation has been + * returned, the sampiing buffer has been freed. We must convert this call + * into a spurious interrupt. However, we must also avoid infinite overflows + * by stopping monitoring for this task. We can only come here for a per-task + * context. All we need to do is to stop monitoring using the psr bits which + * are always task private. By re-enabling secure montioring, we ensure that + * the monitored task will not be able to re-activate monitoring. + * The task will eventually be context switched out, at which point the context + * will be reclaimed (that includes releasing ownership of the PMU). + * + * So there might be a window of time where the number of per-task session is zero + * yet one PMU might have a owner and get at most one overflow interrupt for a zombie + * context. This is safe because if a per-task session comes in, it will push this one + * out and by the virtue on pfm_save_regs(), this one will disappear. If a system wide + * session is force on that CPU, given that we use task pinning, pfm_save_regs() will + * also push our zombie context out. + * + * Overall pretty hairy stuff.... + */ + DPRINT(("ctx is zombie for [%d], converted to spurious\n", task ? task->pid: -1)); + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + return; +} + +static int +pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_context_t *ctx; + unsigned long flags; + u64 pmc0; + int this_cpu = smp_processor_id(); + int retval = 0; + + pfm_stats[this_cpu].pfm_ovfl_intr_count++; + + /* + * srlz.d done before arriving here + */ + pmc0 = ia64_get_pmc(0); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + /* + * if we have some pending bits set + * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1 + */ + if (PMC0_HAS_OVFL(pmc0) && task) { + /* + * we assume that pmc0.fr is always set here + */ + + /* sanity check */ + if (!ctx) goto report_spurious; + + if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) { + printk("perfmon: current [%d] owner = [%d] PMVALID=0 state=%d\n", current->pid, task->pid, ctx->ctx_state); + goto report_spurious; + } + + PROTECT_CTX_NOPRINT(ctx, flags); + + pfm_overflow_handler(task, ctx, pmc0, regs); + + UNPROTECT_CTX_NOPRINT(ctx, flags); + + } else { + pfm_stats[this_cpu].pfm_spurious_ovfl_intr_count++; + retval = -1; + } + /* + * keep it unfrozen at all times + */ + pfm_unfreeze_pmu(); + + return retval; + +report_spurious: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n", + this_cpu, task->pid); + pfm_unfreeze_pmu(); + return -1; +} + +static pfm_irq_handler_t +pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + unsigned long m; + unsigned long min, max; + int this_cpu; + int ret; + + this_cpu = smp_processor_id(); + min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; + max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; + + m = ia64_get_itc(); + + ret = pfm_do_interrupt_handler(irq, arg, regs); + + m = ia64_get_itc() - m; + + /* + * don't measure spurious interrupts + */ + if (ret == 0) { + if (m < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = m; + if (m > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = m; + pfm_stats[this_cpu].pfm_ovfl_intr_cycles += m; + } + PFM_IRQ_HANDLER_RET(); +} + + +/* for debug only */ +static int +pfm_proc_info(char *page) +{ + char *p = page; + pfm_buffer_fmt_t *b; + unsigned long psr; + int i; + + p += sprintf(p, "model : %s\n", pmu_conf.pmu_name); + p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); + p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val); + + for(i=0; i < NR_CPUS; i++) { + if (cpu_is_online(i) == 0) continue; + p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count); + p += sprintf(p, "CPU%-2d overflow cycles : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles); + p += sprintf(p, "CPU%-2d overflow min : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles_min); + p += sprintf(p, "CPU%-2d overflow max : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles_max); + p += sprintf(p, "CPU%-2d smpl handler calls : %lu\n", i, pfm_stats[i].pfm_smpl_handler_calls); + p += sprintf(p, "CPU%-2d smpl handler cycles : %lu\n", i, pfm_stats[i].pfm_smpl_handler_cycles); + p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count); + p += sprintf(p, "CPU%-2d sysupdt count : %lu\n", i, pfm_stats[i].pfm_sysupdt_count); + p += sprintf(p, "CPU%-2d sysupdt cycles : %lu\n", i, pfm_stats[i].pfm_sysupdt_cycles); + p += sprintf(p, "CPU%-2d syst_wide : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_SYST_WIDE ? 1 : 0); + p += sprintf(p, "CPU%-2d dcr_pp : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_DCR_PP ? 1 : 0); + p += sprintf(p, "CPU%-2d exclude idle : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0); + p += sprintf(p, "CPU%-2d owner : %d\n" , i, pfm_get_cpu_data(pmu_owner, i) ? pfm_get_cpu_data(pmu_owner, i)->pid: -1); + p += sprintf(p, "CPU%-2d context : %p\n" , i, pfm_get_cpu_data(pmu_ctx, i)); + p += sprintf(p, "CPU%-2d activations : %lu\n", i, pfm_get_cpu_data(pmu_activation_number,i)); + } + + if (hweight64(PFM_CPU_ONLINE_MAP) == 1) + { + psr = pfm_get_psr(); + ia64_srlz_d(); + p += sprintf(p, "CPU%-2d psr : 0x%lx\n", smp_processor_id(), psr); + p += sprintf(p, "CPU%-2d pmc0 : 0x%lx\n", smp_processor_id(), ia64_get_pmc(0)); + for(i=4; i < 8; i++) { + p += sprintf(p, "CPU%-2d pmc%u : 0x%lx\n", smp_processor_id(), i, ia64_get_pmc(i)); + p += sprintf(p, "CPU%-2d pmd%u : 0x%lx\n", smp_processor_id(), i, ia64_get_pmd(i)); + } + } + + LOCK_PFS(); + p += sprintf(p, "proc_sessions : %u\n" + "sys_sessions : %u\n" + "sys_use_dbregs : %u\n" + "ptrace_use_dbregs : %u\n", + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_sys_use_dbregs, + pfm_sessions.pfs_ptrace_use_dbregs); + UNLOCK_PFS(); + + LOCK_BUF_FMT_LIST(); + + for (b = pfm_buffer_fmt_list; b ; b = b->fmt_next) { + p += sprintf(p, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n", + b->fmt_uuid[0], + b->fmt_uuid[1], + b->fmt_uuid[2], + b->fmt_uuid[3], + b->fmt_uuid[4], + b->fmt_uuid[5], + b->fmt_uuid[6], + b->fmt_uuid[7], + b->fmt_uuid[8], + b->fmt_uuid[9], + b->fmt_uuid[10], + b->fmt_uuid[11], + b->fmt_uuid[12], + b->fmt_uuid[13], + b->fmt_uuid[14], + b->fmt_uuid[15], + b->fmt_name); + } + UNLOCK_BUF_FMT_LIST(); + + return p - page; +} + +/* /proc interface, for debug only */ +static int +perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = pfm_proc_info(page); + + if (len <= off+count) *eof = 1; + + *start = page + off; + len -= off; + + if (len>count) len = count; + if (len<0) len = 0; + + return len; +} + +/* + * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens + * during pfm_enable() hence before pfm_start(). We cannot assume monitoring + * is active or inactive based on mode. We must rely on the value in + * local_cpu_data->pfm_syst_info + */ +void +pfm_do_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +{ + struct pt_regs *regs; + unsigned long dcr; + unsigned long dcr_pp; + + dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0; + + /* + * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 + * on every CPU, so we can rely on the pid to identify the idle task. + */ + if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) { + regs = ia64_task_regs(task); + ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0; + return; + } + /* + * if monitoring has started + */ + if (dcr_pp) { + dcr = ia64_get_dcr(); + /* + * context switching in? + */ + if (is_ctxswin) { + /* mask monitoring for the idle task */ + ia64_set_dcr(dcr & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + ia64_srlz_i(); + return; + } + /* + * context switching out + * restore monitoring for next task + * + * Due to inlining this odd if-then-else construction generates + * better code. + */ + ia64_set_dcr(dcr |IA64_DCR_PP); + pfm_set_psr_pp(); + ia64_srlz_i(); + } +} + +void +pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +{ + unsigned long start, end; + pfm_stats[smp_processor_id()].pfm_sysupdt_count++; + start = ia64_get_itc(); + pfm_do_syst_wide_update_task(task, info, is_ctxswin); + end = ia64_get_itc(); + pfm_stats[smp_processor_id()].pfm_sysupdt_cycles += end-start; +} + +#ifdef CONFIG_SMP +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + u64 psr; + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) goto save_error; + t = &task->thread; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + + if (CTX_IS_ZOMBIE(ctx)) { + struct pt_regs *regs = ia64_task_regs(task); + + pfm_clear_psr_up(); + + DPRINT(("ctx zombie, forcing cleanup for [%d]\n", task->pid)); + + pfm_force_cleanup(ctx, regs); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + pfm_context_free(ctx); + return; + } + + /* + * sanity check + */ + if (ctx->ctx_last_activation != GET_ACTIVATION()) { + DPRINT(("ctx_activation=%lu activation=%lu state=%d: no save\n", + ctx->ctx_last_activation, + GET_ACTIVATION(), ctx->ctx_state)); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + return; + } + + /* + * save current PSR: needed because we modify it + */ + psr = pfm_get_psr(); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of the saved psr (for reload) + */ + ctx->ctx_saved_psr = psr; + + /* + * release ownership of this PMU. + * PM interrupts are masked, so nothing + * can happen. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * we systematically save the PMD as we have no + * guarantee we will be schedule at that same + * CPU again. + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * we will need it on the restore path to check + * for pending overflow. + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~1UL) pfm_unfreeze_pmu(); + + /* + * finally, unmask interrupts and allow context + * access. + * Any pended overflow interrupt may be delivered + * here and will be treated as spurious because we + * have have no PMU owner anymore. + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); + + return; + +save_error: + printk(KERN_ERR "perfmon: pfm_save_regs CPU%d [%d] NULL context PM_VALID=%ld\n", + smp_processor_id(), task->pid, + task->thread.flags & IA64_THREAD_PM_VALID); +} + +#else /* !CONFIG_SMP */ + +/* + * in 2.5, interrupts are masked when we come here + */ +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + u64 psr; + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) goto save_error; + + /* + * save current PSR: needed because we modify it + */ + psr = pfm_get_psr(); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of the saved psr (for reload) + */ + ctx->ctx_saved_psr = psr; + + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_save_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, GET_PMU_OWNER()->pid, psr); + } + if (psr & IA64_PSR_I) { + printk(KERN_ERR " perfmon: pfm_save_regs: psr.i set current [%d] owner [%d] psr=0x%lx\n", current->pid, GET_PMU_OWNER()->pid, psr); + } + + return; +save_error: + printk(KERN_ERR "perfmon: pfm_save_regs CPU%d [%d] NULL context PM_VALID=%ld\n", + smp_processor_id(), task->pid, + task->thread.flags & IA64_THREAD_PM_VALID); +} + +static void +pfm_lazy_save_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + unsigned long psr; + +#if 1 + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_lazy_save_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, task->pid, psr); + pfm_clear_psr_up(); + } +#endif + + ctx = PFM_GET_CTX(task); + t = &task->thread; + + DPRINT(("on [%d] used_pmds=0x%lx\n", task->pid, ctx->ctx_used_pmds[0])); + + /* + * we need to mask PMU overflow here to + * make sure that we maintain pmc0 until + * we save it. overflow interrupts are + * treated as spurious if there is no + * owner. + * + * XXX: I don't think this is necessary + */ + PROTECT_CTX(ctx,flags); + + /* + * release ownership of this PMU. + * must be done before we save the registers. + * + * after this call any PMU interrupt is treated + * as spurious. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * save all the pmds we use + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * it is needed to check for pended overflow + * on the restore path + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~1UL) pfm_unfreeze_pmu(); + + /* + * now get can unmask PMU interrupts, they will + * be treated as purely spurious and we will not + * lose any information + */ + UNPROTECT_CTX(ctx,flags); +} +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_SMP +void +pfm_load_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + struct task_struct *owner; + unsigned long pmc_mask = 0UL, pmd_mask = 0UL; + unsigned long flags; + u64 psr; + + ctx = PFM_GET_CTX(task); + if (unlikely(ctx == NULL)) { + printk(KERN_ERR "perfmon: pfm_load_regs() null context\n"); + return; + } + + owner = GET_PMU_OWNER(); + t = &task->thread; + +#if 1 + psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_UP); + psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_I); +#endif + + + /* + * possible on unload + */ + if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) { + DPRINT(("[%d] PM_VALID=0, nothing to do\n", task->pid)); + return; + } + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + + if (unlikely(CTX_IS_ZOMBIE(ctx))) { + struct pt_regs *regs = ia64_task_regs(task); + + BUG_ON(ctx->ctx_smpl_hdr); + + DPRINT(("ctx zombie, forcing cleanup for [%d]\n", task->pid)); + + pfm_force_cleanup(ctx, regs); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + /* + * this one (kmalloc'ed) is fine with interrupts disabled + */ + pfm_context_free(ctx); + + return; + } + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } + /* + * retrieve saved psr + */ + psr = ctx->ctx_saved_psr; + + /* + * if we were the last user of the PMU on that CPU, + * then nothing to do except restore psr + */ + if (GET_LAST_CPU(ctx) == smp_processor_id() && ctx->ctx_last_activation == GET_ACTIVATION()) { + + /* + * retrieve partial reload masks (due to user modifications) + */ + pmc_mask = ctx->ctx_reload_pmcs[0]; + pmd_mask = ctx->ctx_reload_pmds[0]; + + if (pmc_mask || pmd_mask) DPRINT(("partial reload [%d] pmd_mask=0x%lx pmc_mask=0x%lx\n", task->pid, pmd_mask, pmc_mask)); + } else { + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately. + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + + DPRINT(("full reload for [%d] owner=%d activation=%lu last_activation=%lu last_cpu=%d pmd_mask=0x%lx pmc_mask=0x%lx\n", + task->pid, owner ? owner->pid : -1, + GET_ACTIVATION(), ctx->ctx_last_activation, + GET_LAST_CPU(ctx), pmd_mask, pmc_mask)); + + } + /* + * when context is MASKED, we will restore PMC with plm=0 + * and PMD with stale information, but that's ok, nothing + * will be captured. + * + * XXX: optimize here + */ + if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask); + if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * check for pending overflow at the time the state + * was saved. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + struct pt_regs *regs = ia64_task_regs(task); + pfm_overflow_handler(task, ctx, t->pmcs[0], regs); + } + + /* + * we clear PMC0, to ensure that any in flight interrupt + * will not be attributed to the new context we are installing + * because the actual overflow has been processed above already. + * No real effect until we unmask interrupts at the end of the + * function. + */ + pfm_unfreeze_pmu(); + + /* + * we just did a reload, so we reset the partial reload fields + */ + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + SET_LAST_CPU(ctx, smp_processor_id()); + + /* + * dump activation value for this PMU + */ + INC_ACTIVATION(); + /* + * record current activation for this context + */ + SET_ACTIVATION(ctx); + + /* + * establish new ownership. Interrupts + * are still masked at this point. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr we changed + */ + pfm_set_psr_l(psr); + + /* + * allow concurrent access to context + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); +} +#else /* !CONFIG_SMP */ +/* + * reload PMU state for UP kernels + * in 2.5 we come here with interrupts disabled + */ +void +pfm_load_regs (struct task_struct *task) +{ + struct thread_struct *t; + pfm_context_t *ctx; + struct task_struct *owner; + unsigned long pmd_mask, pmc_mask; + u64 psr; + + owner = GET_PMU_OWNER(); + ctx = PFM_GET_CTX(task); + t = &task->thread; + +#if 1 + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_load_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, owner->pid, psr); + } + psr = pfm_get_psr(); + if (psr & IA64_PSR_I) { + printk(KERN_ERR " perfmon: pfm_load_regs: psr.i set current [%d] owner [%d] psr=0x%lx\n", current->pid, owner->pid, psr); + } +#endif + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } + + /* + * retrieved save psr + */ + psr = ctx->ctx_saved_psr; + + /* + * short path, our state is still there, just + * need to restore psr and we go + * + * we do not touch either PMC nor PMD. the psr is not touched + * by the overflow_handler. So we are safe w.r.t. to interrupt + * concurrency even without interrupt masking. + */ + if (likely(owner == task)) { + pfm_set_psr_l(psr); + return; + } + + DPRINT(("reload for [%d] owner=%d\n", task->pid, owner ? owner->pid : -1)); + + /* + * someone else is still using the PMU, first push it out and + * then we'll be able to install our stuff ! + * + * Upon return, there will be no owner for the current PMU + */ + if (owner) pfm_lazy_save_regs(owner); + + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + + pfm_restore_pmds(t->pmds, pmd_mask); + pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * Check for pending overflow when state was last saved. + * invoked handler is overflow status bits set. + * + * Any PMU overflow in flight at this point, will still + * be treated as spurious because we have no declared + * owner. Note that the first level interrupt handler + * DOES NOT TOUCH any PMC except PMC0 for which we have + * a copy already. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + struct pt_regs *regs = ia64_task_regs(task); + pfm_overflow_handler(task, ctx, t->pmcs[0], regs); + } + + /* + * we clear PMC0, to ensure that any in flight interrupt + * will not be attributed to the new context we are installing + * because the actual overflow has been processed above already. + * + * This is an atomic operation. + */ + pfm_unfreeze_pmu(); + + /* + * establish new ownership. If there was an in-flight + * overflow interrupt, it will be treated as spurious + * before and after the call, because no overflow + * status bit can possibly be set. No new overflow + * can be generated because, at this point, psr.up + * is still cleared. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr. This is the point at which + * new overflow interrupts can be generated again. + */ + pfm_set_psr_l(psr); + +} +#endif /* CONFIG_SMP */ + +/* + * this function assumes monitoring is stopped + */ +static void +pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + u64 pmc0; + unsigned long mask2, val, pmd_val; + int i, can_access_pmu = 0; + int is_self; + + /* + * is the caller the task being monitored (or which initiated the + * session for system wide measurements) + */ + is_self = ctx->ctx_task == task ? 1 : 0; + +#ifdef CONFIG_SMP + if (task == current) { +#else + /* + * in UP, the state can still be in the registers + */ + if (task == current || GET_PMU_OWNER() == task) { +#endif + can_access_pmu = 1; + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * reset freeze bit, overflow status information destroyed + */ + pfm_unfreeze_pmu(); + } else { + pmc0 = task->thread.pmcs[0]; + /* + * clear whatever overflow status bits there were + */ + task->thread.pmcs[0] &= ~0x1; + } + + /* + * we save all the used pmds + * we take care of overflows for counting PMDs + * + * XXX: sampling situation is not taken into account here + */ + mask2 = ctx->ctx_used_pmds[0]; + for (i = 0; mask2; i++, mask2>>=1) { + + /* skip non used pmds */ + if ((mask2 & 0x1) == 0) continue; + + /* + * can access PMU always true in system wide mode + */ + val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i]; + + if (PMD_IS_COUNTING(i)) { + DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n", + task->pid, + i, + ctx->ctx_pmds[i].val, + val & pmu_conf.ovfl_val)); + + /* + * we rebuild the full 64 bit value of the counter + */ + val = ctx->ctx_pmds[i].val + (val & pmu_conf.ovfl_val); + + /* + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + pmd_val = 0UL; + + /* + * take care of overflow inline + */ + if (pmc0 & (1UL << i)) { + val += 1 + pmu_conf.ovfl_val; + DPRINT(("[%d] pmd[%d] overflowed\n", task->pid, i)); + } + } + + DPRINT(("[%d] is_self=%d ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, is_self, i, val, pmd_val)); + + if (is_self) task->thread.pmds[i] = pmd_val; + ctx->ctx_pmds[i].val = val; + } +} + +static struct irqaction perfmon_irqaction = { + .handler = pfm_interrupt_handler, + .flags = SA_INTERRUPT, + .name = "perfmon" +}; + +/* + * perfmon initialization routine, called from the initcall() table + */ +static int init_pfm_fs(void); + +int __init +pfm_init(void) +{ + unsigned int n, n_counters, i; + + printk("perfmon: version %u.%u IRQ %u\n", + PFM_VERSION_MAJ, + PFM_VERSION_MIN, + IA64_PERFMON_VECTOR); + + /* + * PMU type sanity check + * XXX: maybe better to implement autodetection (but then we have a larger kernel) + */ + if (local_cpu_data->family != pmu_conf.pmu_family) { + printk(KERN_INFO "perfmon: disabled, kernel only supports %s PMU family\n", pmu_conf.pmu_name); + return -ENODEV; + } + + /* + * compute the number of implemented PMD/PMC from the + * description tables + */ + n = 0; + for (i=0; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63); + n++; + } + pmu_conf.num_pmcs = n; + + n = 0; n_counters = 0; + for (i=0; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63); + n++; + if (PMD_IS_COUNTING(i)) n_counters++; + } + pmu_conf.num_pmds = n; + pmu_conf.num_counters = n_counters; + + /* + * sanity checks on the number of debug registers + */ + if (pmu_conf.use_rr_dbregs) { + if (pmu_conf.num_ibrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of code debug registers (%u)\n", pmu_conf.num_ibrs); + return -1; + } + if (pmu_conf.num_dbrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of data debug registers (%u)\n", pmu_conf.num_ibrs); + return -1; + } + } + + printk("perfmon: %s PMU detected, %u PMCs, %u PMDs, %u counters (%lu bits)\n", + pmu_conf.pmu_name, + pmu_conf.num_pmcs, + pmu_conf.num_pmds, + pmu_conf.num_counters, + ffz(pmu_conf.ovfl_val)); + + /* sanity check */ + if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n"); + return -1; + } + + /* + * create /proc/perfmon (mostly for debugging purposes) + */ + perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); + if (perfmon_dir == NULL) { + printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); + return -1; + } + + /* + * create /proc/sys/kernel/perfmon (for debugging purposes) + */ + pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); + + /* + * initialize all our spinlocks + */ + spin_lock_init(&pfm_sessions.pfs_lock); + spin_lock_init(&pfm_smpl_fmt_lock); + + init_pfm_fs(); + + for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL; + + /* we are all set */ + pmu_conf.enabled = 1; + + return 0; +} + +__initcall(pfm_init); + +void +pfm_init_percpu (void) +{ + int i; + + /* + * make sure no measurement is active + * (may inherit programmed PMCs from EFI). + */ + pfm_clear_psr_pp(); + pfm_clear_psr_up(); + + + if (smp_processor_id() == 0) + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_set_pmv(IA64_PERFMON_VECTOR); + ia64_srlz_d(); + + /* + * we first initialize the PMU to a stable state. + * the values may have been changed from their power-up + * values by software executed before the kernel took over. + * + * At this point, pmu_conf has not yet been initialized + * + * On McKinley, this code is ineffective until PMC4 is initialized + * but that's all right because we take care of pmc0 later. + * + * XXX: potential problems with pmc1. + */ + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + ia64_set_pmc(i, PMC_DFL_VAL(i)); + } + + for (i=0; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + ia64_set_pmd(i, 0UL); + } + + /* + * we run with the PMU not frozen at all times + */ + pfm_unfreeze_pmu(); +} + +/* + * used for debug purposes only + */ +void +dump_pmu_state(void) +{ + struct task_struct *task; + struct thread_struct *t; + pfm_context_t *ctx; + unsigned long psr; + int i; + + printk("current [%d] %s\n", current->pid, current->comm); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + printk("owner [%d] ctx=%p\n", task ? task->pid : -1, ctx); + + psr = pfm_get_psr(); + + printk("psr.pp=%ld psr.up=%ld\n", (psr >> IA64_PSR_PP_BIT) &0x1UL, (psr >> IA64_PSR_PP_BIT)&0x1UL); + + t = ¤t->thread; + + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + printk("pmc[%d]=0x%lx tpmc=0x%lx\n", i, ia64_get_pmc(i), t->pmcs[i]); + } + + for (i=1; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + printk("pmd[%d]=0x%lx tpmd=0x%lx\n", i, ia64_get_pmd(i), t->pmds[i]); + } + if (ctx) { + printk("ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr=0x%lx\n", + ctx->ctx_state, + ctx->ctx_smpl_vaddr, + ctx->ctx_smpl_hdr, + ctx->ctx_msgq_head, + ctx->ctx_msgq_tail, + ctx->ctx_saved_psr); + } +} + +/* + * called from process.c:copy_thread(). task is new child. + */ +void +pfm_inherit(struct task_struct *task, struct pt_regs *regs) +{ + struct thread_struct *thread; + + DPRINT(("perfmon: pfm_inherit clearing state for [%d] current [%d]\n", task->pid, current->pid)); + + thread = &task->thread; + + /* + * cut links inherited from parent (current) + */ + thread->pfm_context = NULL; + + PFM_SET_WORK_PENDING(task, 0); + + /* + * restore default psr settings + */ + ia64_psr(regs)->pp = ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; +} +#else /* !CONFIG_PERFMON */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, + long arg8, long stack) +{ + return -ENOSYS; +} +#endif /* CONFIG_PERFMON */ diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c new file mode 100644 index 00000000000..4ee7b1379ef --- /dev/null +++ b/arch/ia64/kernel/perfmon_default_smpl.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for the Linux/ia64 perfmon-2 subsystem. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Stephane Eranian "); +MODULE_DESCRIPTION("perfmon default sampling format"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "debug"); + +MODULE_PARM(debug_ovfl, "i"); +MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); + + +#define DEFAULT_DEBUG 1 + +#ifdef DEFAULT_DEBUG +#define DPRINT(a) \ + do { \ + if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#else +#define DPRINT(a) +#define DPRINT_ovfl(a) +#endif + +static int debug, debug_ovfl; + +static int +default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data; + int ret = 0; + + if (data == NULL) { + DPRINT(("[%d] no argument passed\n", task->pid)); + return -EINVAL; + } + + DPRINT(("[%d] validate flags=0x%x CPU%d\n", task->pid, flags, cpu)); + + /* + * must hold at least the buffer header + one minimally sized entry + */ + if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL; + + DPRINT(("buf_size=%lu\n", arg->buf_size)); + + return ret; +} + +static int +default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + /* + * size has been validated in default_validate + */ + *size = arg->buf_size; + + return 0; +} + +static int +default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION; + hdr->hdr_buf_size = arg->buf_size; + hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr); + hdr->hdr_last_pos = (void *)((unsigned long)buf)+arg->buf_size; + hdr->hdr_overflows = 0UL; + hdr->hdr_count = 0UL; + + DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u\n", + task->pid, + buf, + hdr->hdr_buf_size, + sizeof(*hdr), + hdr->hdr_version)); + + return 0; +} + +static int +default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_entry_t *ent; + void *cur, *last; + unsigned long *e; + unsigned long ovfl_mask; + unsigned long ovfl_notify; + unsigned long stamp; + unsigned int npmds, i; + + /* + * some time stamp + */ + stamp = ia64_get_itc(); + + if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) { + DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg)); + return -EINVAL; + } + + hdr = (pfm_default_smpl_hdr_t *)buf; + cur = hdr->hdr_cur_pos; + last = hdr->hdr_last_pos; + ovfl_mask = arg->ovfl_pmds[0]; + ovfl_notify = arg->ovfl_notify[0]; + + /* + * check for space against largest possibly entry. + * We may waste space at the end of the buffer. + */ + if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; + + npmds = hweight64(arg->smpl_pmds[0]); + + ent = (pfm_default_smpl_entry_t *)cur; + + prefetch(arg->smpl_pmds_values); + + /* position for first pmd */ + e = (unsigned long *)(ent+1); + + hdr->hdr_count++; + + DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmds=0x%lx ovfl_notify=0x%lx npmds=%u\n", + task->pid, + hdr->hdr_count, + cur, last, + last-cur, + ovfl_mask, + ovfl_notify, npmds)); + + /* + * current = task running at the time of the overflow. + * + * per-task mode: + * - this is ususally the task being monitored. + * Under certain conditions, it might be a different task + * + * system-wide: + * - this is not necessarily the task controlling the session + */ + ent->pid = current->pid; + ent->cpu = smp_processor_id(); + ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; + + /* + * where did the fault happen (includes slot number) + */ + ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3); + + /* + * which registers overflowed + */ + ent->ovfl_pmds = ovfl_mask; + ent->tstamp = stamp; + ent->set = arg->active_set; + ent->reserved1 = 0; + + /* + * selectively store PMDs in increasing index number + */ + if (npmds) { + unsigned long *val = arg->smpl_pmds_values; + for(i=0; i < npmds; i++) { + *e++ = *val++; + } + } + + /* + * update position for next entry + */ + hdr->hdr_cur_pos = cur + sizeof(*ent) + (npmds << 3); + + /* + * keep same ovfl_pmds, ovfl_notify + */ + arg->ovfl_ctrl.notify_user = 0; + arg->ovfl_ctrl.block = 0; + arg->ovfl_ctrl.stop_monitoring = 0; + arg->ovfl_ctrl.reset_pmds = 1; + + return 0; +full: + DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=0x%lx\n", last-cur, hdr->hdr_count, ovfl_notify)); + + /* + * increment number of buffer overflow. + * important to detect duplicate set of samples. + */ + hdr->hdr_overflows++; + + /* + * if no notification is needed, then we just reset the buffer index. + */ + if (ovfl_notify == 0UL) { + hdr->hdr_count = 0UL; + arg->ovfl_ctrl.notify_user = 0; + arg->ovfl_ctrl.block = 0; + arg->ovfl_ctrl.stop_monitoring = 0; + arg->ovfl_ctrl.reset_pmds = 1; + } else { + /* keep same ovfl_pmds, ovfl_notify */ + arg->ovfl_ctrl.notify_user = 1; + arg->ovfl_ctrl.block = 1; + arg->ovfl_ctrl.stop_monitoring = 1; + arg->ovfl_ctrl.reset_pmds = 0; + } + return 0; +} + +static int +default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + pfm_default_smpl_hdr_t *hdr; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_count = 0UL; + hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr); + + ctrl->stop_monitoring = 0; + ctrl->reset_pmds = PFM_PMD_LONG_RESET; + + return 0; +} + +static int +default_exit(struct task_struct *task, void *buf, struct pt_regs *regs) +{ + DPRINT(("[%d] exit(%p)\n", task->pid, buf)); + return 0; +} + +static pfm_buffer_fmt_t default_fmt={ + .fmt_name = "default_format", + .fmt_uuid = PFM_DEFAULT_SMPL_UUID, + .fmt_arg_size = sizeof(pfm_default_smpl_arg_t), + .fmt_validate = default_validate, + .fmt_getsize = default_get_size, + .fmt_init = default_init, + .fmt_handler = default_handler, + .fmt_restart = default_restart, + .fmt_exit = default_exit, +}; + +static int __init +pfm_default_smpl_init_module(void) +{ + int ret; + + ret = pfm_register_buffer_fmt(&default_fmt); + if (ret == 0) { + printk("perfmon_default_smpl: %s v%u.%u registered\n", + default_fmt.fmt_name, + PFM_DEFAULT_SMPL_VERSION_MAJ, + PFM_DEFAULT_SMPL_VERSION_MIN); + } else { + printk("perfmon_default_smpl: %s cannot register ret=%d\n", + default_fmt.fmt_name, + ret); + } + + return ret; +} + +static void __exit +pfm_default_smpl_cleanup_module(void) +{ + int ret; + ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid); + + printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret); +} + +module_init(pfm_default_smpl_init_module); +module_exit(pfm_default_smpl_cleanup_module); + diff --git a/arch/ia64/kernel/perfmon_generic.h b/arch/ia64/kernel/perfmon_generic.h index 72fb6269231..39aecdb2a99 100644 --- a/arch/ia64/kernel/perfmon_generic.h +++ b/arch/ia64/kernel/perfmon_generic.h @@ -1,17 +1,19 @@ /* - * This file contains the architected PMU register description tables + * This file contains the generic PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ + + #define RDEP(x) (1UL<<(x)) #if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY) #error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined" #endif -static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={ +static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -23,7 +25,7 @@ static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={ { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ }; -static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={ +static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={ /* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, @@ -39,10 +41,13 @@ static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 32) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_gen_pmd_desc, - .pmc_desc = pfm_gen_pmc_desc + .pmu_name = "Generic", + .pmu_family = 0xff, /* any */ + .enabled = 0, + .ovfl_val = (1UL << 32) - 1, + .num_ibrs = 0, /* does not use */ + .num_dbrs = 0, /* does not use */ + .pmd_desc = pfm_gen_pmd_desc, + .pmc_desc = pfm_gen_pmc_desc }; + diff --git a/arch/ia64/kernel/perfmon_itanium.h b/arch/ia64/kernel/perfmon_itanium.h index b0f9a887696..05f92744411 100644 --- a/arch/ia64/kernel/perfmon_itanium.h +++ b/arch/ia64/kernel/perfmon_itanium.h @@ -2,7 +2,7 @@ * This file contains the Itanium PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ @@ -12,8 +12,8 @@ #error "This file is only valid when CONFIG_ITANIUM is defined" #endif -static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); +static int pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -59,52 +59,53 @@ static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 32) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_ita_pmd_desc, - .pmc_desc = pfm_ita_pmc_desc + .pmu_name = "Itanium", + .pmu_family = 0x7, + .enabled = 0, + .ovfl_val = (1UL << 32) - 1, + .pmd_desc = pfm_ita_pmd_desc, + .pmc_desc = pfm_ita_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ }; - static int -pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) { - pfm_context_t *ctx = task->thread.pfm_context; int ret; /* * we must clear the (instruction) debug registers if pmc13.ta bit is cleared - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); if (ret) return ret; } /* * we must clear the (data) debug registers if pmc11.pt bit is cleared - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); if (ret) return ret; } return 0; diff --git a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h index a02cd6c5f92..2e67421055c 100644 --- a/arch/ia64/kernel/perfmon_mckinley.h +++ b/arch/ia64/kernel/perfmon_mckinley.h @@ -2,7 +2,7 @@ * This file contains the McKinley PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ @@ -12,9 +12,8 @@ #error "This file is only valid when CONFIG_MCKINLEY is defined" #endif -static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); +static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -22,17 +21,17 @@ static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={ /* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ }; @@ -62,20 +61,22 @@ static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 47) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_mck_pmd_desc, - .pmc_desc = pfm_mck_pmc_desc + .pmu_name = "Itanium 2", + .pmu_family = 0x1f, + .enabled = 0, + .ovfl_val = (1UL << 47) - 1, + .pmd_desc = pfm_mck_pmd_desc, + .pmc_desc = pfm_mck_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ }; - /* * PMC reserved fields must have their power-up values preserved */ static int -pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) { unsigned long tmp1, tmp2, ival = *val; @@ -87,52 +88,56 @@ pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val *val = tmp1 | tmp2; - DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", - cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); + DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", + cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); return 0; } +/* + * task can be NULL if the context is unloaded + */ static int -pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) { - struct thread_struct *th = &task->thread; - pfm_context_t *ctx = task->thread.pfm_context; int ret = 0, check_case1 = 0; unsigned long val8 = 0, val14 = 0, val13 = 0; /* first preserve the reserved fields */ - pfm_mck_reserved(task, cnum, val, regs); + pfm_mck_reserved(cnum, val, regs); + + /* sanitfy check */ + if (ctx == NULL) return -EINVAL; /* - * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); if (ret) return ret; } - /* - * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled - * before they are (fl_using_dbreg==0) to avoid picking up stale information. + /* + * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled + * before they are (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); if (ret) return ret; } @@ -141,17 +146,17 @@ pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *va case 4: *val |= 1UL << 23; /* force power enable bit */ break; case 8: val8 = *val; - val13 = th->pmc[13]; - val14 = th->pmc[14]; + val13 = ctx->ctx_pmcs[13]; + val14 = ctx->ctx_pmcs[14]; check_case1 = 1; break; - case 13: val8 = th->pmc[8]; + case 13: val8 = ctx->ctx_pmcs[8]; val13 = *val; - val14 = th->pmc[14]; + val14 = ctx->ctx_pmcs[14]; check_case1 = 1; break; - case 14: val8 = th->pmc[13]; - val13 = th->pmc[13]; + case 14: val8 = ctx->ctx_pmcs[13]; + val13 = ctx->ctx_pmcs[13]; val14 = *val; check_case1 = 1; break; @@ -165,7 +170,7 @@ pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *va && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); - if (ret) printk(KERN_DEBUG "perfmon: failure check_case1\n"); + if (ret) printk("perfmon: failure check_case1\n"); } return ret ? -EINVAL : 0; diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 2a477a56e75..cd46496a8d5 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -33,16 +32,15 @@ #include #include -#ifdef CONFIG_IA64_SGI_SN -#include -#endif - #ifdef CONFIG_PERFMON # include #endif #include "sigframe.h" +void (*ia64_mark_idle)(int); + + void ia64_do_show_stack (struct unw_frame_info *info, void *arg) { @@ -64,13 +62,7 @@ ia64_do_show_stack (struct unw_frame_info *info, void *arg) } void -show_trace_task (struct task_struct *task) -{ - show_stack(task); -} - -void -show_stack (struct task_struct *task) +show_stack (struct task_struct *task, unsigned long *sp) { if (!task) unw_init_running(ia64_do_show_stack, 0); @@ -85,7 +77,7 @@ show_stack (struct task_struct *task) void dump_stack (void) { - show_stack(NULL); + show_stack(NULL, NULL); } void @@ -103,6 +95,7 @@ show_regs (struct pt_regs *regs) regs->ar_rnat, regs->ar_bspstore, regs->pr); printk("ldrs: %016lx ccv : %016lx fpsr: %016lx\n", regs->loadrs, regs->ar_ccv, regs->ar_fpsr); + printk("csd : %016lx ssd : %016lx\n", regs->ar_csd, regs->ar_ssd); printk("b0 : %016lx b6 : %016lx b7 : %016lx\n", regs->b0, regs->b6, regs->b7); printk("f6 : %05lx%016lx f7 : %05lx%016lx\n", regs->f6.u.bits[1], regs->f6.u.bits[0], @@ -110,6 +103,9 @@ show_regs (struct pt_regs *regs) printk("f8 : %05lx%016lx f9 : %05lx%016lx\n", regs->f8.u.bits[1], regs->f8.u.bits[0], regs->f9.u.bits[1], regs->f9.u.bits[0]); + printk("f10 : %05lx%016lx f11 : %05lx%016lx\n", + regs->f10.u.bits[1], regs->f10.u.bits[0], + regs->f11.u.bits[1], regs->f11.u.bits[0]); printk("r1 : %016lx r2 : %016lx r3 : %016lx\n", regs->r1, regs->r2, regs->r3); printk("r8 : %016lx r9 : %016lx r10 : %016lx\n", regs->r8, regs->r9, regs->r10); @@ -135,24 +131,22 @@ show_regs (struct pt_regs *regs) ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } else - show_stack(NULL); + show_stack(NULL, NULL); } void do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { -#ifdef CONFIG_FSYS if (fsys_mode(current, &scr->pt)) { /* defer signal-handling etc. until we return to privilege-level 0. */ if (!ia64_psr(&scr->pt)->lp) ia64_psr(&scr->pt)->lp = 1; return; } -#endif #ifdef CONFIG_PERFMON - if (current->thread.pfm_ovfl_block_reset) - pfm_ovfl_block_reset(); + if (current->thread.pfm_needs_checking) + pfm_handle_work(); #endif /* deal with pending signal delivery */ @@ -175,6 +169,8 @@ default_idle (void) void __attribute__((noreturn)) cpu_idle (void *unused) { + void (*mark_idle)(int) = ia64_mark_idle; + /* endless idle loop with no priority at all */ while (1) { void (*idle)(void) = pm_idle; @@ -187,15 +183,13 @@ cpu_idle (void *unused) #endif while (!need_resched()) { -#ifdef CONFIG_IA64_SGI_SN - snidle(); -#endif + if (mark_idle) + (*mark_idle)(1); (*idle)(); } -#ifdef CONFIG_IA64_SGI_SN - snidleoff(); -#endif + if (mark_idle) + (*mark_idle)(0); #ifdef CONFIG_SMP normal_xtp(); @@ -379,7 +373,7 @@ copy_thread (int nr, unsigned long clone_flags, # define THREAD_FLAGS_TO_SET 0 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); - p->thread.last_fph_cpu = -1; + ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */ #ifdef CONFIG_IA32_SUPPORT /* * If we're cloning an IA32 task then save the IA32 extra @@ -390,16 +384,8 @@ copy_thread (int nr, unsigned long clone_flags, #endif #ifdef CONFIG_PERFMON - /* - * reset notifiers and owner check (may not have a perfmon context) - */ - atomic_set(&p->thread.pfm_notifiers_check, 0); - atomic_set(&p->thread.pfm_owners_check, 0); - /* clear list of sampling buffer to free for new task */ - p->thread.pfm_smpl_buf_list = NULL; - if (current->thread.pfm_context) - retval = pfm_inherit(p, child_ptregs); + pfm_inherit(p, child_ptregs); #endif return retval; } @@ -472,6 +458,8 @@ do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void * dst[52] = pt->ar_pfs; /* UNW_AR_PFS is == to pt->cr_ifs for interrupt frames */ unw_get_ar(info, UNW_AR_LC, &dst[53]); unw_get_ar(info, UNW_AR_EC, &dst[54]); + unw_get_ar(info, UNW_AR_CSD, &dst[55]); + unw_get_ar(info, UNW_AR_SSD, &dst[56]); } void @@ -579,7 +567,8 @@ pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { struct task_struct *parent = current; - int result, tid; + int result; + pid_t tid; tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0); if (parent != current) { @@ -606,41 +595,9 @@ flush_thread (void) { /* drop floating-point and debug-register state if it exists: */ current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); - -#ifndef CONFIG_SMP - if (ia64_get_fpu_owner() == current) - ia64_set_fpu_owner(0); -#endif + ia64_drop_fpu(current); } -#ifdef CONFIG_PERFMON -/* - * by the time we get here, the task is detached from the tasklist. This is important - * because it means that no other tasks can ever find it as a notified task, therfore there - * is no race condition between this code and let's say a pfm_context_create(). - * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if this - * other task is in the middle of its own pfm_context_exit() because it would already be out of - * the task list. Note that this case is very unlikely between a direct child and its parents - * (if it is the notified process) because of the way the exit is notified via SIGCHLD. - */ - -void -release_thread (struct task_struct *task) -{ - if (task->thread.pfm_context) - pfm_context_exit(task); - - if (atomic_read(&task->thread.pfm_notifiers_check) > 0) - pfm_cleanup_notifiers(task); - - if (atomic_read(&task->thread.pfm_owners_check) > 0) - pfm_cleanup_owners(task); - - if (task->thread.pfm_smpl_buf_list) - pfm_cleanup_smpl_buf(task); -} -#endif - /* * Clean up state associated with current thread. This is called when * the thread calls exit(). @@ -648,14 +605,11 @@ release_thread (struct task_struct *task) void exit_thread (void) { -#ifndef CONFIG_SMP - if (ia64_get_fpu_owner() == current) - ia64_set_fpu_owner(0); -#endif + ia64_drop_fpu(current); #ifdef CONFIG_PERFMON /* if needed, stop monitoring and flush state to perfmon context */ - if (current->thread.pfm_context) - pfm_flush_regs(current); + if (current->thread.pfm_context) + pfm_exit_thread(current); /* free debug register resources */ if (current->thread.flags & IA64_THREAD_DBG_VALID) @@ -740,29 +694,3 @@ machine_power_off (void) pm_power_off(); machine_halt(); } - -void __init -init_task_struct_cache (void) -{ -} - -struct task_struct * -dup_task_struct(struct task_struct *orig) -{ - struct task_struct *tsk; - - tsk = (void *) __get_free_pages(GFP_KERNEL, KERNEL_STACK_SIZE_ORDER); - if (!tsk) - return NULL; - - memcpy(tsk, orig, sizeof(struct task_struct) + sizeof(struct thread_info)); - tsk->thread_info = (struct thread_info *) ((char *) tsk + IA64_TASK_SIZE); - atomic_set(&tsk->usage, 2); - return tsk; -} - -void -free_task_struct (struct task_struct *tsk) -{ - free_pages((unsigned long) tsk, KERNEL_STACK_SIZE_ORDER); -} diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index c8eedecd68d..b78a08624cd 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -200,14 +200,20 @@ ia64_decrement_ip (struct pt_regs *regs) */ static unsigned long get_rnat (struct pt_regs *pt, struct switch_stack *sw, - unsigned long *krbs, unsigned long *urnat_addr) + unsigned long *krbs, unsigned long *urnat_addr, unsigned long *urbs_end) { - unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0UL; + unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0, mask, m; unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; - long num_regs; + long num_regs, nbits; kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; + + if (urbs_end < urnat_addr) + nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_end); + else + nbits = 63; + mask = (1UL << nbits) - 1; /* * First, figure out which bit number slot 0 in user-land maps to in the kernel * rnat. Do this by figuring out how many register slots we're beyond the user's @@ -221,20 +227,26 @@ get_rnat (struct pt_regs *pt, struct switch_stack *sw, if (ubspstore + 63 > urnat_addr) { /* some bits need to be merged in from pt->ar_rnat */ - umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1); + umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1) & mask; urnat = (pt->ar_rnat & umask); + mask &= ~umask; + if (!mask) + return urnat; } - if (rnat0_kaddr >= kbsp) { + + m = mask << shift; + if (rnat0_kaddr >= kbsp) rnat0 = sw->ar_rnat; - } else if (rnat0_kaddr > krbs) { + else if (rnat0_kaddr > krbs) rnat0 = *rnat0_kaddr; - } - if (rnat1_kaddr >= kbsp) { + urnat |= (rnat0 & m) >> shift; + + m = mask >> (63 - shift); + if (rnat1_kaddr >= kbsp) rnat1 = sw->ar_rnat; - } else if (rnat1_kaddr > krbs) { + else if (rnat1_kaddr > krbs) rnat1 = *rnat1_kaddr; - } - urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & ~umask; + urnat |= (rnat1 & m) << (63 - shift); return urnat; } @@ -243,60 +255,58 @@ get_rnat (struct pt_regs *pt, struct switch_stack *sw, */ static void put_rnat (struct pt_regs *pt, struct switch_stack *sw, - unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat) + unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat, + unsigned long *urbs_end) { unsigned long rnat0 = 0, rnat1 = 0, *slot0_kaddr, umask = 0, mask, m; - unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift, slot, ndirty; + unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; long num_regs, nbits; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - nbits = ndirty % 63; - kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; + + if (urbs_end < urnat_addr) + nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_end); + else + nbits = 63; + mask = (1UL << nbits) - 1; + /* * First, figure out which bit number slot 0 in user-land maps to in the kernel * rnat. Do this by figuring out how many register slots we're beyond the user's * backingstore and then computing the equivalent address in kernel space. */ - num_regs = (long) ia64_rse_num_regs(ubspstore, urnat_addr + 1); + num_regs = ia64_rse_num_regs(ubspstore, urnat_addr + 1); slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); shift = ia64_rse_slot_num(slot0_kaddr); rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr); rnat0_kaddr = rnat1_kaddr - 64; -printk("%s: ubspstore=%p urnat_addr=%p\n", __FUNCTION__, ubspstore, urnat_addr); if (ubspstore + 63 > urnat_addr) { /* some bits need to be place in pt->ar_rnat: */ - slot = ia64_rse_slot_num(ubspstore); - umask = ((1UL << slot) - 1); + umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1) & mask; pt->ar_rnat = (pt->ar_rnat & ~umask) | (urnat & umask); - nbits -= slot; - if (nbits <= 0) + mask &= ~umask; + if (!mask) return; } - mask = (1UL << nbits) - 1; /* * Note: Section 11.1 of the EAS guarantees that bit 63 of an * rnat slot is ignored. so we don't have to clear it here. */ rnat0 = (urnat << shift); m = mask << shift; -printk("%s: rnat0=%016lx, m=%016lx, rnat0_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat0, m, rnat0_kaddr, kbsp); - if (rnat0_kaddr >= kbsp) { + if (rnat0_kaddr >= kbsp) sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat0 & m); - } else if (rnat0_kaddr > krbs) { + else if (rnat0_kaddr > krbs) *rnat0_kaddr = ((*rnat0_kaddr & ~m) | (rnat0 & m)); - } rnat1 = (urnat >> (63 - shift)); m = mask >> (63 - shift); -printk("%s: rnat1=%016lx, m=%016lx, rnat1_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat1, m, rnat1_kaddr, kbsp); - if (rnat1_kaddr >= kbsp) { + if (rnat1_kaddr >= kbsp) sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat1 & m); - } else if (rnat1_kaddr > krbs) { + else if (rnat1_kaddr > krbs) *rnat1_kaddr = ((*rnat1_kaddr & ~m) | (rnat1 & m)); - } } /* @@ -329,7 +339,7 @@ ia64_peek (struct task_struct *child, struct switch_stack *child_stack, unsigned * read the corresponding bits in the kernel RBS. */ rnat_addr = ia64_rse_rnat_addr(laddr); - ret = get_rnat(child_regs, child_stack, krbs, rnat_addr); + ret = get_rnat(child_regs, child_stack, krbs, rnat_addr, urbs_end); if (laddr == rnat_addr) { /* return NaT collection word itself */ @@ -380,7 +390,7 @@ ia64_poke (struct task_struct *child, struct switch_stack *child_stack, unsigned * => write the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) - put_rnat(child_regs, child_stack, krbs, laddr, val); + put_rnat(child_regs, child_stack, krbs, laddr, val, urbs_end); else { if (laddr < urbs_end) { regnum = ia64_rse_num_regs(bspstore, laddr); @@ -588,17 +598,11 @@ inline void ia64_flush_fph (struct task_struct *task) { struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); -#ifdef CONFIG_SMP - struct task_struct *fpu_owner = current; -#else - struct task_struct *fpu_owner = ia64_get_fpu_owner(); -#endif - if (task == fpu_owner && psr->mfh) { + if (ia64_is_local_fpu_owner(task) && psr->mfh) { psr->mfh = 0; - ia64_save_fpu(&task->thread.fph[0]); task->thread.flags |= IA64_THREAD_FPH_VALID; - task->thread.last_fph_cpu = smp_processor_id(); + ia64_save_fpu(&task->thread.fph[0]); } } @@ -618,11 +622,9 @@ ia64_sync_fph (struct task_struct *task) ia64_flush_fph(task); if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) { task->thread.flags |= IA64_THREAD_FPH_VALID; - task->thread.last_fph_cpu = -1; /* force reload */ memset(&task->thread.fph, 0, sizeof(task->thread.fph)); } - if (ia64_get_fpu_owner() == task) - ia64_set_fpu_owner(0); + ia64_drop_fpu(task); psr->dfh = 1; } @@ -667,9 +669,13 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data else ia64_flush_fph(child); ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); - } else if (addr >= PT_F10 && addr < PT_F15 + 16) { + } else if ((addr >= PT_F10) && (addr < PT_F11 + 16)) { + /* scratch registers untouched by kernel (saved in pt_regs) */ + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, f10) + addr - PT_F10); + } else if (addr >= PT_F12 && addr < PT_F15 + 16) { /* scratch registers untouched by kernel (saved in switch_stack) */ - ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); + ptr = (unsigned long *) ((long) sw + (addr - PT_NAT_BITS - 32)); } else if (addr < PT_AR_LC + 8) { /* preserved state: */ unsigned long nat_bits, scratch_unat, dummy = 0; @@ -805,22 +811,75 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data else return ia64_peek(child, sw, urbs_end, rnat_addr, data); - case PT_R1: case PT_R2: case PT_R3: + case PT_R1: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r1)); + break; + + case PT_R2: case PT_R3: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r2) + addr - PT_R2); + break; case PT_R8: case PT_R9: case PT_R10: case PT_R11: - case PT_R12: case PT_R13: case PT_R14: case PT_R15: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r8)+ addr - PT_R8); + break; + case PT_R12: case PT_R13: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r12)+ addr - PT_R12); + break; + case PT_R14: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r14)); + break; + case PT_R15: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r15)); + break; case PT_R16: case PT_R17: case PT_R18: case PT_R19: case PT_R20: case PT_R21: case PT_R22: case PT_R23: case PT_R24: case PT_R25: case PT_R26: case PT_R27: case PT_R28: case PT_R29: case PT_R30: case PT_R31: - case PT_B0: case PT_B6: case PT_B7: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r16) + addr - PT_R16); + break; + case PT_B0: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b0)); + break; + case PT_B6: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b6)); + break; + case PT_B7: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b7)); + break; case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, f6) + addr - PT_F6); + break; case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: - case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: - /* scratch register */ - ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR); + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, ar_bspstore)); + break; + case PT_AR_RSC: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_rsc)); + break; + case PT_AR_UNAT: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_unat)); + break; + case PT_AR_PFS: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_pfs)); break; + case PT_AR_CCV: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_ccv)); + break; + case PT_AR_FPSR: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_fpsr)); + break; + case PT_CR_IIP: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, cr_iip)); + break; + case PT_PR: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, pr)); + break; + /* scratch register */ default: /* disallow accessing anything else... */ @@ -828,6 +887,9 @@ access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data addr); return -1; } + } else if (addr <= PT_AR_SSD) { + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, ar_csd) + addr - PT_AR_CSD); } else { /* access debug registers */ @@ -934,7 +996,8 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr1-gr3 */ - retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long) * 3); + retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[2], &pt->r2, sizeof(long) *2); /* gr4-gr7 */ @@ -948,7 +1011,9 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr12-gr15 */ - retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 4); + retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 2); + retval |= __copy_to_user(&ppr->gr[14], &pt->r14, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[15], &pt->r15, sizeof(long)); /* gr16-gr31 */ @@ -976,13 +1041,13 @@ ptrace_getregs (struct task_struct *child, struct pt_all_user_regs *ppr) retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); } - /* fr6-fr9 */ + /* fr6-fr11 */ - retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 4); + retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 6); - /* fp scratch regs(10-15) */ + /* fp scratch regs(12-15) */ - retval |= __copy_to_user(&ppr->fr[10], &sw->f10, sizeof(struct ia64_fpreg) * 6); + retval |= __copy_to_user(&ppr->fr[12], &sw->f12, sizeof(struct ia64_fpreg) * 4); /* fr16-fr31 */ @@ -1059,7 +1124,8 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr1-gr3 */ - retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long) * 3); + retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long)); + retval |= __copy_from_user(&pt->r2, &ppr->gr[2], sizeof(long) * 2); /* gr4-gr7 */ @@ -1077,7 +1143,9 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) /* gr12-gr15 */ - retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 4); + retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 2); + retval |= __copy_from_user(&pt->r14, &ppr->gr[14], sizeof(long)); + retval |= __copy_from_user(&pt->r15, &ppr->gr[15], sizeof(long)); /* gr16-gr31 */ @@ -1105,13 +1173,13 @@ ptrace_setregs (struct task_struct *child, struct pt_all_user_regs *ppr) retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); } - /* fr6-fr9 */ + /* fr6-fr11 */ - retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 4); + retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 6); - /* fp scratch regs(10-15) */ + /* fp scratch regs(12-15) */ - retval |= __copy_from_user(&sw->f10, &ppr->fr[10], sizeof(ppr->fr[10]) * 6); + retval |= __copy_from_user(&sw->f12, &ppr->fr[12], sizeof(ppr->fr[12]) * 4); /* fr16-fr31 */ diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 18eba8d44b9..02fa6ce8526 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -34,14 +34,16 @@ #include #include +#include +#include #include +#include #include -#include #include #include -#include -#include #include +#include +#include #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) # error "struct cpuinfo_ia64 too big!" @@ -66,6 +68,17 @@ unsigned int num_io_spaces; unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ +/* + * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This + * mask specifies a mask of address bits that must be 0 in order for two buffers to be + * mergeable by the I/O MMU (i.e., the end address of the first buffer and the start + * address of the second buffer must be aligned to (merge_mask+1) in order to be + * mergeable). By default, we assume there is no I/O MMU which can merge physically + * discontiguous buffers, so we set the merge_mask to ~0UL, which corresponds to a iommu + * page-size of 2^64. + */ +unsigned long ia64_max_iommu_merge_mask = ~0UL; + #define COMMAND_LINE_SIZE 512 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ @@ -102,11 +115,11 @@ static unsigned long bootmap_start; /* physical address where the bootmem map is static int find_max_pfn (unsigned long start, unsigned long end, void *arg) { - unsigned long *max_pfn = arg, pfn; + unsigned long *max_pfnp = arg, pfn; pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT; - if (pfn > *max_pfn) - *max_pfn = pfn; + if (pfn > *max_pfnp) + *max_pfnp = pfn; return 0; } @@ -265,9 +278,8 @@ sort_regions (struct rsvd_region *rsvd_region, int max) static void find_memory (void) { -# define KERNEL_END ((unsigned long) &_end) +# define KERNEL_END (&_end) unsigned long bootmap_size; - unsigned long max_pfn; int n = 0; /* @@ -286,8 +298,8 @@ find_memory (void) + strlen(__va(ia64_boot_param->command_line)) + 1); n++; - rsvd_region[n].start = KERNEL_START; - rsvd_region[n].end = KERNEL_END; + rsvd_region[n].start = (unsigned long) ia64_imva((void *)KERNEL_START); + rsvd_region[n].end = (unsigned long) ia64_imva(KERNEL_END); n++; #ifdef CONFIG_BLK_DEV_INITRD @@ -350,11 +362,14 @@ find_memory (void) void __init setup_arch (char **cmdline_p) { + extern unsigned long *__start___vtop_patchlist[], *__end____vtop_patchlist[]; extern unsigned long ia64_iobase; unsigned long phys_iobase; unw_init(); + ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end____vtop_patchlist); + *cmdline_p = __va(ia64_boot_param->command_line); strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); @@ -459,8 +474,6 @@ setup_arch (char **cmdline_p) platform_setup(cmdline_p); paging_init(); - - unw_create_gate_table(); } /* @@ -735,6 +748,8 @@ cpu_init (void) /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); + ia64_set_kr(IA64_KR_FPU_OWNER, 0); + /* * Initialize default control register to defer all speculative faults. The * kernel MUST NOT depend on a particular setting of these bits (in other words, @@ -745,20 +760,15 @@ cpu_init (void) */ ia64_set_dcr( IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC); -#ifndef CONFIG_SMP - ia64_set_fpu_owner(0); -#endif - atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if (current->mm) BUG(); - ia64_mmu_init(cpu_data); + ia64_mmu_init(ia64_imva(cpu_data)); #ifdef CONFIG_IA32_SUPPORT - /* initialize global ia32 state - CR0 and CR4 */ - asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); + ia32_cpu_init(); #endif /* disable all local interrupt sources: */ @@ -800,27 +810,9 @@ cpu_init (void) void check_bugs (void) { - extern int __start___mckinley_e9_bundles[]; - extern int __end___mckinley_e9_bundles[]; - u64 *bundle; - int *wp; + extern char __start___mckinley_e9_bundles[]; + extern char __end___mckinley_e9_bundles[]; - if (local_cpu_data->family == 0x1f && local_cpu_data->model == 0) - printk(KERN_INFO "check_bugs: leaving McKinley Errata 9 workaround enabled\n"); - else { - printk(KERN_INFO "check_bugs: McKinley Errata 9 workaround not needed; " - "disabling it\n"); - for (wp = __start___mckinley_e9_bundles; wp < __end___mckinley_e9_bundles; ++wp) { - bundle = (u64 *) ((char *) wp + *wp); - /* install a bundle of NOPs: */ - bundle[0] = 0x0000000100000000; - bundle[1] = 0x0004000000000200; - ia64_fc(bundle); - } - ia64_insn_group_barrier(); - ia64_sync_i(); - ia64_insn_group_barrier(); - ia64_srlz_i(); - ia64_insn_group_barrier(); - } + ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles, + (unsigned long) __end___mckinley_e9_bundles); } diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 3b55d7fd3f8..21f97a864a3 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -108,25 +108,22 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) long err; /* restore scratch that always needs gets updated during signal delivery: */ - err = __get_user(flags, &sc->sc_flags); - + err = __get_user(flags, &sc->sc_flags); err |= __get_user(nat, &sc->sc_nat); err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ err |= __get_user(cfm, &sc->sc_cfm); err |= __get_user(um, &sc->sc_um); /* user mask */ err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); - err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); err |= __get_user(scr->pt.pr, &sc->sc_pr); /* predicates */ err |= __get_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ err |= __get_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ - err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ - err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ + err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 8); /* r1 */ err |= __copy_from_user(&scr->pt.r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ - err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ - err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 2*8); /* r12-r13 */ + err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8); /* r15 */ scr->pt.cr_ifs = cfm | (1UL << 63); @@ -137,17 +134,27 @@ restore_sigcontext (struct sigcontext *sc, struct sigscratch *scr) scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat); + if (!(flags & IA64_SC_FLAG_IN_SYSCALL)) { + /* Restore most scratch-state only when not in syscall. */ + err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + err |= __get_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ + err |= __copy_from_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_from_user(&scr->pt.r2, &sc->sc_gr[2], 2*8); /* r2-r3 */ + err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + } + if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) { struct ia64_psr *psr = ia64_psr(&scr->pt); __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); psr->mfh = 0; /* drop signal handler's fph contents... */ if (psr->dfh) - current->thread.last_fph_cpu = -1; + ia64_drop_fpu(current); else { + /* We already own the local fph, otherwise psr->dfh wouldn't be 0. */ __ia64_load_fpu(current->thread.fph); - ia64_set_fpu_owner(current); - current->thread.last_fph_cpu = smp_processor_id(); + ia64_set_local_fpu_owner(current); } } return err; @@ -166,11 +173,10 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) int err; /* - * If you change siginfo_t structure, please be sure - * this code is fixed accordingly. It should never - * copy any pad contained in the structure to avoid - * security leaks, but must copy the generic 3 ints - * plus the relevant union member. + * If you change siginfo_t structure, please be sure this code is fixed + * accordingly. It should never copy any pad contained in the structure + * to avoid security leaks, but must copy the generic 3 ints plus the + * relevant union member. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); @@ -183,24 +189,15 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_imm, &to->si_imm); break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - case __SI_PROF >> 16: - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_pid, &to->si_pid); - if (from->si_code == PROF_OVFL) { - err |= __put_user(from->si_pfm_ovfl[0], &to->si_pfm_ovfl[0]); - err |= __put_user(from->si_pfm_ovfl[1], &to->si_pfm_ovfl[1]); - err |= __put_user(from->si_pfm_ovfl[2], &to->si_pfm_ovfl[2]); - err |= __put_user(from->si_pfm_ovfl[3], &to->si_pfm_ovfl[3]); - } case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_value, &to->si_value); break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); default: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); @@ -237,10 +234,6 @@ copy_siginfo_from_user (siginfo_t *to, siginfo_t *from) to->si_code |= __SI_POLL; break; - case SIGPROF: - to->si_code |= __SI_PROF; - break; - default: break; } @@ -352,27 +345,40 @@ setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr) nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); err = __put_user(flags, &sc->sc_flags); - err |= __put_user(nat, &sc->sc_nat); err |= PUT_SIGSET(mask, &sc->sc_mask); err |= __put_user(cfm, &sc->sc_cfm); err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um); err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); - err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); err |= __put_user(scr->pt.ar_unat, &sc->sc_ar_unat); /* ar.unat */ err |= __put_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */ err |= __put_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); err |= __put_user(scr->pt.pr, &sc->sc_pr); /* predicates */ err |= __put_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ err |= __put_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ - err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ - - err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 3*8); /* r1-r3 */ + err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 8); /* r1 */ err |= __copy_to_user(&sc->sc_gr[8], &scr->pt.r8, 4*8); /* r8-r11 */ - err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 4*8); /* r12-r15 */ - err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ - + err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 2*8); /* r12-r13 */ + err |= __copy_to_user(&sc->sc_gr[15], &scr->pt.r15, 8); /* r15 */ err |= __put_user(scr->pt.cr_iip + ia64_psr(&scr->pt)->ri, &sc->sc_ip); + + if (flags & IA64_SC_FLAG_IN_SYSCALL) { + /* Clear scratch registers if the signal interrupted a system call. */ + err |= __put_user(0, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __put_user(0, &sc->sc_br[7]); /* b7 */ + err |= __put_user(0, &sc->sc_gr[14]); /* r14 */ + err |= __clear_user(&sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __clear_user(&sc->sc_gr[2], 2*8); /* r2-r3 */ + err |= __clear_user(&sc->sc_gr[16], 16*8); /* r16-r31 */ + } else { + /* Copy scratch regs to sigcontext if the signal didn't interrupt a syscall. */ + err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + err |= __put_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ + err |= __copy_to_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_to_user(&sc->sc_gr[2], &scr->pt.r2, 2*8); /* r2-r3 */ + err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ + } return err; } @@ -389,14 +395,14 @@ static long setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct sigscratch *scr) { - extern char ia64_sigtramp[], __start_gate_section[]; + extern char __kernel_sigtramp[]; unsigned long tramp_addr, new_rbs = 0; struct sigframe *frame; struct siginfo si; long err; frame = (void *) scr->pt.r12; - tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section); + tramp_addr = (unsigned long) __kernel_sigtramp; if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) { frame = (void *) ((current->sas_ss_sp + current->sas_ss_size) & ~(STACK_ALIGN - 1)); @@ -406,7 +412,7 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, * in the kernel, register stack is switched in the signal trampoline). */ if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) - new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); + new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); } frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); @@ -451,8 +457,8 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */ #if DEBUG_SIG - printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", - current->comm, current->pid, sig, scr->pt.r12, scr->pt.cr_iip, scr->pt.r3); + printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%p\n", + current->comm, current->pid, sig, scr->pt.r12, frame->sc.sc_ip, frame->handler); #endif return 1; diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 8c183cdf894..d04533c90df 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -352,10 +352,10 @@ static struct task_struct * __init fork_by_hand (void) { /* - * don't care about the eip and regs settings since we'll never reschedule the + * Don't care about the IP and regs settings since we'll never reschedule the * forked task. */ - return do_fork(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL); + return copy_process(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL); } static int __init @@ -370,6 +370,7 @@ do_boot_cpu (int sapicid, int cpu) idle = fork_by_hand(); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); + wake_up_forked_process(idle); /* * We remove it from the pidhash and the runqueue @@ -449,7 +450,7 @@ smp_build_cpu_map (void) for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) { sapicid = smp_boot_data.cpu_phys_id[i]; - if (sapicid == -1 || sapicid == boot_cpu_id) + if (sapicid == boot_cpu_id) continue; phys_cpu_present_map |= (1 << cpu); ia64_cpu_to_sapicid[cpu] = sapicid; @@ -598,7 +599,7 @@ init_smp_config(void) /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, - __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0); + ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index d69684babc5..6de52294bd8 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -2,7 +2,7 @@ * This file contains various system calls that have different calling * conventions on different platforms. * - * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co + * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co * David Mosberger-Tang */ #include diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 1c358ee1107..4fd11063955 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,10 +26,11 @@ #include extern unsigned long wall_jiffies; -extern unsigned long last_nsec_offset; u64 jiffies_64 = INITIAL_JIFFIES; +#define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */ + #ifdef CONFIG_IA64_DEBUG_IRQ unsigned long last_cli_ip; @@ -59,19 +61,32 @@ do_profile (unsigned long ip) atomic_inc((atomic_t *) &prof_buffer[ip]); } +static void +itc_reset (void) +{ +} + +/* + * Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or + * larger than NSEC_PER_SEC. + */ +static void +itc_update (long delta_nsec) +{ +} + /* * Return the number of nano-seconds that elapsed since the last update to jiffy. The * xtime_lock must be at least read-locked when calling this routine. */ -static inline unsigned long -gettimeoffset (void) +unsigned long +itc_get_offset (void) { unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; unsigned long now, last_tick; -# define time_keeper_id 0 /* smp_processor_id() of time-keeper */ - last_tick = (cpu_data(time_keeper_id)->itm_next - - (lost + 1)*cpu_data(time_keeper_id)->itm_delta); + last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next + - (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta); now = ia64_get_itc(); if (unlikely((long) (now - last_tick) < 0)) { @@ -83,6 +98,12 @@ gettimeoffset (void) return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; } +static struct time_interpolator itc_interpolator = { + .get_offset = itc_get_offset, + .update = itc_update, + .reset = itc_reset +}; + static inline void set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) { @@ -115,7 +136,7 @@ do_settimeofday (struct timespec *tv) * Discover what correction gettimeofday would have done, and then undo * it! */ - nsec -= gettimeoffset(); + nsec -= time_interpolator_get_offset(); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); @@ -127,6 +148,7 @@ do_settimeofday (struct timespec *tv) time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; + time_interpolator_reset(); } write_sequnlock_irq(&xtime_lock); clock_was_set(); @@ -138,14 +160,11 @@ do_gettimeofday (struct timeval *tv) { unsigned long seq, nsec, usec, sec, old, offset; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - while (1) { seq = read_seqbegin(&xtime_lock); { old = last_nsec_offset; - offset = gettimeoffset(); + offset = time_interpolator_get_offset(); sec = xtime.tv_sec; nsec = xtime.tv_nsec; } @@ -221,7 +240,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) #endif new_itm += local_cpu_data->itm_delta; - if (smp_processor_id() == 0) { + if (smp_processor_id() == TIME_KEEPER_ID) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on @@ -283,16 +302,17 @@ ia64_cpu_local_tick (void) void __init ia64_init_itm (void) { - unsigned long platform_base_freq, itc_freq, drift; + unsigned long platform_base_freq, itc_freq; struct pal_freq_ratio itc_ratio, proc_ratio; - long status; + long status, platform_base_drift, itc_drift; /* * According to SAL v2.6, we need to use a SAL call to determine the platform base * frequency and then a PAL call to determine the frequency ratio between the ITC * and the base frequency. */ - status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift); + status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, + &platform_base_freq, &platform_base_drift); if (status != 0) { printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); } else { @@ -305,6 +325,7 @@ ia64_init_itm (void) printk(KERN_ERR "SAL/PAL failed to obtain frequency info---inventing reasonable values\n"); platform_base_freq = 100000000; + platform_base_drift = -1; /* no drift info */ itc_ratio.num = 3; itc_ratio.den = 1; } @@ -312,6 +333,7 @@ ia64_init_itm (void) printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n", platform_base_freq); platform_base_freq = 75000000; + platform_base_drift = -1; } if (!proc_ratio.den) proc_ratio.den = 1; /* avoid division by zero */ @@ -319,11 +341,17 @@ ia64_init_itm (void) itc_ratio.den = 1; /* avoid division by zero */ itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + if (platform_base_drift != -1) + itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den; + else + itc_drift = -1; + local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " - "ITC freq=%lu.%03luMHz\n", smp_processor_id(), + "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, - itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); + itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000, + itc_drift); local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; local_cpu_data->itc_freq = itc_freq; @@ -331,6 +359,12 @@ ia64_init_itm (void) local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<itc_freq; + itc_interpolator.drift = itc_drift; + register_time_interpolator(&itc_interpolator); + } + /* Setup the CPU local timer tick */ ia64_cpu_local_tick(); } diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index f17048bb088..70df2828e83 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -247,16 +247,17 @@ disabled_fph_fault (struct pt_regs *regs) psr->dfh = 0; #ifndef CONFIG_SMP { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); + struct task_struct *fpu_owner + = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); - if (fpu_owner == current) + if (ia64_is_local_fpu_owner(current)) return; if (fpu_owner) ia64_flush_fph(fpu_owner); } #endif /* !CONFIG_SMP */ - ia64_set_fpu_owner(current); + ia64_set_local_fpu_owner(current); if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { __ia64_load_fpu(current->thread.fph); psr->mfh = 0; @@ -274,7 +275,6 @@ static inline int fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, struct pt_regs *regs) { - struct ia64_fpreg f6_11[6]; fp_state_t fp_state; fpswa_ret_t ret; @@ -289,11 +289,8 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long * pointer to point to these registers. */ fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ - f6_11[0] = regs->f6; f6_11[1] = regs->f7; - f6_11[2] = regs->f8; f6_11[3] = regs->f9; - __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4])); - __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5])); - fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11; + + fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, @@ -309,10 +306,7 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long (unsigned long *) ipsr, (unsigned long *) fpsr, (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); - regs->f6 = f6_11[0]; regs->f7 = f6_11[1]; - regs->f8 = f6_11[2]; regs->f9 = f6_11[3]; - __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_11[4])); - __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_11[5])); + return ret.status; } @@ -336,8 +330,9 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; - if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { + if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { last_time = jiffies; + ++fpu_swa_count; printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr); } @@ -533,9 +528,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, case 29: /* Debug */ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ -#ifdef CONFIG_FSYS if (fsys_mode(current, regs)) { - extern char syscall_via_break[], __start_gate_section[]; + extern char __kernel_syscall_via_break[]; /* * Got a trap in fsys-mode: Taken Branch Trap and Single Step trap * need special handling; Debug trap is not supposed to happen. @@ -546,12 +540,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, return; } /* re-do the system call via break 0x100000: */ - regs->cr_iip = GATE_ADDR + (syscall_via_break - __start_gate_section); + regs->cr_iip = (unsigned long) __kernel_syscall_via_break; ia64_psr(regs)->ri = 0; ia64_psr(regs)->cpl = 3; return; } -#endif switch (vector) { case 29: siginfo.si_code = TRAP_HWBKPT; diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 4436fb8c336..c7f8012eb75 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -218,8 +218,9 @@ static u16 fr_info[32]={ RSW(f2), RSW(f3), RSW(f4), RSW(f5), RPT(f6), RPT(f7), RPT(f8), RPT(f9), + RPT(f10), RPT(f11), - RSW(f10), RSW(f11), RSW(f12), RSW(f13), RSW(f14), + RSW(f12), RSW(f13), RSW(f14), RSW(f15), RSW(f16), RSW(f17), RSW(f18), RSW(f19), RSW(f20), RSW(f21), RSW(f22), RSW(f23), RSW(f24), RSW(f25), RSW(f26), RSW(f27), RSW(f28), RSW(f29), diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 9f1588149c3..428c481f2c9 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -1,6 +1,8 @@ /* * Copyright (C) 1999-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 2003 Fenghua Yu + * - Change pt_regs_off() to make it less dependant on pt_regs structure. */ /* * This file implements call frame unwind support for the Linux @@ -25,6 +27,7 @@ * acquired, then the read-write lock must be acquired first. */ #include +#include #include #include #include @@ -76,7 +79,7 @@ # define STAT(x...) #endif -#define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) +#define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) @@ -84,8 +87,6 @@ typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; -#define struct_offset(str,fld) ((char *)&((str *)NULL)->fld - (char *) 0) - static struct { spinlock_t lock; /* spinlock for unwind data */ @@ -104,6 +105,8 @@ static struct { /* index into unw_frame_info for preserved register i */ unsigned short preg_index[UNW_NUM_REGS]; + short pt_regs_offsets[32]; + /* unwind table for the kernel: */ struct unw_table kernel_table; @@ -153,47 +156,78 @@ static struct { UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR }, .preg_index = { - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ - struct_offset(struct unw_frame_info, bsp_loc)/8, - struct_offset(struct unw_frame_info, bspstore_loc)/8, - struct_offset(struct unw_frame_info, pfs_loc)/8, - struct_offset(struct unw_frame_info, rnat_loc)/8, - struct_offset(struct unw_frame_info, psp)/8, - struct_offset(struct unw_frame_info, rp_loc)/8, - struct_offset(struct unw_frame_info, r4)/8, - struct_offset(struct unw_frame_info, r5)/8, - struct_offset(struct unw_frame_info, r6)/8, - struct_offset(struct unw_frame_info, r7)/8, - struct_offset(struct unw_frame_info, unat_loc)/8, - struct_offset(struct unw_frame_info, pr_loc)/8, - struct_offset(struct unw_frame_info, lc_loc)/8, - struct_offset(struct unw_frame_info, fpsr_loc)/8, - struct_offset(struct unw_frame_info, b1_loc)/8, - struct_offset(struct unw_frame_info, b2_loc)/8, - struct_offset(struct unw_frame_info, b3_loc)/8, - struct_offset(struct unw_frame_info, b4_loc)/8, - struct_offset(struct unw_frame_info, b5_loc)/8, - struct_offset(struct unw_frame_info, f2_loc)/8, - struct_offset(struct unw_frame_info, f3_loc)/8, - struct_offset(struct unw_frame_info, f4_loc)/8, - struct_offset(struct unw_frame_info, f5_loc)/8, - struct_offset(struct unw_frame_info, fr_loc[16 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[17 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[18 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[19 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[20 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[21 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[22 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[23 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[24 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[25 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[26 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[27 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[28 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[29 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8, + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ + offsetof(struct unw_frame_info, bsp_loc)/8, + offsetof(struct unw_frame_info, bspstore_loc)/8, + offsetof(struct unw_frame_info, pfs_loc)/8, + offsetof(struct unw_frame_info, rnat_loc)/8, + offsetof(struct unw_frame_info, psp)/8, + offsetof(struct unw_frame_info, rp_loc)/8, + offsetof(struct unw_frame_info, r4)/8, + offsetof(struct unw_frame_info, r5)/8, + offsetof(struct unw_frame_info, r6)/8, + offsetof(struct unw_frame_info, r7)/8, + offsetof(struct unw_frame_info, unat_loc)/8, + offsetof(struct unw_frame_info, pr_loc)/8, + offsetof(struct unw_frame_info, lc_loc)/8, + offsetof(struct unw_frame_info, fpsr_loc)/8, + offsetof(struct unw_frame_info, b1_loc)/8, + offsetof(struct unw_frame_info, b2_loc)/8, + offsetof(struct unw_frame_info, b3_loc)/8, + offsetof(struct unw_frame_info, b4_loc)/8, + offsetof(struct unw_frame_info, b5_loc)/8, + offsetof(struct unw_frame_info, f2_loc)/8, + offsetof(struct unw_frame_info, f3_loc)/8, + offsetof(struct unw_frame_info, f4_loc)/8, + offsetof(struct unw_frame_info, f5_loc)/8, + offsetof(struct unw_frame_info, fr_loc[16 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[17 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[18 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[19 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[20 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[21 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[22 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[23 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[24 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[25 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[26 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[27 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[28 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[29 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[30 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[31 - 16])/8, + }, + .pt_regs_offsets = { + [0] = -1, + offsetof(struct pt_regs, r1), + offsetof(struct pt_regs, r2), + offsetof(struct pt_regs, r3), + [4] = -1, [5] = -1, [6] = -1, [7] = -1, + offsetof(struct pt_regs, r8), + offsetof(struct pt_regs, r9), + offsetof(struct pt_regs, r10), + offsetof(struct pt_regs, r11), + offsetof(struct pt_regs, r12), + offsetof(struct pt_regs, r13), + offsetof(struct pt_regs, r14), + offsetof(struct pt_regs, r15), + offsetof(struct pt_regs, r16), + offsetof(struct pt_regs, r17), + offsetof(struct pt_regs, r18), + offsetof(struct pt_regs, r19), + offsetof(struct pt_regs, r20), + offsetof(struct pt_regs, r21), + offsetof(struct pt_regs, r22), + offsetof(struct pt_regs, r23), + offsetof(struct pt_regs, r24), + offsetof(struct pt_regs, r25), + offsetof(struct pt_regs, r26), + offsetof(struct pt_regs, r27), + offsetof(struct pt_regs, r28), + offsetof(struct pt_regs, r29), + offsetof(struct pt_regs, r30), + offsetof(struct pt_regs, r31), }, .hash = { [0 ... UNW_HASH_SIZE - 1] = -1 }, #ifdef UNW_DEBUG @@ -209,7 +243,6 @@ static struct { #endif }; - /* Unwind accessors. */ /* @@ -218,19 +251,16 @@ static struct { static inline unsigned long pt_regs_off (unsigned long reg) { - unsigned long off =0; + short off = -1; - if (reg >= 1 && reg <= 3) - off = struct_offset(struct pt_regs, r1) + 8*(reg - 1); - else if (reg <= 11) - off = struct_offset(struct pt_regs, r8) + 8*(reg - 8); - else if (reg <= 15) - off = struct_offset(struct pt_regs, r12) + 8*(reg - 12); - else if (reg <= 31) - off = struct_offset(struct pt_regs, r16) + 8*(reg - 16); - else + if (reg < ARRAY_SIZE(unw.pt_regs_offsets)) + off = unw.pt_regs_offsets[reg]; + + if (off < 0) { UNW_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg); - return off; + off = 0; + } + return (unsigned long) off; } static inline struct pt_regs * @@ -239,7 +269,10 @@ get_scratch_regs (struct unw_frame_info *info) if (!info->pt) { /* This should not happen with valid unwind info. */ UNW_DPRINT(0, "unwind.%s: bad unwind info: resetting info->pt\n", __FUNCTION__); - info->pt = info->sp - 16; + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + info->pt = (unsigned long) ((struct pt_regs *) info->psp - 1); + else + info->pt = info->sp - 16; } UNW_DPRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", __FUNCTION__, info->sp, info->pt); return (struct pt_regs *) info->pt; @@ -371,12 +404,11 @@ unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int unsigned long *addr; struct pt_regs *pt; - pt = get_scratch_regs(info); switch (regnum) { /* scratch: */ - case 0: addr = &pt->b0; break; - case 6: addr = &pt->b6; break; - case 7: addr = &pt->b7; break; + case 0: pt = get_scratch_regs(info); addr = &pt->b0; break; + case 6: pt = get_scratch_regs(info); addr = &pt->b6; break; + case 7: pt = get_scratch_regs(info); addr = &pt->b7; break; /* preserved: */ case 1: case 2: case 3: case 4: case 5: @@ -409,17 +441,17 @@ unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, return -1; } - pt = get_scratch_regs(info); - if (regnum <= 5) { addr = *(&info->f2_loc + (regnum - 2)); if (!addr) addr = &info->sw->f2 + (regnum - 2); } else if (regnum <= 15) { - if (regnum <= 9) + if (regnum <= 11) { + pt = get_scratch_regs(info); addr = &pt->f6 + (regnum - 6); + } else - addr = &info->sw->f10 + (regnum - 10); + addr = &info->sw->f12 + (regnum - 12); } else if (regnum <= 31) { addr = info->fr_loc[regnum - 16]; if (!addr) @@ -447,7 +479,6 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int unsigned long *addr; struct pt_regs *pt; - pt = get_scratch_regs(info); switch (regnum) { case UNW_AR_BSP: addr = info->bsp_loc; @@ -502,13 +533,25 @@ unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int break; case UNW_AR_RSC: + pt = get_scratch_regs(info); addr = &pt->ar_rsc; break; case UNW_AR_CCV: + pt = get_scratch_regs(info); addr = &pt->ar_ccv; break; + case UNW_AR_CSD: + pt = get_scratch_regs(info); + addr = &pt->ar_csd; + break; + + case UNW_AR_SSD: + pt = get_scratch_regs(info); + addr = &pt->ar_ssd; + break; + default: UNW_DPRINT(0, "unwind.%s: trying to access non-existent ar%u\n", __FUNCTION__, regnum); @@ -782,7 +825,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave static inline void desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) { - if (abi == 0 && context == 'i') { + if (abi == 3 && context == 'i') { sr->flags |= UNW_FLAG_INTERRUPT_FRAME; UNW_DPRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__); } @@ -1376,8 +1419,8 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; else { opc = UNW_INSN_MOVE_SCRATCH; - if (rval <= 9) - val = struct_offset(struct pt_regs, f6) + 16*(rval - 6); + if (rval <= 11) + val = offsetof(struct pt_regs, f6) + 16*(rval - 6); else UNW_DPRINT(0, "unwind.%s: kernel may not touch f%lu\n", __FUNCTION__, rval); @@ -1390,11 +1433,11 @@ compile_reg (struct unw_state_record *sr, int i, struct unw_script *script) else { opc = UNW_INSN_MOVE_SCRATCH; if (rval == 0) - val = struct_offset(struct pt_regs, b0); + val = offsetof(struct pt_regs, b0); else if (rval == 6) - val = struct_offset(struct pt_regs, b6); + val = offsetof(struct pt_regs, b6); else - val = struct_offset(struct pt_regs, b7); + val = offsetof(struct pt_regs, b7); } break; @@ -1594,7 +1637,7 @@ build_script (struct unw_frame_info *info) && sr.curr.reg[UNW_REG_PSP].val != 0) { /* new psp is sp plus frame size */ insn.opc = UNW_INSN_ADD; - insn.dst = struct_offset(struct unw_frame_info, psp)/8; + insn.dst = offsetof(struct unw_frame_info, psp)/8; insn.val = sr.curr.reg[UNW_REG_PSP].val; /* frame size */ script_emit(script, insn); } @@ -1728,14 +1771,13 @@ run_script (struct unw_script *script, struct unw_frame_info *state) lazy_init: off = unw.sw_off[val]; s[val] = (unsigned long) state->sw + off; - if (off >= struct_offset(struct switch_stack, r4) - && off <= struct_offset(struct switch_stack, r7)) + if (off >= offsetof(struct switch_stack, r4) && off <= offsetof(struct switch_stack, r7)) /* * We're initializing a general register: init NaT info, too. Note that * the offset is a multiple of 8 which gives us the 3 bits needed for * the type field. */ - s[val+1] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; + s[val+1] = (offsetof(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; goto redo; } @@ -1799,11 +1841,7 @@ unw_unwind (struct unw_frame_info *info) return -1; } ip = info->ip = *info->rp_loc; - if (ip < GATE_ADDR + PAGE_SIZE) { - /* - * We don't have unwind info for the gate page, so we consider that part - * of user-space for the purpose of unwinding. - */ + if (ip < GATE_ADDR) { UNW_DPRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; @@ -1825,7 +1863,7 @@ unw_unwind (struct unw_frame_info *info) if ((pr & (1UL << pNonSys)) != 0) num_regs = *info->cfm_loc & 0x7f; /* size of frame */ info->pfs_loc = - (unsigned long *) (info->pt + struct_offset(struct pt_regs, ar_pfs)); + (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); UNW_DPRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt); } else num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */ @@ -1876,11 +1914,7 @@ unw_unwind_to_user (struct unw_frame_info *info) __FUNCTION__, ip); return -1; } - /* - * We don't have unwind info for the gate page, so we consider that part - * of user-space for the purpose of unwinding. - */ - if (ip < GATE_ADDR + PAGE_SIZE) + if (ip < GATE_ADDR) return 0; } unw_get_ip(info, &ip); @@ -2090,30 +2124,41 @@ unw_remove_unwind_table (void *handle) kfree(table); } -void -unw_create_gate_table (void) +static void __init +create_gate_table (void) { - extern char __start_gate_section[], __stop_gate_section[]; - unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base; - const struct unw_table_entry *entry, *first, *unw_table_end; - extern int ia64_unw_end; + const struct unw_table_entry *entry, *start, *end; + unsigned long *lp, segbase = GATE_ADDR; size_t info_size, size; char *info; + Elf64_Phdr *punw = NULL, *phdr = (Elf64_Phdr *) (GATE_ADDR + GATE_EHDR->e_phoff); + int i; + + for (i = 0; i < GATE_EHDR->e_phnum; ++i, ++phdr) + if (phdr->p_type == PT_IA_64_UNWIND) { + punw = phdr; + break; + } + + if (!punw) { + printk("%s: failed to find gate DSO's unwind table!\n", __FUNCTION__); + return; + } - start = (unsigned long) __start_gate_section - segbase; - end = (unsigned long) __stop_gate_section - segbase; - unw_table_end = (struct unw_table_entry *) &ia64_unw_end; + start = (const struct unw_table_entry *) punw->p_vaddr; + end = (struct unw_table_entry *) ((char *) start + punw->p_memsz); size = 0; - first = lookup(&unw.kernel_table, start); - for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry) + unw_add_unwind_table("linux-gate.so", segbase, 0, start, end); + + for (entry = start; entry < end; ++entry) size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); size += 8; /* reserve space for "end of table" marker */ - unw.gate_table = alloc_bootmem(size); + unw.gate_table = kmalloc(size, GFP_KERNEL); if (!unw.gate_table) { unw.gate_table_size = 0; - printk(KERN_ERR "unwind: unable to create unwind data for gate page!\n"); + printk(KERN_ERR "%s: unable to create unwind data for gate page!\n", __FUNCTION__); return; } unw.gate_table_size = size; @@ -2121,19 +2166,21 @@ unw_create_gate_table (void) lp = unw.gate_table; info = (char *) unw.gate_table + size; - for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry, lp += 3) { + for (entry = start; entry < end; ++entry, lp += 3) { info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); info -= info_size; memcpy(info, (char *) segbase + entry->info_offset, info_size); - lp[0] = entry->start_offset - start + GATE_ADDR; /* start */ - lp[1] = entry->end_offset - start + GATE_ADDR; /* end */ - lp[2] = info - (char *) unw.gate_table; /* info */ + lp[0] = segbase + entry->start_offset; /* start */ + lp[1] = segbase + entry->end_offset; /* end */ + lp[2] = info - (char *) unw.gate_table; /* info */ } *lp = 0; /* end-of-table marker */ } -void +__initcall(create_gate_table); + +void __init unw_init (void) { extern int ia64_unw_start, ia64_unw_end, __gp; @@ -2174,6 +2221,14 @@ unw_init (void) } /* + * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + * + * This system call has been deprecated. The new and improved way to get + * at the kernel's unwind info is via the gate DSO. The address of the + * ELF header for this DSO is passed to user-level via AT_SYSINFO_EHDR. + * + * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + * * This system call copies the unwind data into the buffer pointed to by BUF and returns * the size of the unwind data. If BUF_SIZE is smaller than the size of the unwind data * or if BUF is NULL, nothing is copied, but the system call still returns the size of the diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 6252fd06ab1..c8188240788 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -13,6 +13,12 @@ lib-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o lib-$(CONFIG_PERFMON) += carta_random.o +ifeq ($(CONFIG_MD_RAID5),m) + lib-y += xor.o +else + lib-$(CONFIG_MD_RAID5) += xor.o +endif + IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff --git a/arch/ia64/lib/idiv64.S b/arch/ia64/lib/idiv64.S index 404ebeca665..f69bd2b0987 100644 --- a/arch/ia64/lib/idiv64.S +++ b/arch/ia64/lib/idiv64.S @@ -37,57 +37,44 @@ #define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) GLOBAL_ENTRY(NAME) - .prologue .regstk 2,0,0,0 // Transfer inputs to FP registers. setf.sig f8 = in0 setf.sig f9 = in1 ;; - .fframe 16 - .save.f 0x20 - stf.spill [sp] = f17,-16 - // Convert the inputs to FP, to avoid FP software-assist faults. INT_TO_FP(f8, f8) - ;; - - .save.f 0x10 - stf.spill [sp] = f16 - .body INT_TO_FP(f9, f9) ;; - frcpa.s1 f17, p6 = f8, f9 // y0 = frcpa(b) + frcpa.s1 f11, p6 = f8, f9 // y0 = frcpa(b) ;; -(p6) fmpy.s1 f7 = f8, f17 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 +(p6) fmpy.s1 f7 = f8, f11 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f11, f1 // e0 = -b*y0 + 1 ;; -(p6) fma.s1 f16 = f7, f6, f7 // q1 = q0*e0 + q0 +(p6) fma.s1 f10 = f7, f6, f7 // q1 = q0*e0 + q0 (p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 ;; #ifdef MODULO sub in1 = r0, in1 // in1 = -b #endif -(p6) fma.s1 f16 = f16, f7, f16 // q2 = q1*e1 + q1 -(p6) fma.s1 f6 = f17, f6, f17 // y1 = y0*e0 + y0 +(p6) fma.s1 f10 = f10, f7, f10 // q2 = q1*e1 + q1 +(p6) fma.s1 f6 = f11, f6, f11 // y1 = y0*e0 + y0 ;; (p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 -(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a +(p6) fnma.s1 f7 = f9, f10, f8 // r = -b*q2 + a ;; #ifdef MODULO setf.sig f8 = in0 // f8 = a setf.sig f9 = in1 // f9 = -b #endif -(p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 +(p6) fma.s1 f11 = f7, f6, f10 // q3 = r*y2 + q2 ;; - .restore sp - ldf.fill f16 = [sp], 16 - FP_TO_INT(f17, f17) // q = trunc(q3) + FP_TO_INT(f11, f11) // q = trunc(q3) ;; #ifdef MODULO - xma.l f17 = f17, f9, f8 // r = q*(-b) + a + xma.l f11 = f11, f9, f8 // r = q*(-b) + a ;; #endif - getf.sig r8 = f17 // transfer result to result register - ldf.fill f17 = [sp] + getf.sig r8 = f11 // transfer result to result register br.ret.sptk.many rp END(NAME) diff --git a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S index 2e7559eeb30..76eb542fd75 100644 --- a/arch/ia64/lib/memcpy_mck.S +++ b/arch/ia64/lib/memcpy_mck.S @@ -15,11 +15,7 @@ #include #include -#if __GNUC__ >= 3 -# define EK(y...) EX(y) -#else -# define EK(y,x...) x -#endif +#define EK(y...) EX(y) GLOBAL_ENTRY(bcopy) .regstk 3,0,0,0 diff --git a/arch/ia64/lib/xor.S b/arch/ia64/lib/xor.S new file mode 100644 index 00000000000..5ea9cdb71ea --- /dev/null +++ b/arch/ia64/lib/xor.S @@ -0,0 +1,184 @@ +/* + * arch/ia64/lib/xor.S + * + * Optimized RAID-5 checksumming functions for IA-64. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +GLOBAL_ENTRY(xor_ia64_2) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 3, 0, 13, 16 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov ar.lc = in0 + mov pr.rot = 1 << 16 + ;; + .rotr s1[6+1], s2[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[6+1])st8.nta [r8] = d[1], 8 + nop.f 0 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_2) + +GLOBAL_ENTRY(xor_ia64_3) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 4, 0, 20, 24 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] + ;; +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], s3[6] + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_3) + +GLOBAL_ENTRY(xor_ia64_4) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 5, 0, 27, 32 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + mov r19 = in4 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[0]) ld8.nta s4[0] = [r19], 8 +(p[6]) xor r20 = s3[6], s4[6] + ;; +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], r20 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_4) + +GLOBAL_ENTRY(xor_ia64_5) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 6, 0, 34, 40 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + mov r19 = in4 + mov r20 = in5 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], s5[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[0]) ld8.nta s4[0] = [r19], 8 +(p[6]) xor r21 = s3[6], s4[6] + ;; +(p[0]) ld8.nta s5[0] = [r20], 8 +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], r21 + ;; +(p[6]) xor d[0] = d[0], s5[6] + nop.f 0 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_5) diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index e39bd20123a..c2bd413eedb 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -285,9 +285,11 @@ discontig_paging_init(void) kaddr = (unsigned long)__va(bdp->node_boot_start); ekaddr = (unsigned long)__va(bdp->node_low_pfn << PAGE_SHIFT); while (kaddr < ekaddr) { - bid = BANK_MEM_MAP_INDEX(kaddr); - node_data[mynode]->node_id_map[bid] = node; - node_data[mynode]->bank_mem_map_base[bid] = page; + if (paddr_to_nid(__pa(kaddr)) == node) { + bid = BANK_MEM_MAP_INDEX(kaddr); + node_data[mynode]->node_id_map[bid] = node; + node_data[mynode]->bank_mem_map_base[bid] = page; + } kaddr += BANKSIZE; page += BANKSIZE/PAGE_SIZE; } diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 68f3b4aaf2e..fa66ec8b4cf 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -43,6 +43,33 @@ expand_backing_store (struct vm_area_struct *vma, unsigned long address) return 0; } +/* + * Return TRUE if ADDRESS points at a page in the kernel's mapped segment + * (inside region 5, on ia64) and that page is present. + */ +static int +mapped_kernel_page_is_present (unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset_k(address); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + return 0; + + pmd = pmd_offset(pgd,address); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + return 0; + + ptep = pte_offset_kernel(pmd, address); + if (!ptep) + return 0; + + pte = *ptep; + return pte_present(pte); +} + void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { @@ -190,6 +217,16 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re return; /* + * Since we have no vma's for region 5, we might get here even if the address is + * valid, due to the VHPT walker inserting a non present translation that becomes + * stale. If that happens, the non present fault handler already purged the stale + * translation, which fixed the problem. So, we check to see if the translation is + * valid, and return if it is. + */ + if (REGION_NUMBER(address) == 5 && mapped_kernel_page_is_present(address)) + return; + + /* * Oops. The kernel tried to access some bad page. We'll have to terminate things * with extreme prejudice. */ diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c index c7f12f6b8e7..20426c58c63 100644 --- a/arch/ia64/mm/hugetlbpage.c +++ b/arch/ia64/mm/hugetlbpage.c @@ -116,7 +116,7 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) /* This function checks if the address and address+len falls out of HugeTLB region. It * return -EINVAL if any part of address range falls in HugeTLB region. */ -int is_invalid_hugepage_range(unsigned long addr, unsigned long len) +int check_valid_hugepage_range(unsigned long addr, unsigned long len) { if (REGION_NUMBER(addr) == REGION_HPAGE) return -EINVAL; diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 32f620cb00d..8fc22262ce0 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -1,7 +1,7 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang */ #include @@ -9,13 +9,14 @@ #include #include +#include +#include #include +#include #include #include #include #include -#include -#include #include #include @@ -23,13 +24,15 @@ #include #include #include +#include #include #include #include -#include #include +#include +#include -struct mmu_gather mmu_gathers[NR_CPUS]; +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end, _end; @@ -47,6 +50,8 @@ unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; static int pgt_cache_water[2] = { 25, 50 }; +struct page *zero_page_memmap_ptr; /* map entry for zero page */ + void check_pgt_cache (void) { @@ -65,6 +70,36 @@ check_pgt_cache (void) } } +void +update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) +{ + unsigned long addr; + struct page *page; + + if (!pte_exec(pte)) + return; /* not an executable page... */ + + page = pte_page(pte); + /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ + addr = (unsigned long) page_address(page); + + if (test_bit(PG_arch_1, &page->flags)) + return; /* i-cache is already coherent with d-cache */ + + flush_icache_range(addr, addr + PAGE_SIZE); + set_bit(PG_arch_1, &page->flags); /* mark page as clean */ +} + +inline void +ia64_set_rbs_bot (void) +{ + unsigned long stack_size = current->rlim[RLIMIT_STACK].rlim_max & -16; + + if (stack_size > MAX_USER_STACK_SIZE) + stack_size = MAX_USER_STACK_SIZE; + current->thread.rbs_bot = STACK_TOP - stack_size; +} + /* * This performs some platform-dependent address space initialization. * On IA-64, we want to setup the VM area for the register backing @@ -76,6 +111,8 @@ ia64_init_addr_space (void) { struct vm_area_struct *vma; + ia64_set_rbs_bot(); + /* * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore * the problem. When the process attempts to write to the register backing store @@ -84,7 +121,7 @@ ia64_init_addr_space (void) vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma) { vma->vm_mm = current->mm; - vma->vm_start = IA64_RBS_BOT; + vma->vm_start = current->thread.rbs_bot; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; @@ -112,14 +149,16 @@ ia64_init_addr_space (void) void free_initmem (void) { - unsigned long addr; + unsigned long addr, eaddr; - addr = (unsigned long) &__init_begin; - for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) { + addr = (unsigned long) ia64_imva(&__init_begin); + eaddr = (unsigned long) ia64_imva(&__init_end); + while (addr < eaddr) { ClearPageReserved(virt_to_page(addr)); set_page_count(virt_to_page(addr), 1); free_page(addr); ++totalram_pages; + addr += PAGE_SIZE; } printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", (&__init_end - &__init_begin) >> 10); @@ -230,18 +269,17 @@ show_mem(void) } /* - * This is like put_dirty_page() but installs a clean page with PAGE_GATE protection - * (execute-only, typically). + * This is like put_dirty_page() but installs a clean page in the kernel's page table. */ struct page * -put_gate_page (struct page *page, unsigned long address) +put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) { pgd_t *pgd; pmd_t *pmd; pte_t *pte; if (!PageReserved(page)) - printk(KERN_ERR "put_gate_page: gate page at 0x%p not in reserved memory\n", + printk(KERN_ERR "put_kernel_page: page at 0x%p not in reserved memory\n", page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ @@ -258,7 +296,7 @@ put_gate_page (struct page *page, unsigned long address) pte_unmap(pte); goto out; } - set_pte(pte, mk_pte(page, PAGE_GATE)); + set_pte(pte, mk_pte(page, pgprot)); pte_unmap(pte); } out: spin_unlock(&init_mm.page_table_lock); @@ -266,10 +304,31 @@ put_gate_page (struct page *page, unsigned long address) return page; } +static void +setup_gate (void) +{ + struct page *page; + extern char __start_gate_section[]; + + /* + * Map the gate page twice: once read-only to export the ELF headers etc. and once + * execute-only page to enable privilege-promotion via "epc": + */ + page = virt_to_page(ia64_imva(__start_gate_section)); + put_kernel_page(page, GATE_ADDR, PAGE_READONLY); +#ifdef HAVE_BUGGY_SEGREL + page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE)); + put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE); +#else + put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE); +#endif + ia64_patch_gate(); +} + void __init ia64_mmu_init (void *my_cpu_data) { - unsigned long psr, rid, pta, impl_va_bits; + unsigned long psr, pta, impl_va_bits; extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 @@ -277,21 +336,8 @@ ia64_mmu_init (void *my_cpu_data) # define VHPT_ENABLE_BIT 1 #endif - /* - * Set up the kernel identity mapping for regions 6 and 5. The mapping for region - * 7 is setup up in _start(). - */ + /* Pin mapping for percpu area into TLB */ psr = ia64_clear_ic(); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); - ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); - - /* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */ - ia64_srlz_d(); - ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PERCPU_PAGE_SHIFT); @@ -489,6 +535,7 @@ paging_init (void) discontig_paging_init(); efi_memmap_walk(count_pages, &num_physpages); + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } #else /* !CONFIG_DISCONTIGMEM */ void @@ -560,6 +607,7 @@ paging_init (void) } free_area_init(zones_size); # endif /* !CONFIG_VIRTUAL_MEM_MAP */ + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } #endif /* !CONFIG_DISCONTIGMEM */ @@ -576,13 +624,32 @@ count_reserved_pages (u64 start, u64 end, void *arg) return 0; } +/* + * Boot command-line option "nolwsys" can be used to disable the use of any light-weight + * system call handler. When this option is in effect, all fsyscalls will end up bubbling + * down into the kernel and calling the normal (heavy-weight) syscall handler. This is + * useful for performance testing, but conceivably could also come in handy for debugging + * purposes. + */ + +static int nolwsys; + +static int __init +nolwsys_setup (char *s) +{ + nolwsys = 1; + return 1; +} + +__setup("nolwsys", nolwsys_setup); + void mem_init (void) { - extern char __start_gate_section[]; long reserved_pages, codesize, datasize, initsize; unsigned long num_pgt_pages; pg_data_t *pgdat; + int i; static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; #ifdef CONFIG_PCI @@ -634,8 +701,19 @@ mem_init (void) if (num_pgt_pages > (u64) pgt_cache_water[1]) pgt_cache_water[1] = num_pgt_pages; - /* install the gate page in the global page table: */ - put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); + /* + * For fsyscall entrpoints with no light-weight handler, use the ordinary + * (heavy-weight) handler, but mark it by setting bit 0, so the fsyscall entry + * code can tell them apart. + */ + for (i = 0; i < NR_syscalls; ++i) { + extern unsigned long fsyscall_table[NR_syscalls]; + extern unsigned long sys_call_table[NR_syscalls]; + + if (!fsyscall_table[i] || nolwsys) + fsyscall_table[i] = sys_call_table[i] | 1; + } + setup_gate(); /* setup gate pages before we free up boot memory... */ #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index af5955328e3..a9235e8567d 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -1,7 +1,7 @@ /* * TLB support routines. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * David Mosberger-Tang * * 08/02/00 A. Mallick @@ -22,17 +22,10 @@ #include #include -#define SUPPORTED_PGBITS ( \ - 1 << _PAGE_SIZE_256M | \ - 1 << _PAGE_SIZE_64M | \ - 1 << _PAGE_SIZE_16M | \ - 1 << _PAGE_SIZE_4M | \ - 1 << _PAGE_SIZE_1M | \ - 1 << _PAGE_SIZE_256K | \ - 1 << _PAGE_SIZE_64K | \ - 1 << _PAGE_SIZE_16K | \ - 1 << _PAGE_SIZE_8K | \ - 1 << _PAGE_SIZE_4K ) +static struct { + unsigned long mask; /* mask of supported purge page-sizes */ + unsigned long max_bits; /* log2() of largest supported purge page-size */ +} purge; struct ia64_ctx ia64_ctx = { .lock = SPIN_LOCK_UNLOCKED, @@ -154,22 +147,10 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start, unsigned long } nbits = ia64_fls(size + 0xfff); - if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) { - if (nbits > _PAGE_SIZE_256M) - nbits = _PAGE_SIZE_256M; - else - /* - * Some page sizes are not implemented in the - * IA-64 arch, so if we get asked to clear an - * unsupported page size, round up to the - * nearest page size. Note that we depend on - * the fact that if page size N is not - * implemented, 2*N _is_ implemented. - */ - ++nbits; - if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) - panic("flush_tlb_range: BUG: nbits=%lu\n", nbits); - } + while (unlikely (((1UL << nbits) & purge.mask) == 0) && (nbits < purge.max_bits)) + ++nbits; + if (nbits > purge.max_bits) + nbits = purge.max_bits; start &= ~((1UL << nbits) - 1); # ifdef CONFIG_SMP @@ -190,6 +171,15 @@ void __init ia64_tlb_init (void) { ia64_ptce_info_t ptce_info; + unsigned long tr_pgbits; + long status; + + if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { + printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld;" + "defaulting to architected purge page-sizes.\n", status); + purge.mask = 0x115557000; + } + purge.max_bits = ia64_fls(purge.mask); ia64_get_ptce(&ptce_info); local_cpu_data->ptce_base = ptce_info.base; diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 3a5cbbef532..58ff5b17a03 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -59,7 +59,7 @@ struct pci_fixup pcibios_fixups[1]; static int -__pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) +pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) { int result = 0; u64 data = 0; @@ -75,7 +75,7 @@ __pci_sal_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) } static int -__pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) +pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) { if ((seg > 255) || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) return -EINVAL; @@ -83,28 +83,33 @@ __pci_sal_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, dev, fn, reg), len, value); } +struct pci_raw_ops pci_sal_ops = { + .read = pci_sal_read, + .write = pci_sal_write +}; + +struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; /* default to SAL */ + static int -pci_sal_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) +pci_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return __pci_sal_read(pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), - where, size, value); + return raw_pci_ops->read(pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); } static int -pci_sal_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +pci_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { - return __pci_sal_write(pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), - where, size, value); + return raw_pci_ops->write(pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value); } -struct pci_ops pci_sal_ops = { - .read = pci_sal_read, - .write = pci_sal_write +static struct pci_ops pci_root_ops = { + .read = pci_read, + .write = pci_write, }; -struct pci_ops *pci_root_ops = &pci_sal_ops; /* default to SAL */ - static int __init pci_acpi_init (void) { @@ -307,7 +312,7 @@ pcibios_scan_root (void *handle, int seg, int bus) info.name = name; acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info); - return scan_root_bus(bus, pci_root_ops, controller); + return scan_root_bus(bus, &pci_root_ops, controller); out3: kfree(controller->window); diff --git a/arch/ia64/scripts/check-gas b/arch/ia64/scripts/check-gas index b7a4b1261ac..2499e0b2243 100644 --- a/arch/ia64/scripts/check-gas +++ b/arch/ia64/scripts/check-gas @@ -2,8 +2,11 @@ dir=$(dirname $0) CC=$1 OBJDUMP=$2 -$CC -c $dir/check-gas-asm.S -res=$($OBJDUMP -r --section .data check-gas-asm.o | fgrep 00004 | tr -s ' ' |cut -f3 -d' ') +tmp=${TMPDIR:-/tmp} +out=$tmp/out$$.o +$CC -c $dir/check-gas-asm.S -o $out +res=$($OBJDUMP -r --section .data $out | fgrep 00004 | tr -s ' ' |cut -f3 -d' ') +rm -f $out if [ $res != ".text" ]; then echo buggy else diff --git a/arch/ia64/scripts/check-segrel.S b/arch/ia64/scripts/check-segrel.S new file mode 100644 index 00000000000..3be4e3dbeb8 --- /dev/null +++ b/arch/ia64/scripts/check-segrel.S @@ -0,0 +1,4 @@ + .rodata + data4 @segrel(start) + .data +start: diff --git a/arch/ia64/scripts/check-segrel.lds b/arch/ia64/scripts/check-segrel.lds new file mode 100644 index 00000000000..1c2f13e181d --- /dev/null +++ b/arch/ia64/scripts/check-segrel.lds @@ -0,0 +1,11 @@ +SECTIONS { + . = SIZEOF_HEADERS; + .rodata : { *(.rodata) } :ro + . = 0xa0000; + .data : { *(.data) } :dat + /DISCARD/ : { *(*) } +} +PHDRS { + ro PT_LOAD FILEHDR PHDRS; + dat PT_LOAD; +} diff --git a/arch/ia64/scripts/toolchain-flags b/arch/ia64/scripts/toolchain-flags new file mode 100644 index 00000000000..7e21e177351 --- /dev/null +++ b/arch/ia64/scripts/toolchain-flags @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Check whether linker can handle cross-segment @segrel(): +# +CC=$1 +LD=$2 +OBJDUMP=$3 +dir=$(dirname $0) +tmp=${TMPDIR:-/tmp} +out=$tmp/out$$ +$CC -c $dir/check-segrel.S -o $out.o +$LD -static -T$dir/check-segrel.lds $out.o -o $out +res=$($OBJDUMP --full --section .rodata $out | fgrep 000 | cut -f3 -d' ') +rm -f $out $out.o +if [ $res != 00000a00 ]; then + echo " -DHAVE_BUGGY_SEGREL" + cat >&2 <, where dn is the digit number. The amount of memory is 8MB*2**. (If = 0, the memory size is 0). - SN1 doesnt support dimms this small but small memory systems + SN1 doesn't support dimms this small but small memory systems boot faster on Medusa. diff --git a/arch/ia64/sn/fakeprom/fpmem.c b/arch/ia64/sn/fakeprom/fpmem.c index d59234d709e..360631871ab 100644 --- a/arch/ia64/sn/fakeprom/fpmem.c +++ b/arch/ia64/sn/fakeprom/fpmem.c @@ -13,7 +13,7 @@ * FPROM EFI memory descriptor build routines * * - Routines to build the EFI memory descriptor map - * - Should also be usable by the SGI SN1 prom to convert + * - Should also be usable by the SGI prom to convert * klconfig to efi_memmap */ @@ -53,10 +53,7 @@ sn_config_t *sn_config ; #define KERNEL_SIZE (4*MB) #define PROMRESERVED_SIZE (1*MB) -#ifdef CONFIG_IA64_SGI_SN1 -#define PHYS_ADDRESS(_n, _x) (((long)_n<<33) | (long)_x) -#define MD_BANK_SHFT 30 -#else +#ifdef SGI_SN2 #define PHYS_ADDRESS(_n, _x) (((long)_n<<38) | (long)_x | 0x3000000000UL) #define MD_BANK_SHFT 34 #endif @@ -77,7 +74,7 @@ GetNumCpus(void) return sn_config->cpus; } -/* For SN1, get the index th nasid */ +/* For SN, get the index th nasid */ int GetNasid(int index) @@ -104,40 +101,7 @@ IsCpuPresent(int cnode, int cpu) * actually disabled etc. */ -#ifdef CONFIG_IA64_SGI_SN1 -int -IsBankPresent(int index, node_memmap_t nmemmap) -{ - switch (index) { - case 0:return nmemmap.b0; - case 1:return nmemmap.b1; - case 2:return nmemmap.b2; - case 3:return nmemmap.b3; - case 4:return nmemmap.b4; - case 5:return nmemmap.b5; - case 6:return nmemmap.b6; - case 7:return nmemmap.b7; - default:return -1 ; - } -} - -int -GetBankSize(int index, node_memmap_t nmemmap) -{ - switch (index) { - case 0: - case 1:return nmemmap.b01size; - case 2: - case 3:return nmemmap.b23size; - case 4: - case 5:return nmemmap.b45size; - case 6: - case 7:return nmemmap.b67size; - default:return -1 ; - } -} - -#else +#ifdef SGI_SN2 int IsBankPresent(int index, node_memmap_t nmemmap) { @@ -192,12 +156,12 @@ build_efi_memmap(void *md, int mdsize) for (cnode=0;cnode /* - * Structure of the mem config of the node as a SN1 MI reg + * Structure of the mem config of the node as a SN MI reg * Medusa supports this reg config. * * BankSize nibble to bank size mapping @@ -24,32 +24,7 @@ #define MBSHIFT 20 -#ifdef CONFIG_IA64_SGI_SN1 -typedef struct node_memmap_s -{ - unsigned int b0 :1, /* 0 bank 0 present */ - b1 :1, /* 1 bank 1 present */ - r01 :2, /* 2-3 reserved */ - b01size :4, /* 4-7 Size of bank 0 and 1 */ - b2 :1, /* 8 bank 2 present */ - b3 :1, /* 9 bank 3 present */ - r23 :2, /* 10-11 reserved */ - b23size :4, /* 12-15 Size of bank 2 and 3 */ - b4 :1, /* 16 bank 4 present */ - b5 :1, /* 17 bank 5 present */ - r45 :2, /* 18-19 reserved */ - b45size :4, /* 20-23 Size of bank 4 and 5 */ - b6 :1, /* 24 bank 6 present */ - b7 :1, /* 25 bank 7 present */ - r67 :2, /* 26-27 reserved */ - b67size :4; /* 28-31 Size of bank 6 and 7 */ -} node_memmap_t ; - -/* Support the medusa hack for 8M/16M/32M nodes */ -#define SN1_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ -#define BankSizeBytes(bsize) ((bsize<6) ? (1<<((bsize-1)+SN1_BANK_SIZE_SHIFT)) :\ - (1<<((bsize-9)+MBSHIFT))) -#else +#ifdef SGI_SN2 typedef struct node_memmap_s { unsigned int b0size :3, /* 0-2 bank 0 size */ @@ -73,6 +48,8 @@ typedef struct node_memmap_s #define SN2_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ #define BankPresent(bsize) (bsize<6) #define BankSizeBytes(bsize) (BankPresent(bsize) ? 1UL<<((bsize)+SN2_BANK_SIZE_SHIFT) : 0) +#define MD_BANKS_PER_NODE 4 +#define MD_BANKSIZE (1UL << 34) #endif typedef struct sn_memmap_s diff --git a/arch/ia64/sn/fakeprom/fpromasm.S b/arch/ia64/sn/fakeprom/fpromasm.S index 2c9c6038923..aa24f6f1f86 100644 --- a/arch/ia64/sn/fakeprom/fpromasm.S +++ b/arch/ia64/sn/fakeprom/fpromasm.S @@ -8,7 +8,7 @@ * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -57,9 +57,7 @@ * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) * IOSPEC_BASE value */ -#ifdef CONFIG_IA64_SGI_SN1 -#define IOPB_PA 0xc0000FFFFC000000 -#else +#ifdef SGI_SN2 #define IOPB_PA 0xc000000fcc000000 #endif @@ -84,10 +82,7 @@ _start: // Isolate node number we are running on. mov r6 = ip;; -#ifdef CONFIG_IA64_SGI_SN1 - shr r5 = r6,33;; // r5 = node number - shl r6 = r5,33 // r6 = base memory address of node -#else +#ifdef SGI_SN2 shr r5 = r6,38 // r5 = node number dep r6 = 0,r6,0,36 // r6 = base memory address of node @@ -99,7 +94,7 @@ _start: or r1 = r1,r6 // Relocate to boot node // Lets figure out who we are & put it in the LID register. -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 // On SN2, we (currently) pass the cpu number in r10 at boot and r25=3,r10;; movl r16=0x8000008110000400 // Allow IPIs @@ -324,10 +319,7 @@ static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ 1: cmp.eq p6,p7=8,r28 /* PAL_VM_SUMMARY */ (p7) br.cond.sptk.few 1f movl r8=0 -#ifdef CONFIG_IA64_SGI_SN1 - movl r9=0x0203083001151059 - movl r10=0x1232 -#else +#ifdef SGI_SN2 movl r9=0x0203083001151065 movl r10=0x183f #endif diff --git a/arch/ia64/sn/fakeprom/fw-emu.c b/arch/ia64/sn/fakeprom/fw-emu.c index 792abb0a59b..ce5c919b2f0 100644 --- a/arch/ia64/sn/fakeprom/fw-emu.c +++ b/arch/ia64/sn/fakeprom/fw-emu.c @@ -5,7 +5,7 @@ * Copyright (C) 1998-2000 David Mosberger-Tang * * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -36,14 +36,13 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include -#include #include #include #include #include #include #include -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 #include #include #endif @@ -69,10 +68,7 @@ #define ACPI_SLIT_REVISION 1 #define OEMID "SGI" -#ifdef CONFIG_IA64_SGI_SN1 -#define PRODUCT "SN1" -#define PROXIMITY_DOMAIN(nasid) (nasid) -#else +#ifdef SGI_SN2 #define PRODUCT "SN2" #define PROXIMITY_DOMAIN(nasid) (((nasid)>>1) & 255) #endif @@ -100,12 +96,7 @@ typedef union ia64_nasid_va { struct { -#if defined(CONFIG_IA64_SGI_SN1) - unsigned long off : 33; /* intra-region offset */ - unsigned long nasid : 7; /* NASID */ - unsigned long off2 : 21; /* fill */ - unsigned long reg : 3; /* region number */ -#elif defined(CONFIG_IA64_SGI_SN2) +#if defined(SGI_SN2) unsigned long off : 36; /* intra-region offset */ unsigned long attr : 2; unsigned long nasid : 11; /* NASID */ @@ -125,9 +116,7 @@ typedef struct { #define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;}) #define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p))) -#if defined(CONFIG_IA64_SGI_SN1) -#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.l;}) -#elif defined(CONFIG_IA64_SGI_SN2) +#if defined(SGI_SN2) #define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.f.attr = 3; _v.l;}) #endif @@ -208,7 +197,7 @@ efi_unimplemented (void) return EFI_UNSUPPORTED; } -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 #undef cpu_physical_id #define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) @@ -301,7 +290,7 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, ; } else if (index == SAL_UPDATE_PAL) { ; -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 } else if (index == SN_SAL_LOG_CE) { #ifdef ajmtestcpei fprom_send_cpei(); @@ -501,9 +490,7 @@ sys_fw_init (const char *args, int arglen, int bsp) /* * Pass the parameter base address to the build_efi_xxx routines. */ -#if defined(CONFIG_IA64_SGI_SN1) - build_init(8LL*GB*base_nasid); -#else +#if defined(SGI_SN2) build_init(0x3000000000UL | ((long)base_nasid<<38)); #endif @@ -559,7 +546,7 @@ sys_fw_init (const char *args, int arglen, int bsp) * You can also edit this line to pass other arguments to the kernel. * Note: disable kernel text replication. */ - strcpy(cmd_line, "init=/bin/bash ktreplicate=0"); + strcpy(cmd_line, "init=/bin/bash console=ttyS0"); memset(efi_systab, 0, sizeof(efi_systab)); efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; @@ -625,10 +612,7 @@ sys_fw_init (const char *args, int arglen, int bsp) lsapic20->header.length = sizeof(struct acpi_table_lsapic); lsapic20->acpi_id = cnode*4+cpu; lsapic20->flags.enabled = 1; -#if defined(CONFIG_IA64_SGI_SN1) - lsapic20->eid = cpu; - lsapic20->id = nasid; -#else +#if defined(SGI_SN2) lsapic20->eid = nasid&0xffff; lsapic20->id = (cpu<<4) | (nasid>>16); #endif @@ -649,12 +633,9 @@ sys_fw_init (const char *args, int arglen, int bsp) srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); srat_memory_affinity->base_addr_lo = 0; srat_memory_affinity->length_lo = 0; -#if defined(CONFIG_IA64_SGI_SN1) - srat_memory_affinity->base_addr_hi = nasid<<1; - srat_memory_affinity->length_hi = SN1_NODE_SIZE>>32; -#else +#if defined(SGI_SN2) srat_memory_affinity->base_addr_hi = (nasid<<6) | (3<<4); - srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32; + srat_memory_affinity->length_hi = (MD_BANKSIZE*MD_BANKS_PER_NODE)>>32; #endif srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY; srat_memory_affinity->flags.enabled = 1; @@ -671,10 +652,7 @@ sys_fw_init (const char *args, int arglen, int bsp) srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity); srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); srat_cpu_affinity->flags.enabled = 1; -#if defined(CONFIG_IA64_SGI_SN1) - srat_cpu_affinity->apic_id = nasid; - srat_cpu_affinity->lsapic_eid = cpu; -#else +#if defined(SGI_SN2) srat_cpu_affinity->lsapic_eid = nasid&0xffff; srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16); #endif @@ -708,7 +686,7 @@ sys_fw_init (const char *args, int arglen, int bsp) sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */ strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN1"); + strcpy(sal_systab->product_id, "SN2"); /* fill in an entry point: */ sal_ed->type = SAL_DESC_ENTRY_POINT; @@ -757,7 +735,7 @@ sys_fw_init (const char *args, int arglen, int bsp) sal_systab->checksum = -checksum; /* If the checksum is correct, the kernel tries to use the - * table. We don't build enough table & the kernel aborts. + * table. We dont build enough table & the kernel aborts. * Note that the PROM hasd thhhe same problem!! */ @@ -786,9 +764,7 @@ sys_fw_init (const char *args, int arglen, int bsp) for(cpu=0; cpu 0) diff --git a/arch/ia64/sn/io/klgraph_hack.c b/arch/ia64/sn/fakeprom/klgraph_init.c similarity index 69% rename from arch/ia64/sn/io/klgraph_hack.c rename to arch/ia64/sn/fakeprom/klgraph_init.c index e8cefe29e4e..9d382ab5aa2 100644 --- a/arch/ia64/sn/io/klgraph_hack.c +++ b/arch/ia64/sn/fakeprom/klgraph_init.c @@ -1,10 +1,10 @@ -/* $Id$ +/* $Id: klgraph_init.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ @@ -13,29 +13,25 @@ * initial klgraph information that is normally provided by prom. */ -#include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include - -extern u64 klgraph_addr[]; -void * real_port; -void * real_io_base; -void * real_addr; - -char *BW0 = NULL; - -kl_config_hdr_t *linux_klcfg; - -#ifdef DEFINE_DUMP_RTNS -/* forward declarations */ -static void dump_ii(void), dump_crossbow(void); -static void clear_ii_error(void); -#endif /* DEFINE_DUMP_RTNS */ #define SYNERGY_WIDGET ((char *)0xc0000e0000000000) #define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) @@ -49,32 +45,41 @@ static void clear_ii_error(void); #define WIDGET0 ((char *)0xc0000a0000000000) #define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c - void -klgraph_hack_init(void) +klgraph_init(void) { - u64 *temp; - -#ifdef CONFIG_IA64_SGI_SN1 + u64 *temp; /* - * We need to know whether we are booting from PROM or - * boot from disk. + * Initialize some hub/xbow registers that allows access to + * Xbridge etc. These are normally done in PROM. */ - linux_klcfg = (kl_config_hdr_t *)0xe000000000030000; - if (linux_klcfg->ch_magic == 0xbeedbabe) { - return; - } else { - panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n"); - } - convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000); + /* Write IOERR clear to clear the CRAZY bit in the status */ + *(volatile uint64_t *)0xc000000801c001f8 = (uint64_t)0xffffffff; + + /* set widget control register...setting bedrock widget id to a */ + *(volatile uint64_t *)0xc000000801c00020 = (uint64_t)0x801a; + + /* set io outbound widget access...allow all */ + *(volatile uint64_t *)0xc000000801c00110 = (uint64_t)0xff01; + + /* set io inbound widget access...allow all */ + *(volatile uint64_t *)0xc000000801c00118 = (uint64_t)0xff01; + + /* set io crb timeout to max */ + *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; + *(volatile uint64_t *)0xc000000801c003c0 = (uint64_t)0xffffff; -#else + /* set local block io permission...allow all */ +// [LB] *(volatile uint64_t *)0xc000000801e04010 = (uint64_t)0xfffffffffffffff; - if (IS_RUNNING_ON_SIMULATOR()) { - printk("Creating FAKE Klconfig Structure for Embeded Kernel\n"); - klgraph_addr[0] = 0xe000003000030000; + /* clear any errors */ + /* clear_ii_error(); medusa should have cleared these */ + + /* set default read response buffers in bridge */ +// [PI] *(volatile u32 *)0xc00000080f000280L = 0xba98; +// [PI] *(volatile u32 *)0xc00000080f000288L = 0xba98; /* * klconfig entries initialization - mankato @@ -198,144 +203,3 @@ klgraph_hack_init(void) convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff); convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000); } - -#endif - -} - - - - - -#ifdef DEFINE_DUMP_RTNS -/* - * these were useful for printing out registers etc - * during bringup - */ - -static void -xdump(long long *addr, int count) -{ - int ii; - volatile long long *xx = addr; - - for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%p\n", (void *)xx, (void *)*xx); - } -} - -static void -xdump32(unsigned int *addr, int count) -{ - int ii; - volatile unsigned int *xx = addr; - - for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%0x\n", (void *)xx, (int)*xx); - } -} - -static void -clear_ii_error(void) -{ - volatile long long *tmp; - - printk("... WSTAT "); - xdump((long long *)0xc0000a0001c00008, 1); - printk("... WCTRL "); - xdump((long long *)0xc0000a0001c00020, 1); - printk("... WLCSR "); - xdump((long long *)0xc0000a0001c00128, 1); - printk("... IIDSR "); - xdump((long long *)0xc0000a0001c00138, 1); - printk("... IOPRBs "); - xdump((long long *)0xc0000a0001c00198, 9); - printk("... IXSS "); - xdump((long long *)0xc0000a0001c00210, 1); - printk("... IBLS0 "); - xdump((long long *)0xc0000a0001c10000, 1); - printk("... IBLS1 "); - xdump((long long *)0xc0000a0001c20000, 1); - - /* Write IOERR clear to clear the CRAZY bit in the status */ - tmp = (long long *)0xc0000a0001c001f8; *tmp = (long long)0xffffffff; - - /* dump out local block error registers */ - printk("... "); - xdump((long long *)0xc0000a0001e04040, 1); /* LB_ERROR_BITS */ - printk("... "); - xdump((long long *)0xc0000a0001e04050, 1); /* LB_ERROR_HDR1 */ - printk("... "); - xdump((long long *)0xc0000a0001e04058, 1); /* LB_ERROR_HDR2 */ - /* and clear the LB_ERROR_BITS */ - tmp = (long long *)0xc0000a0001e04040; *tmp = 0x0; - printk("clr: "); - xdump((long long *)0xc0000a0001e04040, 1); /* LB_ERROR_BITS */ - tmp = (long long *)0xc0000a0001e04050; *tmp = 0x0; - tmp = (long long *)0xc0000a0001e04058; *tmp = 0x0; -} - - -static void -dump_ii(void) -{ - printk("===== Dump the II regs =====\n"); - xdump((long long *)0xc0000a0001c00000, 2); - xdump((long long *)0xc0000a0001c00020, 1); - xdump((long long *)0xc0000a0001c00100, 37); - xdump((long long *)0xc0000a0001c00300, 98); - xdump((long long *)0xc0000a0001c10000, 6); - xdump((long long *)0xc0000a0001c20000, 6); - xdump((long long *)0xc0000a0001c30000, 2); - - xdump((long long *)0xc0000a0000000000, 1); - xdump((long long *)0xc0000a0001000000, 1); - xdump((long long *)0xc0000a0002000000, 1); - xdump((long long *)0xc0000a0003000000, 1); - xdump((long long *)0xc0000a0004000000, 1); - xdump((long long *)0xc0000a0005000000, 1); - xdump((long long *)0xc0000a0006000000, 1); - xdump((long long *)0xc0000a0007000000, 1); - xdump((long long *)0xc0000a0008000000, 1); - xdump((long long *)0xc0000a0009000000, 1); - xdump((long long *)0xc0000a000a000000, 1); - xdump((long long *)0xc0000a000b000000, 1); - xdump((long long *)0xc0000a000c000000, 1); - xdump((long long *)0xc0000a000d000000, 1); - xdump((long long *)0xc0000a000e000000, 1); - xdump((long long *)0xc0000a000f000000, 1); -} - -static void -dump_crossbow(void) -{ - printk("===== Dump the Crossbow regs =====\n"); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000000004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000000000, 1); - printk("and again..\n"); - xdump32((unsigned int *)0xc0000a0000000000, 1); - xdump32((unsigned int *)0xc0000a0000000000, 1); - - - clear_ii_error(); - - xdump32((unsigned int *)0xc000020000000004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc000020000000000, 1); - clear_ii_error(); - - xdump32((unsigned int *)0xc0000a0000800004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000800000, 1); - clear_ii_error(); - - xdump32((unsigned int *)0xc000020000800004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc000020000800000, 1); - clear_ii_error(); - - -} -#endif /* DEFINE_DUMP_RTNS */ diff --git a/arch/ia64/sn/fakeprom/main.c b/arch/ia64/sn/fakeprom/main.c index 723aa51bb71..96df8ec276d 100644 --- a/arch/ia64/sn/fakeprom/main.c +++ b/arch/ia64/sn/fakeprom/main.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -33,25 +33,9 @@ fmain(int lid, int bsp) { * First lets figure out who we are. This is done from the * LID passed to us. */ - -#ifdef CONFIG_IA64_SGI_SN1 - nasid = (lid>>24); - syn = (lid>>17)&1; - cpu = (lid>>16)&1; - - /* - * Now pick a synergy master to initialize synergy registers. - */ - if (test_and_set_bit(syn, &nasidmaster[nasid]) == 0) { - synergy_init(nasid, syn); - test_and_set_bit(syn+2, &nasidmaster[nasid]); - } else - while (get_bit(syn+2, &nasidmaster[nasid]) == 0); -#else nasid = (lid>>16)&0xfff; cpu = (lid>>28)&3; syn = 0; -#endif /* * Now pick a nasid master to initialize Bedrock registers. diff --git a/arch/ia64/sn/fakeprom/make_textsym b/arch/ia64/sn/fakeprom/make_textsym index 9cce974e0cb..39eecbff6a5 100644 --- a/arch/ia64/sn/fakeprom/make_textsym +++ b/arch/ia64/sn/fakeprom/make_textsym @@ -7,7 +7,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. +# Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. # help() { @@ -37,6 +37,7 @@ while getopts "$OPTS" c ; do done shift `expr $OPTIND - 1` +#OBJDUMP=/usr/bin/ia64-linux-objdump LINUX=${1:-vmlinux} TEXTSYM=${2:-${LINUX}.sym} TMPSYM=${2:-${LINUX}.sym.tmp} @@ -130,6 +131,8 @@ END awk ' +/ _start$/ {start=1} +/ start_ap$/ {start=1} /__start_gate_section/ {start=1} /^'${dataprefix}\|${textprefix}'/ { if ($4 == ".kdb") @@ -142,7 +145,7 @@ awk ' n = 0 s = $(NF-1) while (length(s) > 0) { - n = n*16 + substr(s,1,1) + n = n*16 + (index("0123456789abcdef", substr(s,1,1)) - 1) s = substr(s,2) } printf "GLOBAL | %s | DATA | %s | %d\n", $1, $NF, n diff --git a/arch/ia64/sn/io/Makefile b/arch/ia64/sn/io/Makefile index 8622f00bc7d..b2080573dc8 100644 --- a/arch/ia64/sn/io/Makefile +++ b/arch/ia64/sn/io/Makefile @@ -11,16 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -ifdef CONFIG_IA64_SGI_SN2 -EXTRA_CFLAGS += -DSHUB_SWAP_WAR -endif - -obj-$(CONFIG_IA64_SGI_SN) += stubs.o sgi_if.o xswitch.o klgraph_hack.o \ - hcl.o labelcl.o invent.o sgi_io_sim.o \ - klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \ - alenlist.o pci.o pci_dma.o ate_utils.o \ - ifconfig_net.o io.o ioconfig_bus.o - -obj-$(CONFIG_IA64_SGI_SN2) += sn2/ - -obj-$(CONFIG_PCIBA) += pciba.o +obj-y += sgi_if.o xswitch.o sgi_io_sim.o cdl.o ate_utils.o \ + io.o machvec/ drivers/ platform_init/ sn2/ hwgfs/ diff --git a/arch/ia64/sn/io/alenlist.c b/arch/ia64/sn/io/alenlist.c deleted file mode 100644 index 329407f6cce..00000000000 --- a/arch/ia64/sn/io/alenlist.c +++ /dev/null @@ -1,899 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* Implementation of Address/Length Lists. */ - - -#include -#include -#include -#include -#include - -/* - * Logically, an Address/Length List is a list of Pairs, where each pair - * holds an Address and a Length, all in some Address Space. In this - * context, "Address Space" is a particular Crosstalk Widget address - * space, a PCI device address space, a VME bus address space, a - * physical memory address space, etc. - * - * The main use for these Lists is to provide a single mechanism that - * describes where in an address space a DMA occurs. This allows the - * various I/O Bus support layers to provide a single interface for - * DMA mapping and DMA translation without regard to how the DMA target - * was specified by upper layers. The upper layers commonly specify a - * DMA target via a buf structure page list, a kernel virtual address, - * a user virtual address, a vector of addresses (a la uio and iov), - * or possibly a pfn list. - * - * Address/Length Lists also enable drivers to take advantage of their - * inate scatter/gather capabilities in systems where some address - * translation may be required between bus adapters. The driver forms - * a List that represents physical memory targets. This list is passed - * to the various adapters, which apply various translations. The final - * list that's returned to the driver is in terms of its local address - * address space -- addresses which can be passed off to a scatter/gather - * capable DMA controller. - * - * The current implementation is intended to be useful both in kernels - * that support interrupt threads (INTR_KTHREAD) and in systems that do - * not support interrupt threads. Of course, in the latter case, some - * interfaces can be called only within a suspendable context. - * - * Basic operations on Address/Length Lists include: - * alenlist_create Create a list - * alenlist_clear Clear a list - * alenlist_destroy Destroy a list - * alenlist_append Append a Pair to the end of a list - * alenlist_replace Replace a Pair in the middle of a list - * alenlist_get Get an Address/Length Pair from a list - * alenlist_size Return the number of Pairs in a list - * alenlist_concat Append one list to the end of another - * alenlist_clone Create a new copy of a list - * - * Operations that convert from upper-level specifications to Address/ - * Length Lists currently include: - * kvaddr_to_alenlist Convert from a kernel virtual address - * uvaddr_to_alenlist Convert from a user virtual address - * buf_to_alenlist Convert from a buf structure - * alenlist_done Tell system that we're done with an alenlist - * obtained from a conversion. - * Additional convenience operations: - * alenpair_init Create a list and initialize it with a Pair - * alenpair_get Peek at the first pair on a List - * - * A supporting type for Address/Length Lists is an alenlist_cursor_t. A - * cursor marks a position in a List, and determines which Pair is fetched - * by alenlist_get. - * alenlist_cursor_create Allocate and initialize a cursor - * alenlist_cursor_destroy Free space consumed by a cursor - * alenlist_cursor_init (Re-)Initialize a cursor to point - * to the start of a list - * alenlist_cursor_clone Clone a cursor (at the current offset) - * alenlist_cursor_offset Return the number of bytes into - * a list that this cursor marks - * Multiple cursors can point at various points into a List. Also, each - * list maintains one "internal cursor" which may be updated by alenlist_clear - * and alenlist_get. If calling code simply wishes to scan sequentially - * through a list starting at the beginning, and if it is the only user of - * a list, it can rely on this internal cursor rather than managing a - * separate explicit cursor. - * - * The current implementation allows callers to allocate both cursors and - * the lists as local stack (structure) variables. This allows for some - * extra efficiency at the expense of forward binary compatibility. It - * is recommended that customer drivers refrain from local allocation. - * In fact, we likely will choose to move the structures out of the public - * header file into a private place in order to discourage this usage. - * - * Currently, no locking is provided by the alenlist implementation. - * - * Implementation notes: - * For efficiency, Pairs are grouped into "chunks" of, say, 32 Pairs - * and a List consists of some number of these chunks. Chunks are completely - * invisible to calling code. Chunks should be large enough to hold most - * standard-sized DMA's, but not so large that they consume excessive space. - * - * It is generally expected that Lists will be constructed at one time and - * scanned at a later time. It is NOT expected that drivers will scan - * a List while the List is simultaneously extended, although this is - * theoretically possible with sufficient upper-level locking. - * - * In order to support demands of Real-Time drivers and in order to support - * swapping under low-memory conditions, we support the concept of a - * "pre-allocated fixed-sized List". After creating a List with - * alenlist_create, a driver may explicitly grow the list (via "alenlist_grow") - * to a specific number of Address/Length pairs. It is guaranteed that future - * operations involving this list will never automatically grow the list - * (i.e. if growth is ever required, the operation will fail). Additionally, - * operations that use alenlist's (e.g. DMA operations) accept a flag which - * causes processing to take place "in-situ"; that is, the input alenlist - * entries are replaced with output alenlist entries. The combination of - * pre-allocated Lists and in-situ processing allows us to avoid the - * potential deadlock scenario where we sleep (waiting for memory) in the - * swap out path. - * - * For debugging, we track the number of allocated Lists in alenlist_count - * the number of allocated chunks in alenlist_chunk_count, and the number - * of allocate cursors in alenlist_cursor_count. We also provide a debug - * routine, alenlist_show, which dumps the contents of an Address/Length List. - * - * Currently, Lists are formed by drivers on-demand. Eventually, we may - * associate an alenlist with a buf structure and keep it up to date as - * we go along. In that case, buf_to_alenlist simply returns a pointer - * to the existing List, and increments the Lists's reference count. - * alenlist_done would decrement the reference count and destroys the List - * if it was the last reference. - * - * Eventually alenlist's may allow better support for user-level scatter/ - * gather operations (e.g. via readv/writev): With proper support, we - * could potentially handle a vector of reads with a single scatter/gather - * DMA operation. This could be especially useful on NUMA systems where - * there's more of a reason for users to use vector I/O operations. - * - * Eventually, alenlist's may replace kaio lists, vhand page lists, - * buffer cache pfdat lists, DMA page lists, etc. - */ - -/* Opaque data types */ - -/* An Address/Length pair. */ -typedef struct alen_s { - alenaddr_t al_addr; - size_t al_length; -} alen_t; - -/* - * Number of elements in one chunk of an Address/Length List. - * - * This size should be sufficient to hold at least an "average" size - * DMA request. Must be at least 1, and should be a power of 2, - * for efficiency. - */ -#define ALEN_CHUNK_SZ ((512*1024)/NBPP) - -/* - * A fixed-size set of Address/Length Pairs. Chunks of Pairs are strung together - * to form a complete Address/Length List. Chunking is entirely hidden within the - * alenlist implementation, and it simply makes allocation and growth of lists more - * efficient. - */ -typedef struct alenlist_chunk_s { - alen_t alc_pair[ALEN_CHUNK_SZ];/* list of addr/len pairs */ - struct alenlist_chunk_s *alc_next; /* point to next chunk of pairs */ -} *alenlist_chunk_t; - -/* - * An Address/Length List. An Address/Length List is allocated with alenlist_create. - * Alternatively, a list can be allocated on the stack (local variable of type - * alenlist_t) and initialized with alenpair_init or with a combination of - * alenlist_clear and alenlist_append, etc. Code which statically allocates these - * structures loses forward binary compatibility! - * - * A statically allocated List is sufficiently large to hold ALEN_CHUNK_SZ pairs. - */ -struct alenlist_s { - unsigned short al_flags; - unsigned short al_logical_size; /* logical size of list, in pairs */ - unsigned short al_actual_size; /* actual size of list, in pairs */ - struct alenlist_chunk_s *al_last_chunk; /* pointer to last logical chunk */ - struct alenlist_cursor_s al_cursor; /* internal cursor */ - struct alenlist_chunk_s al_chunk; /* initial set of pairs */ - alenaddr_t al_compaction_address; /* used to compact pairs */ -}; - -/* al_flags field */ -#define AL_FIXED_SIZE 0x1 /* List is pre-allocated, and of fixed size */ - - -struct zone *alenlist_zone = NULL; -struct zone *alenlist_chunk_zone = NULL; -struct zone *alenlist_cursor_zone = NULL; - -#if DEBUG -int alenlist_count=0; /* Currently allocated Lists */ -int alenlist_chunk_count = 0; /* Currently allocated chunks */ -int alenlist_cursor_count = 0; /* Currently allocate cursors */ -#define INCR_COUNT(ptr) atomic_inc((ptr)); -#define DECR_COUNT(ptr) atomic_dec((ptr)); -#else -#define INCR_COUNT(ptr) -#define DECR_COUNT(ptr) -#endif /* DEBUG */ - -#if DEBUG -static void alenlist_show(alenlist_t); -#endif /* DEBUG */ - -/* - * Initialize Address/Length List management. One time initialization. - */ -void -alenlist_init(void) -{ - alenlist_zone = snia_kmem_zone_init(sizeof(struct alenlist_s), "alenlist"); - alenlist_chunk_zone = snia_kmem_zone_init(sizeof(struct alenlist_chunk_s), "alchunk"); - alenlist_cursor_zone = snia_kmem_zone_init(sizeof(struct alenlist_cursor_s), "alcursor"); -#if DEBUG - idbg_addfunc("alenshow", alenlist_show); -#endif /* DEBUG */ -} - - -/* - * Initialize an Address/Length List cursor. - */ -static void -do_cursor_init(alenlist_t alenlist, alenlist_cursor_t cursorp) -{ - cursorp->al_alenlist = alenlist; - cursorp->al_offset = 0; - cursorp->al_chunk = &alenlist->al_chunk; - cursorp->al_index = 0; - cursorp->al_bcount = 0; -} - - -/* - * Create an Address/Length List, and clear it. - * Set the cursor to the beginning. - */ -alenlist_t -alenlist_create(unsigned flags) -{ - alenlist_t alenlist; - - alenlist = snia_kmem_zone_alloc(alenlist_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - if (alenlist) { - INCR_COUNT(&alenlist_count); - - alenlist->al_flags = 0; - alenlist->al_logical_size = 0; - alenlist->al_actual_size = ALEN_CHUNK_SZ; - alenlist->al_last_chunk = &alenlist->al_chunk; - alenlist->al_chunk.alc_next = NULL; - do_cursor_init(alenlist, &alenlist->al_cursor); - } - - return(alenlist); -} - - -/* - * Grow an Address/Length List so that all resources needed to contain - * the specified number of Pairs are pre-allocated. An Address/Length - * List that has been explicitly "grown" will never *automatically* - * grow, shrink, or be destroyed. - * - * Pre-allocation is useful for Real-Time drivers and for drivers that - * may be used along the swap-out path and therefore cannot afford to - * sleep until memory is freed. - * - * The cursor is set to the beginning of the list. - */ -int -alenlist_grow(alenlist_t alenlist, size_t npairs) -{ - /* - * This interface should be used relatively rarely, so - * the implementation is kept simple: We clear the List, - * then append npairs bogus entries. Finally, we mark - * the list as FIXED_SIZE and re-initialize the internal - * cursor. - */ - - /* - * Temporarily mark as non-fixed size, since we're about - * to shrink and expand it. - */ - alenlist->al_flags &= ~AL_FIXED_SIZE; - - /* Free whatever was in the alenlist. */ - alenlist_clear(alenlist); - - /* Allocate everything that we need via automatic expansion. */ - while (npairs--) - if (alenlist_append(alenlist, 0, 0, AL_NOCOMPACT) == ALENLIST_FAILURE) - return(ALENLIST_FAILURE); - - /* Now, mark as FIXED_SIZE */ - alenlist->al_flags |= AL_FIXED_SIZE; - - /* Clear out bogus entries */ - alenlist_clear(alenlist); - - /* Initialize internal cursor to the beginning */ - do_cursor_init(alenlist, &alenlist->al_cursor); - - return(ALENLIST_SUCCESS); -} - - -/* - * Clear an Address/Length List so that it holds no pairs. - */ -void -alenlist_clear(alenlist_t alenlist) -{ - alenlist_chunk_t chunk, freechunk; - - /* - * If this List is not FIXED_SIZE, free all the - * extra chunks. - */ - if (!(alenlist->al_flags & AL_FIXED_SIZE)) { - /* First, free any extension alenlist chunks */ - chunk = alenlist->al_chunk.alc_next; - while (chunk) { - freechunk = chunk; - chunk = chunk->alc_next; - snia_kmem_zone_free(alenlist_chunk_zone, freechunk); - DECR_COUNT(&alenlist_chunk_count); - } - alenlist->al_actual_size = ALEN_CHUNK_SZ; - alenlist->al_chunk.alc_next = NULL; - } - - alenlist->al_logical_size = 0; - alenlist->al_last_chunk = &alenlist->al_chunk; - do_cursor_init(alenlist, &alenlist->al_cursor); -} - - -/* - * Create and initialize an Address/Length Pair. - * This is intended for degenerate lists, consisting of a single - * address/length pair. - */ -alenlist_t -alenpair_init( alenaddr_t address, - size_t length) -{ - alenlist_t alenlist; - - alenlist = alenlist_create(0); - - alenlist->al_logical_size = 1; - ASSERT(alenlist->al_last_chunk == &alenlist->al_chunk); - alenlist->al_chunk.alc_pair[0].al_length = length; - alenlist->al_chunk.alc_pair[0].al_addr = address; - - return(alenlist); -} - -/* - * Return address/length from a degenerate (1-pair) List, or - * first pair from a larger list. Does NOT update the internal cursor, - * so this is an easy way to peek at a start address. - */ -int -alenpair_get( alenlist_t alenlist, - alenaddr_t *address, - size_t *length) -{ - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - - *length = alenlist->al_chunk.alc_pair[0].al_length; - *address = alenlist->al_chunk.alc_pair[0].al_addr; - return(ALENLIST_SUCCESS); -} - - -/* - * Destroy an Address/Length List. - */ -void -alenlist_destroy(alenlist_t alenlist) -{ - if (alenlist == NULL) - return; - - /* - * Turn off FIXED_SIZE so this List can be - * automatically shrunk. - */ - alenlist->al_flags &= ~AL_FIXED_SIZE; - - /* Free extension chunks first */ - if (alenlist->al_chunk.alc_next) - alenlist_clear(alenlist); - - /* Now, free the alenlist itself */ - snia_kmem_zone_free(alenlist_zone, alenlist); - DECR_COUNT(&alenlist_count); -} - -/* - * Release an Address/Length List. - * This is in preparation for a day when alenlist's may be longer-lived, and - * perhaps associated with a buf structure. We'd add a reference count, and - * this routine would decrement the count. For now, we create alenlist's on - * on demand and free them when done. If the driver is not explicitly managing - * a List for its own use, it should call alenlist_done rather than alenlist_destroy. - */ -void -alenlist_done(alenlist_t alenlist) -{ - alenlist_destroy(alenlist); -} - - -/* - * Append another address/length to the end of an Address/Length List, - * growing the list if permitted and necessary. - * - * Returns: SUCCESS/FAILURE - */ -int -alenlist_append( alenlist_t alenlist, /* append to this list */ - alenaddr_t address, /* address to append */ - size_t length, /* length to append */ - unsigned flags) -{ - alen_t *alenp; - int index, last_index; - - index = alenlist->al_logical_size % ALEN_CHUNK_SZ; - - if ((alenlist->al_logical_size > 0)) { - /* - * See if we can compact this new pair in with the previous entry. - * al_compaction_address holds that value that we'd need to see - * in order to compact. - */ - if (!(flags & AL_NOCOMPACT) && - (alenlist->al_compaction_address == address)) { - last_index = (alenlist->al_logical_size-1) % ALEN_CHUNK_SZ; - alenp = &(alenlist->al_last_chunk->alc_pair[last_index]); - alenp->al_length += length; - alenlist->al_compaction_address += length; - return(ALENLIST_SUCCESS); - } - - /* - * If we're out of room in this chunk, move to a new chunk. - */ - if (index == 0) { - if (alenlist->al_flags & AL_FIXED_SIZE) { - alenlist->al_last_chunk = alenlist->al_last_chunk->alc_next; - - /* If we're out of space in a FIXED_SIZE List, quit. */ - if (alenlist->al_last_chunk == NULL) { - ASSERT(alenlist->al_logical_size == alenlist->al_actual_size); - return(ALENLIST_FAILURE); - } - } else { - alenlist_chunk_t new_chunk; - - new_chunk = snia_kmem_zone_alloc(alenlist_chunk_zone, - flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - - if (new_chunk == NULL) - return(ALENLIST_FAILURE); - - alenlist->al_last_chunk->alc_next = new_chunk; - new_chunk->alc_next = NULL; - alenlist->al_last_chunk = new_chunk; - alenlist->al_actual_size += ALEN_CHUNK_SZ; - INCR_COUNT(&alenlist_chunk_count); - } - } - } - - alenp = &(alenlist->al_last_chunk->alc_pair[index]); - alenp->al_addr = address; - alenp->al_length = length; - - alenlist->al_logical_size++; - alenlist->al_compaction_address = address + length; - - return(ALENLIST_SUCCESS); -} - - -/* - * Replace an item in an Address/Length List. Cursor is updated so - * that alenlist_get will get the next item in the list. This interface - * is not very useful for drivers; but it is useful to bus providers - * that need to translate between address spaced in situ. The old Address - * and Length are returned. - */ -/* ARGSUSED */ -int -alenlist_replace( alenlist_t alenlist, /* in: replace in this list */ - alenlist_cursor_t cursorp, /* inout: which item to replace */ - alenaddr_t *addrp, /* inout: address */ - size_t *lengthp, /* inout: length */ - unsigned flags) -{ - alen_t *alenp; - alenlist_chunk_t chunk; - unsigned int index; - size_t length; - alenaddr_t addr; - - if ((addrp == NULL) || (lengthp == NULL)) - return(ALENLIST_FAILURE); - - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - - addr = *addrp; - length = *lengthp; - - /* - * If no cursor explicitly specified, use the Address/Length List's - * internal cursor. - */ - if (cursorp == NULL) - cursorp = &alenlist->al_cursor; - - chunk = cursorp->al_chunk; - index = cursorp->al_index; - - ASSERT(cursorp->al_alenlist == alenlist); - if (cursorp->al_alenlist != alenlist) - return(ALENLIST_FAILURE); - - alenp = &chunk->alc_pair[index]; - - /* Return old values */ - *addrp = alenp->al_length; - *lengthp = alenp->al_addr; - - /* Set up new values */ - alenp->al_length = length; - alenp->al_addr = addr; - - /* Update cursor to point to next item */ - cursorp->al_bcount = length; - - return(ALENLIST_SUCCESS); -} - - -/* - * Initialize a cursor in order to walk an alenlist. - * An alenlist_cursor always points to the last thing that was obtained - * from the list. If al_chunk is NULL, then nothing has yet been obtained. - * - * Note: There is an "internal cursor" associated with every Address/Length List. - * For users that scan sequentially through a List, it is more efficient to - * simply use the internal cursor. The caller must insure that no other users - * will simultaneously scan the List. The caller can reposition the internal - * cursor by calling alenlist_cursor_init with a NULL cursorp. - */ -int -alenlist_cursor_init(alenlist_t alenlist, size_t offset, alenlist_cursor_t cursorp) -{ - size_t byte_count; - - if (cursorp == NULL) - cursorp = &alenlist->al_cursor; - - /* Get internal cursor's byte count for use as a hint. - * - * If the internal cursor points passed the point that we're interested in, - * we need to seek forward from the beginning. Otherwise, we can seek forward - * from the internal cursor. - */ - if ((offset > 0) && - ((byte_count = alenlist_cursor_offset(alenlist, (alenlist_cursor_t)NULL)) <= offset)) { - offset -= byte_count; - alenlist_cursor_clone(alenlist, NULL, cursorp); - } else - do_cursor_init(alenlist, cursorp); - - /* We could easily speed this up, but it shouldn't be used very often. */ - while (offset != 0) { - alenaddr_t addr; - size_t length; - - if (alenlist_get(alenlist, cursorp, offset, &addr, &length, 0) != ALENLIST_SUCCESS) - return(ALENLIST_FAILURE); - offset -= length; - } - return(ALENLIST_SUCCESS); -} - - -/* - * Copy a cursor. The source cursor is either an internal alenlist cursor - * or an explicit cursor. - */ -int -alenlist_cursor_clone( alenlist_t alenlist, - alenlist_cursor_t cursorp_in, - alenlist_cursor_t cursorp_out) -{ - ASSERT(cursorp_out); - - if (alenlist && cursorp_in) - if (alenlist != cursorp_in->al_alenlist) - return(ALENLIST_FAILURE); - - if (alenlist) - *cursorp_out = alenlist->al_cursor; /* small structure copy */ - else if (cursorp_in) - *cursorp_out = *cursorp_in; /* small structure copy */ - else - return(ALENLIST_FAILURE); /* no source */ - - return(ALENLIST_SUCCESS); -} - -/* - * Return the number of bytes passed so far according to the specified cursor. - * If cursorp is NULL, use the alenlist's internal cursor. - */ -size_t -alenlist_cursor_offset(alenlist_t alenlist, alenlist_cursor_t cursorp) -{ - ASSERT(!alenlist || !cursorp || (alenlist == cursorp->al_alenlist)); - - if (cursorp == NULL) { - ASSERT(alenlist); - cursorp = &alenlist->al_cursor; - } - - return(cursorp->al_offset); -} - -/* - * Allocate and initialize an Address/Length List cursor. - */ -alenlist_cursor_t -alenlist_cursor_create(alenlist_t alenlist, unsigned flags) -{ - alenlist_cursor_t cursorp; - - ASSERT(alenlist != NULL); - cursorp = snia_kmem_zone_alloc(alenlist_cursor_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - if (cursorp) { - INCR_COUNT(&alenlist_cursor_count); - alenlist_cursor_init(alenlist, 0, cursorp); - } - return(cursorp); -} - -/* - * Free an Address/Length List cursor. - */ -void -alenlist_cursor_destroy(alenlist_cursor_t cursorp) -{ - DECR_COUNT(&alenlist_cursor_count); - snia_kmem_zone_free(alenlist_cursor_zone, cursorp); -} - - -/* - * Fetch an address/length pair from an Address/Length List. Update - * the "cursor" so that next time this routine is called, we'll get - * the next address range. Never return a length that exceeds maxlength - * (if non-zero). If maxlength is a power of 2, never return a length - * that crosses a maxlength boundary. [This may seem strange at first, - * but it's what many drivers want.] - * - * Returns: SUCCESS/FAILURE - */ -int -alenlist_get( alenlist_t alenlist, /* in: get from this list */ - alenlist_cursor_t cursorp, /* inout: which item to get */ - size_t maxlength, /* in: at most this length */ - alenaddr_t *addrp, /* out: address */ - size_t *lengthp, /* out: length */ - unsigned flags) -{ - alen_t *alenp; - alenlist_chunk_t chunk; - unsigned int index; - size_t bcount; - size_t length; - - /* - * If no cursor explicitly specified, use the Address/Length List's - * internal cursor. - */ - if (cursorp == NULL) { - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - cursorp = &alenlist->al_cursor; - } - - chunk = cursorp->al_chunk; - index = cursorp->al_index; - bcount = cursorp->al_bcount; - - ASSERT(cursorp->al_alenlist == alenlist); - if (cursorp->al_alenlist != alenlist) - return(ALENLIST_FAILURE); - - alenp = &chunk->alc_pair[index]; - length = alenp->al_length - bcount; - - /* Bump up to next pair, if we're done with this pair. */ - if (length == 0) { - cursorp->al_bcount = bcount = 0; - cursorp->al_index = index = (index + 1) % ALEN_CHUNK_SZ; - - /* Bump up to next chunk, if we're done with this chunk. */ - if (index == 0) { - if (cursorp->al_chunk == alenlist->al_last_chunk) - return(ALENLIST_FAILURE); - chunk = chunk->alc_next; - ASSERT(chunk != NULL); - } else { - /* If in last chunk, don't go beyond end. */ - if (cursorp->al_chunk == alenlist->al_last_chunk) { - int last_size = alenlist->al_logical_size % ALEN_CHUNK_SZ; - if (last_size && (index >= last_size)) - return(ALENLIST_FAILURE); - } - } - - alenp = &chunk->alc_pair[index]; - length = alenp->al_length; - } - - /* Constrain what we return according to maxlength */ - if (maxlength) { - size_t maxlen1 = maxlength - 1; - - if ((maxlength & maxlen1) == 0) /* power of 2 */ - maxlength -= - ((alenp->al_addr + cursorp->al_bcount) & maxlen1); - - length = min(maxlength, length); - } - - /* Update the cursor, if desired. */ - if (!(flags & AL_LEAVE_CURSOR)) { - cursorp->al_bcount += length; - cursorp->al_chunk = chunk; - } - - *lengthp = length; - *addrp = alenp->al_addr + bcount; - - return(ALENLIST_SUCCESS); -} - - -/* - * Return the number of pairs in the specified Address/Length List. - * (For FIXED_SIZE Lists, this returns the logical size of the List, - * not the actual capacity of the List.) - */ -int -alenlist_size(alenlist_t alenlist) -{ - return(alenlist->al_logical_size); -} - - -/* - * Concatenate two Address/Length Lists. - */ -void -alenlist_concat(alenlist_t from, - alenlist_t to) -{ - struct alenlist_cursor_s cursor; - alenaddr_t addr; - size_t length; - - alenlist_cursor_init(from, 0, &cursor); - - while(alenlist_get(from, &cursor, (size_t)0, &addr, &length, 0) == ALENLIST_SUCCESS) - alenlist_append(to, addr, length, 0); -} - -/* - * Create a copy of a list. - * (Not all attributes of the old list are cloned. For instance, if - * a FIXED_SIZE list is cloned, the resulting list is NOT FIXED_SIZE.) - */ -alenlist_t -alenlist_clone(alenlist_t old_list, unsigned flags) -{ - alenlist_t new_list; - - new_list = alenlist_create(flags); - if (new_list != NULL) - alenlist_concat(old_list, new_list); - - return(new_list); -} - - -/* - * Convert a kernel virtual address to a Physical Address/Length List. - */ -alenlist_t -kvaddr_to_alenlist(alenlist_t alenlist, caddr_t kvaddr, size_t length, unsigned flags) -{ - alenaddr_t paddr; - long offset; - size_t piece_length; - int created_alenlist; - - if (length <=0) - return(NULL); - - /* If caller supplied a List, use it. Otherwise, allocate one. */ - if (alenlist == NULL) { - alenlist = alenlist_create(0); - created_alenlist = 1; - } else { - alenlist_clear(alenlist); - created_alenlist = 0; - } - - paddr = kvtophys(kvaddr); - offset = poff(kvaddr); - - /* Handle first page */ - piece_length = min((size_t)(NBPP - offset), length); - if (alenlist_append(alenlist, paddr, piece_length, flags) == ALENLIST_FAILURE) - goto failure; - length -= piece_length; - kvaddr += piece_length; - - /* Handle middle pages */ - while (length >= NBPP) { - paddr = kvtophys(kvaddr); - if (alenlist_append(alenlist, paddr, NBPP, flags) == ALENLIST_FAILURE) - goto failure; - length -= NBPP; - kvaddr += NBPP; - } - - /* Handle last page */ - if (length) { - ASSERT(length < NBPP); - paddr = kvtophys(kvaddr); - if (alenlist_append(alenlist, paddr, length, flags) == ALENLIST_FAILURE) - goto failure; - } - - alenlist_cursor_init(alenlist, 0, NULL); - return(alenlist); - -failure: - if (created_alenlist) - alenlist_destroy(alenlist); - return(NULL); -} - - -#if DEBUG -static void -alenlist_show(alenlist_t alenlist) -{ - struct alenlist_cursor_s cursor; - alenaddr_t addr; - size_t length; - int i = 0; - - alenlist_cursor_init(alenlist, 0, &cursor); - - qprintf("Address/Length List@0x%x:\n", alenlist); - qprintf("logical size=0x%x actual size=0x%x last_chunk at 0x%x\n", - alenlist->al_logical_size, alenlist->al_actual_size, - alenlist->al_last_chunk); - qprintf("cursor: chunk=0x%x index=%d offset=0x%x\n", - alenlist->al_cursor.al_chunk, - alenlist->al_cursor.al_index, - alenlist->al_cursor.al_bcount); - while(alenlist_get(alenlist, &cursor, (size_t)0, &addr, &length, 0) == ALENLIST_SUCCESS) - qprintf("%d:\t0x%lx 0x%lx\n", ++i, addr, length); -} -#endif /* DEBUG */ diff --git a/arch/ia64/sn/io/ate_utils.c b/arch/ia64/sn/io/ate_utils.c index a789a164861..a5b11ae21b5 100644 --- a/arch/ia64/sn/io/ate_utils.c +++ b/arch/ia64/sn/io/ate_utils.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/arch/ia64/sn/io/cdl.c b/arch/ia64/sn/io/cdl.c index 8ffba2495ee..f5a0e5f2cae 100644 --- a/arch/ia64/sn/io/cdl.c +++ b/arch/ia64/sn/io/cdl.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -18,9 +18,9 @@ #include /* these get called directly in cdl_add_connpt in fops bypass hack */ -extern int pcibr_attach(devfs_handle_t); -extern int xbow_attach(devfs_handle_t); -extern int pic_attach(devfs_handle_t); +extern int pcibr_attach(vertex_hdl_t); +extern int xbow_attach(vertex_hdl_t); +extern int pic_attach(vertex_hdl_t); /* @@ -32,75 +32,20 @@ extern int pic_attach(devfs_handle_t); * IO Infrastructure Drivers e.g. pcibr. */ -struct cdl { - int part_num; - int mfg_num; - int (*attach) (devfs_handle_t); -} dummy_reg; - -#ifdef CONFIG_IA64_SGI_SN1 -#define MAX_SGI_IO_INFRA_DRVR 4 -#else #define MAX_SGI_IO_INFRA_DRVR 7 -#endif + static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = { { XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, { BRIDGE_WIDGET_PART_NUM, BRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, -#ifndef CONFIG_IA64_SGI_SN1 { PIC_WIDGET_PART_NUM_BUS0, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, { PIC_WIDGET_PART_NUM_BUS1, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, -#endif { XXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, { XBOW_WIDGET_PART_NUM, XBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, -#ifndef CONFIG_IA64_SGI_SN1 { PXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, -#endif }; /* - * cdl_new: Called by pciio and xtalk. - */ -cdl_p -cdl_new(char *name, char *k1str, char *k2str) -{ - /* - * Just return a dummy pointer. - */ - return((cdl_p)&dummy_reg); -} - -/* - * cdl_del: Do nothing. - */ -void -cdl_del(cdl_p reg) -{ - return; -} - -/* - * cdl_add_driver: The driver part number and manufacturers number - * are statically initialized above. - * - Do nothing. - */ -int -cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags, cdl_drv_f *func) -{ - return 0; -} - -/* - * cdl_del_driver: Not supported. - */ -void -cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func) -{ - return; -} - -/* * cdl_add_connpt: We found a device and it's connect point. Call the * attach routine of that driver. * @@ -112,8 +57,8 @@ cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func) * vertices. */ int -cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, - devfs_handle_t connpt, int drv_flags) +cdl_add_connpt(int part_num, int mfg_num, + vertex_hdl_t connpt, int drv_flags) { int i; @@ -121,7 +66,6 @@ cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, * Find the driver entry point and call the attach routine. */ for (i = 0; i < MAX_SGI_IO_INFRA_DRVR; i++) { - if ( (part_num == sgi_infrastructure_drivers[i].part_num) && ( mfg_num == sgi_infrastructure_drivers[i].mfg_num) ) { /* @@ -139,73 +83,3 @@ cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, return (0); } - -/* - * cdl_del_connpt: Not implemented. - */ -int -cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt, int drv_flags) -{ - - return(0); -} - -/* - * cdl_iterate: Not Implemented. - */ -void -cdl_iterate(cdl_p reg, - char *prefix, - cdl_iter_f * func) -{ - return; -} - -async_attach_t -async_attach_new(void) -{ - - return(0); -} - -void -async_attach_free(async_attach_t aa) -{ - return; -} - -async_attach_t -async_attach_get_info(devfs_handle_t vhdl) -{ - - return(0); -} - -void -async_attach_add_info(devfs_handle_t vhdl, async_attach_t aa) -{ - return; - -} - -void -async_attach_del_info(devfs_handle_t vhdl) -{ - return; -} - -void async_attach_signal_start(async_attach_t aa) -{ - return; -} - -void async_attach_signal_done(async_attach_t aa) -{ - return; -} - -void async_attach_waitall(async_attach_t aa) -{ - return; -} - diff --git a/arch/ia64/sn/io/drivers/Makefile b/arch/ia64/sn/io/drivers/Makefile new file mode 100644 index 00000000000..b0d1ee12743 --- /dev/null +++ b/arch/ia64/sn/io/drivers/Makefile @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += ioconfig_bus.o ifconfig_net.o diff --git a/arch/ia64/sn/io/ifconfig_net.c b/arch/ia64/sn/io/drivers/ifconfig_net.c similarity index 97% rename from arch/ia64/sn/io/ifconfig_net.c rename to arch/ia64/sn/io/drivers/ifconfig_net.c index c7b2b27edcc..87febc7f3e8 100644 --- a/arch/ia64/sn/io/ifconfig_net.c +++ b/arch/ia64/sn/io/drivers/ifconfig_net.c @@ -6,7 +6,7 @@ * * ifconfig_net - SGI's Persistent Network Device names. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -37,8 +37,8 @@ /* * Some Global definitions. */ -devfs_handle_t ifconfig_net_handle = NULL; -unsigned long ifconfig_net_debug = 0; +static devfs_handle_t ifconfig_net_handle; +static unsigned long ifconfig_net_debug; /* * ifconfig_net_open - Opens the special device node "/devhw/.ifconfig_net". @@ -284,7 +284,7 @@ int __init init_ifconfig_net(void) { ifconfig_net_handle = NULL; ifconfig_net_handle = hwgraph_register(hwgraph_root, ".ifconfig_net", - 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, &ifconfig_net_fops, NULL); diff --git a/arch/ia64/sn/io/ioconfig_bus.c b/arch/ia64/sn/io/drivers/ioconfig_bus.c similarity index 94% rename from arch/ia64/sn/io/ioconfig_bus.c rename to arch/ia64/sn/io/drivers/ioconfig_bus.c index 91dea65c3fc..66dfaf0f1ed 100644 --- a/arch/ia64/sn/io/ioconfig_bus.c +++ b/arch/ia64/sn/io/drivers/ioconfig_bus.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -35,8 +34,8 @@ /* * Some Global definitions. */ -devfs_handle_t ioconfig_bus_handle = NULL; -unsigned long ioconfig_bus_debug = 0; +static vertex_hdl_t ioconfig_bus_handle; +static unsigned long ioconfig_bus_debug; #ifdef IOCONFIG_BUS_DEBUG #define DBG(x...) printk(x) @@ -44,22 +43,22 @@ unsigned long ioconfig_bus_debug = 0; #define DBG(x...) #endif -u64 ioconfig_file = 0; -u64 ioconfig_file_size = 0; -u64 ioconfig_activated = 0; -char ioconfig_kernopts[128]; +static u64 ioconfig_file; +static u64 ioconfig_file_size; +static u64 ioconfig_activated; +static char ioconfig_kernopts[128]; /* * For debugging purpose .. hardcode a table .. */ struct ascii_moduleid *ioconfig_bus_table; -u64 ioconfig_bus_table_size = 0; +u64 ioconfig_bus_table_size; -int free_entry = 0; -int new_entry = 0; +static int free_entry; +static int new_entry; -int next_basebus_number = 0; +int next_basebus_number; void ioconfig_get_busnum(char *io_moduleid, int *bus_num) @@ -96,8 +95,8 @@ ioconfig_get_busnum(char *io_moduleid, int *bus_num) free_entry++; } -void -dump_ioconfig_table() +static void +dump_ioconfig_table(void) { int index = 0; @@ -264,14 +263,14 @@ ioconfig_bus_init(void) */ DBG("ioconfig_bus_init: Kernel Options given.\n"); (void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table); - (void) dump_ioconfig_table(ioconfig_bus_table); + (void) dump_ioconfig_table(); return; } if (ioconfig_activated) { DBG("ioconfig_bus_init: ioconfig file given.\n"); (void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table); - (void) dump_ioconfig_table(ioconfig_bus_table); + (void) dump_ioconfig_table(); } else { DBG("ioconfig_bus_init: ioconfig command not executed in prom\n"); } @@ -295,7 +294,7 @@ ioconfig_bus_new_entries(void) index = new_entry; temp = &ioconfig_bus_table[index]; while (index < free_entry) { - printk("%s\n", temp); + printk("%s\n", (char *)temp); temp++; index++; } @@ -362,7 +361,7 @@ int init_ioconfig_bus(void) { ioconfig_bus_handle = NULL; ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", - 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, &ioconfig_bus_fops, NULL); diff --git a/arch/ia64/sn/io/eeprom.c b/arch/ia64/sn/io/eeprom.c deleted file mode 100644 index 5b190517de6..00000000000 --- a/arch/ia64/sn/io/eeprom.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * WARNING: There is more than one copy of this file in different isms. - * All copies must be kept exactly in sync. - * Do not modify this file without also updating the following: - * - * irix/kern/io/eeprom.c - * stand/arcs/lib/libsk/ml/eeprom.c - * stand/arcs/lib/libkl/io/eeprom.c - * - * (from time to time they might not be in sync but that's due to bringup - * activity - this comment is to remind us that they eventually have to - * get back together) - * - * eeprom.c - * - * access to board-mounted EEPROMs via the L1 system controllers - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(EEPROM_DEBUG) -#define db_printf(x) printk x -#else -#define db_printf(x) printk x -#endif - -#define BCOPY(x,y,z) memcpy(y,x,z) - -#define UNDERSCORE 0 /* don't convert underscores to hyphens */ -#define HYPHEN 1 /* convert underscores to hyphens */ - -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ); -uint64_t generate_unique_id( char *sn, int sn_len ); -uchar_t char_to_base36( char c ); -int nicify( char *dst, eeprom_brd_record_t *src ); -static void int64_to_hex_string( char *out, uint64_t val ); - -// extern int router_lock( net_vec_t, int, int ); -// extern int router_unlock( net_vec_t ); -#define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000) -#define ROUTER_UNLOCK(p) // router_unlock(p) - -#define IP27LOG_OVNIC "OverrideNIC" - - -/* the following function converts an EEPROM record to a close facsimile - * of the string returned by reading a Dallas Semiconductor NIC (see - * one of the many incarnations of nic.c for details on that driver) - */ -int nicify( char *dst, eeprom_brd_record_t *src ) -{ - int field_len; - uint64_t unique_id; - char *cur_dst = dst; - eeprom_board_ia_t *board; - - board = src->board_ia; - ASSERT( board ); /* there should always be a board info area */ - - /* copy part number */ - strcpy( cur_dst, "Part:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->part_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN ); - cur_dst += field_len; - - /* copy product name */ - strcpy( cur_dst, ";Name:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII ); - field_len = board->product_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE ); - cur_dst += field_len; - - /* copy serial number */ - strcpy( cur_dst, ";Serial:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->serial_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->serial_num, field_len, - HYPHEN); - - cur_dst += field_len; - - /* copy revision */ - strcpy( cur_dst, ";Revision:"); - cur_dst += strlen( cur_dst ); - ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->board_rev_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN ); - cur_dst += field_len; - - /* EEPROMs don't have equivalents for the Group, Capability and - * Variety fields, so we pad these with 0's - */ - strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" ); - cur_dst += strlen( cur_dst ); - - /* use the board serial number to "fake" a laser id */ - strcpy( cur_dst, ";Laser:" ); - cur_dst += strlen( cur_dst ); - unique_id = generate_unique_id( board->serial_num, - board->serial_num_tl & FIELD_LENGTH_MASK ); - int64_to_hex_string( cur_dst, unique_id ); - strcat( dst, ";" ); - - return 1; -} - - -/* These functions borrow heavily from chars2* in nic.c - */ -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ) -{ - int i; - for( i = 0; i < length; i++ ) { - - /* change underscores to hyphens if requested */ - if( from[i] == '_' && change_underscore == HYPHEN ) - to[i] = '-'; - - /* ; and ; are separators, so mustn't appear within - * a field */ - else if( from[i] == ':' || from[i] == ';' ) - to[i] = '?'; - - /* I'm not sure why or if ASCII character 0xff would - * show up in an EEPROM field, but the NIC parsing - * routines wouldn't like it if it did... so we - * get rid of it, just in case. */ - else if( (unsigned char)from[i] == (unsigned char)0xff ) - to[i] = ' '; - - /* unprintable characters are replaced with . */ - else if( from[i] < ' ' || from[i] >= 0x7f ) - to[i] = '.'; - - /* otherwise, just copy the character */ - else - to[i] = from[i]; - } - - if( i == 0 ) { - to[i] = ' '; /* return at least a space... */ - i++; - } - to[i] = 0; /* terminating null */ -} - -/* Note that int64_to_hex_string currently only has a big-endian - * implementation. - */ -#ifdef _MIPSEB -static void int64_to_hex_string( char *out, uint64_t val ) -{ - int i; - uchar_t table[] = "0123456789abcdef"; - uchar_t *byte_ptr = (uchar_t *)&val; - for( i = 0; i < sizeof(uint64_t); i++ ) { - out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ]; - out[i*2+1] = table[ (*byte_ptr) & 0x0f ]; - byte_ptr++; - } - out[i*2] = '\0'; -} - -#else /* little endian */ - -static void int64_to_hex_string( char *out, uint64_t val ) -{ - - - printk("int64_to_hex_string needs a little-endian implementation.\n"); -} -#endif /* _MIPSEB */ - -/* Convert a standard ASCII serial number to a unique integer - * id number by treating the serial number string as though - * it were a base 36 number - */ -uint64_t generate_unique_id( char *sn, int sn_len ) -{ - int uid = 0; - int i; - - #define VALID_BASE36(c) ((c >= '0' && c <='9') \ - || (c >= 'A' && c <='Z') \ - || (c >= 'a' && c <='z')) - - for( i = 0; i < sn_len; i++ ) { - if( !VALID_BASE36(sn[i]) ) - continue; - uid *= 36; - uid += char_to_base36( sn[i] ); - } - - if( uid == 0 ) - return rtc_time(); - - return uid; -} - -uchar_t char_to_base36( char c ) -{ - uchar_t val; - - if( c >= '0' && c <= '9' ) - val = (c - '0'); - - else if( c >= 'A' && c <= 'Z' ) - val = (c - 'A' + 10); - - else if( c >= 'a' && c <= 'z' ) - val = (c - 'a' + 10); - - else val = 0; - - return val; -} - - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ) -{ - int rval = 0; - rval += *src; src++; - rval += ((int)(*src) << 8); src ++; - rval += ((int)(*src) << 16); - return rval; -} - - -int eeprom_str( char *nic_str, nasid_t nasid, int component ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - if( (component & C_DIMM) == C_DIMM ) { - /* this function isn't applicable to DIMMs */ - return EEP_PARAM; - } - else { - eep.board_ia = &board; - eep.spd = NULL; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - } - - switch( component & BRICK_MASK ) { - case C_BRICK: - r = cbrick_eeprom_read( &eep, nasid, component ); - break; - case IO_BRICK: - r = iobrick_eeprom_read( &eep, nasid, component ); - break; - default: - return EEP_PARAM; /* must be an invalid component */ - } - if( r ) - return r; - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - - if( !(component & VECTOR) ) - return EEP_PARAM; - - if( (r = vector_eeprom_read( &eep, nasid, path, component )) ) - return r; - - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - - -int is_iobrick( int nasid, int widget_num ) -{ - uint32_t wid_reg; - int part_num, mfg_num; - - /* Read the widget's WIDGET_ID register to get - * its part number and mfg number - */ - wid_reg = *(volatile int32_t *) - (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID); - - part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT; - - /* Is this the "xbow part" of an XBridge? If so, this - * widget is definitely part of an I/O brick. - */ - if( part_num == XXBOW_WIDGET_PART_NUM && - mfg_num == XXBOW_WIDGET_MFGR_NUM ) - - return 1; - - /* Is this a "bridge part" of an XBridge? If so, once - * again, we know this widget is part of an I/O brick. - */ - if( part_num == XBRIDGE_WIDGET_PART_NUM && - mfg_num == XBRIDGE_WIDGET_MFGR_NUM ) - - return 1; - - return 0; -} - - -int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 ) - { - /* We successfully read IP27LOG_OVNIC, so return it as the UID. */ - db_printf(( "cbrick_uid_get:" - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - *uid = strtoull( uid_str, NULL, 0 ); - return EEP_OK; - } -#endif - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one. - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = ≻ - sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); - } - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( scp, subch, msg, msg, &len ) ) { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* free up subchannel */ - sc_close(scp, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - return( EEP_L1 ); - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - -#define FAIL \ - { \ - *uid = rtc_time(); \ - printk( "rbrick_uid_get failed; using current time as uid\n" ); \ - return EEP_OK; \ - } - - ROUTER_LOCK(path); - sc_init( &sc, nasid, path ); - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) { - ROUTER_UNLOCK(path); - FAIL; - } - - if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* send the request to the L1 */ - if( sc_command( &sc, subch, msg, msg, &len ) ) { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* free up subchannel */ - ROUTER_UNLOCK(path); - sc_close(&sc, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - FAIL; - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - -int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( r != EEP_OK ) { - *uid = rtc_time(); - return r; - } - - *uid = generate_unique_id( board.serial_num, - board.serial_num_tl & FIELD_LENGTH_MASK ); - - return EEP_OK; -} - - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - char *tmp; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) { - db_printf(( "ibrick_mac_addr_get: " - "Couldn't read MAC address from EEPROM\n" )); - return EEP_L1; - } - else { - /* successfully read info area */ - int ix; - tmp = board.mac_addr; - for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ ) - { - *eaddr++ = *tmp++; - } - *eaddr = '\0'; - } - - return EEP_OK; -} - - -/* - * eeprom_vertex_info_set - * - * Given a vertex handle, a component designation, a starting nasid - * and (in the case of a router) a vector path to the component, this - * function will read the EEPROM and attach the resulting information - * to the vertex in the same string format as that provided by the - * Dallas Semiconductor NIC drivers. If the vertex already has the - * string, this function just returns the string. - */ - -extern char *nic_vertex_info_get( devfs_handle_t ); -extern void nic_vmc_check( devfs_handle_t, char * ); -/* the following were lifted from nic.c - change later? */ -#define MAX_INFO 2048 -#define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) -#define DEL(ptr) (kern_free((ptr))) - -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ) -{ - char *info_tmp; - int info_len; - char *info; - - /* see if this vertex is already marked */ - info_tmp = nic_vertex_info_get(v); - if (info_tmp) return info_tmp; - - /* get a temporary place for the data */ - NEWSZ(info_tmp, MAX_INFO); - if (!info_tmp) return NULL; - - /* read the EEPROM */ - if( component & R_BRICK ) { - if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK ) - return NULL; - } - else { - if( eeprom_str( info_tmp, nasid, component ) != EEP_OK ) - return NULL; - } - - /* allocate a smaller final place */ - info_len = strlen(info_tmp)+1; - NEWSZ(info, info_len); - if (info) { - strcpy(info, info_tmp); - DEL(info_tmp); - } else { - info = info_tmp; - } - - /* add info to the vertex */ - hwgraph_info_add_LBL(v, INFO_LBL_NIC, - (arbitrary_info_t) info); - - /* see if someone else got there first */ - info_tmp = nic_vertex_info_get(v); - if (info != info_tmp) { - DEL(info); - return info_tmp; - } - - /* export the data */ - hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len); - - /* trigger all matching callbacks */ - nic_vmc_check(v, info); - - return info; -} - - -/********************************************************************* - * - * stubs for use until the Bedrock/L1 link is available - * - */ - -#include - -/* #define EEPROM_TEST */ - -/* fake eeprom reading functions (replace when the BR/L1 communication - * channel is in working order) - */ - - -/* generate a charater in [0-9A-Z]; if an "extra" character is - * specified (such as '_'), include it as one of the possibilities. - */ -char random_eeprom_ch( char extra ) -{ - char ch; - int modval = 36; - if( extra ) - modval++; - - ch = rtc_time() % modval; - - if( ch < 10 ) - ch += '0'; - else if( ch >= 10 && ch < 36 ) - ch += ('A' - 10); - else - ch = extra; - - return ch; -} - -/* create a part number of the form xxx-xxxx-xxx. - * It may be important later to generate different - * part numbers depending on the component we're - * supposed to be "reading" from, so the component - * paramter is provided. - */ -void fake_a_part_number( char *buf, int component ) -{ - int i; - switch( component ) { - - /* insert component-specific routines here */ - - case C_BRICK: - strcpy( buf, "030-1266-001" ); - break; - default: - for( i = 0; i < 12; i++ ) { - if( i == 3 || i == 8 ) - buf[i] = '-'; - else - buf[i] = random_eeprom_ch(0); - } - } -} - - -/* create a six-character serial number */ -void fake_a_serial_number( char *buf, uint64_t ser ) -{ - int i; - static const char hexchars[] = "0123456789ABCDEF"; - - if (ser) { - for( i = 5; i >=0; i-- ) { - buf[i] = hexchars[ser & 0xf]; - ser >>= 4; - } - } - else { - for( i = 0; i < 6; i++ ) - buf[i] = random_eeprom_ch(0); - } -} - - -void fake_a_product_name( uchar_t *format, char* buf, int component ) -{ - switch( component & BRICK_MASK ) { - - case C_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "C_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "IP35" ); - *format = 0xC4; - } - break; - - case R_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "R_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "R_BRICK" ); - *format = 0xC7; - } - break; - - case IO_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "IO_BRICK_SUB" ); - *format = 0xCC; - } - else { - strcpy( buf, "IO_BRICK" ); - *format = 0xC8; - } - break; - - default: - strcpy( buf, "UNK_DEVICE" ); - *format = 0xCA; - } -} - - - -int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, - uint64_t ser ) -{ - eeprom_board_ia_t *board; - eeprom_chassis_ia_t *chassis; - int i, cs; - - board = buf->board_ia; - chassis = buf->chassis_ia; - - if( !(component & SUBORD_MASK) ) { - if( !chassis ) - return EEP_PARAM; - chassis->format = 0; - chassis->length = 5; - chassis->type = 0x17; - - chassis->part_num_tl = 0xCC; - fake_a_part_number( chassis->part_num, component ); - chassis->serial_num_tl = 0xC6; - fake_a_serial_number( chassis->serial_num, ser ); - - cs = chassis->format + chassis->length + chassis->type - + chassis->part_num_tl + chassis->serial_num_tl; - for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->part_num[i]; - for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->serial_num[i]; - chassis->checksum = 256 - (cs % 256); - } - - if( !board ) - return EEP_PARAM; - board->format = 0; - board->length = 10; - board->language = 0; - board->mfg_date = 1789200; /* noon, 5/26/99 */ - board->manuf_tl = 0xC3; - strcpy( board->manuf, "SGI" ); - - fake_a_product_name( &(board->product_tl), board->product, component ); - - board->serial_num_tl = 0xC6; - fake_a_serial_number( board->serial_num, ser ); - - board->part_num_tl = 0xCC; - fake_a_part_number( board->part_num, component ); - - board->board_rev_tl = 0xC2; - board->board_rev[0] = '0'; - board->board_rev[1] = '1'; - - board->eeprom_size_tl = 0x01; - board->eeprom_size = 1; - - board->temp_waiver_tl = 0xC2; - board->temp_waiver[0] = '0'; - board->temp_waiver[1] = '1'; - - cs = board->format + board->length + board->language - + (board->mfg_date & 0xFF) - + (board->mfg_date & 0xFF00) - + (board->mfg_date & 0xFF0000) - + board->manuf_tl + board->product_tl + board->serial_num_tl - + board->part_num_tl + board->board_rev_tl - + board->board_rev[0] + board->board_rev[1] - + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl - + board->temp_waiver[0] + board->temp_waiver[1]; - for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->manuf[i]; - for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->product[i]; - for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->serial_num[i]; - for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->part_num[i]; - - board->checksum = 256 - (cs % 256); - - return EEP_OK; -} - -#define EEPROM_CHUNKSIZE 64 - -#if defined(EEPROM_DEBUG) -#define RETURN_ERROR \ -{ \ - printk( "read_ia error return, component 0x%x, line %d" \ - ", address 0x%x, ia code 0x%x\n", \ - l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \ - return EEP_L1; \ -} - -#else -#define RETURN_ERROR return(EEP_L1) -#endif - -int read_ia( l1sc_t *sc, int subch, int l1_compt, - int ia_code, char *eep_record ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ - int offset = 0; /* current offset into info area */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( ia_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, ia_code, - L1_ARG_INT, offset, - L1_ARG_INT, ia_len )) < 0 ) - { - RETURN_ERROR; - } - - /* send the request to the L1 */ - - if( sc_command( sc, subch, msg, msg, &len ) ) { - RETURN_ERROR; - } - - /* check response */ - if( sc_interpret_resp( msg, 5, - L1_ARG_INT, &ia_len, - L1_ARG_UNKNOWN, &len, eep_record ) < 0 ) - { - RETURN_ERROR; - } - - if( ia_len > EEPROM_CHUNKSIZE ) - ia_len = EEPROM_CHUNKSIZE; - - eep_record += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_spd( l1sc_t *sc, int subch, int l1_compt, - eeprom_spd_u *spd ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int resp; /* l1 response code */ - int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ - int offset = 0; /* current offset into spd record */ - char *spd_p = spd->bytes; /* "thumb" for writing to spd */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( spd_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, L1_EEP_SPD, - L1_ARG_INT, offset, - L1_ARG_INT, spd_len )) < 0 ) - { - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - return( EEP_L1 ); - } - - /* check response */ - if( (resp = sc_interpret_resp( msg, 5, - L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) - { - /* - * translate l1 response code to eeprom.c error codes: - * The L1 response will be L1_RESP_NAVAIL if the spd - * can't be read (i.e. the spd isn't physically there). It will - * return L1_RESP_INVAL if the spd exists, but fails the checksum - * test because the eeprom wasn't programmed, programmed incorrectly, - * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, - * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is - * invalid. - */ - if(resp == L1_RESP_INVAL) { - resp = EEP_BAD_CHECKSUM; - } else { - resp = EEP_L1; - } - return( resp ); - } - - if( spd_len > EEPROM_CHUNKSIZE ) - spd_len = EEPROM_CHUNKSIZE; - - spd_p += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_chassis_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* use to verify eeprom record checksum */ - int i; - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record ) - != EEP_OK ) - { - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->type = *eep_rec_p++; - - ia->part_num_tl = *eep_rec_p++; - - (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->serial_num, - (ia->serial_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->checksum = eep_record[(8 * ia->length) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_chassis_ia: bad checksum\n" )); - db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int read_board_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_board_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* running checksum total */ - int i; - - BZERO( ia, sizeof( eeprom_board_ia_t ) ); - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record ) - != EEP_OK ) - { - db_printf(( "read_board_ia: error reading info area from L1\n" )); - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_board_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->language = *eep_rec_p++; - - ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p ); - eep_rec_p += 3; - - ia->manuf_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK); - - ia->product_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK)); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->part_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - eep_rec_p++; /* we do not use the FRU file id */ - - ia->board_rev_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK); - - ia->eeprom_size_tl = *eep_rec_p++; - ia->eeprom_size = *eep_rec_p++; - - ia->temp_waiver_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->temp_waiver, - (ia->temp_waiver_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK); - - /* if there's more, we must be reading a main board; get - * additional fields - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->ekey_G_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_G, - ia->ekey_G_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK); - - ia->ekey_P_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_P, - ia->ekey_P_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK); - - ia->ekey_Y_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_Y, - ia->ekey_Y_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK); - - /* - * need to get a couple more fields if this is an I brick - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->mac_addr_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->mac_addr, - ia->mac_addr_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK); - - ia->ieee1394_cfg_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->ieee1394_cfg, - ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK ); - - } - } - - ia->checksum = eep_record[(ia->length * 8) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_board_ia: bad checksum\n" )); - db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; -#ifdef LOG_GETENV - char uid_str[32]; -#endif - int l1_compt, subch; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting a cbrick */ - if( !(component & C_BRICK) ) - return EEP_PARAM; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 ) - { - db_printf(( "_cbrick_eeprom_read: " - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - uid = strtoull( uid_str, NULL, 0 ); - } -#endif - - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if((component & C_DIMM) == C_DIMM) { - l1_compt = L1_EEP_DIMM(component & COMPT_MASK); - r = read_spd(scp,subch,l1_compt, buf->spd); - sc_close(scp,subch); - return(r); - } - - switch( component ) - { - case C_BRICK: - /* c-brick motherboard */ - l1_compt = L1_EEP_NODE; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( scp, subch ); - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - if( uid ) { - /* If IP27LOG_OVNIC is set, we want to put that value - * in as our UID. */ - fake_a_serial_number( buf->chassis_ia->serial_num, uid ); - buf->chassis_ia->serial_num_tl = 6; - } - break; - - case C_PIMM: - /* one of the PIMM boards */ - l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) - { - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - return _cbrick_eeprom_read( buf, scp, component ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - int l1_compt, subch; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're talking to an applicable brick */ - if( !(component & IO_BRICK) ) { - return EEP_PARAM; - } - - /* If we're talking to this c-brick's attached io brick, use - * the local l1sc_t; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) - return EEP_L1; - - - switch( component ) - { - case IO_BRICK: - /* IO brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - - if( r != EEP_OK ) { - sc_close( scp, subch ); - /* - * Whenever we no longer need to test on hardware - * that does not have EEPROMS, then this can be removed. - */ - r = fake_an_eeprom_record( buf, component, rtc_time() ); - return r; - } - break; - - case IO_POWER: - /* IO brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) { - return r; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; - int l1_compt, subch; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting an applicable brick */ - if( !(component & VECTOR) ) - return EEP_PARAM; - - switch( component & BRICK_MASK ) - { - case R_BRICK: - ROUTER_LOCK( path ); - sc_init( &sc, nasid, path ); - - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) - { - db_printf(( "vector_eeprom_read: couldn't open subch\n" )); - ROUTER_UNLOCK(path); - return EEP_L1; - } - switch( component ) - { - case R_BRICK: - /* r-brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - printk( "vector_eeprom_read: couldn't get rbrick eeprom info;" - " using current time as uid\n" ); - uid = rtc_time(); - db_printf(("vector_eeprom_read: using a fake eeprom record\n")); - return fake_an_eeprom_record( buf, component, uid ); - } - break; - - case R_POWER: - /* r-brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - return EEP_PARAM; - } - r = read_board_ia( &sc, subch, l1_compt, buf->board_ia ); - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - if( r != EEP_OK ) { - db_printf(( "vector_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; - - case C_BRICK: - sc_init( &sc, nasid, path ); - return _cbrick_eeprom_read( buf, &sc, component ); - - default: - /* unsupported brick type */ - return EEP_PARAM; - } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} diff --git a/arch/ia64/sn/io/efi-rtc.c b/arch/ia64/sn/io/efi-rtc.c deleted file mode 100644 index b0e12fe47dd..00000000000 --- a/arch/ia64/sn/io/efi-rtc.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. - * Copyright (C) 2001 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * No locking necessary when this is called from efirtc which protects us - * from racing by efi_rtc_lock. - */ -#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) -#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) -#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) - -#define TOD_SGS_M48T35 1 -#define TOD_DALLAS_DS1386 2 - -static unsigned long nvram_base = 0; -static int tod_chip_type; - -static int -get_tod_chip_type(void) -{ - unsigned char testval; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_DAY_ADDR, 0xff); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - - testval = read_io_port(RTC_DAL_DAY_ADDR); - if (testval == 0xff) - return TOD_SGS_M48T35; - - return TOD_DALLAS_DS1386; -} - -efi_status_t -ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - memset(time, 0, sizeof(*time)); - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); - - time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; - time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); - time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); - time->nanosecond = 0; - - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - - time->nanosecond = 0; - time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); - time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); - time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - if (caps) { - caps->resolution = 50000000; /* 50PPM */ - caps->accuracy = 1000; /* 1ms */ - caps->sets_to_zero = 0; - } - - return EFI_SUCCESS; -} - -static efi_status_t ioc3_set_time (efi_time_t *t) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); - write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - return EFI_SUCCESS; -} - -/* The following two are not supported atm. */ -static efi_status_t -ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -static efi_status_t -ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -/* - * It looks like the master IOC3 is usually on bus 0, device 4. Hope - * that's right - */ -static __init int efi_ioc3_time_init(void) -{ - struct pci_dev *dev; - static struct ioc3 *ioc3; - - dev = pci_find_slot(0, PCI_DEVFN(4, 0)); - if (!dev) { - printk(KERN_CRIT "Couldn't find master IOC3\n"); - - return -ENODEV; - } - - ioc3 = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - nvram_base = (unsigned long) ioc3 + IOC3_BYTEBUS_DEV0; - - tod_chip_type = get_tod_chip_type(); - if (tod_chip_type == 1) - printk(KERN_NOTICE "TOD type is SGS M48T35\n"); - else if (tod_chip_type == 2) - printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); - else - printk(KERN_CRIT "No or unknown TOD\n"); - - efi.get_time = ioc3_get_time; - efi.set_time = ioc3_set_time; - efi.get_wakeup_time = ioc3_get_wakeup_time; - efi.set_wakeup_time = ioc3_set_wakeup_time; - - return 0; -} - -module_init(efi_ioc3_time_init); diff --git a/arch/ia64/sn/io/hcl.c b/arch/ia64/sn/io/hcl.c deleted file mode 100644 index a8b8b98a6f8..00000000000 --- a/arch/ia64/sn/io/hcl.c +++ /dev/null @@ -1,1515 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * hcl - SGI's Hardware Graph compatibility layer. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER" -#define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE" -#define HCL_TEMP_NAME_LEN 44 -#define HCL_VERSION "1.0" -devfs_handle_t hwgraph_root = NULL; -devfs_handle_t linux_busnum = NULL; - -/* - * Debug flag definition. - */ -#define OPTION_NONE 0x00 -#define HCL_DEBUG_NONE 0x00000 -#define HCL_DEBUG_ALL 0x0ffff -#if defined(CONFIG_HCL_DEBUG) -static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; -#endif -static unsigned int hcl_debug = HCL_DEBUG_NONE; -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) -static unsigned int boot_options = OPTION_NONE; -#endif - -/* - * Some Global definitions. - */ -devfs_handle_t hcl_handle = NULL; - -invplace_t invplace_none = { - GRAPH_VERTEX_NONE, - GRAPH_VERTEX_PLACE_NONE, - NULL -}; - -/* - * HCL device driver. - * The purpose of this device driver is to provide a facility - * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path - * to manipulate label entries without having to implement - * system call interfaces. This methodology will enable us to - * make this feature module loadable. - */ -static int hcl_open(struct inode * inode, struct file * filp) -{ - if (hcl_debug) { - printk("HCL: hcl_open called.\n"); - } - - return(0); - -} - -static int hcl_close(struct inode * inode, struct file * filp) -{ - - if (hcl_debug) { - printk("HCL: hcl_close called.\n"); - } - - return(0); - -} - -static int hcl_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - - if (hcl_debug) { - printk("HCL: hcl_ioctl called.\n"); - } - - switch (cmd) { - default: - if (hcl_debug) { - printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd); - } - } - - return(0); - -} - -struct file_operations hcl_fops = { - (struct module *)0, - NULL, /* lseek - default */ - NULL, /* read - general block-dev read */ - NULL, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - hcl_ioctl, /* ioctl */ - NULL, /* mmap */ - hcl_open, /* open */ - NULL, /* flush */ - hcl_close, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ - NULL, /* readv */ - NULL, /* writev */ -}; - - -/* - * init_hcl() - Boot time initialization. Ensure that it is called - * after devfs has been initialized. - * - * For now this routine is being called out of devfs/base.c. Actually - * Not a bad place to be .. - * - */ -#ifdef MODULE -int init_module (void) -#else -int __init init_hcl(void) -#endif -{ - extern void string_table_init(struct string_table *); - extern struct string_table label_string_table; - extern int init_ifconfig_net(void); - int rv = 0; - -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) - printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n", - HCL_NAME, HCL_VERSION); - - hcl_debug = hcl_debug_init; - printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug); - printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options); -#endif - - /* - * Create the hwgraph_root on devfs. - */ - rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); - if (rv) - printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); - - /* - * Create the hcl driver to support inventory entry manipulations. - * By default, it is expected that devfs is mounted on /dev. - * - */ - hcl_handle = hwgraph_register(hwgraph_root, ".hcl", - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &hcl_fops, NULL); - - if (hcl_handle == NULL) { - panic("HCL: Unable to create HCL Driver in init_hcl().\n"); - return(0); - } - - /* - * Initialize the HCL string table. - */ - string_table_init(&label_string_table); - - /* - * Create the directory that links Linux bus numbers to our Xwidget. - */ - rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); - if (linux_busnum == NULL) { - panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); - return(0); - } - - /* - * Initialize the ifconfgi_net driver that does network devices - * Persistent Naming. - */ - init_ifconfig_net(); - - return(0); - -} - - -/* - * hcl_setup() - Process boot time parameters if given. - * "hcl=" - * This routine gets called only if "hcl=" is given in the - * boot line and before init_hcl(). - * - * We currently do not have any boot options .. when we do, - * functionalities can be added here. - * - */ -static int __init hcl_setup(char *str) -{ - while ( (*str != '\0') && !isspace (*str) ) - { -#ifdef CONFIG_HCL_DEBUG - if (strncmp (str, "all", 3) == 0) { - hcl_debug_init |= HCL_DEBUG_ALL; - str += 3; - } else - return 0; -#endif - if (*str != ',') return 0; - ++str; - } - - return 1; - -} - -__setup("hcl=", hcl_setup); - - -/* - * Set device specific "fast information". - * - */ -void -hwgraph_fastinfo_set(devfs_handle_t de, arbitrary_info_t fastinfo) -{ - - if (hcl_debug) { - printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", (void *)de, fastinfo); - } - - labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL); - -} - - -/* - * Get device specific "fast information". - * - */ -arbitrary_info_t -hwgraph_fastinfo_get(devfs_handle_t de) -{ - arbitrary_info_t fastinfo; - int rv; - - if (!de) { - printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n"); - return(-1); - } - - rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo); - if (rv == 0) - return(fastinfo); - - return(0); -} - - -/* - * hwgraph_connectpt_set - Sets the connect point handle in de to the - * given connect_de handle. By default, the connect point of the - * devfs node is the parent. This effectively changes this assumption. - */ -int -hwgraph_connectpt_set(devfs_handle_t de, devfs_handle_t connect_de) -{ - int rv; - - if (!de) - return(-1); - - rv = labelcl_info_connectpt_set(de, connect_de); - - return(rv); -} - - -/* - * hwgraph_connectpt_get: Returns the entry's connect point in the devfs - * tree. - */ -devfs_handle_t -hwgraph_connectpt_get(devfs_handle_t de) -{ - int rv; - arbitrary_info_t info; - devfs_handle_t connect; - - rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); - if (rv != 0) { - return(NULL); - } - - connect = (devfs_handle_t)info; - return(connect); - -} - - -/* - * hwgraph_mk_dir - Creates a directory entry with devfs. - * Note that a directory entry in devfs can have children - * but it cannot be a char|block special file. - */ -devfs_handle_t -hwgraph_mk_dir(devfs_handle_t de, const char *name, - unsigned int namelen, void *info) -{ - - int rv; - labelcl_info_t *labelcl_info = NULL; - devfs_handle_t new_devfs_handle = NULL; - devfs_handle_t parent = NULL; - - /* - * Create the device info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(NULL); - - /* - * Create a devfs entry. - */ - new_devfs_handle = devfs_mk_dir(de, name, (void *)labelcl_info); - if (!new_devfs_handle) { - labelcl_info_destroy(labelcl_info); - return(NULL); - } - - /* - * Get the parent handle. - */ - parent = devfs_get_parent (new_devfs_handle); - - /* - * To provide the same semantics as the hwgraph, set the connect point. - */ - rv = hwgraph_connectpt_set(new_devfs_handle, parent); - if (!rv) { - /* - * We need to clean up! - */ - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - return(new_devfs_handle); - -} - -/* - * hwgraph_vertex_create - Create a vertex by giving it a temp name. - */ - -/* - * hwgraph_path_add - Create a directory node with the given path starting - * from the given devfs_handle_t. - */ -extern char * dev_to_name(devfs_handle_t, char *, uint); -int -hwgraph_path_add(devfs_handle_t fromv, - char *path, - devfs_handle_t *new_de) -{ - - unsigned int namelen = strlen(path); - int rv; - - /* - * We need to handle the case when fromv is NULL .. - * in this case we need to create the path from the - * hwgraph root! - */ - if (fromv == NULL) - fromv = hwgraph_root; - - /* - * check the entry doesn't already exist, if it does - * then we simply want new_de to point to it (otherwise - * we'll overwrite the existing labelcl_info struct) - */ - rv = hwgraph_edge_get(fromv, path, new_de); - if (rv) { /* couldn't find entry so we create it */ - *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL); - if (new_de == NULL) - return(-1); - else - return(0); - } - else - return(0); - -} - -/* - * hwgraph_register - Creates a file entry with devfs. - * Note that a file entry cannot have children .. it is like a - * char|block special vertex in hwgraph. - */ -devfs_handle_t -hwgraph_register(devfs_handle_t de, const char *name, - unsigned int namelen, unsigned int flags, - unsigned int major, unsigned int minor, - umode_t mode, uid_t uid, gid_t gid, - struct file_operations *fops, - void *info) -{ - - int rv; - void *labelcl_info = NULL; - devfs_handle_t new_devfs_handle = NULL; - devfs_handle_t parent = NULL; - - /* - * Create the labelcl info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(NULL); - - /* - * Create a devfs entry. - */ - new_devfs_handle = devfs_register(de, name, flags, major, - minor, mode, fops, labelcl_info); - if (!new_devfs_handle) { - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - return(NULL); - } - - /* - * Get the parent handle. - */ - if (de == NULL) - parent = devfs_get_parent (new_devfs_handle); - else - parent = de; - - /* - * To provide the same semantics as the hwgraph, set the connect point. - */ - rv = hwgraph_connectpt_set(new_devfs_handle, parent); - if (rv) { - /* - * We need to clean up! - */ - printk(KERN_WARNING "HCL: Unable to set the connect point to its parent 0x%p\n", - (void *)new_devfs_handle); - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - return(new_devfs_handle); - -} - - -/* - * hwgraph_mk_symlink - Create a symbolic link. - */ -int -hwgraph_mk_symlink(devfs_handle_t de, const char *name, unsigned int namelen, - unsigned int flags, const char *link, unsigned int linklen, - devfs_handle_t *handle, void *info) -{ - - void *labelcl_info = NULL; - int status = 0; - devfs_handle_t new_devfs_handle = NULL; - - /* - * Create the labelcl info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(-1); - - /* - * Create a symbolic link devfs entry. - */ - status = devfs_mk_symlink(de, name, flags, link, - &new_devfs_handle, labelcl_info); - if ( (!new_devfs_handle) || (!status) ){ - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - return(-1); - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - *handle = new_devfs_handle; - return(0); - -} - -/* - * hwgraph_vertex_get_next - this routine returns the next sibbling for the - * device entry given in de. If there are no more sibbling, NULL - * is returned in next_sibbling. - * - * Currently we do not have any protection against de being deleted - * while it's handle is being held. - */ -int -hwgraph_vertex_get_next(devfs_handle_t *next_sibbling, devfs_handle_t *de) -{ - *next_sibbling = devfs_get_next_sibling (*de); - - if (*next_sibbling != NULL) - *de = *next_sibbling; - return (0); -} - - -/* - * hwgraph_vertex_destroy - Destroy the devfs entry - */ -int -hwgraph_vertex_destroy(devfs_handle_t de) -{ - - void *labelcl_info = NULL; - - labelcl_info = devfs_get_info(de); - devfs_unregister(de); - - if (labelcl_info) - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - - return(0); -} - -/* -** See if a vertex has an outgoing edge with a specified name. -** Vertices in the hwgraph *implicitly* contain these edges: -** "." refers to "current vertex" -** ".." refers to "connect point vertex" -** "char" refers to current vertex (character device access) -** "block" refers to current vertex (block device access) -*/ - -/* - * hwgraph_edge_add - This routines has changed from the original conext. - * All it does now is to create a symbolic link from "from" to "to". - */ -/* ARGSUSED */ -int -hwgraph_edge_add(devfs_handle_t from, devfs_handle_t to, char *name) -{ - - char *path; - char *s1; - char *index; - int name_start; - devfs_handle_t handle = NULL; - int rv; - int i, count; - - path = kmalloc(1024, GFP_KERNEL); - memset(path, 0x0, 1024); - name_start = devfs_generate_path (from, path, 1024); - s1 = &path[name_start]; - count = 0; - while (1) { - index = strstr (s1, "/"); - if (index) { - count++; - s1 = ++index; - } else { - count++; - break; - } - } - - memset(path, 0x0, 1024); - name_start = devfs_generate_path (to, path, 1024); - - for (i = 0; i < count; i++) { - strcat(path,"../"); - } - - strcat(path, &path[name_start]); - - /* - * Otherwise, just create a symlink to the vertex. - * In this case the vertex was previous created with a REAL pathname. - */ - rv = devfs_mk_symlink (from, (const char *)name, - DEVFS_FL_DEFAULT, path, - &handle, NULL); - - name_start = devfs_generate_path (handle, path, 1024); - return(rv); - - -} -/* ARGSUSED */ -int -hwgraph_edge_get(devfs_handle_t from, char *name, devfs_handle_t *toptr) -{ - - int namelen = 0; - devfs_handle_t target_handle = NULL; - - if (name == NULL) - return(-1); - - if (toptr == NULL) - return(-1); - - /* - * If the name is "." just return the current devfs entry handle. - */ - if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) { - if (toptr) { - *toptr = from; - } - } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) { - /* - * Hmmm .. should we return the connect point or parent .. - * see in hwgraph, the concept of parent is the connectpt! - * - * Maybe we should see whether the connectpt is set .. if - * not just return the parent! - */ - target_handle = hwgraph_connectpt_get(from); - if (target_handle) { - /* - * Just return the connect point. - */ - *toptr = target_handle; - return(0); - } - target_handle = devfs_get_parent(from); - *toptr = target_handle; - - } else { - /* - * Call devfs to get the devfs entry. - */ - namelen = (int) strlen(name); - target_handle = devfs_get_handle(from, name, 1); /* Yes traverse symbolic links */ - if (target_handle == NULL) - return(-1); - else - *toptr = target_handle; - } - - return(0); -} - - -/* - * hwgraph_edge_get_next - Retrieves the next sibbling given the current - * entry number "placeptr". - * - * Allow the caller to retrieve walk through the sibblings of "source" - * devfs_handle_t. The implicit edges "." and ".." is returned first - * followed by each of the real children. - * - * We may end up returning garbage if another thread perform any deletion - * in this directory before "placeptr". - * - */ -/* ARGSUSED */ -int -hwgraph_edge_get_next(devfs_handle_t source, char *name, devfs_handle_t *target, - uint *placeptr) - -{ - - uint which_place; - unsigned int namelen = 0; - const char *tempname = NULL; - - if (placeptr == NULL) - return(-1); - - which_place = *placeptr; - -again: - if (which_place <= HWGRAPH_RESERVED_PLACES) { - if (which_place == EDGE_PLACE_WANT_CURRENT) { - /* - * Looking for "." - * Return the current devfs handle. - */ - if (name != NULL) - strcpy(name, HWGRAPH_EDGELBL_DOT); - - if (target != NULL) { - *target = source; - /* XXX should incr "source" ref count here if we - * ever implement ref counts */ - } - - } else if (which_place == EDGE_PLACE_WANT_CONNECTPT) { - /* - * Looking for the connect point or parent. - * If the connect point is set .. it returns the connect point. - * Otherwise, it returns the parent .. will we support - * connect point? - */ - devfs_handle_t connect_point = hwgraph_connectpt_get(source); - - if (connect_point == NULL) { - /* - * No connectpoint set .. either the User - * explicitly NULL it or this node was not - * created via hcl. - */ - which_place++; - goto again; - } - - if (name != NULL) - strcpy(name, HWGRAPH_EDGELBL_DOTDOT); - - if (target != NULL) - *target = connect_point; - - } else if (which_place == EDGE_PLACE_WANT_REAL_EDGES) { - /* - * return first "real" entry in directory, and increment - * placeptr. Next time around we should have - * which_place > HWGRAPH_RESERVED_EDGES so we'll fall through - * this nested if block. - */ - *target = devfs_get_first_child(source); - if (*target && name) { - tempname = devfs_get_name(*target, &namelen); - if (tempname && namelen) - strcpy(name, tempname); - } - - *placeptr = which_place + 1; - return (0); - } - - *placeptr = which_place+1; - return(0); - } - - /* - * walk linked list, (which_place - HWGRAPH_RESERVED_PLACES) times - */ - { - devfs_handle_t curr; - int i = 0; - - for (curr=devfs_get_first_child(source), i= i+HWGRAPH_RESERVED_PLACES; - curr!=NULL && iinv_next) { - if ((int)class != -1 && old_pinv->inv_class != class) - continue; - if ((int)type != -1 && old_pinv->inv_type != type) - continue; - if ((int)state != -1 && old_pinv->inv_state != state) - continue; - if ((int)controller != -1 - && old_pinv->inv_controller != controller) - continue; - if ((int)unit != -1 && old_pinv->inv_unit != unit) - continue; - - /* exact duplicate of previously-added inventory item */ - rv = LABELCL_DUP; - goto failure; - } - - /* Not a duplicate, so we know that we need to add something. */ - if (pinv == NULL) { - /* Release lock while we wait for memory. */ - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - pinv = (inventory_t *)kmalloc(sizeof(inventory_t), GFP_KERNEL); - replace_in_inventory(pinv, class, type, controller, unit, state); - goto again; - } - - pinv->inv_next = NULL; - if (last_pinv) { - last_pinv->inv_next = pinv; - } else { - rv = labelcl_info_add_LBL(de, INFO_LBL_INVENT, - sizeof(inventory_t), (arbitrary_info_t)pinv); - - if (!rv) - goto failure; - } - - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - return(0); - -failure: - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - if (pinv) - kfree(pinv); - return(rv); -} - - -/* - * hwgraph_inventory_remove - Removes an inventory entry. - * - * Remove an inventory item associated with a vertex. It is the caller's - * responsibility to make sure that there are no races between removing - * inventory from a vertex and simultaneously removing that vertex. -*/ -int -hwgraph_inventory_remove( devfs_handle_t de, - int class, - int type, - major_t controller, - minor_t unit, - int state) -{ - inventory_t *pinv = NULL, *last_pinv = NULL, *next_pinv = NULL; - labelcl_error_t rv; - - /* - * We never remove stuff from ".invent" .. - */ - if (!de) - return (-1); - - /* - * Remove our inventory data to the list of inventory data - * associated with this vertex. - */ - /* GRAPH_LOCK_UPDATE(&invent_lock); */ - rv = labelcl_info_get_LBL(de, - INFO_LBL_INVENT, - NULL, (arbitrary_info_t *)&pinv); - if (rv != LABELCL_SUCCESS) - goto failure; - - /* - * Search through inventory items associated with this - * vertex, looking for a match. - */ - for (;pinv; pinv = next_pinv) { - next_pinv = pinv->inv_next; - - if(((int)class == -1 || pinv->inv_class == class) && - ((int)type == -1 || pinv->inv_type == type) && - ((int)state == -1 || pinv->inv_state == state) && - ((int)controller == -1 || pinv->inv_controller == controller) && - ((int)unit == -1 || pinv->inv_unit == unit)) { - - /* Found a matching inventory item. Remove it. */ - if (last_pinv) { - last_pinv->inv_next = pinv->inv_next; - } else { - rv = hwgraph_info_replace_LBL(de, INFO_LBL_INVENT, (arbitrary_info_t)pinv->inv_next, NULL); - if (rv != LABELCL_SUCCESS) - goto failure; - } - - pinv->inv_next = NULL; /* sanity */ - kfree(pinv); - } else - last_pinv = pinv; - } - - if (last_pinv == NULL) { - rv = hwgraph_info_remove_LBL(de, INFO_LBL_INVENT, NULL); - if (rv != LABELCL_SUCCESS) - goto failure; - } - - rv = LABELCL_SUCCESS; - -failure: - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - return(rv); -} - -/* - * hwgraph_inventory_get_next - Get next inventory item associated with the - * specified vertex. - * - * No locking is really needed. We don't yet have the ability - * to remove inventory items, and new items are always added to - * the end of a vertex' inventory list. - * - * However, a devfs entry can be removed! -*/ -int -hwgraph_inventory_get_next(devfs_handle_t de, invplace_t *place, inventory_t **ppinv) -{ - inventory_t *pinv; - labelcl_error_t rv; - - if (de == NULL) - return(LABELCL_BAD_PARAM); - - if (place->invplace_vhdl == NULL) { - place->invplace_vhdl = de; - place->invplace_inv = NULL; - } - - if (de != place->invplace_vhdl) - return(LABELCL_BAD_PARAM); - - if (place->invplace_inv == NULL) { - /* Just starting on this vertex */ - rv = labelcl_info_get_LBL(de, INFO_LBL_INVENT, - NULL, (arbitrary_info_t *)&pinv); - if (rv != LABELCL_SUCCESS) - return(LABELCL_NOT_FOUND); - - } else { - /* Advance to next item on this vertex */ - pinv = place->invplace_inv->inv_next; - } - place->invplace_inv = pinv; - *ppinv = pinv; - - return(LABELCL_SUCCESS); -} - -/* - * hwgraph_controller_num_get - Returns the controller number in the inventory - * entry. - */ -int -hwgraph_controller_num_get(devfs_handle_t device) -{ - inventory_t *pinv; - invplace_t invplace = { NULL, NULL, NULL }; - int val = -1; - if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) { - val = (pinv->inv_class == INV_NETWORK)? pinv->inv_unit: pinv->inv_controller; - } -#ifdef DEBUG - /* - * It does not make any sense to call this on vertexes with multiple - * inventory structs chained together - */ - if ( device_inventory_get_next(device, &invplace) != NULL ) { - printk("Should panic here ... !\n"); -#endif - return (val); -} - -/* - * hwgraph_controller_num_set - Sets the controller number in the inventory - * entry. - */ -void -hwgraph_controller_num_set(devfs_handle_t device, int contr_num) -{ - inventory_t *pinv; - invplace_t invplace = { NULL, NULL, NULL }; - if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) { - if (pinv->inv_class == INV_NETWORK) - pinv->inv_unit = contr_num; - else { - if (pinv->inv_class == INV_FCNODE) - pinv = device_inventory_get_next(device, &invplace); - if (pinv != NULL) - pinv->inv_controller = contr_num; - } - } -#ifdef DEBUG - /* - * It does not make any sense to call this on vertexes with multiple - * inventory structs chained together - */ - if(pinv != NULL) - ASSERT(device_inventory_get_next(device, &invplace) == NULL); -#endif -} - -/* - * Find the canonical name for a given vertex by walking back through - * connectpt's until we hit the hwgraph root vertex (or until we run - * out of buffer space or until something goes wrong). - * - * COMPATIBILITY FUNCTIONALITY - * Walks back through 'parents', not necessarily the same as connectpts. - * - * Need to resolve the fact that devfs does not return the path from - * "/" but rather it just stops right before /dev .. - */ -int -hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen) -{ - char *locbuf; - int pos; - - if (buflen < 1) - return(-1); /* XXX should be GRAPH_BAD_PARAM ? */ - - locbuf = kmalloc(buflen, GFP_KERNEL); - - pos = devfs_generate_path(vhdl, locbuf, buflen); - if (pos < 0) { - kfree(locbuf); - return pos; - } - - strcpy(buf, &locbuf[pos]); - kfree(locbuf); - return 0; -} - -/* -** vertex_to_name converts a vertex into a canonical name by walking -** back through connect points until we hit the hwgraph root (or until -** we run out of buffer space). -** -** Usually returns a pointer to the original buffer, filled in as -** appropriate. If the buffer is too small to hold the entire name, -** or if anything goes wrong while determining the name, vertex_to_name -** returns "UnknownDevice". -*/ - -#define DEVNAME_UNKNOWN "UnknownDevice" - -char * -vertex_to_name(devfs_handle_t vhdl, char *buf, uint buflen) -{ - if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS) - return(buf); - else - return(DEVNAME_UNKNOWN); -} - -#ifdef LATER -/* -** Return the compact node id of the node that ultimately "owns" the specified -** vertex. In order to do this, we walk back through masters and connect points -** until we reach a vertex that represents a node. -*/ -cnodeid_t -master_node_get(devfs_handle_t vhdl) -{ - cnodeid_t cnodeid; - devfs_handle_t master; - - for (;;) { - cnodeid = nodevertex_to_cnodeid(vhdl); - if (cnodeid != CNODEID_NONE) - return(cnodeid); - - master = device_master_get(vhdl); - - /* Check for exceptional cases */ - if (master == vhdl) { - /* Since we got a reference to the "master" thru - * device_master_get() we should decrement - * its reference count by 1 - */ - hwgraph_vertex_unref(master); - return(CNODEID_NONE); - } - - if (master == GRAPH_VERTEX_NONE) { - master = hwgraph_connectpt_get(vhdl); - if ((master == GRAPH_VERTEX_NONE) || - (master == vhdl)) { - if (master == vhdl) - /* Since we got a reference to the - * "master" thru - * hwgraph_connectpt_get() we should - * decrement its reference count by 1 - */ - hwgraph_vertex_unref(master); - return(CNODEID_NONE); - } - } - - vhdl = master; - /* Decrement the reference to "master" which was got - * either thru device_master_get() or hwgraph_connectpt_get() - * above. - */ - hwgraph_vertex_unref(master); - } -} - -/* - * Using the canonical path name to get hold of the desired vertex handle will - * not work on multi-hub sn0 nodes. Hence, we use the following (slightly - * convoluted) algorithm. - * - * - Start at the vertex corresponding to the driver (provided as input parameter) - * - Loop till you reach a vertex which has EDGE_LBL_MEMORY - * - If EDGE_LBL_CONN exists, follow that up. - * else if EDGE_LBL_MASTER exists, follow that up. - * else follow EDGE_LBL_DOTDOT up. - * - * * We should be at desired hub/heart vertex now * - * - Follow EDGE_LBL_CONN to the widget vertex. - * - * - return vertex handle of this widget. - */ -devfs_handle_t -mem_vhdl_get(devfs_handle_t drv_vhdl) -{ -devfs_handle_t cur_vhdl, cur_upper_vhdl; -devfs_handle_t tmp_mem_vhdl, mem_vhdl; -graph_error_t loop_rv; - - /* Initializations */ - cur_vhdl = drv_vhdl; - loop_rv = ~GRAPH_SUCCESS; - - /* Loop till current vertex has EDGE_LBL_MEMORY */ - while (loop_rv != GRAPH_SUCCESS) { - - if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &cur_upper_vhdl)) == GRAPH_SUCCESS) { - - } else if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_MASTER, &cur_upper_vhdl)) == GRAPH_SUCCESS) { - } else { /* Follow HWGRAPH_EDGELBL_DOTDOT up */ - (void) hwgraph_edge_get(cur_vhdl, HWGRAPH_EDGELBL_DOTDOT, &cur_upper_vhdl); - } - - cur_vhdl = cur_upper_vhdl; - -#if DEBUG && HWG_DEBUG - printf("Current vhdl %d \n", cur_vhdl); -#endif /* DEBUG */ - - loop_rv = hwgraph_edge_get(cur_vhdl, EDGE_LBL_MEMORY, &tmp_mem_vhdl); - } - - /* We should be at desired hub/heart vertex now */ - if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &mem_vhdl)) != GRAPH_SUCCESS) - return (GRAPH_VERTEX_NONE); - - return (mem_vhdl); -} -#endif /* LATER */ - - -/* -** Add a char device -- if the driver supports it -- at a specified vertex. -*/ -graph_error_t -hwgraph_char_device_add( devfs_handle_t from, - char *path, - char *prefix, - devfs_handle_t *devhdl) -{ - devfs_handle_t xx = NULL; - - printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n"); - *devhdl = xx; // Must set devhdl - return(GRAPH_SUCCESS); -} - -graph_error_t -hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr) -{ - printk("WARNING: hwgraph_edge_remove NOT supported.\n"); - return(GRAPH_ILLEGAL_REQUEST); -} - -graph_error_t -hwgraph_vertex_unref(devfs_handle_t vhdl) -{ - return(GRAPH_ILLEGAL_REQUEST); -} - - -EXPORT_SYMBOL(hwgraph_mk_dir); -EXPORT_SYMBOL(hwgraph_path_add); -EXPORT_SYMBOL(hwgraph_char_device_add); -EXPORT_SYMBOL(hwgraph_register); -EXPORT_SYMBOL(hwgraph_vertex_destroy); - -EXPORT_SYMBOL(hwgraph_fastinfo_get); -EXPORT_SYMBOL(hwgraph_edge_get); - -EXPORT_SYMBOL(hwgraph_fastinfo_set); -EXPORT_SYMBOL(hwgraph_connectpt_set); -EXPORT_SYMBOL(hwgraph_connectpt_get); -EXPORT_SYMBOL(hwgraph_edge_get_next); -EXPORT_SYMBOL(hwgraph_info_add_LBL); -EXPORT_SYMBOL(hwgraph_info_remove_LBL); -EXPORT_SYMBOL(hwgraph_info_replace_LBL); -EXPORT_SYMBOL(hwgraph_info_get_LBL); -EXPORT_SYMBOL(hwgraph_info_get_exported_LBL); -EXPORT_SYMBOL(hwgraph_info_get_next_LBL); -EXPORT_SYMBOL(hwgraph_info_export_LBL); -EXPORT_SYMBOL(hwgraph_info_unexport_LBL); -EXPORT_SYMBOL(hwgraph_path_lookup); -EXPORT_SYMBOL(hwgraph_traverse); -EXPORT_SYMBOL(hwgraph_path_to_vertex); -EXPORT_SYMBOL(hwgraph_path_to_dev); -EXPORT_SYMBOL(hwgraph_block_device_get); -EXPORT_SYMBOL(hwgraph_char_device_get); -EXPORT_SYMBOL(hwgraph_vertex_name_get); diff --git a/arch/ia64/sn/io/hubdev.c b/arch/ia64/sn/io/hubdev.c deleted file mode 100644 index 9b346dcd328..00000000000 --- a/arch/ia64/sn/io/hubdev.c +++ /dev/null @@ -1,132 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct hubdev_callout { - int (*attach_method)(devfs_handle_t); - struct hubdev_callout *fp; -}; - -typedef struct hubdev_callout hubdev_callout_t; - -mutex_t hubdev_callout_mutex; -hubdev_callout_t *hubdev_callout_list = NULL; - -void -hubdev_init(void) -{ - mutex_init(&hubdev_callout_mutex); - hubdev_callout_list = NULL; -} - -void -hubdev_register(int (*attach_method)(devfs_handle_t)) -{ - hubdev_callout_t *callout; - - ASSERT(attach_method); - - callout = (hubdev_callout_t *)snia_kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); - ASSERT(callout); - - mutex_lock(&hubdev_callout_mutex); - /* - * Insert at the end of the list - */ - callout->fp = hubdev_callout_list; - hubdev_callout_list = callout; - callout->attach_method = attach_method; - mutex_unlock(&hubdev_callout_mutex); -} - -int -hubdev_unregister(int (*attach_method)(devfs_handle_t)) -{ - hubdev_callout_t **p; - - ASSERT(attach_method); - - mutex_lock(&hubdev_callout_mutex); - /* - * Remove registry element containing attach_method - */ - for (p = &hubdev_callout_list; *p != NULL; p = &(*p)->fp) { - if ((*p)->attach_method == attach_method) { - hubdev_callout_t* victim = *p; - *p = (*p)->fp; - kfree(victim); - mutex_unlock(&hubdev_callout_mutex); - return (0); - } - } - mutex_unlock(&hubdev_callout_mutex); - return (ENOENT); -} - - -int -hubdev_docallouts(devfs_handle_t hub) -{ - hubdev_callout_t *p; - int errcode; - - mutex_lock(&hubdev_callout_mutex); - - for (p = hubdev_callout_list; p != NULL; p = p->fp) { - ASSERT(p->attach_method); - errcode = (*p->attach_method)(hub); - if (errcode != 0) { - mutex_unlock(&hubdev_callout_mutex); - return (errcode); - } - } - mutex_unlock(&hubdev_callout_mutex); - return (0); -} - -/* - * Given a hub vertex, return the base address of the Hspec space - * for that hub. - */ - -#if defined(CONFIG_IA64_SGI_SN1) - -caddr_t -hubdev_prombase_get(devfs_handle_t hub) -{ - hubinfo_t hinfo = NULL; - - hubinfo_get(hub, &hinfo); - ASSERT(hinfo); - - return ((caddr_t)NODE_RBOOT_BASE(hinfo->h_nasid)); -} - -cnodeid_t -hubdev_cnodeid_get(devfs_handle_t hub) -{ - hubinfo_t hinfo = NULL; - hubinfo_get(hub, &hinfo); - ASSERT(hinfo); - - return hinfo->h_cnodeid; -} - -#endif /* CONFIG_IA64_SGI_SN1 */ diff --git a/arch/ia64/sn/io/hubspc.c b/arch/ia64/sn/io/hubspc.c deleted file mode 100644 index 803226ec16f..00000000000 --- a/arch/ia64/sn/io/hubspc.c +++ /dev/null @@ -1,251 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * hubspc.c - Hub Memory Space Management Driver - * This driver implements the managers for the following - * memory resources: - * 1) reference counters - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Uncomment the following line for tracing */ -/* #define HUBSPC_DEBUG 1 */ - -int hubspc_devflag = D_MP; - - -/***********************************************************************/ -/* CPU Prom Space */ -/***********************************************************************/ - -typedef struct cpuprom_info { - devfs_handle_t prom_dev; - devfs_handle_t nodevrtx; - struct cpuprom_info *next; -}cpuprom_info_t; - -static cpuprom_info_t *cpuprom_head; -static spinlock_t cpuprom_spinlock; -#define PROM_LOCK() mutex_spinlock(&cpuprom_spinlock) -#define PROM_UNLOCK(s) mutex_spinunlock(&cpuprom_spinlock, (s)) - -/* - * Add prominfo to the linked list maintained. - */ -void -prominfo_add(devfs_handle_t hub, devfs_handle_t prom) -{ - cpuprom_info_t *info; - unsigned long s; - - info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL); - ASSERT(info); - info->prom_dev = prom; - info->nodevrtx = hub; - - - s = PROM_LOCK(); - info->next = cpuprom_head; - cpuprom_head = info; - PROM_UNLOCK(s); -} - -void -prominfo_del(devfs_handle_t prom) -{ - unsigned long s; - cpuprom_info_t *info; - cpuprom_info_t **prev; - - s = PROM_LOCK(); - prev = &cpuprom_head; - while ( (info = *prev) ) { - if (info->prom_dev == prom) { - *prev = info->next; - PROM_UNLOCK(s); - return; - } - - prev = &info->next; - } - PROM_UNLOCK(s); - ASSERT(0); -} - -devfs_handle_t -prominfo_nodeget(devfs_handle_t prom) -{ - unsigned long s; - cpuprom_info_t *info; - - s = PROM_LOCK(); - info = cpuprom_head; - while (info) { - if(info->prom_dev == prom) { - PROM_UNLOCK(s); - return info->nodevrtx; - } - info = info->next; - } - PROM_UNLOCK(s); - return 0; -} - -#if defined(CONFIG_IA64_SGI_SN1) -#define SN_PROMVERSION INV_IP35PROM - -/* Add "detailed" labelled inventory information to the - * prom vertex - */ -void -cpuprom_detailed_inventory_info_add(devfs_handle_t prom_dev,devfs_handle_t node) -{ - invent_miscinfo_t *cpuprom_inventory_info; - extern invent_generic_t *klhwg_invent_alloc(cnodeid_t cnode, - int class, int size); - cnodeid_t cnode = hubdev_cnodeid_get(node); - - /* Allocate memory for the extra inventory information - * for the prom - */ - cpuprom_inventory_info = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); - - ASSERT(cpuprom_inventory_info); - - /* Set the enabled flag so that the hinv interprets this - * information - */ - cpuprom_inventory_info->im_gen.ig_flag = INVENT_ENABLED; - cpuprom_inventory_info->im_type = SN_PROMVERSION; - /* Store prom revision into inventory information */ - cpuprom_inventory_info->im_rev = IP27CONFIG.pvers_rev; - cpuprom_inventory_info->im_version = IP27CONFIG.pvers_vers; - - /* Store this info as labelled information hanging off the - * prom device vertex - */ - hwgraph_info_add_LBL(prom_dev, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) cpuprom_inventory_info); - /* Export this information so that user programs can get to - * this by using attr_get() - */ - hwgraph_info_export_LBL(prom_dev, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/***********************************************************************/ -/* Base Hub Space Driver */ -/***********************************************************************/ - -/* - * hubspc_init - * Registration of the hubspc devices with the hub manager - */ -void -hubspc_init(void) -{ - /* - * Register with the hub manager - */ - - /* The reference counters */ -#if defined(CONFIG_IA64_SGI_SN1) - hubdev_register(mem_refcnt_attach); -#endif - -#ifdef CONFIG_IA64_SGI_SN1 - /* L1 system controller link */ - if ( !IS_RUNNING_ON_SIMULATOR() ) { - /* initialize the L1 link */ - extern void l1_init(void); - l1_init(); - } -#endif /* CONFIG_IA64_SGI_SN1 */ -#ifdef HUBSPC_DEBUG - printk("hubspc_init: Completed\n"); -#endif /* HUBSPC_DEBUG */ - /* Initialize spinlocks */ - mutex_spinlock_init(&cpuprom_spinlock); -} - -/* ARGSUSED */ -int -hubspc_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) -{ - return (0); -} - - -/* ARGSUSED */ -int -hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return (0); -} - -/* ARGSUSED */ -int -hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - /*REFERENCED*/ - int errcode = 0; - - /* check validity of request */ - if( len == 0 ) { - return -ENXIO; - } - - return errcode; -} - -/* ARGSUSED */ -int -hubspc_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return (0); - -} - -/* ARGSUSED */ -int -hubspc_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int mode, - cred_t *cred_p, - int *rvalp) -{ - return (0); - -} diff --git a/arch/ia64/sn/io/hwgfs/Makefile b/arch/ia64/sn/io/hwgfs/Makefile new file mode 100644 index 00000000000..5107e0c9ae9 --- /dev/null +++ b/arch/ia64/sn/io/hwgfs/Makefile @@ -0,0 +1,13 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += hcl.o labelcl.o hcl_util.o invent_stub.o \ + ramfs.o interface.o diff --git a/arch/ia64/sn/io/hwgfs/hcl.c b/arch/ia64/sn/io/hwgfs/hcl.c new file mode 100644 index 00000000000..b85db9911bd --- /dev/null +++ b/arch/ia64/sn/io/hwgfs/hcl.c @@ -0,0 +1,938 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * hcl - SGI's Hardware Graph compatibility layer. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* needed for smp_lock.h :( */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER" +#define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE" +#define HCL_TEMP_NAME_LEN 44 +#define HCL_VERSION "1.0" + +#define vertex_hdl_t hwgfs_handle_t +vertex_hdl_t hwgraph_root; +vertex_hdl_t linux_busnum; + +extern void pci_bus_cvlink_init(void); + +/* + * Debug flag definition. + */ +#define OPTION_NONE 0x00 +#define HCL_DEBUG_NONE 0x00000 +#define HCL_DEBUG_ALL 0x0ffff +#if defined(CONFIG_HCL_DEBUG) +static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; +#endif +static unsigned int hcl_debug = HCL_DEBUG_NONE; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) +static unsigned int boot_options = OPTION_NONE; +#endif + +/* + * Some Global definitions. + */ +vertex_hdl_t hcl_handle; + +invplace_t invplace_none = { + GRAPH_VERTEX_NONE, + GRAPH_VERTEX_PLACE_NONE, + NULL +}; + +/* + * HCL device driver. + * The purpose of this device driver is to provide a facility + * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path + * to manipulate label entries without having to implement + * system call interfaces. This methodology will enable us to + * make this feature module loadable. + */ +static int hcl_open(struct inode * inode, struct file * filp) +{ + if (hcl_debug) { + printk("HCL: hcl_open called.\n"); + } + + return(0); + +} + +static int hcl_close(struct inode * inode, struct file * filp) +{ + + if (hcl_debug) { + printk("HCL: hcl_close called.\n"); + } + + return(0); + +} + +static int hcl_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + if (hcl_debug) { + printk("HCL: hcl_ioctl called.\n"); + } + + switch (cmd) { + default: + if (hcl_debug) { + printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd); + } + } + + return(0); + +} + +struct file_operations hcl_fops = { + (struct module *)0, + NULL, /* lseek - default */ + NULL, /* read - general block-dev read */ + NULL, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + hcl_ioctl, /* ioctl */ + NULL, /* mmap */ + hcl_open, /* open */ + NULL, /* flush */ + hcl_close, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* lock */ + NULL, /* readv */ + NULL, /* writev */ +}; + + +/* + * init_hcl() - Boot time initialization. + * + */ +int __init init_hcl(void) +{ + extern void string_table_init(struct string_table *); + extern struct string_table label_string_table; + extern int init_ifconfig_net(void); + extern int init_ioconfig_bus(void); + extern int init_hwgfs_fs(void); + int rv = 0; + + if (IS_RUNNING_ON_SIMULATOR()) { + extern u64 klgraph_addr[]; + klgraph_addr[0] = 0xe000003000030000; + } + + init_hwgfs_fs(); + + /* + * Create the hwgraph_root. + */ + rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); + if (rv) + printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); + + /* + * Create the hcl driver to support inventory entry manipulations. + * + */ + hcl_handle = hwgraph_register(hwgraph_root, ".hcl", + 0, 0, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &hcl_fops, NULL); + + if (hcl_handle == NULL) { + panic("HCL: Unable to create HCL Driver in init_hcl().\n"); + return(0); + } + + /* + * Initialize the HCL string table. + */ + + string_table_init(&label_string_table); + + /* + * Create the directory that links Linux bus numbers to our Xwidget. + */ + rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); + if (linux_busnum == NULL) { + panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); + return(0); + } + + pci_bus_cvlink_init(); + + /* + * Initialize the ifconfgi_net driver that does network devices + * Persistent Naming. + */ + init_ifconfig_net(); + init_ioconfig_bus(); + + return(0); + +} + + +/* + * hcl_setup() - Process boot time parameters if given. + * "hcl=" + * This routine gets called only if "hcl=" is given in the + * boot line and before init_hcl(). + * + * We currently do not have any boot options .. when we do, + * functionalities can be added here. + * + */ +static int __init hcl_setup(char *str) +{ + while ( (*str != '\0') && !isspace (*str) ) + { +#ifdef CONFIG_HCL_DEBUG + if (strncmp (str, "all", 3) == 0) { + hcl_debug_init |= HCL_DEBUG_ALL; + str += 3; + } else + return 0; +#endif + if (*str != ',') return 0; + ++str; + } + + return 1; + +} + +__setup("hcl=", hcl_setup); + + +/* + * Set device specific "fast information". + * + */ +void +hwgraph_fastinfo_set(vertex_hdl_t de, arbitrary_info_t fastinfo) +{ + labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL); +} + + +/* + * Get device specific "fast information". + * + */ +arbitrary_info_t +hwgraph_fastinfo_get(vertex_hdl_t de) +{ + arbitrary_info_t fastinfo; + int rv; + + if (!de) { + printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n"); + return(-1); + } + + rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo); + if (rv == 0) + return(fastinfo); + + return(0); +} + + +/* + * hwgraph_connectpt_set - Sets the connect point handle in de to the + * given connect_de handle. By default, the connect point of the + * node is the parent. This effectively changes this assumption. + */ +int +hwgraph_connectpt_set(vertex_hdl_t de, vertex_hdl_t connect_de) +{ + int rv; + + if (!de) + return(-1); + + rv = labelcl_info_connectpt_set(de, connect_de); + + return(rv); +} + + +/* + * hwgraph_connectpt_get: Returns the entry's connect point. + * + */ +vertex_hdl_t +hwgraph_connectpt_get(vertex_hdl_t de) +{ + int rv; + arbitrary_info_t info; + vertex_hdl_t connect; + + rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); + if (rv != 0) { + return(NULL); + } + + connect = (vertex_hdl_t)info; + return(connect); + +} + + +/* + * hwgraph_mk_dir - Creates a directory entry. + */ +vertex_hdl_t +hwgraph_mk_dir(vertex_hdl_t de, const char *name, + unsigned int namelen, void *info) +{ + + int rv; + labelcl_info_t *labelcl_info = NULL; + vertex_hdl_t new_handle = NULL; + vertex_hdl_t parent = NULL; + + /* + * Create the device info structure for hwgraph compatiblity support. + */ + labelcl_info = labelcl_info_create(); + if (!labelcl_info) + return(NULL); + + /* + * Create an entry. + */ + new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info); + if (!new_handle) { + labelcl_info_destroy(labelcl_info); + return(NULL); + } + + /* + * Get the parent handle. + */ + parent = hwgfs_get_parent (new_handle); + + /* + * To provide the same semantics as the hwgraph, set the connect point. + */ + rv = hwgraph_connectpt_set(new_handle, parent); + if (!rv) { + /* + * We need to clean up! + */ + } + + /* + * If the caller provides a private data pointer, save it in the + * labelcl info structure(fastinfo). This can be retrieved via + * hwgraph_fastinfo_get() + */ + if (info) + hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); + + return(new_handle); + +} + +/* + * hwgraph_path_add - Create a directory node with the given path starting + * from the given fromv. + */ +int +hwgraph_path_add(vertex_hdl_t fromv, + char *path, + vertex_hdl_t *new_de) +{ + + unsigned int namelen = strlen(path); + int rv; + + /* + * We need to handle the case when fromv is NULL .. + * in this case we need to create the path from the + * hwgraph root! + */ + if (fromv == NULL) + fromv = hwgraph_root; + + /* + * check the entry doesn't already exist, if it does + * then we simply want new_de to point to it (otherwise + * we'll overwrite the existing labelcl_info struct) + */ + rv = hwgraph_edge_get(fromv, path, new_de); + if (rv) { /* couldn't find entry so we create it */ + *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL); + if (new_de == NULL) + return(-1); + else + return(0); + } + else + return(0); + +} + +/* + * hwgraph_register - Creates a special device file. + * + */ +vertex_hdl_t +hwgraph_register(vertex_hdl_t de, const char *name, + unsigned int namelen, unsigned int flags, + unsigned int major, unsigned int minor, + umode_t mode, uid_t uid, gid_t gid, + struct file_operations *fops, + void *info) +{ + + vertex_hdl_t new_handle = NULL; + + /* + * Create an entry. + */ + new_handle = hwgfs_register(de, name, flags, major, + minor, mode, fops, info); + + return(new_handle); + +} + + +/* + * hwgraph_mk_symlink - Create a symbolic link. + */ +int +hwgraph_mk_symlink(vertex_hdl_t de, const char *name, unsigned int namelen, + unsigned int flags, const char *link, unsigned int linklen, + vertex_hdl_t *handle, void *info) +{ + + void *labelcl_info = NULL; + int status = 0; + vertex_hdl_t new_handle = NULL; + + /* + * Create the labelcl info structure for hwgraph compatiblity support. + */ + labelcl_info = labelcl_info_create(); + if (!labelcl_info) + return(-1); + + /* + * Create a symbolic link. + */ + status = hwgfs_mk_symlink(de, name, flags, link, + &new_handle, labelcl_info); + if ( (!new_handle) || (!status) ){ + labelcl_info_destroy((labelcl_info_t *)labelcl_info); + return(-1); + } + + /* + * If the caller provides a private data pointer, save it in the + * labelcl info structure(fastinfo). This can be retrieved via + * hwgraph_fastinfo_get() + */ + if (info) + hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); + + *handle = new_handle; + return(0); + +} + +/* + * hwgraph_vertex_destroy - Destroy the entry + */ +int +hwgraph_vertex_destroy(vertex_hdl_t de) +{ + + void *labelcl_info = NULL; + + labelcl_info = hwgfs_get_info(de); + hwgfs_unregister(de); + + if (labelcl_info) + labelcl_info_destroy((labelcl_info_t *)labelcl_info); + + return(0); +} + +#if 0 +/* + * hwgraph_edge_add - This routines has changed from the original conext. + * All it does now is to create a symbolic link from "from" to "to". + */ +/* ARGSUSED */ +int +hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name) +{ + + char *path, *link; + vertex_hdl_t handle = NULL; + int rv, i; + + handle = hwgfs_find_handle(from, name, 0, 0, 0, 1); + if (handle) { + return(0); + } + + path = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + link = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + i = hwgfs_generate_path (to, link, 1024); + rv = hwgfs_mk_symlink (from, (const char *)name, + DEVFS_FL_DEFAULT, link, + &handle, NULL); + return(0); + + +} +#endif + +int +hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name) +{ + + char *path, *link; + char *s1; + char *index; + vertex_hdl_t handle = NULL; + int rv; + int i, count; + + path = kmalloc(1024, GFP_KERNEL); + memset((char *)path, 0x0, 1024); + link = kmalloc(1024, GFP_KERNEL); + memset((char *)link, 0x0, 1024); + + i = hwgfs_generate_path (from, path, 1024); + s1 = (char *)path; + count = 0; + while (1) { + index = strstr (s1, "/"); + if (index) { + count++; + s1 = ++index; + } else { + count++; + break; + } + } + + for (i = 0; i < count; i++) { + strcat((char *)link,"../"); + } + + memset(path, 0x0, 1024); + i = hwgfs_generate_path (to, path, 1024); + strcat((char *)link, (char *)path); + + /* + * Otherwise, just create a symlink to the vertex. + * In this case the vertex was previous created with a REAL pathname. + */ + rv = hwgfs_mk_symlink (from, (const char *)name, + DEVFS_FL_DEFAULT, link, + &handle, NULL); + kfree(path); + kfree(link); + + return(rv); + + +} + +/* ARGSUSED */ +int +hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr) +{ + + vertex_hdl_t target_handle = NULL; + + if (name == NULL) + return(-1); + + if (toptr == NULL) + return(-1); + + /* + * If the name is "." just return the current entry handle. + */ + if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) { + if (toptr) { + *toptr = from; + } + } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) { + /* + * Hmmm .. should we return the connect point or parent .. + * see in hwgraph, the concept of parent is the connectpt! + * + * Maybe we should see whether the connectpt is set .. if + * not just return the parent! + */ + target_handle = hwgraph_connectpt_get(from); + if (target_handle) { + /* + * Just return the connect point. + */ + *toptr = target_handle; + return(0); + } + target_handle = hwgfs_get_parent(from); + *toptr = target_handle; + + } else { + target_handle = hwgfs_find_handle (from, name, 0, 0, + 0, 1); /* Yes traverse symbolic links */ + } + + if (target_handle == NULL) + return(-1); + else + *toptr = target_handle; + + return(0); +} + +/* + * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc + * of the label as INFO_DESC_PRIVATE and store the info in the label. + */ +/* ARGSUSED */ +int +hwgraph_info_add_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t info) +{ + return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info)); +} + +/* + * hwgraph_info_remove_LBL - Remove the label entry for the device. + */ +/* ARGSUSED */ +int +hwgraph_info_remove_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t *old_info) +{ + return(labelcl_info_remove_LBL(de, name, NULL, old_info)); +} + +/* + * hwgraph_info_replace_LBL - replaces an existing label with + * a new label info value. + */ +/* ARGSUSED */ +int +hwgraph_info_replace_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t info, + arbitrary_info_t *old_info) +{ + return(labelcl_info_replace_LBL(de, name, + INFO_DESC_PRIVATE, info, + NULL, old_info)); +} +/* + * hwgraph_info_get_LBL - Get and return the info value in the label of the + * device. + */ +/* ARGSUSED */ +int +hwgraph_info_get_LBL(vertex_hdl_t de, + char *name, + arbitrary_info_t *infop) +{ + return(labelcl_info_get_LBL(de, name, NULL, infop)); +} + +/* + * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer + * of the given label for the device. The weird thing is that the label + * that matches the name is return irrespective of the info_desc value! + * Do not understand why the word "exported" is used! + */ +/* ARGSUSED */ +int +hwgraph_info_get_exported_LBL(vertex_hdl_t de, + char *name, + int *export_info, + arbitrary_info_t *infop) +{ + int rc; + arb_info_desc_t info_desc; + + rc = labelcl_info_get_LBL(de, name, &info_desc, infop); + if (rc == 0) + *export_info = (int)info_desc; + + return(rc); +} + +/* + * hwgraph_info_get_next_LBL - Returns the next label info given the + * current label entry in place. + * + * Once again this has no locking or reference count for protection. + * + */ +/* ARGSUSED */ +int +hwgraph_info_get_next_LBL(vertex_hdl_t de, + char *buf, + arbitrary_info_t *infop, + labelcl_info_place_t *place) +{ + return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place)); +} + +/* + * hwgraph_info_export_LBL - Retrieve the specified label entry and modify + * the info_desc field with the given value in nbytes. + */ +/* ARGSUSED */ +int +hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes) +{ + arbitrary_info_t info; + int rc; + + if (nbytes == 0) + nbytes = INFO_DESC_EXPORT; + + if (nbytes < 0) + return(-1); + + rc = labelcl_info_get_LBL(de, name, NULL, &info); + if (rc != 0) + return(rc); + + rc = labelcl_info_replace_LBL(de, name, + nbytes, info, NULL, NULL); + + return(rc); +} + +/* + * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the + * label info_descr filed to INFO_DESC_PRIVATE. + */ +/* ARGSUSED */ +int +hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name) +{ + arbitrary_info_t info; + int rc; + + rc = labelcl_info_get_LBL(de, name, NULL, &info); + if (rc != 0) + return(rc); + + rc = labelcl_info_replace_LBL(de, name, + INFO_DESC_PRIVATE, info, NULL, NULL); + + return(rc); +} + +/* + * hwgraph_path_lookup - return the handle for the given path. + * + */ +int +hwgraph_path_lookup(vertex_hdl_t start_vertex_handle, + char *lookup_path, + vertex_hdl_t *vertex_handle_ptr, + char **remainder) +{ + *vertex_handle_ptr = hwgfs_find_handle(start_vertex_handle, /* start dir */ + lookup_path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1); /* traverse symlinks */ + if (*vertex_handle_ptr == NULL) + return(-1); + else + return(0); +} + +/* + * hwgraph_traverse - Find and return the handle starting from de. + * + */ +graph_error_t +hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found) +{ + /* + * get the directory entry (path should end in a directory) + */ + + *found = hwgfs_find_handle(de, /* start dir */ + path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1); /* traverse symlinks */ + if (*found == NULL) + return(GRAPH_NOT_FOUND); + else + return(GRAPH_SUCCESS); +} + +/* + * hwgraph_path_to_vertex - Return the entry handle for the given + * pathname .. assume traverse symlinks too!. + */ +vertex_hdl_t +hwgraph_path_to_vertex(char *path) +{ + return(hwgfs_find_handle(NULL, /* start dir */ + path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1)); /* traverse symlinks */ +} + +/* + * hwgraph_inventory_remove - Removes an inventory entry. + * + * Remove an inventory item associated with a vertex. It is the caller's + * responsibility to make sure that there are no races between removing + * inventory from a vertex and simultaneously removing that vertex. +*/ +int +hwgraph_inventory_remove( vertex_hdl_t de, + int class, + int type, + major_t controller, + minor_t unit, + int state) +{ + return(0); /* Just a Stub for IRIX code. */ +} + +/* + * Find the canonical name for a given vertex by walking back through + * connectpt's until we hit the hwgraph root vertex (or until we run + * out of buffer space or until something goes wrong). + * + * COMPATIBILITY FUNCTIONALITY + * Walks back through 'parents', not necessarily the same as connectpts. + * + * Need to resolve the fact that does not return the path from + * "/" but rather it just stops right before /dev .. + */ +int +hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen) +{ + char *locbuf; + int pos; + + if (buflen < 1) + return(-1); /* XXX should be GRAPH_BAD_PARAM ? */ + + locbuf = kmalloc(buflen, GFP_KERNEL); + + pos = hwgfs_generate_path(vhdl, locbuf, buflen); + if (pos < 0) { + kfree(locbuf); + return pos; + } + + strcpy(buf, &locbuf[pos]); + kfree(locbuf); + return 0; +} + +/* +** vertex_to_name converts a vertex into a canonical name by walking +** back through connect points until we hit the hwgraph root (or until +** we run out of buffer space). +** +** Usually returns a pointer to the original buffer, filled in as +** appropriate. If the buffer is too small to hold the entire name, +** or if anything goes wrong while determining the name, vertex_to_name +** returns "UnknownDevice". +*/ + +#define DEVNAME_UNKNOWN "UnknownDevice" + +char * +vertex_to_name(vertex_hdl_t vhdl, char *buf, uint buflen) +{ + if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS) + return(buf); + else + return(DEVNAME_UNKNOWN); +} + +graph_error_t +hwgraph_edge_remove(vertex_hdl_t from, char *name, vertex_hdl_t *toptr) +{ + return(GRAPH_ILLEGAL_REQUEST); +} + +graph_error_t +hwgraph_vertex_unref(vertex_hdl_t vhdl) +{ + return(GRAPH_ILLEGAL_REQUEST); +} + + +EXPORT_SYMBOL(hwgraph_mk_dir); +EXPORT_SYMBOL(hwgraph_path_add); +EXPORT_SYMBOL(hwgraph_register); +EXPORT_SYMBOL(hwgraph_vertex_destroy); +EXPORT_SYMBOL(hwgraph_fastinfo_get); +EXPORT_SYMBOL(hwgraph_fastinfo_set); +EXPORT_SYMBOL(hwgraph_connectpt_set); +EXPORT_SYMBOL(hwgraph_connectpt_get); +EXPORT_SYMBOL(hwgraph_info_add_LBL); +EXPORT_SYMBOL(hwgraph_info_remove_LBL); +EXPORT_SYMBOL(hwgraph_info_replace_LBL); +EXPORT_SYMBOL(hwgraph_info_get_LBL); +EXPORT_SYMBOL(hwgraph_info_get_exported_LBL); +EXPORT_SYMBOL(hwgraph_info_get_next_LBL); +EXPORT_SYMBOL(hwgraph_info_export_LBL); +EXPORT_SYMBOL(hwgraph_info_unexport_LBL); +EXPORT_SYMBOL(hwgraph_path_lookup); +EXPORT_SYMBOL(hwgraph_traverse); +EXPORT_SYMBOL(hwgraph_vertex_name_get); diff --git a/arch/ia64/sn/io/hcl_util.c b/arch/ia64/sn/io/hwgfs/hcl_util.c similarity index 80% rename from arch/ia64/sn/io/hcl_util.c rename to arch/ia64/sn/io/hwgfs/hcl_util.c index 961abe3a3ee..6b6bb228bd6 100644 --- a/arch/ia64/sn/io/hcl_util.c +++ b/arch/ia64/sn/io/hwgfs/hcl_util.c @@ -4,25 +4,25 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include -#include -#include #include #include #include #include +#include #include #include #include +#include #include #include -static devfs_handle_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE; -extern devfs_handle_t hwgraph_root; +static vertex_hdl_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE; +extern vertex_hdl_t hwgraph_root; /* @@ -30,11 +30,11 @@ extern devfs_handle_t hwgraph_root; ** controller or adapter or other piece of hardware that the given ** vertex passes through on the way to the rest of the system. */ -devfs_handle_t -device_master_get(devfs_handle_t vhdl) +vertex_hdl_t +device_master_get(vertex_hdl_t vhdl) { graph_error_t rc; - devfs_handle_t master; + vertex_hdl_t master; rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master); if (rc == GRAPH_SUCCESS) @@ -48,7 +48,7 @@ device_master_get(devfs_handle_t vhdl) ** Returns 0 on success, non-0 indicates failure */ int -device_master_set(devfs_handle_t vhdl, devfs_handle_t master) +device_master_set(vertex_hdl_t vhdl, vertex_hdl_t master) { graph_error_t rc; @@ -63,10 +63,10 @@ device_master_set(devfs_handle_t vhdl, devfs_handle_t master) ** until we reach a vertex that represents a node. */ cnodeid_t -master_node_get(devfs_handle_t vhdl) +master_node_get(vertex_hdl_t vhdl) { cnodeid_t cnodeid; - devfs_handle_t master; + vertex_hdl_t master; for (;;) { cnodeid = nodevertex_to_cnodeid(vhdl); @@ -96,11 +96,11 @@ master_node_get(devfs_handle_t vhdl) } } -static devfs_handle_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; +static vertex_hdl_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; extern int maxcpus; void -mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid) +mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid) { if (cpuid == CPU_NONE) return; @@ -128,7 +128,7 @@ mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid) ** compact node ID; otherwise, return CNODEID_NONE. */ cnodeid_t -nodevertex_to_cnodeid(devfs_handle_t vhdl) +nodevertex_to_cnodeid(vertex_hdl_t vhdl) { int rv = 0; arbitrary_info_t cnodeid = CNODEID_NONE; @@ -139,7 +139,7 @@ nodevertex_to_cnodeid(devfs_handle_t vhdl) } void -mark_nodevertex_as_node(devfs_handle_t vhdl, cnodeid_t cnodeid) +mark_nodevertex_as_node(vertex_hdl_t vhdl, cnodeid_t cnodeid) { if (cnodeid == CNODEID_NONE) return; @@ -169,7 +169,7 @@ mark_nodevertex_as_node(devfs_handle_t vhdl, cnodeid_t cnodeid) ** otherwise, return CPU_NONE. */ cpuid_t -cpuvertex_to_cpuid(devfs_handle_t vhdl) +cpuvertex_to_cpuid(vertex_hdl_t vhdl) { arbitrary_info_t cpuid = CPU_NONE; @@ -180,9 +180,9 @@ cpuvertex_to_cpuid(devfs_handle_t vhdl) /* -** dev_to_name converts a devfs_handle_t into a canonical name. If the devfs_handle_t +** dev_to_name converts a vertex_hdl_t into a canonical name. If the vertex_hdl_t ** represents a vertex in the hardware graph, it is converted in the -** normal way for vertices. If the devfs_handle_t is an old devfs_handle_t (one which +** normal way for vertices. If the vertex_hdl_t is an old vertex_hdl_t (one which ** does not represent a hwgraph vertex), we synthesize a name based ** on major/minor number. ** @@ -192,7 +192,7 @@ cpuvertex_to_cpuid(devfs_handle_t vhdl) ** returns "UnknownDevice". */ char * -dev_to_name(devfs_handle_t dev, char *buf, uint buflen) +dev_to_name(vertex_hdl_t dev, char *buf, uint buflen) { return(vertex_to_name(dev, buf, buflen)); } diff --git a/arch/ia64/sn/io/hwgfs/interface.c b/arch/ia64/sn/io/hwgfs/interface.c new file mode 100644 index 00000000000..b1d5d702877 --- /dev/null +++ b/arch/ia64/sn/io/hwgfs/interface.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Portions based on Adam Richter's smalldevfs and thus + * Copyright 2002-2003 Yggdrasil Computing, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +extern struct vfsmount *hwgfs_vfsmount; + +/* TODO: Move this to some .h file or, more likely, use a slightly + different interface from lookup_create. */ +extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); + +static int +walk_parents_mkdir( + const char **path, + struct nameidata *nd, + int is_dir) +{ + char *slash; + char buf[strlen(*path)+1]; + int error; + + while ((slash = strchr(*path, '/')) != NULL) { + int len = slash - *path; + memcpy(buf, *path, len); + buf[len] = '\0'; + + error = link_path_walk(buf, nd); + if (unlikely(error)) + return error; + + nd->dentry = lookup_create(nd, is_dir); + if (unlikely(IS_ERR(nd->dentry))) + return PTR_ERR(nd->dentry); + + if (!nd->dentry->d_inode) + error = vfs_mkdir(nd->dentry->d_parent->d_inode, + nd->dentry, 0755); + + up(&nd->dentry->d_parent->d_inode->i_sem); + if (unlikely(error)) + return error; + + *path += len + 1; + } + + return 0; +} + +/* On success, returns with parent_inode->i_sem taken. */ +static int +hwgfs_decode( + hwgfs_handle_t dir, + const char *name, + int is_dir, + struct inode **parent_inode, + struct dentry **dentry) +{ + struct nameidata nd; + int error; + + if (!dir) + dir = hwgfs_vfsmount->mnt_sb->s_root; + + memset(&nd, 0, sizeof(nd)); + nd.flags = LOOKUP_PARENT; + nd.mnt = mntget(hwgfs_vfsmount); + nd.dentry = dget(dir); + + error = walk_parents_mkdir(&name, &nd, is_dir); + if (unlikely(error)) + return error; + + error = link_path_walk(name, &nd); + if (unlikely(error)) + return error; + + *dentry = lookup_create(&nd, is_dir); + + if (unlikely(IS_ERR(*dentry))) + return PTR_ERR(*dentry); + *parent_inode = (*dentry)->d_parent->d_inode; + return 0; +} + +static int +path_len( + struct dentry *de, + struct dentry *root) +{ + int len = 0; + + while (de != root) { + len += de->d_name.len + 1; /* count the '/' */ + de = de->d_parent; + } + return len; /* -1 because we omit the leading '/', + +1 because we include trailing '\0' */ +} + +int +hwgfs_generate_path( + hwgfs_handle_t de, + char *path, + int buflen) +{ + struct dentry *hwgfs_root; + int len; + char *path_orig = path; + + if (unlikely(de == NULL)) + return -EINVAL; + + hwgfs_root = hwgfs_vfsmount->mnt_sb->s_root; + if (unlikely(de == hwgfs_root)) + return -EINVAL; + + spin_lock(&dcache_lock); + len = path_len(de, hwgfs_root); + if (len > buflen) { + spin_unlock(&dcache_lock); + return -ENAMETOOLONG; + } + + path += len - 1; + *path = '\0'; + + for (;;) { + path -= de->d_name.len; + memcpy(path, de->d_name.name, de->d_name.len); + de = de->d_parent; + if (de == hwgfs_root) + break; + *(--path) = '/'; + } + + spin_unlock(&dcache_lock); + BUG_ON(path != path_orig); + return 0; +} + +hwgfs_handle_t +hwgfs_register( + hwgfs_handle_t dir, + const char *name, + unsigned int flags, + unsigned int major, + unsigned int minor, + umode_t mode, + void *ops, + void *info) +{ + dev_t devnum = MKDEV(major, minor); + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_mknod(parent_inode, dentry, mode, devnum); + if (likely(!error)) { + /* + * Do this inside parents i_sem to avoid racing + * with lookups. + */ + if (S_ISCHR(mode)) + dentry->d_inode->i_fop = ops; + dentry->d_fsdata = info; + up(&parent_inode->i_sem); + } else { + up(&parent_inode->i_sem); + dput(dentry); + dentry = NULL; + } + } + + return dentry; +} + +int +hwgfs_mk_symlink( + hwgfs_handle_t dir, + const char *name, + unsigned int flags, + const char *link, + hwgfs_handle_t *handle, + void *info) +{ + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_symlink(parent_inode, dentry, link); + dentry->d_fsdata = info; + if (handle) + *handle = dentry; + up(&parent_inode->i_sem); + /* dput(dentry); */ + } + return error; +} + +hwgfs_handle_t +hwgfs_mk_dir( + hwgfs_handle_t dir, + const char *name, + void *info) +{ + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 1, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_mkdir(parent_inode, dentry, 0755); + up(&parent_inode->i_sem); + + if (unlikely(error)) { + dput(dentry); + dentry = NULL; + } else { + dentry->d_fsdata = info; + } + } + return dentry; +} + +void +hwgfs_unregister( + hwgfs_handle_t de) +{ + struct inode *parent_inode = de->d_parent->d_inode; + + if (S_ISDIR(de->d_inode->i_mode)) + vfs_rmdir(parent_inode, de); + else + vfs_unlink(parent_inode, de); +} + +/* XXX: this function is utterly bogus. Every use of it is racy and the + prototype is stupid. You have been warned. --hch. */ +hwgfs_handle_t +hwgfs_find_handle( + hwgfs_handle_t base, + const char *name, + unsigned int major, /* IGNORED */ + unsigned int minor, /* IGNORED */ + char type, /* IGNORED */ + int traverse_symlinks) +{ + struct dentry *dentry = NULL; + struct nameidata nd; + int error; + + BUG_ON(*name=='/'); + + memset(&nd, 0, sizeof(nd)); + + nd.mnt = mntget(hwgfs_vfsmount); + nd.dentry = dget(base ? base : hwgfs_vfsmount->mnt_sb->s_root); + if (traverse_symlinks) + nd.flags = LOOKUP_FOLLOW; + + error = link_path_walk(name, &nd); + if (likely(!error)) { + dentry = nd.dentry; + path_release(&nd); /* stale data from here! */ + } + + return dentry; +} + +hwgfs_handle_t +hwgfs_get_parent( + hwgfs_handle_t de) +{ + struct dentry *parent; + + spin_lock(&de->d_lock); + parent = de->d_parent; + spin_unlock(&de->d_lock); + + return parent; +} + +int +hwgfs_set_info( + hwgfs_handle_t de, + void *info) +{ + if (unlikely(de == NULL)) + return -EINVAL; + de->d_fsdata = info; + return 0; +} + +void * +hwgfs_get_info( + hwgfs_handle_t de) +{ + return de->d_fsdata; +} + +EXPORT_SYMBOL(hwgfs_generate_path); +EXPORT_SYMBOL(hwgfs_register); +EXPORT_SYMBOL(hwgfs_unregister); +EXPORT_SYMBOL(hwgfs_mk_symlink); +EXPORT_SYMBOL(hwgfs_mk_dir); +EXPORT_SYMBOL(hwgfs_find_handle); +EXPORT_SYMBOL(hwgfs_get_parent); +EXPORT_SYMBOL(hwgfs_set_info); +EXPORT_SYMBOL(hwgfs_get_info); diff --git a/arch/ia64/sn/io/hwgfs/invent_stub.c b/arch/ia64/sn/io/hwgfs/invent_stub.c new file mode 100644 index 00000000000..0087bf21164 --- /dev/null +++ b/arch/ia64/sn/io/hwgfs/invent_stub.c @@ -0,0 +1,148 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * Hardware Inventory + * + * See sys/sn/invent.h for an explanation of the hardware inventory contents. + * + */ +#include +#include +#include +#include +#include +#include +#include + +void +inventinit(void) +{ +} + +/* + * For initializing/updating an inventory entry. + */ +void +replace_in_inventory( + inventory_t *pinv, int class, int type, + int controller, int unit, int state) +{ +} + +/* + * Inventory addition + * + * XXX NOTE: Currently must be called after dynamic memory allocator is + * initialized. + * + */ +void +add_to_inventory(int class, int type, int controller, int unit, int state) +{ +} + + +/* + * Inventory retrieval + * + * These two routines are intended to prevent the caller from having to know + * the internal structure of the inventory table. + * + * The caller of get_next_inventory is supposed to call start_scan_invent + * before the irst call to get_next_inventory, and the caller is required + * to call end_scan_invent after the last call to get_next_inventory. + */ +inventory_t * +get_next_inventory(invplace_t *place) +{ + return((inventory_t *) NULL); +} + +/* ARGSUSED */ +int +get_sizeof_inventory(int abi) +{ + return sizeof(inventory_t); +} + +/* Must be called prior to first call to get_next_inventory */ +void +start_scan_inventory(invplace_t *iplace) +{ +} + +/* Must be called after last call to get_next_inventory */ +void +end_scan_inventory(invplace_t *iplace) +{ +} + +/* + * Hardware inventory scanner. + * + * Calls fun() for every entry in inventory list unless fun() returns something + * other than 0. + */ +int +scaninvent(int (*fun)(inventory_t *, void *), void *arg) +{ + return 0; +} + +/* + * Find a particular inventory object + * + * pinv can be a pointer to an inventory entry and the search will begin from + * there, or it can be 0 in which case the search starts at the beginning. + * A -1 for any of the other arguments is a wildcard (i.e. it always matches). + */ +inventory_t * +find_inventory(inventory_t *pinv, int class, int type, int controller, + int unit, int state) +{ + return((inventory_t *) NULL); +} + + +/* +** Retrieve inventory data associated with a device. +*/ +inventory_t * +device_inventory_get_next( vertex_hdl_t device, + invplace_t *invplace) +{ + return((inventory_t *) NULL); +} + + +/* +** Associate canonical inventory information with a device (and +** add it to the general inventory). +*/ +void +device_inventory_add( vertex_hdl_t device, + int class, + int type, + major_t controller, + minor_t unit, + int state) +{ +} + +int +device_controller_num_get(vertex_hdl_t device) +{ + return (0); +} + +void +device_controller_num_set(vertex_hdl_t device, int contr_num) +{ +} diff --git a/arch/ia64/sn/io/labelcl.c b/arch/ia64/sn/io/hwgfs/labelcl.c similarity index 90% rename from arch/ia64/sn/io/labelcl.c rename to arch/ia64/sn/io/hwgfs/labelcl.c index 33c2bd8c4da..0521b4c3295 100644 --- a/arch/ia64/sn/io/labelcl.c +++ b/arch/ia64/sn/io/hwgfs/labelcl.c @@ -4,14 +4,18 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include +#include +#include +#include +#include /* needed for smp_lock.h :( */ +#include #include -#include -#include +#include #include #include #include @@ -166,8 +170,8 @@ out: /* * labelcl_info_create - Creates the data structure that will hold the - * device private information asscoiated with a devfs entry. - * The pointer to this structure is what gets stored in the devfs + * device private information asscoiated with a entry. + * The pointer to this structure is what gets stored in the * (void * info). */ labelcl_info_t * @@ -188,11 +192,11 @@ labelcl_info_create() /* * labelcl_info_destroy - Frees the data structure that holds the - * device private information asscoiated with a devfs entry. This + * device private information asscoiated with a entry. This * data structure was created by device_info_create(). * * The caller is responsible for nulling the (void *info) in the - * corresponding devfs entry. + * corresponding entry. */ int labelcl_info_destroy(labelcl_info_t *labelcl_info) @@ -219,7 +223,7 @@ labelcl_info_destroy(labelcl_info_t *labelcl_info) * Error is returned if we find another label with the same name. */ int -labelcl_info_add_LBL(devfs_handle_t de, +labelcl_info_add_LBL(vertex_hdl_t de, char *info_name, arb_info_desc_t info_desc, arbitrary_info_t info) @@ -234,7 +238,7 @@ labelcl_info_add_LBL(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -275,7 +279,6 @@ labelcl_info_add_LBL(devfs_handle_t de, if (!strcmp(info_name, old_label_list[i].name)) { /* Not allowed to add duplicate labelled info names. */ kfree(new_label_list); - printk(KERN_WARNING "labelcl_info_add_LBL: Duplicate label name %s for vertex 0x%p\n", info_name, (void *)de); return(-1); } new_label_list[i] = old_label_list[i]; /* structure copy */ @@ -298,7 +301,7 @@ labelcl_info_add_LBL(devfs_handle_t de, * labelcl_info_remove_LBL - Remove a label entry. */ int -labelcl_info_remove_LBL(devfs_handle_t de, +labelcl_info_remove_LBL(vertex_hdl_t de, char *info_name, arb_info_desc_t *info_desc, arbitrary_info_t *info) @@ -314,7 +317,7 @@ labelcl_info_remove_LBL(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -388,7 +391,7 @@ found: * Label entry must exist. */ int -labelcl_info_replace_LBL(devfs_handle_t de, +labelcl_info_replace_LBL(vertex_hdl_t de, char *info_name, arb_info_desc_t info_desc, arbitrary_info_t info, @@ -403,7 +406,7 @@ labelcl_info_replace_LBL(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -446,7 +449,7 @@ labelcl_info_replace_LBL(devfs_handle_t de, * given label entry. */ int -labelcl_info_get_LBL(devfs_handle_t de, +labelcl_info_get_LBL(vertex_hdl_t de, char *info_name, arb_info_desc_t *info_desc, arbitrary_info_t *info) @@ -459,7 +462,7 @@ labelcl_info_get_LBL(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -493,7 +496,7 @@ labelcl_info_get_LBL(devfs_handle_t de, * labelcl_info_get_next_LBL - returns the next label entry on the list. */ int -labelcl_info_get_next_LBL(devfs_handle_t de, +labelcl_info_get_next_LBL(vertex_hdl_t de, char *buffer, arb_info_desc_t *info_descp, arbitrary_info_t *infop, @@ -512,7 +515,7 @@ labelcl_info_get_next_LBL(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -543,7 +546,7 @@ labelcl_info_get_next_LBL(devfs_handle_t de, int -labelcl_info_replace_IDX(devfs_handle_t de, +labelcl_info_replace_IDX(vertex_hdl_t de, int index, arbitrary_info_t info, arbitrary_info_t *old_info) @@ -552,13 +555,13 @@ labelcl_info_replace_IDX(devfs_handle_t de, labelcl_info_t *labelcl_info = NULL; if (de == NULL) { - printk(KERN_ALERT "labelcl: NULL devfs handle given.\n"); + printk(KERN_ALERT "labelcl: NULL handle given.\n"); return(-1); } - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) { - printk(KERN_ALERT "labelcl: Entry does not have info pointer.\n"); + printk(KERN_ALERT "labelcl: Entry %p does not have info pointer.\n", (void *)de); return(-1); } @@ -585,8 +588,8 @@ labelcl_info_replace_IDX(devfs_handle_t de, * labelcl_info_connectpt_set - Sets the connectpt. */ int -labelcl_info_connectpt_set(struct devfs_entry *de, - struct devfs_entry *connect_de) +labelcl_info_connectpt_set(hwgfs_handle_t de, + hwgfs_handle_t connect_de) { arbitrary_info_t old_info; int rv; @@ -607,7 +610,7 @@ labelcl_info_connectpt_set(struct devfs_entry *de, * */ int -labelcl_info_get_IDX(devfs_handle_t de, +labelcl_info_get_IDX(vertex_hdl_t de, int index, arbitrary_info_t *info) { @@ -617,7 +620,7 @@ labelcl_info_get_IDX(devfs_handle_t de, if (de == NULL) return(-1); - labelcl_info = devfs_get_info(de); + labelcl_info = hwgfs_get_info(de); if (labelcl_info == NULL) return(-1); @@ -640,8 +643,8 @@ labelcl_info_get_IDX(devfs_handle_t de, /* * labelcl_info_connectpt_get - Retrieve the connect point for a device entry. */ -struct devfs_entry * -labelcl_info_connectpt_get(struct devfs_entry *de) +hwgfs_handle_t +labelcl_info_connectpt_get(hwgfs_handle_t de) { int rv; arbitrary_info_t info; @@ -650,5 +653,5 @@ labelcl_info_connectpt_get(struct devfs_entry *de) if (rv) return(NULL); - return((struct devfs_entry *)info); + return((hwgfs_handle_t) info); } diff --git a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c new file mode 100644 index 00000000000..0bad4c76da9 --- /dev/null +++ b/arch/ia64/sn/io/hwgfs/ramfs.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Mostly shameless copied from Linus Torvalds' ramfs and thus + * Copyright (C) 2000 Linus Torvalds. + * 2000 Transmeta Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* some random number */ +#define HWGFS_MAGIC 0x12061983 + +static struct super_operations hwgfs_ops; +static struct address_space_operations hwgfs_aops; +static struct file_operations hwgfs_file_operations; +static struct inode_operations hwgfs_file_inode_operations; +static struct inode_operations hwgfs_dir_inode_operations; + +static struct backing_dev_info hwgfs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; + +struct inode *hwgfs_get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode * inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &hwgfs_aops; + inode->i_mapping->backing_dev_info = &hwgfs_backing_dev_info; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_op = &hwgfs_file_inode_operations; + inode->i_fop = &hwgfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &hwgfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +static int hwgfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode * inode = hwgfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int hwgfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + return hwgfs_mknod(dir, dentry, mode | S_IFDIR, 0); +} + +static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return hwgfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int hwgfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = hwgfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} + +static struct address_space_operations hwgfs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, + .commit_write = simple_commit_write +}; + +static struct file_operations hwgfs_file_operations = { + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .fsync = simple_sync_file, + .sendfile = generic_file_sendfile, +}; + +static struct inode_operations hwgfs_file_inode_operations = { + .getattr = simple_getattr, +}; + +static struct inode_operations hwgfs_dir_inode_operations = { + .create = hwgfs_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = simple_unlink, + .symlink = hwgfs_symlink, + .mkdir = hwgfs_mkdir, + .rmdir = simple_rmdir, + .mknod = hwgfs_mknod, + .rename = simple_rename, +}; + +static struct super_operations hwgfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static int hwgfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = HWGFS_MAGIC; + sb->s_op = &hwgfs_ops; + inode = hwgfs_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return 0; +} + +static struct super_block *hwgfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, hwgfs_fill_super); +} + +static struct file_system_type hwgfs_fs_type = { + .owner = THIS_MODULE, + .name = "hwgfs", + .get_sb = hwgfs_get_sb, + .kill_sb = kill_litter_super, +}; + +struct vfsmount *hwgfs_vfsmount; + +int __init init_hwgfs_fs(void) +{ + int error; + + error = register_filesystem(&hwgfs_fs_type); + if (error) + return error; + + hwgfs_vfsmount = kern_mount(&hwgfs_fs_type); + if (IS_ERR(hwgfs_vfsmount)) + goto fail; + return 0; + +fail: + unregister_filesystem(&hwgfs_fs_type); + return PTR_ERR(hwgfs_vfsmount); +} + +static void __exit exit_hwgfs_fs(void) +{ + unregister_filesystem(&hwgfs_fs_type); +} + +MODULE_LICENSE("GPL"); + +module_init(init_hwgfs_fs) +module_exit(exit_hwgfs_fs) diff --git a/arch/ia64/sn/io/invent.c b/arch/ia64/sn/io/invent.c deleted file mode 100644 index 9fce77d24cc..00000000000 --- a/arch/ia64/sn/io/invent.c +++ /dev/null @@ -1,224 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * Hardware Inventory - * - * See sys/sn/invent.h for an explanation of the hardware inventory contents. - * - */ -#include -#include -#include -#include -#include - -void -inventinit(void) -{ -} - -/* - * For initializing/updating an inventory entry. - */ -void -replace_in_inventory( - inventory_t *pinv, int class, int type, - int controller, int unit, int state) -{ - pinv->inv_class = class; - pinv->inv_type = type; - pinv->inv_controller = controller; - pinv->inv_unit = unit; - pinv->inv_state = state; -} - -/* - * Inventory addition - * - * XXX NOTE: Currently must be called after dynamic memory allocator is - * initialized. - * - */ -void -add_to_inventory(int class, int type, int controller, int unit, int state) -{ - (void)device_inventory_add((devfs_handle_t)GRAPH_VERTEX_NONE, class, type, - controller, unit, state); -} - - -/* - * Inventory retrieval - * - * These two routines are intended to prevent the caller from having to know - * the internal structure of the inventory table. - * - * The caller of get_next_inventory is supposed to call start_scan_invent - * before the irst call to get_next_inventory, and the caller is required - * to call end_scan_invent after the last call to get_next_inventory. - */ -inventory_t * -get_next_inventory(invplace_t *place) -{ - inventory_t *pinv; - devfs_handle_t device = place->invplace_vhdl; - int rv; - - while ((pinv = device_inventory_get_next(device, place)) == NULL) { - /* - * We've exhausted inventory items on the last device. - * Advance to next device. - */ - place->invplace_inv = NULL; /* Start from beginning invent on this device */ - rv = hwgraph_vertex_get_next(&device, &place->invplace_vplace); - if (rv == LABELCL_SUCCESS) { - place->invplace_vhdl = device; - } - else { - place->invplace_vhdl = GRAPH_VERTEX_NONE; - return(NULL); - } - } - - return(pinv); -} - -/* ARGSUSED */ -int -get_sizeof_inventory(int abi) -{ - return sizeof(inventory_t); -} - -/* Must be called prior to first call to get_next_inventory */ -void -start_scan_inventory(invplace_t *iplace) -{ - *iplace = INVPLACE_NONE; -} - -/* Must be called after last call to get_next_inventory */ -void -end_scan_inventory(invplace_t *iplace) -{ - devfs_handle_t vhdl = iplace->invplace_vhdl; - if (vhdl != GRAPH_VERTEX_NONE) - hwgraph_vertex_unref(vhdl); - *iplace = INVPLACE_NONE; /* paranoia */ -} - -/* - * Hardware inventory scanner. - * - * Calls fun() for every entry in inventory list unless fun() returns something - * other than 0. - */ -int -scaninvent(int (*fun)(inventory_t *, void *), void *arg) -{ - inventory_t *ie; - invplace_t iplace = { NULL,NULL, NULL }; - int rc; - - ie = 0; - rc = 0; - start_scan_inventory(&iplace); - while ((ie = (inventory_t *)get_next_inventory(&iplace))) { - rc = (*fun)(ie, arg); - if (rc) - break; - } - end_scan_inventory(&iplace); - return rc; -} - -/* - * Find a particular inventory object - * - * pinv can be a pointer to an inventory entry and the search will begin from - * there, or it can be 0 in which case the search starts at the beginning. - * A -1 for any of the other arguments is a wildcard (i.e. it always matches). - */ -inventory_t * -find_inventory(inventory_t *pinv, int class, int type, int controller, - int unit, int state) -{ - invplace_t iplace = { NULL,NULL, NULL }; - - start_scan_inventory(&iplace); - while ((pinv = (inventory_t *)get_next_inventory(&iplace)) != NULL) { - if (class != -1 && pinv->inv_class != class) - continue; - if (type != -1 && pinv->inv_type != type) - continue; - - /* XXXX - perhaps the "state" entry should be ignored so an - * an existing entry can be updated. See vino_init() and - * ml/IP22.c:add_ioboard() for an example. - */ - if (state != -1 && pinv->inv_state != state) - continue; - if (controller != -1 - && pinv->inv_controller != controller) - continue; - if (unit != -1 && pinv->inv_unit != unit) - continue; - break; - } - end_scan_inventory(&iplace); - - return(pinv); -} - - -/* -** Retrieve inventory data associated with a device. -*/ -inventory_t * -device_inventory_get_next( devfs_handle_t device, - invplace_t *invplace) -{ - inventory_t *pinv; - int rv; - - rv = hwgraph_inventory_get_next(device, invplace, &pinv); - if (rv == LABELCL_SUCCESS) - return(pinv); - else - return(NULL); -} - - -/* -** Associate canonical inventory information with a device (and -** add it to the general inventory). -*/ -void -device_inventory_add( devfs_handle_t device, - int class, - int type, - major_t controller, - minor_t unit, - int state) -{ - hwgraph_inventory_add(device, class, type, controller, unit, state); -} - -int -device_controller_num_get(devfs_handle_t device) -{ - return (hwgraph_controller_num_get(device)); -} - -void -device_controller_num_set(devfs_handle_t device, int contr_num) -{ - hwgraph_controller_num_set(device, contr_num); -} diff --git a/arch/ia64/sn/io/io.c b/arch/ia64/sn/io/io.c index c37cd823264..6059bbc37e5 100644 --- a/arch/ia64/sn/io/io.c +++ b/arch/ia64/sn/io/io.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -29,17 +29,11 @@ #include extern xtalk_provider_t hub_provider; -extern void hub_intr_init(devfs_handle_t hubv); +extern void hub_intr_init(vertex_hdl_t hubv); +static int force_fire_and_forget = 1; +static int ignore_conveyor_override; -/* - * Perform any initializations needed to support hub-based I/O. - * Called once during startup. - */ -void -hubio_init(void) -{ -} /* * Implementation of hub iobus operations. @@ -58,8 +52,8 @@ hubio_init(void) /* * Setup pio structures needed for a particular hub. */ -void -hub_pio_init(devfs_handle_t hubv) +static void +hub_pio_init(vertex_hdl_t hubv) { xwidgetnum_t widget; hubinfo_t hubinfo; @@ -114,7 +108,7 @@ hub_pio_init(devfs_handle_t hubv) */ /* ARGSUSED */ hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +hub_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -123,7 +117,7 @@ hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); hubinfo_t hubinfo; hub_piomap_t bw_piomap; int bigwin, free_bw_index; @@ -288,7 +282,7 @@ done: void hub_piomap_free(hub_piomap_t hub_piomap) { - devfs_handle_t hubv; + vertex_hdl_t hubv; hubinfo_t hubinfo; nasid_t nasid; unsigned long s; @@ -371,7 +365,7 @@ hub_piomap_done(hub_piomap_t hub_piomap) /* done with these mapping resources */ */ /* ARGSUSED */ caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ +hub_piotrans_addr( vertex_hdl_t dev, /* translate to this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -379,7 +373,7 @@ hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); hub_piomap_t hub_piomap; hubinfo_t hubinfo; caddr_t addr; @@ -416,7 +410,7 @@ hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ */ /* ARGSUSED */ hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for this device */ +hub_dmamap_alloc( vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) /* defined in dma.h */ @@ -424,7 +418,7 @@ hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for this device */ hub_dmamap_t dmamap; xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); dmamap = kmalloc(sizeof(struct hub_dmamap_s), GFP_ATOMIC); dmamap->hdma_xtalk_info.xd_dev = dev; @@ -460,7 +454,7 @@ hub_dmamap_addr( hub_dmamap_t dmamap, /* use these mapping resources */ paddr_t paddr, /* map for this address */ size_t byte_count) /* map this many bytes */ { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); @@ -479,12 +473,7 @@ hub_dmamap_addr( hub_dmamap_t dmamap, /* use these mapping resources */ } /* There isn't actually any DMA mapping hardware on the hub. */ -#ifdef CONFIG_IA64_SGI_SN2 return( (PHYS_TO_DMA(paddr)) ); -#else - /* no translation needed */ - return(paddr); -#endif } /* @@ -498,7 +487,7 @@ hub_dmamap_list(hub_dmamap_t hub_dmamap, /* use these mapping resources */ alenlist_t palenlist, /* map this area of memory */ unsigned flags) { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); @@ -527,7 +516,7 @@ hub_dmamap_list(hub_dmamap_t hub_dmamap, /* use these mapping resources */ void hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */ { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED; @@ -549,18 +538,13 @@ hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */ */ /* ARGSUSED */ iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_addr( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags) /* defined in dma.h */ { -#ifdef CONFIG_IA64_SGI_SN2 return( (PHYS_TO_DMA(paddr)) ); -#else - /* no translation needed */ - return(paddr); -#endif } /* @@ -570,7 +554,7 @@ hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ */ /* ARGSUSED */ alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_list( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags) /* defined in dma.h */ @@ -589,7 +573,7 @@ hub_dmamap_drain( hub_dmamap_t map) /*ARGSUSED*/ void -hub_dmaaddr_drain( devfs_handle_t vhdl, +hub_dmaaddr_drain( vertex_hdl_t vhdl, paddr_t addr, size_t bytes) { @@ -598,7 +582,7 @@ hub_dmaaddr_drain( devfs_handle_t vhdl, /*ARGSUSED*/ void -hub_dmalist_drain( devfs_handle_t vhdl, +hub_dmalist_drain( vertex_hdl_t vhdl, alenlist_t list) { /* XXX- flush caches, if cache coherency WAR is needed */ @@ -612,10 +596,8 @@ hub_dmalist_drain( devfs_handle_t vhdl, * Perform initializations that allow this hub to start crosstalk support. */ void -hub_provider_startup(devfs_handle_t hubv) +hub_provider_startup(vertex_hdl_t hubv) { - extern void hub_pio_init(devfs_handle_t hubv); - hub_pio_init(hubv); hub_intr_init(hubv); } @@ -624,7 +606,7 @@ hub_provider_startup(devfs_handle_t hubv) * Shutdown crosstalk support from a hub. */ void -hub_provider_shutdown(devfs_handle_t hub) +hub_provider_shutdown(vertex_hdl_t hub) { /* TBD */ xtalk_provider_unregister(hub); @@ -666,46 +648,6 @@ hub_check_window_equiv(void *addra, void *addrb) /* - * Determine whether two PCI addresses actually refer to the same device. - * This only works if both addresses are in small windows. It's used to - * determine whether prom addresses refer to particular PCI devices. - */ -/* - * XXX - This won't work as written if we ever have more than two nodes - * on a crossbow. In that case, we'll need an array or partners. - */ -int -hub_check_pci_equiv(void *addra, void *addrb) -{ - nasid_t nasida, nasidb; - - /* - * This is for a permanent workaround that causes us to use a - * big window in place of small window 0. - */ - if (!hub_check_window_equiv(addra, addrb)) - return 0; - - /* If the offsets aren't the same, forget it. */ - if (SWIN_WIDGETADDR((__psunsigned_t)addra) != - (SWIN_WIDGETADDR((__psunsigned_t)addrb))) - return 0; - - /* Now, check the nasids */ - nasida = NASID_GET(addra); - nasidb = NASID_GET(addrb); - - ASSERT(NASID_TO_COMPACT_NODEID(nasida) != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasidb) != INVALID_NASID); - - /* - * Either the NASIDs must be the same or they must be crossbow - * partners (on the same crossbow). - */ - return (check_nasid_equiv(nasida, nasidb)); -} - -/* * hub_setup_prb(nasid, prbnum, credits, conveyor) * * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, @@ -716,8 +658,6 @@ hub_setup_prb(nasid_t nasid, int prbnum, int credits, int conveyor) { iprb_t prb; int prb_offset; - extern int force_fire_and_forget; - extern volatile int ignore_conveyor_override; if (force_fire_and_forget && !ignore_conveyor_override) if (conveyor == HUB_PIO_CONVEYOR) @@ -776,13 +716,8 @@ hub_set_piomode(nasid_t nasid, int conveyor) int direct_connect; hubii_wcr_t ii_wcr; int prbnum; - int cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); - if (nasid == get_console_nasid()) { - PUTBUF_LOCK(s); - cons_lock = 1; - } ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); @@ -812,9 +747,6 @@ hub_set_piomode(nasid_t nasid, int conveyor) } REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); - - if (cons_lock) - PUTBUF_UNLOCK(s); } /* Interface to allow special drivers to set hub specific * device flags. @@ -842,90 +774,6 @@ hub_widget_flags_set(nasid_t nasid, return 1; } -/* Interface to allow special drivers to set hub specific - * device flags. - * Return 0 on failure , 1 on success - */ -int -hub_device_flags_set(devfs_handle_t widget_vhdl, - hub_widget_flags_t flags) -{ - xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); - xwidgetnum_t widget_num = xwidget_info_id_get(widget_info); - devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); - hubinfo_t hub_info = 0; - nasid_t nasid; - unsigned long s; - int rv; - - /* Use the nasid from the hub info hanging off the hub vertex - * and widget number from the widget vertex - */ - hubinfo_get(hub_vhdl, &hub_info); - /* Being over cautious by grabbing a lock */ - s = mutex_spinlock(&hub_info->h_bwlock); - nasid = hub_info->h_nasid; - rv = hub_widget_flags_set(nasid,widget_num,flags); - mutex_spinunlock(&hub_info->h_bwlock, s); - - return rv; -} - -/* - * hub_device_inquiry - * Find out the xtalk widget related information stored in this - * hub's II. - */ -void -hub_device_inquiry(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - devfs_handle_t xconn, hub_vhdl; - char widget_name[8]; - hubreg_t ii_iidem,ii_iiwa, ii_iowa; - hubinfo_t hubinfo; - nasid_t nasid; - int d; - - sprintf(widget_name, "%d", widget); - if (hwgraph_traverse(xbus_vhdl, widget_name, &xconn) - != GRAPH_SUCCESS) - return; - - hub_vhdl = device_master_get(xconn); - if (hub_vhdl == GRAPH_VERTEX_NONE) - return; - - hubinfo_get(hub_vhdl, &hubinfo); - if (!hubinfo) - return; - - nasid = hubinfo->h_nasid; - - ii_iidem = REMOTE_HUB_L(nasid, IIO_IIDEM); - ii_iiwa = REMOTE_HUB_L(nasid, IIO_IIWA); - ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA); - -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("Inquiry Info for %v\n", xconn); -#else - printk("Inquiry Info for %p\n", (void *)xconn); -#endif - - printk("\tDevices shutdown [ "); - - for (d = 0 ; d <= 7 ; d++) - if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d)))) - printk(" %d", d); - - printk("]\n"); - - printk("\tInbound access ? %s\n", - ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no"); - - printk("\tOutbound access ? %s\n", - ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no"); - -} /* * A pointer to this structure hangs off of every hub hwgraph vertex. @@ -955,8 +803,6 @@ xtalk_provider_t hub_provider = { (xtalk_intr_free_f *) hub_intr_free, (xtalk_intr_connect_f *) hub_intr_connect, (xtalk_intr_disconnect_f *) hub_intr_disconnect, - (xtalk_intr_cpu_get_f *) hub_intr_cpu_get, - (xtalk_provider_startup_f *) hub_provider_startup, (xtalk_provider_shutdown_f *) hub_provider_shutdown, }; diff --git a/arch/ia64/sn/io/klconflib.c b/arch/ia64/sn/io/klconflib.c deleted file mode 100644 index 7f8d63fd67b..00000000000 --- a/arch/ia64/sn/io/klconflib.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define printf printk -int hasmetarouter; - -#define LDEBUG 0 -#define NIC_UNKNOWN ((nic_t) -1) - -#undef DEBUG_KLGRAPH -#ifdef DEBUG_KLGRAPH -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_KLGRAPH */ - -static void sort_nic_names(lboard_t *) ; - -u64 klgraph_addr[MAX_COMPACT_NODES]; - -lboard_t * -find_lboard(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (start->brd_type == brd_type) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_class(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -klinfo_t * -find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) -{ - int index, j; - - if (kli == (klinfo_t *)NULL) { - index = 0; - } else { - for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { - if (kli == KLCF_COMP(brd, j)) - break; - } - index = j; - if (index == KLCF_NUM_COMPS(brd)) { - DBG("find_component: Bad pointer: 0x%p\n", kli); - return (klinfo_t *)NULL; - } - index++; /* next component */ - } - - for (; index < KLCF_NUM_COMPS(brd); index++) { - kli = KLCF_COMP(brd, index); - DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); - if (KLCF_COMP_TYPE(kli) == struct_type) - return kli; - } - - /* Didn't find it. */ - return (klinfo_t *)NULL; -} - -klinfo_t * -find_first_component(lboard_t *brd, unsigned char struct_type) -{ - return find_component(brd, (klinfo_t *)NULL, struct_type); -} - -lboard_t * -find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod) && - (start->brd_slot == slot)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module(lboard_t *start, moduleid_t mod) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_type) -{ - while (start) { - - DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type); - - if (MODULE_MATCH(start->brd_module, mod) && - (KLCLASS(start->brd_type) == KLCLASS(brd_type))) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - - -/* - * Convert a NIC name to a name for use in the hardware graph. - */ -void -nic_name_convert(char *old_name, char *new_name) -{ - int i; - char c; - char *compare_ptr; - - if ((old_name[0] == '\0') || (old_name[1] == '\0')) { - strcpy(new_name, EDGE_LBL_XWIDGET); - } else { - for (i = 0; i < strlen(old_name); i++) { - c = old_name[i]; - - if (isalpha(c)) - new_name[i] = tolower(c); - else if (isdigit(c)) - new_name[i] = c; - else - new_name[i] = '_'; - } - new_name[i] = '\0'; - } - - /* XXX - - * Since a bunch of boards made it out with weird names like - * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and - * replace it with "baseio" to avoid confusion in the field. - * We also have to make sure we don't report media_io instead of - * baseio. - */ - - /* Skip underscores at the beginning of the name */ - for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) - ; - - /* - * Check for some names we need to replace. Early boards - * had junk following the name so check only the first - * characters. - */ - if (!strncmp(new_name, "io6", 3) || - !strncmp(new_name, "mio", 3) || - !strncmp(new_name, "media_io", 8)) - strcpy(new_name, "baseio"); - else if (!strncmp(new_name, "divo", 4)) - strcpy(new_name, "divo") ; - -} - -/* Check if the given board corresponds to the global - * master io6 - */ -int -is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot) -{ - lboard_t *board; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -/* If this works then look for callers of is_master_baseio() - * (e.g. iograph.c) and let them pass in a slot if they want - */ - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module); -#else - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), module, slot); -#endif - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - board = find_lboard_module((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module); -#else - board = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module, slot); -#endif - } -#endif - if (!board) - return(0); - return(board->brd_flags & GLOBAL_MASTER_IO6); -} -/* - * Find the lboard structure and get the board name. - * If we can't find the structure or it's too low a revision, - * use default name. - */ -lboard_t * -get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name) -{ - lboard_t *brd; - - brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - mod, slot); - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) - brd = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - mod, slot); - } -#endif - - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, name); - } - - /* - * PV # 540860 - * If the name is not 'baseio' - * get the lowest of all the names in the nic string. - * This is needed for boards like divo, which can have - * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio - * but it has some special case names that we would not - * like to disturb at this point. - */ - - /* gfx boards don't need any of this name scrambling */ - if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { - return(brd); - } - - if (!(!strcmp(name, "baseio") )) { - if (brd) { - sort_nic_names(brd) ; - /* Convert to small case, '-' to '_' etc */ - nic_name_convert(brd->brd_name, name) ; - } - } - - return(brd); -} - -/* - * get_actual_nasid - * - * Completely disabled brds have their klconfig on - * some other nasid as they have no memory. But their - * actual nasid is hidden in the klconfig. Use this - * routine to get it. Works for normal boards too. - */ -nasid_t -get_actual_nasid(lboard_t *brd) -{ - klhub_t *hub ; - - if (!brd) - return INVALID_NASID ; - - /* find out if we are a completely disabled brd. */ - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - if (!hub) - return INVALID_NASID ; - if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ - return hub->hub_info.physid ; - else - return brd->brd_nasid ; -} - -int -xbow_port_io_enabled(nasid_t nasid, int link) -{ - lboard_t *brd; - klxbow_t *xbow_p; - - /* - * look for boards that might contain an xbow or xbridge - */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); - if (brd == NULL) return 0; - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return 0; - - if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) - return 0; - - DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); - - return 1; -} - -void -board_to_path(lboard_t *brd, char *path) -{ - moduleid_t modnum; - char *board_name; - - ASSERT(brd); - - switch (KLCLASS(brd->brd_type)) { - - case KLCLASS_NODE: - board_name = EDGE_LBL_NODE; - break; - case KLCLASS_ROUTER: - if (brd->brd_type == KLTYPE_META_ROUTER) { - board_name = EDGE_LBL_META_ROUTER; - hasmetarouter++; - } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { - board_name = EDGE_LBL_REPEATER_ROUTER; - hasmetarouter++; - } else - board_name = EDGE_LBL_ROUTER; - break; - case KLCLASS_MIDPLANE: - board_name = EDGE_LBL_MIDPLANE; - break; - case KLCLASS_IO: - board_name = EDGE_LBL_IO; - break; - case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PBRICK) - board_name = EDGE_LBL_PBRICK; - else if (brd->brd_type == KLTYPE_IBRICK) - board_name = EDGE_LBL_IBRICK; - else if (brd->brd_type == KLTYPE_XBRICK) - board_name = EDGE_LBL_XBRICK; - else - board_name = EDGE_LBL_IOBRICK; - break; - default: - board_name = EDGE_LBL_UNKNOWN; - } - - modnum = brd->brd_module; - - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#ifdef __ia64 - { - char buffer[16]; - memset(buffer, 0, 16); - format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); - sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); - } -#else - sprintf(path, "%H/%s", modnum, board_name); -#endif -} - -/* - * Get the module number for a NASID. - */ -moduleid_t -get_module_id(nasid_t nasid) -{ - lboard_t *brd; - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (!brd) - return INVALID_MODULE; - else - return brd->brd_module; -} - - -#define MHZ 1000000 - - -/* Get the canonical hardware graph name for the given pci component - * on the given io board. - */ -void -device_component_canonical_name_get(lboard_t *brd, - klinfo_t *component, - char *name) -{ - moduleid_t modnum; - slotid_t slot; - char board_name[20]; - - ASSERT(brd); - - /* Get the module number of this board */ - modnum = brd->brd_module; - - /* Convert the [ CLASS | TYPE ] kind of slotid - * into a string - */ - slot = brd->brd_slot; - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); - - /* Get the io board name */ - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, board_name); - } - - /* Give out the canonical name of the pci device*/ - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" - EDGE_LBL_PCI"/%d", - modnum, board_name,KLCF_BRIDGE_W_ID(component)); -} - -/* - * Get the serial number of the main component of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - * Assumptions: Nic manufacturing string has the following format - * *Serial:;* - */ -static int -component_serial_number_get(lboard_t *board, - klconf_off_t mfg_nic_offset, - char *serial_number, - char *key_pattern) -{ - - char *mfg_nic_string; - char *serial_string,*str; - int i; - char *serial_pattern = "Serial:"; - - /* We have an error on a null mfg nic offset */ - if (!mfg_nic_offset) - return(1); - /* Get the hub's manufacturing nic information - * which is in the form of a pre-formatted string - */ - mfg_nic_string = - (char *)NODE_OFFSET_TO_K0(NASID_GET(board), - mfg_nic_offset); - /* There is no manufacturing nic info */ - if (!mfg_nic_string) - return(1); - - str = mfg_nic_string; - /* Look for the key pattern first (if it is specified) - * and then print the serial number corresponding to that. - */ - if (strcmp(key_pattern,"") && - !(str = strstr(mfg_nic_string,key_pattern))) - return(1); - - /* There is no serial number info in the manufacturing - * nic info - */ - if (!(serial_string = strstr(str,serial_pattern))) - return(1); - - serial_string = serial_string + strlen(serial_pattern); - /* Copy the serial number information from the klconfig */ - i = 0; - while (serial_string[i] != ';') { - serial_number[i] = serial_string[i]; - i++; - } - serial_number[i] = 0; - - return(0); -} -/* - * Get the serial number of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - */ - -int -board_serial_number_get(lboard_t *board,char *serial_number) -{ - ASSERT(board && serial_number); - if (!board || !serial_number) - return(1); - - strcpy(serial_number,""); - switch(KLCLASS(board->brd_type)) { - case KLCLASS_CPU: { /* Node board */ - klhub_t *hub; - - /* Get the hub component information */ - hub = (klhub_t *)find_first_component(board, - KLSTRUCT_HUB); - /* If we don't have a hub component on an IP27 - * then we have a weird klconfig. - */ - if (!hub) - return(1); - /* Get the serial number information from - * the hub's manufacturing nic info - */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - "IP37")) -#else - "IP27")) - /* Try with IP31 key if IP27 key fails */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, - "IP31")) -#endif /* CONFIG_IA64_SGI_SN1 */ - return(1); - break; - } - case KLCLASS_IO: { /* IO board */ - if (KLTYPE(board->brd_type) == KLTYPE_TPU) { - /* Special case for TPU boards */ - kltpu_t *tpu; - - /* Get the tpu component information */ - tpu = (kltpu_t *)find_first_component(board, - KLSTRUCT_TPU); - /* If we don't have a tpu component on a tpu board - * then we have a weird klconfig. - */ - if (!tpu) - return(1); - /* Get the serial number information from - * the tpu's manufacturing nic info - */ - if (component_serial_number_get(board, - tpu->tpu_mfg_nic, - serial_number, - "")) - return(1); - break; - } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) || - (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) { - /* Special case for GSN boards */ - klgsn_t *gsn; - - /* Get the gsn component information */ - gsn = (klgsn_t *)find_first_component(board, - ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ? - KLSTRUCT_GSN_A : KLSTRUCT_GSN_B)); - /* If we don't have a gsn component on a gsn board - * then we have a weird klconfig. - */ - if (!gsn) - return(1); - /* Get the serial number information from - * the gsn's manufacturing nic info - */ - if (component_serial_number_get(board, - gsn->gsn_mfg_nic, - serial_number, - "")) - return(1); - break; - } else { - klbri_t *bridge; - - /* Get the bridge component information */ - bridge = (klbri_t *)find_first_component(board, - KLSTRUCT_BRI); - /* If we don't have a bridge component on an IO board - * then we have a weird klconfig. - */ - if (!bridge) - return(1); - /* Get the serial number information from - * the bridge's manufacturing nic info - */ - if (component_serial_number_get(board, - bridge->bri_mfg_nic, - serial_number, - "")) - return(1); - break; - } - } - case KLCLASS_ROUTER: { /* Router board */ - klrou_t *router; - - /* Get the router component information */ - router = (klrou_t *)find_first_component(board, - KLSTRUCT_ROU); - /* If we don't have a router component on a router board - * then we have a weird klconfig. - */ - if (!router) - return(1); - /* Get the serial number information from - * the router's manufacturing nic info - */ - if (component_serial_number_get(board, - router->rou_mfg_nic, - serial_number, - "")) - return(1); - break; - } - case KLCLASS_GFX: { /* Gfx board */ - klgfx_t *graphics; - - /* Get the graphics component information */ - graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); - /* If we don't have a gfx component on a gfx board - * then we have a weird klconfig. - */ - if (!graphics) - return(1); - /* Get the serial number information from - * the graphics's manufacturing nic info - */ - if (component_serial_number_get(board, - graphics->gfx_mfg_nic, - serial_number, - "")) - return(1); - break; - } - default: - strcpy(serial_number,""); - break; - } - return(0); -} - -#include "asm/sn/sn_private.h" - -xwidgetnum_t -nodevertex_widgetnum_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - return(hubinfo_p->h_widgetid); -} - -devfs_handle_t -nodevertex_xbow_peer_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - nasid_t xbow_peer_nasid; - cnodeid_t xbow_peer; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; - if(xbow_peer_nasid == INVALID_NASID) - return ( (devfs_handle_t)-1); - xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); - return(NODEPDA(xbow_peer)->node_vertex); -} - -/* NIC Sorting Support */ - -#define MAX_NICS_PER_STRING 32 -#define MAX_NIC_NAME_LEN 32 - -static char * -get_nic_string(lboard_t *lb) -{ - int i; - klinfo_t *k = NULL ; - klconf_off_t mfg_off = 0 ; - char *mfg_nic = NULL ; - - for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { - k = KLCF_COMP(lb, i) ; - switch(k->struct_type) { - case KLSTRUCT_BRI: - mfg_off = ((klbri_t *)k)->bri_mfg_nic ; - break ; - - case KLSTRUCT_HUB: - mfg_off = ((klhub_t *)k)->hub_mfg_nic ; - break ; - - case KLSTRUCT_ROU: - mfg_off = ((klrou_t *)k)->rou_mfg_nic ; - break ; - - case KLSTRUCT_GFX: - mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; - break ; - - case KLSTRUCT_TPU: - mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; - break ; - - case KLSTRUCT_GSN_A: - case KLSTRUCT_GSN_B: - mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; - break ; - - case KLSTRUCT_XTHD: - mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; - break; - - default: - mfg_off = 0 ; - break ; - } - if (mfg_off) - break ; - } - - if ((mfg_off) && (k)) - mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; - - return mfg_nic ; -} - -char * -get_first_string(char **ptrs, int n) -{ - int i ; - char *tmpptr ; - - if ((ptrs == NULL) || (n == 0)) - return NULL ; - - tmpptr = ptrs[0] ; - - if (n == 1) - return tmpptr ; - - for (i = 0 ; i < n ; i++) { - if (strcmp(tmpptr, ptrs[i]) > 0) - tmpptr = ptrs[i] ; - } - - return tmpptr ; -} - -int -get_ptrs(char *idata, char **ptrs, int n, char *label) -{ - int i = 0 ; - char *tmp = idata ; - - if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) - return 0 ; - - while ( (tmp = strstr(tmp, label)) ){ - tmp += strlen(label) ; - /* check for empty name field, and last NULL ptr */ - if ((i < (n-1)) && (*tmp != ';')) { - ptrs[i++] = tmp ; - } - } - - ptrs[i] = NULL ; - - return i ; -} - -/* - * sort_nic_names - * - * Does not really do sorting. Find the alphabetically lowest - * name among all the nic names found in a nic string. - * - * Return: - * Nothing - * - * Side Effects: - * - * lb->brd_name gets the new name found - */ - -static void -sort_nic_names(lboard_t *lb) -{ - char *nic_str ; - char *ptrs[MAX_NICS_PER_STRING] ; - char name[MAX_NIC_NAME_LEN] ; - char *tmp, *tmp1 ; - - *name = 0 ; - - /* Get the nic pointer from the lb */ - - if ((nic_str = get_nic_string(lb)) == NULL) - return ; - - tmp = get_first_string(ptrs, - get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; - - if (tmp == NULL) - return ; - - if ( (tmp1 = strchr(tmp, ';')) ){ - strlcpy(name, tmp, tmp1-tmp) ; - } else { - strlcpy(name, tmp, (sizeof(name))) ; - } - - strlcpy(lb->brd_name, name, sizeof(lb->brd_name)) ; -} - - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdp789012345"; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - int rack, position; - char brickchar; - - rack = MODULE_GET_RACK(m); - ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); - brickchar = MODULE_GET_BTCHAR(m); - position = MODULE_GET_BPOS(m); - - if (fmt == MODULE_FORMAT_BRIEF) { - /* Brief module number format, eg. 002c15 */ - - /* Decompress the rack number */ - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - /* Add the brick type */ - *buffer++ = brickchar; - } - else if (fmt == MODULE_FORMAT_LONG) { - /* Fuller hwgraph format, eg. rack/002/bay/15 */ - - strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); - - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); - } - - /* Add the bay position, using at least two digits */ - if (position < 10) - *buffer++ = '0'; - sprintf(buffer, "%d", position); - -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - * The long form does not include a brick type, so it defaults to 0 (CBrick) - */ -int -parse_module_id(char *buffer) -{ - unsigned int v, rack, bay, type, form; - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { - form = MODULE_FORMAT_LONG; - buffer += strlen(EDGE_LBL_RACK "/"); - - /* A long module ID must be exactly 5 non-template chars. */ - if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) - return -1; - } - else { - form = MODULE_FORMAT_BRIEF; - - /* A brief module id must be exactly 6 characters */ - if (strlen(buffer) != 6) - return -2; - } - - /* The rack number must be exactly 3 digits */ - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) - return -3; - - rack = 0; - v = *buffer++ - '0'; - if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return -4; - RACK_ADD_CLASS(rack, v); - - v = *buffer++ - '0'; - if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return -5; - RACK_ADD_GROUP(rack, v); - - v = *buffer++ - '0'; - /* rack numbers are 1-based */ - if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return -6; - RACK_ADD_NUM(rack, v); - - if (form == MODULE_FORMAT_BRIEF) { - /* Next should be a module type character. Accept ucase or lcase. */ - c = *buffer++; - if (!isalpha(c)) - return -7; - - /* strchr() returns a pointer into brick_types[], or NULL */ - type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); - if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) - return -8; - } - else { - /* Hardcode the module type, and skip over the boilerplate */ - type = MODULE_CBRICK; - - if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) - return -9; - - buffer += strlen("/" EDGE_LBL_RPOS "/"); - } - - /* The bay number is last. Make sure it's exactly two digits */ - - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) - return -10; - - bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return -11; - - m = RBT_TO_MODULE(rack, bay, type); - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#else /* CONFIG_IA64_SGI_SN1 */ - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - if (fmt == MODULE_FORMAT_BRIEF) { - sprintf(buffer, "%d", m); - } - else if (fmt == MODULE_FORMAT_LONG) { - sprintf(buffer, EDGE_LBL_MODULE "/%d", m); - } -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - */ -int -parse_module_id(char *buffer) -{ - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_MODULE "/") == buffer) - buffer += strlen(EDGE_LBL_MODULE "/"); - - for (m = 0; *buffer; buffer++) { - c = *buffer; - if (!isdigit(c)) - return -1; - m = 10 * m + (c - '0'); - } - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#endif /* CONFIG_IA64_SGI_SN1 */ - - diff --git a/arch/ia64/sn/io/klgraph.c b/arch/ia64/sn/io/klgraph.c deleted file mode 100644 index dff9b11dee0..00000000000 --- a/arch/ia64/sn/io/klgraph.c +++ /dev/null @@ -1,804 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * klgraph.c- - * This file specifies the interface between the kernel and the PROM's - * configuration data structures. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define KLGRAPH_DEBUG 1 */ -#ifdef KLGRAPH_DEBUG -#define GRPRINTF(x) printk x -#define CE_GRPANIC CE_PANIC -#else -#define GRPRINTF(x) -#define CE_GRPANIC CE_PANIC -#endif - -#include - -extern char arg_maxnodes[]; -extern u64 klgraph_addr[]; - -/* - * Support for verbose inventory via hardware graph. - * klhwg_invent_alloc allocates the necessary size of inventory information - * and fills in the generic information. - */ -invent_generic_t * -klhwg_invent_alloc(cnodeid_t cnode, int class, int size) -{ - invent_generic_t *invent; - - invent = kern_malloc(size); - if (!invent) return NULL; - - invent->ig_module = NODE_MODULEID(cnode); - invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode)); - invent->ig_invclass = class; - - return invent; -} - -/* - * Add information about the baseio prom version number - * as a part of detailed inventory info in the hwgraph. - */ -void -klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) -{ - invent_miscinfo_t *baseio_inventory; - unsigned char version = 0,revision = 0; - - /* Allocate memory for the "detailed inventory" info - * for the baseio - */ - baseio_inventory = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); - baseio_inventory->im_type = INV_IO6PROM; - /* Read the io6prom revision from the nvram */ -#ifdef LATER - nvram_prom_version_get(&version,&revision); -#endif - /* Store the revision info in the inventory */ - baseio_inventory->im_version = version; - baseio_inventory->im_rev = revision; - /* Put the inventory info in the hardware graph */ - hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) baseio_inventory); - /* Make the information available to the user programs - * thru hwgfs. - */ - hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -char *hub_rev[] = { - "0.0", - "1.0", - "2.0", - "2.1", - "2.2", - "2.3" -}; - -/* - * Add detailed cpu inventory info to the hardware graph. - */ -void -klhwg_hub_invent_info(devfs_handle_t hubv, - cnodeid_t cnode, - klhub_t *hub) -{ - invent_miscinfo_t *hub_invent; - - hub_invent = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t)); - if (!hub_invent) - return; - - if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub)) - hub_invent->im_gen.ig_flag = INVENT_ENABLED; - - hub_invent->im_type = INV_HUB; - hub_invent->im_rev = hub->hub_info.revision; - hub_invent->im_speed = hub->hub_speed; - hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) hub_invent); - hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -/* ARGSUSED */ -void -klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) -{ -#if defined(CONFIG_IA64_SGI_SN1) - devfs_handle_t myhubv; - devfs_handle_t hub_mon; - devfs_handle_t synergy; - devfs_handle_t fsb0; - devfs_handle_t fsb1; - int rc; - extern struct file_operations hub_mon_fops; - - GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); - - (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); - rc = device_master_set(myhubv, node_vertex); - - /* - * hub perf stats. - */ - rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO, - (arbitrary_info_t)(&NODEPDA(cnode)->hubstats)); - - if (rc != GRAPH_SUCCESS) { - printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d", - (void *)myhubv, rc); - } - - klhwg_hub_invent_info(myhubv, cnode, hub); - - hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &hub_mon_fops, - (void *)(long)cnode); - - init_hub_stats(cnode, NODEPDA(cnode)); - - /* - * synergy perf - */ - (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy); - (void) hwgraph_path_add(synergy, "0", &fsb0); - (void) hwgraph_path_add(synergy, "1", &fsb1); - - fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0)); - - fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1)); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) -{ - lboard_t *brd; - klxbow_t *xbow_p; - nasid_t hub_nasid; - cnodeid_t hub_cnode; - int widgetnum; - devfs_handle_t xbow_v, hubv; - /*REFERENCED*/ - graph_error_t err; - - if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) - return; - - if (KL_CONFIG_DUPLICATE_BOARD(brd)) - return; - - GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n", - cnode, nasid)); - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return; - -#ifdef LATER - /* - * We cannot support this function in devfs .. see below where - * we use hwgraph_path_add() to create this vertex with a known - * name. - */ - err = hwgraph_vertex_create(&xbow_v); - ASSERT(err == GRAPH_SUCCESS); - - xswitch_vertex_init(xbow_v); -#endif /* LATER */ - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) - continue; - - hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - if (hub_nasid == INVALID_NASID) { - printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); - continue; - } - - hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); - - if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { - continue; - } - - hubv = cnodeid_to_vertex(hub_cnode); - - err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p to vertex 0x%p," - "error %d\n", - (void *)hubv, (void *)xbow_v, err); - } - xswitch_vertex_init(xbow_v); - - NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; - - /* - * XXX - This won't work is we ever hook up two hubs - * by crosstown through a crossbow. - */ - if (hub_nasid != nasid) { - NODEPDA(hub_cnode)->xbow_peer = nasid; - NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer = - hub_nasid; - } - - GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", - hub_nasid, EDGE_LBL_XTALK, hubv)); - -#ifdef LATER - err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " - "error %d\n", - hubv, hubv, xbow_v, xbow_v, err); - } -#endif - } -} - - -/* ARGSUSED */ -void -klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) -{ - nasid_t nasid; - lboard_t *brd; - klhub_t *hub; - devfs_handle_t node_vertex = NULL; - char path_buffer[100]; - int rv; - char *s; - int board_disabled = 0; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", - cnode, nasid, brd)); - ASSERT(brd); - - do { - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Node vertex creation failed. " - "Path == %s", - path_buffer); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - if(hub->hub_info.flags & KLINFO_ENABLE) - board_disabled = 0; - else - board_disabled = 1; - - if(!board_disabled) { - mark_nodevertex_as_node(node_vertex, - cnode + board_disabled * numnodes); - - s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - NODEPDA(cnode)->hwg_node_name = - kmalloc(strlen(s) + 1, - GFP_KERNEL); - ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL); - strcpy(NODEPDA(cnode)->hwg_node_name, s); - - hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); - - /* Set up node board's slot */ - NODEPDA(cnode)->slotdesc = brd->brd_slot; - - /* Set up the module we're in */ - NODEPDA(cnode)->module_id = brd->brd_module; - NODEPDA(cnode)->module = module_lookup(brd->brd_module); - } - - if(!board_disabled) - klhwg_add_hub(node_vertex, hub, cnode); - - brd = KLCF_NEXT(brd); - if (brd) - brd = find_lboard(brd, KLTYPE_SNIA); - else - break; - } while(brd); -} - - -/* ARGSUSED */ -void -klhwg_add_all_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - devfs_handle_t node_vertex; - char path_buffer[100]; - int rv; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - /* No routers stored in this node's memory */ - continue; - - do { - ASSERT(brd); - GRPRINTF(("Router board struct is %p\n", brd)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) - continue; - - GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module)); - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("Router path is %s\n", path_buffer)); - - /* Add the router */ - GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Router vertex creation " - "failed. Path == %s", - path_buffer); - - GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n", - brd)); - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), - KLTYPE_ROUTER)) ); - - GRPRINTF(("klhwg_add_all_routers: Done.\n")); - } - -} - -/* ARGSUSED */ -void -klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, - cnodeid_t cnode, nasid_t nasid) -{ - klrou_t *router; - char path_buffer[50]; - char dest_path[50]; - devfs_handle_t router_hndl; - devfs_handle_t dest_hndl; - int rc; - int port; - lboard_t *dest_brd; - - GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n", - cnode)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) { - GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n", - brd, cnode)); - return; - } - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); - - if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes)) - return; - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find router: %s", path_buffer); - - /* We don't know what to do with multiple router components */ - if (brd->brd_numcompts != 1) { - PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", - brd->brd_numcompts); - return; - } - - - /* Convert component 0 to klrou_t ptr */ - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), - brd->brd_compts[0]); - - for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - /* See if the port's active */ - if (router->rou_port[port].port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", - port)); - continue; - } - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) - == INVALID_CNODEID) { - continue; - } - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find router: %s", dest_path); - } - GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", - path_buffer, port, dest_path)); - - sprintf(dest_path, "%d", port); - - rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); - - if (rc == GRAPH_DUP) { - GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", - port, router->rou_port[port].port_nasid, - path_buffer, dest_path)); - continue; - } - - if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } -} - - -void -klhwg_connect_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - continue; - - do { - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - klhwg_connect_one_router(hwgraph_root, brd, - cnode, nasid); - - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); - } -} - - - -void -klhwg_connect_hubs(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - klhub_t *hub; - lboard_t *dest_brd; - devfs_handle_t hub_hndl; - devfs_handle_t dest_hndl; - char path_buffer[50]; - char dest_path[50]; - graph_error_t rc; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", - cnode)); - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(brd); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - - /* See if the port's active */ - if (hub->hub_port.port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_hubs: port inactive.\n")); - continue; - } - - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID) - continue; - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer)); - rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find hub: %s", path_buffer); - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - hub->hub_port.port_nasid, - hub->hub_port.port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find board: %s", dest_path); - } else { - - - GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n", - path_buffer, dest_path)); - - rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); - - if (rc != GRAPH_SUCCESS) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } - } -} - -/* Store the pci/vme disabled board information as extended administrative - * hints which can later be used by the drivers using the device/driver - * admin interface. - */ -void -klhwg_device_disable_hints_add(void) -{ - cnodeid_t cnode; /* node we are looking at */ - nasid_t nasid; /* nasid of the node */ - lboard_t *board; /* board we are looking at */ - int comp_index; /* component index */ - klinfo_t *component; /* component in the board we are - * looking at - */ - char device_name[MAXDEVNAME]; - -#ifdef LATER - device_admin_table_init(); -#endif - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - /* Check out all the board info stored on a node */ - while(board) { - /* No need to look at duplicate boards or non-io - * boards - */ - if (KL_CONFIG_DUPLICATE_BOARD(board) || - KLCLASS(board->brd_type) != KLCLASS_IO) { - board = KLCF_NEXT(board); - continue; - } - /* Check out all the components of a board */ - for (comp_index = 0; - comp_index < KLCF_NUM_COMPS(board); - comp_index++) { - component = KLCF_COMP(board,comp_index); - /* If the component is enabled move on to - * the next component - */ - if (KLCONFIG_INFO_ENABLED(component)) - continue; - /* NOTE : Since the prom only supports - * the disabling of pci devices the following - * piece of code makes sense. - * Make sure that this assumption is valid - */ - /* This component is disabled. Store this - * hint in the extended device admin table - */ - /* Get the canonical name of the pci device */ - device_component_canonical_name_get(board, - component, - device_name); -#ifdef LATER - device_admin_table_update(device_name, - ADMIN_LBL_DISABLED, - "yes"); -#endif -#ifdef DEBUG - printf("%s DISABLED\n",device_name); -#endif - } - /* go to the next board info stored on this - * node - */ - board = KLCF_NEXT(board); - } - } -} - -void -klhwg_add_all_modules(devfs_handle_t hwgraph_root) -{ - cmoduleid_t cm; - char name[128]; - devfs_handle_t vhdl; - int rc; - char buffer[16]; - - /* Add devices under each module */ - - for (cm = 0; cm < nummodules; cm++) { - /* Use module as module vertex fastinfo */ - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); - sprintf(name, EDGE_LBL_MODULE "/%s", buffer); -#else - sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]); - - /* Add system controller */ - -#ifdef __ia64 - sprintf(name, - EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, - buffer); -#else - sprintf(name, - EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, - modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT_ALWAYS(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_info_add_LBL(vhdl, - INFO_LBL_ELSC, - (arbitrary_info_t) (__psint_t) 1); - -#ifdef LATER - sndrv_attach(vhdl); -#else - /* - * We need to call the drivers attach routine .. - */ - FIXME("klhwg_add_all_modules: Need code to call driver attach.\n"); -#endif - } -} - -void -klhwg_add_all_nodes(devfs_handle_t hwgraph_root) -{ - //gda_t *gdap = GDA; - gda_t *gdap; - cnodeid_t cnode; - - gdap = (gda_t *)0xe000000000002400; - - FIXME("klhwg_add_all_nodes: FIX GDA\n"); - - for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - klhwg_add_node(hwgraph_root, cnode, gdap); - } - - for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - - klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]); - } - - /* - * As for router hardware inventory information, we set this - * up in router.c. - */ - - klhwg_add_all_routers(hwgraph_root); - klhwg_connect_routers(hwgraph_root); - klhwg_connect_hubs(hwgraph_root); - - /* Assign guardian nodes to each of the - * routers in the system. - */ - -#ifdef LATER - router_guardians_set(hwgraph_root); -#endif - - /* Go through the entire system's klconfig - * to figure out which pci components have been disabled - */ - klhwg_device_disable_hints_add(); - -} diff --git a/arch/ia64/sn/io/l1.c b/arch/ia64/sn/io/l1.c deleted file mode 100644 index fb7d48539e7..00000000000 --- a/arch/ia64/sn/io/l1.c +++ /dev/null @@ -1,3056 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* In general, this file is organized in a hierarchy from lower-level - * to higher-level layers, as follows: - * - * UART routines - * Bedrock/L1 "PPP-like" protocol implementation - * System controller "message" interface (allows multiplexing - * of various kinds of requests and responses with - * console I/O) - * Console interface: - * "l1_cons", the glue that allows the L1 to act - * as the system console for the stdio libraries - * - * Routines making use of the system controller "message"-style interface - * can be found in l1_command.c. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Make all console writes atomic */ -#define SYNC_CONSOLE_WRITE 1 - - -/********************************************************************* - * Hardware-level (UART) driver routines. - */ - -/* macros for reading/writing registers */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -/* location of uart receive/xmit data register */ -#if defined(CONFIG_IA64_SGI_SN1) -#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080)) -#define LOCK_HUB REMOTE_HUB_ADDR -#elif defined(CONFIG_IA64_SGI_SN2) -#define L1_UART_BASE(n) ((ulong)REMOTE_HUB((n), SH_JUNK_BUS_UART0)) -#define LOCK_HUB REMOTE_HUB -typedef u64 rtc_time_t; -#endif - - -#define ADDR_L1_REG(n, r) ( L1_UART_BASE(n) | ( (r) << 3 ) ) -#define READ_L1_UART_REG(n, r) ( LD(ADDR_L1_REG((n), (r))) ) -#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) ) - -/* upper layer interface calling methods */ -#define SERIAL_INTERRUPT_MODE 0 -#define SERIAL_POLLED_MODE 1 - - -/* UART-related #defines */ - -#define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 16 -#define UART_DELAY_SPAN 10 -#define UART_PUTC_TIMEOUT 50000 -#define UART_INIT_TIMEOUT 100000 - -/* error codes */ -#define UART_SUCCESS 0 -#define UART_TIMEOUT (-1) -#define UART_LINK (-2) -#define UART_NO_CHAR (-3) -#define UART_VECTOR (-4) - -#define UART_DELAY(x) udelay(x) - -/* Some debug counters */ -#define L1C_INTERRUPTS 0 -#define L1C_OUR_R_INTERRUPTS 1 -#define L1C_OUR_X_INTERRUPTS 2 -#define L1C_SEND_CALLUPS 3 -#define L1C_RECEIVE_CALLUPS 4 -#define L1C_SET_BAUD 5 -#define L1C_ALREADY_LOCKED L1C_SET_BAUD -#define L1C_R_IRQ 6 -#define L1C_R_IRQ_RET 7 -#define L1C_LOCK_TIMEOUTS 8 -#define L1C_LOCK_COUNTER 9 -#define L1C_UNLOCK_COUNTER 10 -#define L1C_REC_STALLS 11 -#define L1C_CONNECT_CALLS 12 -#define L1C_SIZE L1C_CONNECT_CALLS /* Set to the last one */ - -uint64_t L1_collectibles[L1C_SIZE + 1]; - - -/* - * Some macros for handling Endian-ness - */ - -#define COPY_INT_TO_BUFFER(_b, _i, _n) \ - { \ - _b[_i++] = (_n >> 24) & 0xff; \ - _b[_i++] = (_n >> 16) & 0xff; \ - _b[_i++] = (_n >> 8) & 0xff; \ - _b[_i++] = _n & 0xff; \ - } - -#define COPY_BUFFER_TO_INT(_b, _i, _n) \ - { \ - _n = (_b[_i++] << 24) & 0xff; \ - _n |= (_b[_i++] << 16) & 0xff; \ - _n |= (_b[_i++] << 8) & 0xff; \ - _n |= _b[_i++] & 0xff; \ - } - -#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn) \ - { \ - char *_xyz = (char *)_bn; \ - _xyz[3] = _b[_i++]; \ - _xyz[2] = _b[_i++]; \ - _xyz[1] = _b[_i++]; \ - _xyz[0] = _b[_i++]; \ - } - -void snia_kmem_free(void *where, int size); - -#define ALREADY_LOCKED 1 -#define NOT_LOCKED 0 -static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ ); - -#define BCOPY(x,y,z) memcpy(y,x,z) - -uint8_t L1_interrupts_connected; /* Non-zero when we are in interrupt mode */ - - -/* - * Console locking defines and functions. - * - */ - -uint8_t L1_cons_is_inited = 0; /* non-zero when console is init'd */ -nasid_t Master_console_nasid = (nasid_t)-1; -extern nasid_t console_nasid; - -u64 ia64_sn_get_console_nasid(void); - -inline nasid_t -get_master_nasid(void) -{ -#if defined(CONFIG_IA64_SGI_SN1) - nasid_t nasid = Master_console_nasid; - - if ( nasid == (nasid_t)-1 ) { - nasid = (nasid_t)ia64_sn_get_console_nasid(); - if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) { - /* Out of bounds, use local */ - console_nasid = nasid = get_nasid(); - } - else { - /* Got a valid nasid, set the console_nasid */ - char xx[100]; -/* zzzzzz - force nasid to 0 for now */ - sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid); -nasid = 0; -/* end zzzzzz */ - xx[99] = (char)0; - early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED); - Master_console_nasid = console_nasid = nasid; - } - } - return(nasid); -#else - return((nasid_t)0); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - - -#if defined(CONFIG_IA64_SGI_SN1) - -#define HUB_LOCK 16 - -#define PRIMARY_LOCK_TIMEOUT 10000000 -#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) - -#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) -#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) -#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) - -#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) -#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) - -#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) - -/* - * primary_lock - * - * Allows CPU's 0-3 to mutually exclude the hub from one another by - * obtaining a blocking lock. Does nothing if only one CPU is active. - * - * This lock should be held just long enough to set or clear a global - * lock bit. After a relatively short timeout period, this routine - * figures something is wrong, and steals the lock. It does not set - * any other CPU to "dead". - */ -inline void -primary_lock(nasid_t nasid) -{ - rtc_time_t expire; - - expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; - - while (HUB_TEST_AND_SET(nasid)) { - if (rtc_time() > expire) { - HUB_CLEAR(nasid); - } - } -} - -/* - * primary_unlock (internal) - * - * Counterpart to primary_lock - */ - -inline void -primary_unlock(nasid_t nasid) -{ - HUB_CLEAR(nasid); -} - -/* - * hub_unlock - * - * Counterpart to hub_lock_timeout and hub_lock - */ - -inline void -hub_unlock(nasid_t nasid, int level) -{ - uint64_t mask = 1ULL << level; - - primary_lock(nasid); - CLR_BITS(HUB_LOCK_REG(nasid), mask); - primary_unlock(nasid); -} - -/* - * hub_lock_timeout - * - * Uses primary_lock to implement multiple lock levels. - * - * There are 20 lock levels from 0 to 19 (limited by the number of bits - * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be - * obtained in order of increasingly higher level, and released in the - * reverse order. - * - * A timeout value of 0 may be used for no timeout. - * - * Returns 0 if successful, -1 if lock times out. - */ - -inline int -hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) -{ - uint64_t mask = 1ULL << level; - rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); - int done = 0; - - while (! done) { - while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { - if (rtc_time() > expire) - return -1; - } - - primary_lock(nasid); - - if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { - SET_BITS(HUB_LOCK_REG(nasid), mask); - done = 1; - } - primary_unlock(nasid); - } - return 0; -} - - -#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ - -void -lock_console(nasid_t nasid) -{ - int ret; - - /* If we already have it locked, just return */ - L1_collectibles[L1C_LOCK_COUNTER]++; - - ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - if ( ret != 0 ) { - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - /* timeout */ - hub_unlock(nasid, HUB_LOCK); - /* If the 2nd lock fails, just pile ahead.... */ - hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - } -} - -inline void -unlock_console(nasid_t nasid) -{ - L1_collectibles[L1C_UNLOCK_COUNTER]++; - hub_unlock(nasid, HUB_LOCK); -} - -#else /* SN2 */ -inline void lock_console(nasid_t n) {} -inline void unlock_console(nasid_t n) {} - -#endif /* CONFIG_IA64_SGI_SN1 */ - -int -get_L1_baud(void) -{ - return UART_BAUD_RATE; -} - - -/* uart driver functions */ - -static inline void -uart_delay( rtc_time_t delay_span ) -{ - UART_DELAY( delay_span ); -} - -#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) - -static int -uart_putc( l1sc_t *sc ) -{ - WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); - return UART_SUCCESS; -} - - -static int -uart_getc( l1sc_t *sc ) -{ - u_char lsr_reg = 0; - nasid_t nasid = sc->nasid; - - if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & - (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( lsr_reg & LSR_RCA ) - return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) ); - else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -#define PROM_SER_CLK_SPEED 12000000 -#define PROM_SER_DIVISOR(x) (PROM_SER_CLK_SPEED / ((x) * 16)) - -static void -uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + UART_INIT_TIMEOUT; - nasid = sc->nasid; - - /* make sure the transmit FIFO is empty */ - while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) { - uart_delay( UART_DELAY_SPAN ); - if( rtc_time() > expire ) { - break; - } - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* Setup for the proper baud rate */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - - /* 8bit, one stop, clear request to send, auto flow control */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs, trigger on 1 */ - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -uart_intr_enable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg |= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ -static void -uart_intr_disable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg &= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} -#endif /* CONFIG_IA64_SGI_SN1 */ - -#define uart_enable_xmit_intr(sc) \ - uart_intr_enable((sc), ICR_TIEN) - -#define uart_disable_xmit_intr(sc) \ - uart_intr_disable((sc), ~(ICR_TIEN)) - -#define uart_enable_recv_intr(sc) \ - uart_intr_enable((sc), ICR_RIEN) - -#define uart_disable_recv_intr(sc) \ - uart_intr_disable((sc), ~(ICR_RIEN)) - - -/********************************************************************* - * Routines for accessing a remote (router) UART - */ - -#define READ_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_read_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define WRITE_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_write_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 -#define RTR_UART_DELAY_SPAN UART_DELAY_SPAN -#define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 - -static int -rtr_uart_putc( l1sc_t *sc ) -{ - uint64_t regval, c; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; - - c = (sc->send[sc->sent] & 0xffULL); - - while( 1 ) - { - /* Check for "tx hold reg empty" bit. */ - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XHRE ) - { - WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c ); - return UART_SUCCESS; - } - - if( rtc_time() >= expire ) - { - return UART_TIMEOUT; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } -} - - -static int -rtr_uart_getc( l1sc_t *sc ) -{ - uint64_t regval; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( regval & LSR_RCA ) - { - READ_RTR_L1_UART_REG( path, nasid, REG_DAT, ®val ); - return( (int)regval ); - } - else - { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -static int -rtr_uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - net_vec_t path; - uint64_t regval; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + RTR_UART_INIT_TIMEOUT; - nasid = sc->nasid; - path = sc->uart; - - /* make sure the transmit FIFO is empty */ - while(1) { - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XSRE ) { - break; - } - if( rtc_time() > expire ) { - break; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } - - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, - FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); - - return 0; -} - -/********************************************************************* - * locking macros - */ - -#define L1SC_SEND_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); } -#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); } -#define L1SC_RECV_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } -#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); } - - -/********************************************************************* - * subchannel manipulation - * - * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel - * allocation. SUBCH_DATA_[UN]LOCK control access to data structures - * associated with particular subchannels (e.g., receive queues). - * - */ -#define SUBCH_LOCK(sc, p) spin_lock_irqsave( &((sc)->subch_lock), p ) -#define SUBCH_UNLOCK(sc, p) spin_unlock_irqrestore( &((sc)->subch_lock), p ) -#define SUBCH_DATA_LOCK(sbch, p) spin_lock_irqsave( &((sbch)->data_lock), p ) -#define SUBCH_DATA_UNLOCK(sbch, p) spin_unlock_irqrestore( &((sbch)->data_lock), p ) - - -/* - * set a function to be called for subchannel ch in the event of - * a transmission low-water interrupt from the uart - */ -void -subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - - L1SC_SEND_LOCK( sc, pl ); -#if !defined(SYNC_CONSOLE_WRITE) - if ( func && !sc->send_in_use ) - uart_enable_xmit_intr( sc ); -#endif - sc->subch[ch].tx_notify = func; - L1SC_SEND_UNLOCK(sc, pl ); -} - -/* - * set a function to be called for subchannel ch when data is received - */ -void -subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - SUBCH_DATA_LOCK( subch, pl ); - sc->subch[ch].rx_notify = func; - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/********************************************************************* - * Queue manipulation macros - * - * - */ -#define NEXT(p) (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */ - -#define cq_init(q) bzero((q), sizeof (*(q))) -#define cq_empty(q) ((q)->ipos == (q)->opos) -#define cq_full(q) (NEXT((q)->ipos) == (q)->opos) -#define cq_used(q) ((q)->opos <= (q)->ipos ? \ - (q)->ipos - (q)->opos : \ - BRL1_QSIZE + (q)->ipos - (q)->opos) -#define cq_room(q) ((q)->opos <= (q)->ipos ? \ - BRL1_QSIZE - 1 + (q)->opos - (q)->ipos : \ - (q)->opos - (q)->ipos - 1) -#define cq_add(q, c) ((q)->buf[(q)->ipos] = (u_char) (c), \ - (q)->ipos = NEXT((q)->ipos)) -#define cq_rem(q, c) ((c) = (q)->buf[(q)->opos], \ - (q)->opos = NEXT((q)->opos)) -#define cq_discard(q) ((q)->opos = NEXT((q)->opos)) - -#define cq_tent_full(q) (NEXT((q)->tent_next) == (q)->opos) -#define cq_tent_len(q) ((q)->ipos <= (q)->tent_next ? \ - (q)->tent_next - (q)->ipos : \ - BRL1_QSIZE + (q)->tent_next - (q)->ipos) -#define cq_tent_add(q, c) \ - ((q)->buf[(q)->tent_next] = (u_char) (c), \ - (q)->tent_next = NEXT((q)->tent_next)) -#define cq_commit_tent(q) \ - ((q)->ipos = (q)->tent_next) -#define cq_discard_tent(q) \ - ((q)->tent_next = (q)->ipos) - - - - -/********************************************************************* - * CRC-16 (for checking bedrock/L1 packets). - * - * These are based on RFC 1662 ("PPP in HDLC-like framing"). - */ - -static unsigned short fcstab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -#define INIT_CRC 0xFFFF /* initial CRC value */ -#define GOOD_CRC 0xF0B8 /* "good" final CRC value */ - -static unsigned short crc16_calc( unsigned short crc, u_char c ) -{ - return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] ); -} - - -/*********************************************************************** - * The following functions implement the PPP-like bedrock/L1 protocol - * layer. - * - */ - -#define BRL1_FLAG_CH 0x7e -#define BRL1_ESC_CH 0x7d -#define BRL1_XOR_CH 0x20 - -/* L1<->Bedrock packet types */ -#define BRL1_REQUEST 0x00 -#define BRL1_RESPONSE 0x20 -#define BRL1_EVENT 0x40 - -#define BRL1_PKT_TYPE_MASK 0xE0 -#define BRL1_SUBCH_MASK 0x1F - -#define PKT_TYPE(tsb) ((tsb) & BRL1_PKT_TYPE_MASK) -#define SUBCH(tsb) ((tsb) & BRL1_SUBCH_MASK) - -/* timeouts */ -#define BRL1_INIT_TIMEOUT 500000 - -/* - * brl1_discard_packet is a dummy "receive callback" used to get rid - * of packets we don't want - */ -void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &sc->subch[ch]; - - sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); - q->opos = q->ipos; - atomic_set(&(subch->packet_arrived), 0); - SUBCH_DATA_UNLOCK( subch, pl ); -} - - -/* - * brl1_send_chars sends the send buffer in the l1sc_t structure - * out through the uart. Assumes that the caller has locked the - * UART (or send buffer in the kernel). - * - * This routine doesn't block-- if you want it to, call it in - * a loop. - */ -static int -brl1_send_chars( l1sc_t *sc ) -{ - /* We track the depth of the C brick's UART's - * fifo in software, and only check if the UART is accepting - * characters when our count indicates that the fifo should - * be full. - * - * For remote (router) UARTs, we check with the UART before sending every - * character. - */ - if( sc->uart == BRL1_LOCALHUB_UART ) { - if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) - sc->fifo_space = UART_FIFO_DEPTH; - - while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { - uart_putc( sc ); - sc->fifo_space--; - sc->sent++; - } - } - else { - - /* remote (router) UARTs */ - - int result; - int tries = 0; - - while( sc->sent < sc->send_len ) { - result = sc->putc_f( sc ); - if( result >= 0 ) { - (sc->sent)++; - continue; - } - if( result == UART_TIMEOUT ) { - tries++; - /* send this character in TIMEOUT_RETRIES... */ - if( tries < 30 /* TIMEOUT_RETRIES */ ) { - continue; - } - /* ...or else... */ - else { - /* ...drop the packet. */ - sc->sent = sc->send_len; - return sc->send_len; - } - } - if( result < 0 ) { - return result; - } - } - } - return sc->sent; -} - - -/* brl1_send formats up a packet and (at least begins to) send it - * to the uart. If the send buffer is in use when this routine obtains - * the lock, it will behave differently depending on the "wait" parameter. - * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"), - * hopefully encouraging the caller to back off (unlock any high-level - * spinlocks) and allow the buffer some time to drain. For wait==1 (high- - * priority I/O along the lines of kernel error messages), we will flush - * the current contents of the send buffer and beat on the uart - * until our message has been completely transmitted. - */ - -static int -brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) -{ - unsigned long pl = 0; - int index; - int pkt_len = 0; - unsigned short crc = INIT_CRC; - char *send_ptr = sc->send; - - - if( sc->send_in_use && !(wait) ) { - /* We are in the middle of sending, but can wait until done */ - return 0; - } - else if( sc->send_in_use ) { - /* buffer's in use, but we're synchronous I/O, so we're going - * to send whatever's in there right now and take the buffer - */ - int counter = 0; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - while( sc->sent < sc->send_len ) { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (1)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } - } - else { - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - sc->send_in_use = 1; - } - *send_ptr++ = BRL1_FLAG_CH; - *send_ptr++ = type_and_subch; - pkt_len += 2; - crc = crc16_calc( crc, type_and_subch ); - - /* limit number of characters accepted to max payload size */ - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - /* copy in the message buffer (inserting PPP - * framing info where necessary) - */ - for( index = 0; index < len; index++ ) { - - switch( *msg ) { - - case BRL1_FLAG_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - case BRL1_ESC_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - default: - *send_ptr++ = *msg; - pkt_len++; - } - crc = crc16_calc( crc, *msg ); - msg++; - } - crc ^= 0xffff; - - for( index = 0; index < sizeof(crc); index++ ) { - char crc_char = (char)(crc & 0x00FF); - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - *send_ptr++ = BRL1_ESC_CH; - pkt_len++; - crc_char ^= BRL1_XOR_CH; - } - *send_ptr++ = crc_char; - pkt_len++; - crc >>= 8; - } - - *send_ptr++ = BRL1_FLAG_CH; - pkt_len++; - - sc->send_len = pkt_len; - sc->sent = 0; - - { - int counter = 0; - do { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (2)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } while( (sc->sent < sc->send_len) && wait ); - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - - if( sc->sent == sc->send_len ) { - /* success! release the send buffer and call the callup */ -#if !defined(SYNC_CONSOLE_WRITE) - brl1_notif_t callup; -#endif - - sc->send_in_use = 0; - /* call any upper layer that's asked for notification */ -#if defined(XX_SYNC_CONSOLE_WRITE) - /* - * This is probably not a good idea - since the l1_ write func can be called multiple - * time within the callup function. - */ - callup = subch->tx_notify; - if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) { - L1_collectibles[L1C_SEND_CALLUPS]++; - (*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch)); - } -#endif /* SYNC_CONSOLE_WRITE */ - } -#if !defined(SYNC_CONSOLE_WRITE) - else if ( !wait ) { - /* enable low-water interrupts so buffer will be drained */ - uart_enable_xmit_intr(sc); - } -#endif - - L1SC_SEND_UNLOCK(sc, pl); - - return len; -} - -/* brl1_send_cont is intended to be called as an interrupt service - * routine. It sends until the UART won't accept any more characters, - * or until an error is encountered (in which case we surrender the - * send buffer and give up trying to send the packet). Once the - * last character in the packet has been sent, this routine releases - * the send buffer and calls any previously-registered "low-water" - * output routines. - */ - -#if !defined(SYNC_CONSOLE_WRITE) - -int -brl1_send_cont( l1sc_t *sc ) -{ - unsigned long pl = 0; - int done = 0; - brl1_notif_t callups[BRL1_NUM_SUBCHANS]; - brl1_notif_t *callup; - brl1_sch_t *subch; - int index; - - /* - * I'm not sure how I think this is to be handled - whether the lock is held - * over the interrupt - but it seems like it is a bad idea.... - */ - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - brl1_send_chars( sc ); - done = (sc->sent == sc->send_len); - if( done ) { - sc->send_in_use = 0; -#if !defined(SYNC_CONSOLE_WRITE) - uart_disable_xmit_intr(sc); -#endif - } - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - /* Release the lock */ - L1SC_SEND_UNLOCK(sc, pl); - - return 0; -} -#endif /* SYNC_CONSOLE_WRITE */ - -/* internal function -- used by brl1_receive to read a character - * from the uart and check whether errors occurred in the process. - */ -static int -read_uart( l1sc_t *sc, int *c, int *result ) -{ - *c = sc->getc_f( sc ); - - /* no character is available */ - if( *c == UART_NO_CHAR ) { - *result = BRL1_NO_MESSAGE; - return 0; - } - - /* some error in UART */ - if( *c < 0 ) { - *result = BRL1_LINK; - return 0; - } - - /* everything's fine */ - *result = BRL1_VALID; - return 1; -} - - -/* - * brl1_receive - * - * This function reads a Bedrock-L1 protocol packet into the l1sc_t - * response buffer. - * - * The operation of this function can be expressed as a finite state - * machine: - * - -START STATE INPUT TRANSITION -========================================================== -BRL1_IDLE (reset or error) flag BRL1_FLAG - other BRL1_IDLE@ - -BRL1_FLAG (saw a flag (0x7e)) flag BRL1_FLAG - escape BRL1_IDLE@ - header byte BRL1_HDR - other BRL1_IDLE@ - -BRL1_HDR (saw a type/subch byte)(see below) BRL1_BODY - BRL1_HDR - -BRL1_BODY (reading packet body) flag BRL1_FLAG - escape BRL1_ESC - other BRL1_BODY - -BRL1_ESC (saw an escape (0x7d)) flag BRL1_FLAG@ - escape BRL1_IDLE@ - other BRL1_BODY -========================================================== - -"@" denotes an error transition. - - * The BRL1_HDR state is a transient state which doesn't read input, - * but just provides a way in to code which decides to whom an - * incoming packet should be directed. - * - * brl1_receive can be used to poll for input from the L1, or as - * an interrupt service routine. It reads as much data as is - * ready from the junk bus UART and places into the appropriate - * input queues according to subchannel. The header byte is - * stripped from console-type data, but is retained for message- - * type data (L1 responses). A length byte will also be - * prepended to message-type packets. - * - * This routine is non-blocking; if the caller needs to block - * for input, it must call brl1_receive in a loop. - * - * brl1_receive returns when there is no more input, the queue - * for the current incoming message is full, or there is an - * error (parity error, bad header, bad CRC, etc.). - */ - -#define STATE_SET(l,s) ((l)->brl1_state = (s)) -#define STATE_GET(l) ((l)->brl1_state) - -#define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h)) -#define LAST_HDR_GET(l) ((l)->brl1_last_hdr) - -#define VALID_HDR(c) \ - ( SUBCH((c)) <= SC_CONS_SYSTEM \ - ? PKT_TYPE((c)) == BRL1_REQUEST \ - : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ - PKT_TYPE((c)) == BRL1_EVENT ) ) - -#define IS_TTY_PKT(l) ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) - - -int -brl1_receive( l1sc_t *sc, int mode ) -{ - int result; /* value to be returned by brl1_receive */ - int c; /* most-recently-read character */ - int done; /* set done to break out of recv loop */ - unsigned long pl = 0, cpl = 0; - sc_cq_t *q; /* pointer to queue we're working with */ - - result = BRL1_NO_MESSAGE; - - L1SC_RECV_LOCK(sc, cpl); - - done = 0; - while( !done ) - { - switch( STATE_GET(sc) ) - { - - case BRL1_IDLE: - /* Initial or error state. Waiting for a flag character - * to resynchronize with the L1. - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* saw a flag character */ - STATE_SET( sc, BRL1_FLAG ); - continue; - } - break; - - case BRL1_FLAG: - /* One or more flag characters have been read; look for - * the beginning of a packet (header byte). - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* multiple flags are OK */ - continue; - } - - if( !VALID_HDR( c ) ) { - /* if c isn't a flag it should have been - * a valid header, so we have an error - */ - result = BRL1_PROTOCOL; - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - /* we have a valid header byte */ - LAST_HDR_SET( sc, c ); - STATE_SET( sc, BRL1_HDR ); - - break; - - case BRL1_HDR: - /* A header byte has been read. Do some bookkeeping. */ - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - if( !IS_TTY_PKT(sc) ) { - /* if this is an event or command response rather - * than console I/O, we need to reserve a couple - * of extra spaces in the queue for the header - * byte and a length byte; if we can't, stay in - * the BRL1_HDR state. - */ - if( cq_room( q ) < 2 ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - cq_tent_add( q, 0 ); /* reserve length byte */ - cq_tent_add( q, LAST_HDR_GET( sc ) ); /* record header byte */ - } - STATE_SET( sc, BRL1_BODY ); - - break; - - case BRL1_BODY: - /* A header byte has been read. We are now attempting - * to receive the packet body. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* prepare to unescape the next character */ - STATE_SET( sc, BRL1_ESC ); - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag signifies the end of a packet */ - - unsigned short crc; /* holds the crc as we calculate it */ - int i; /* index variable */ - brl1_sch_t *subch; /* subchannel for received packet */ - brl1_notif_t callup; /* "data ready" callup */ - - /* whatever else may happen, we've seen a flag and we're - * starting a new packet - */ - STATE_SET( sc, BRL1_FLAG ); - - /* if the packet body has less than 2 characters, - * it can't be a well-formed packet. Discard it. - */ - if( cq_tent_len( q ) < /* 2 + possible length byte */ - (2 + (IS_TTY_PKT(sc) ? 0 : 1)) ) - { - result = BRL1_PROTOCOL; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* check CRC */ - - /* accumulate CRC, starting with the header byte and - * ending with the transmitted CRC. This should - * result in a known good value. - */ - crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) ); - for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE; - i != q->tent_next; - i = (i + 1) % BRL1_QSIZE ) - { - crc = crc16_calc( crc, q->buf[i] ); - } - - /* verify the caclulated crc against the "good" crc value; - * if we fail, discard the bad packet and return an error. - */ - if( crc != (unsigned short)GOOD_CRC ) { - result = BRL1_CRC; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* so the crc check was ok. Now we discard the CRC - * from the end of the received bytes. - */ - q->tent_next += (BRL1_QSIZE - 2); - q->tent_next %= BRL1_QSIZE; - - /* get the subchannel and lock it */ - subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch, pl ); - - /* if this isn't a console packet, we need to record - * a length byte - */ - if( !IS_TTY_PKT(sc) ) { - q->buf[q->ipos] = cq_tent_len( q ) - 1; - } - - /* record packet for posterity */ - cq_commit_tent( q ); - result = BRL1_VALID; - - /* notify subchannel owner that there's something - * on the queue for them - */ - atomic_inc(&(subch->packet_arrived)); - callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch, pl ); - - if( callup && (mode == SERIAL_INTERRUPT_MODE) ) { - L1SC_RECV_UNLOCK( sc, cpl ); - L1_collectibles[L1C_RECEIVE_CALLUPS]++; - (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs, - sc, SUBCH(LAST_HDR_GET(sc)) ); - L1SC_RECV_LOCK( sc, cpl ); - } - continue; /* go back for more! */ - } - - /* none of the special cases applied; we've got a normal - * body character - */ - cq_tent_add( q, c ); - - break; - - case BRL1_ESC: - /* saw an escape character. The next character will need - * to be unescaped. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) { - cq_discard_tent( q ); - STATE_SET( sc, BRL1_IDLE ); - } - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag after escape is an error */ - STATE_SET( sc, BRL1_FLAG ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* two consecutive escapes is an error */ - STATE_SET( sc, BRL1_IDLE ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - /* otherwise, we've got a character that needs - * to be unescaped - */ - cq_tent_add( q, (c ^ BRL1_XOR_CH) ); - STATE_SET( sc, BRL1_BODY ); - - break; - - } /* end of switch( STATE_GET(sc) ) */ - } /* end of while(!done) */ - - L1SC_RECV_UNLOCK( sc, cpl ); - - return result; -} - - -/* brl1_init initializes the Bedrock/L1 protocol layer. This includes - * zeroing out the send and receive state information. - */ - -void -brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - /* (for now, drop elscuart packets in the kernel) */ - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - subch->rx_notify = NULL; - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - subch->rx_notify = brl1_discard_packet; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* initialize synchronization structures - */ - spin_lock_init( &(sc->subch_lock) ); - spin_lock_init( &(sc->send_lock) ); - spin_lock_init( &(sc->recv_lock) ); - - if( sc->uart == BRL1_LOCALHUB_UART ) { - uart_init( sc, UART_BAUD_RATE ); - } - else { - rtr_uart_init( sc, UART_BAUD_RATE ); - } - - /* Set up remaining fields using L1 command functions-- elsc_module_get - * to read the module id, elsc_debug_get to see whether or not we're - * in verbose mode. - */ - { - extern int elsc_module_get(l1sc_t *); - - sc->modid = elsc_module_get( sc ); - sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); - sc->verbose = 1; - } -} - -/********************************************************************* - * These are interrupt-related functions used in the kernel to service - * the L1. - */ - -/* - * brl1_intrd is the function which is called on a console interrupt. - */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff) -{ - u_char isr_reg; - l1sc_t *sc = get_elsc(); - int ret; - - L1_collectibles[L1C_INTERRUPTS]++; - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - - /* Save for callup args in console */ - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff; - -#if defined(SYNC_CONSOLE_WRITE) - while( isr_reg & ISR_RxRDY ) -#else - while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) -#endif - { - if( isr_reg & ISR_RxRDY ) { - L1_collectibles[L1C_OUR_R_INTERRUPTS]++; - ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - } -#if !defined(SYNC_CONSOLE_WRITE) - if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) { - L1_collectibles[L1C_OUR_X_INTERRUPTS]++; - brl1_send_cont(sc); - } -#endif /* SYNC_CONSOLE_WRITE */ - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - } -} -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when the send buffer - * has been emptied. - */ -static inline void -l1_tx_notif( brl1_notif_t func ) -{ - subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when a packet has been - * received. - */ -static inline void -l1_rx_notif( brl1_notif_t func ) -{ - subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* brl1_intr is called directly from the uart interrupt; after it runs, the - * interrupt "daemon" xthread is signalled to continue. - */ -void -brl1_intr( void ) -{ -} - -#define BRL1_INTERRUPT_LEVEL 65 /* linux request_irq() value */ - -/* Return the current interrupt level */ - -//#define CONSOLE_POLLING_ALSO - -int -l1_get_intr_value( void ) -{ -#ifdef CONSOLE_POLLING_ALSO - return(0); -#else - return(BRL1_INTERRUPT_LEVEL); -#endif -} - -/* Disconnect the callup functions - throw away interrupts */ - -void -l1_unconnect_intr(void) -{ - /* UnRegister the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)NULL); - l1_tx_notif((brl1_notif_t)NULL); - /* We do NOT unregister the interrupts */ -} - -/* Set up uart interrupt handling for this node's uart */ - -void -l1_connect_intr(void *rx_notify, void *tx_notify) -{ - l1sc_t *sc; - nasid_t nasid; -#if defined(CONFIG_IA64_SGI_SN1) - int tmp; -#endif - nodepda_t *console_nodepda; - int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); - - if ( L1_interrupts_connected ) { - /* Interrupts are connected, so just register the callups */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - L1_collectibles[L1C_CONNECT_CALLS]++; - return; - } - else - L1_interrupts_connected = 1; - - nasid = get_master_nasid(); - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid)); - sc = &console_nodepda->module->elsc; - sc->intr_cpu = console_nodepda->node_first_cpu; - -#if defined(CONFIG_IA64_SGI_SN1) - if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - void synergy_intr_connect(int, int); - - synergy_intr_connect(UART_INTR, sc->intr_cpu); - L1_collectibles[L1C_R_IRQ]++; - tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc); - L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp; - if ( tmp ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - /* Register the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - /* Set the uarts the way we like it */ - uart_enable_recv_intr( sc ); - uart_disable_xmit_intr( sc ); - } - } -#endif /* CONFIG_IA64_SGI_SN1 */ -} - - -/* Set the line speed */ - -void -l1_set_baud(int baud) -{ -#if 0 - nasid_t nasid; - static void uart_init(l1sc_t *, int); -#endif - - L1_collectibles[L1C_SET_BAUD]++; - -#if 0 - if ( L1_cons_is_inited ) { - nasid = get_master_nasid(); - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) - uart_init(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, baud); - } -#endif - return; -} - - -/* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. These are external - * interfaces into the protocol driver. - */ - -void -l1_control_out(int offset, int value) -{ - nasid_t nasid = get_master_nasid(); - WRITE_L1_UART_REG(nasid, offset, value); -} - -/* Console input exported interface. Return a register value. */ - -int -l1_control_in_polled(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_POLLED_MODE)); -} - -int -l1_control_in(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE)); -} - -static int -l1_control_in_local(int offset, int mode) -{ - nasid_t nasid; - int ret, input; - static int l1_poll(l1sc_t *, int); - - nasid = get_master_nasid(); - ret = READ_L1_UART_REG(nasid, offset); - - if ( offset == REG_LSR ) { - ret |= (LSR_XHRE | LSR_XSRE); /* can send anytime */ - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode); - if ( input ) { - ret |= LSR_RCA; - } - } - } - } - return(ret); -} - -/* - * Console input exported interface. Return a character (if one is available) - */ - -int -l1_serial_in_polled(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_POLLED_MODE)); -} - -int -l1_serial_in(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_INTERRUPT_MODE)); -} - -static int -l1_serial_in_local(int mode) -{ - nasid_t nasid; - l1sc_t *sc; - int value; - static int l1_getc( l1sc_t *, int ); - static inline l1sc_t *early_sc_init(nasid_t); - - nasid = get_master_nasid(); - sc = early_sc_init(nasid); - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc; - } - } - value = l1_getc(sc, mode); - return(value); -} - -/* Console output exported interface. Write message to the console. */ - -int -l1_serial_out( char *str, int len ) -{ - nasid_t nasid = get_master_nasid(); - int l1_write(l1sc_t *, char *, int, int); - - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) - return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len, -#if defined(SYNC_CONSOLE_WRITE) - 1 -#else - !L1_interrupts_connected -#endif - )); - } - return(early_l1_serial_out(nasid, str, len, NOT_LOCKED)); -} - - -/* - * These are the 'early' functions - when we need to do things before we have - * all the structs setup. - */ - -static l1sc_t Early_console; /* fake l1sc_t */ -static int Early_console_inited = 0; - -static void -early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - static sc_cq_t x_iqp; - - subch->iqp = &x_iqp; - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } -} - -static inline l1sc_t * -early_sc_init(nasid_t nasid) -{ - /* This is for early I/O */ - if ( Early_console_inited == 0 ) { - early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); - Early_console_inited = 1; - } - return(&Early_console); -} - -#define PUTCHAR(ch) \ - { \ - while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ - (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ - WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ - } - -static int -early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ) -{ - int ret, sent = 0; - char *msg = str; - static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); - - while ( sent < len ) { - ret = early_l1_send(nasid, msg, len - sent, lock_state); - sent += ret; - msg += ret; - } - return(len); -} - -static inline int -early_l1_send( nasid_t nasid, char *str, int len, int lock_state ) -{ - int sent; - char crc_char; - unsigned short crc = INIT_CRC; - - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - sent = len; - if ( lock_state == NOT_LOCKED ) - lock_console(nasid); - - PUTCHAR( BRL1_FLAG_CH ); - PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); - crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); - - while( len ) { - - if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { - PUTCHAR( BRL1_ESC_CH ); - PUTCHAR( (*str) ^ BRL1_XOR_CH ); - } - else { - PUTCHAR( *str ); - } - - crc = crc16_calc( crc, *str ); - - str++; len--; - } - - crc ^= 0xffff; - crc_char = crc & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - crc_char = (crc >> 8) & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - PUTCHAR( BRL1_FLAG_CH ); - - if ( lock_state == NOT_LOCKED ) - unlock_console(nasid); - return sent; -} - - -/********************************************************************* - * l1_cons functions - * - * These allow the L1 to act as the system console. They're intended - * to abstract away most of the br/l1 internal details from the - * _L1_cons_* functions (in the prom-- see "l1_console.c") and - * l1_* functions (in the kernel-- see "sio_l1.c") that they support. - * - */ - -static int -l1_poll( l1sc_t *sc, int mode ) -{ - int ret; - - /* in case this gets called before the l1sc_t structure for the module_t - * struct for this node is initialized (i.e., if we're called with a - * zero l1sc_t pointer)... - */ - - - if( !sc ) { - return 0; - } - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - - ret = brl1_receive( sc, mode ); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - return 0; -} - - -/* pull a character off of the system console queue (if one is available) - */ -static int -l1_getc( l1sc_t *sc, int mode ) -{ - unsigned long pl = 0; - int c; - - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - sc_cq_t *q = subch->iqp; - - if( !l1_poll( sc, mode ) ) { - return 0; - } - - SUBCH_DATA_LOCK( subch, pl ); - if( cq_empty( q ) ) { - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - return 0; - } - cq_rem( q, c ); - if( cq_empty( q ) ) - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - - return c; -} - -/* - * Write a message to the L1 on the system console subchannel. - * - * Danger: don't use a non-zero value for the wait parameter unless you're - * someone important (like a kernel error message). - */ - -int -l1_write( l1sc_t *sc, char *msg, int len, int wait ) -{ - int sent = 0, ret = 0; - - if ( wait ) { - while ( sent < len ) { - ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - sent += ret; - msg += ret; - } - ret = len; - } - else { - ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - } - return(ret); -} - -/* initialize the system console subchannel - */ -void -l1_init(void) -{ - /* All we do now is remember that we have been called */ - L1_cons_is_inited = 1; -} - - -/********************************************************************* - * The following functions and definitions implement the "message"- - * style interface to the L1 system controller. - * - * Note that throughout this file, "sc" generally stands for "system - * controller", while "subchannels" tend to be represented by - * variables with names like subch or ch. - * - */ - -#ifdef L1_DEBUG -#define L1_DBG_PRF(x) printf x -#else -#define L1_DBG_PRF(x) -#endif - -/* - * sc_data_ready is called to signal threads that are blocked on l1 input. - */ -void -sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - - brl1_sch_t *subch = &(sc->subch[ch]); - SUBCH_DATA_LOCK( subch, pl ); - sv_signal( &(subch->arrive_sv) ); - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/* sc_open reserves a subchannel to send a request to the L1 (the - * L1's response will arrive on the same channel). The number - * returned by sc_open is the system controller subchannel - * acquired. - */ -int -sc_open( l1sc_t *sc, uint target ) -{ - /* The kernel version implements a locking scheme to arbitrate - * subchannel assignment. - */ - int ch; - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - - /* Look for a free subchannel. Subchannels 0-15 are reserved - * for other purposes. - */ - for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; - ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) { - if( subch->use == BRL1_SUBCH_FREE ) - break; - } - - if( ch == BRL1_NUM_SUBCHANS ) { - /* there were no subchannels available! */ - SUBCH_UNLOCK( sc, pl ); - return SC_NSUBCH; - } - - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = target; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - return ch; -} - - -/* sc_close frees a Bedrock<->L1 subchannel. - */ -int -sc_close( l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[ch]); - if( subch->use != BRL1_SUBCH_RSVD ) { - /* we're trying to close a subchannel that's not open */ - SUBCH_UNLOCK( sc, pl ); - return SC_NOPEN; - } - - atomic_set(&subch->packet_arrived, 0); - subch->use = BRL1_SUBCH_FREE; - - sv_broadcast( &(subch->arrive_sv) ); - sv_destroy( &(subch->arrive_sv) ); - spin_lock_destroy( &(subch->data_lock) ); - - ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); - snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); - subch->iqp = &sc->garbage_q; - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - - SUBCH_UNLOCK( sc, pl ); - - return SC_SUCCESS; -} - - -/* sc_construct_msg builds a bedrock-to-L1 request in the supplied - * buffer. Returns the length of the message. The - * safest course when passing a buffer to be filled in is to use - * BRL1_QSIZE as the buffer size. - * - * Command arguments are passed as type/argument pairs, i.e., to - * pass the number 5 as an argument to an L1 command, call - * sc_construct_msg as follows: - * - * char msg[BRL1_QSIZE]; - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 2, - * L1_ARG_INT, 5 ); - * - * To pass an additional ASCII argument, you'd do the following: - * - * char *str; - * ... str points to a null-terminated ascii string ... - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 4, - * L1_ARG_INT, 5, - * L1_ARG_ASCII, str ); - * - * Finally, arbitrary data of unknown type is passed using the argtype - * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 3, - * L1_ARG_UNKNOWN, 32, bufptr ); - * - * ...passes 32 bytes of data starting at bufptr. Note that no string or - * "unknown"-type argument should be long enough to overflow the message - * buffer. - * - * To construct a message for an L1 command that requires no arguments, - * you'd use the following: - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 0 ); - * - * The final 0 means "no varargs". Notice that this parameter is used to hold - * the number of additional arguments to sc_construct_msg, _not_ the actual - * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] - * type argument, and 3 per L1_ARG_UNKOWN type argument). A call to construct - * an L1 command which required three integer arguments and two arguments of - * some arbitrary (unknown) type would pass 12 as the value for this parameter. - * - * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth - * between byte arrays and four-byte big-endian integers. Depending on the - * system controller connection and endianness of future architectures, some - * rewriting might be necessary. - */ -int -sc_construct_msg( l1sc_t *sc, /* system controller struct */ - int ch, /* subchannel for this message */ - char *msg, /* message buffer */ - int msg_len, /* size of message buffer */ - l1addr_t addr_task, /* target system controller task */ - short req_code, /* 16-bit request code */ - int req_nargs, /* # of arguments (varargs) passed */ - ... ) /* any additional parameters */ -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold command argument addresses */ - va_list al; /* variable argument list */ - int index; /* current index into msg buffer */ - int argno; /* current position in varargs list */ - int l1_argno; /* running total of arguments to l1 */ - int l1_arg_t; /* argument type/length */ - int l1_argno_byte; /* offset of argument count byte */ - - index = argno = 0; - - /* set up destination address */ - if( (msg_len -= sizeof( buf32 )) < 0 ) - return -1; - L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task ); - COPY_INT_TO_BUFFER(msg, index, buf32); - - /* copy request code */ - if( (msg_len -= 2) < 0 ) - return( -1 ); - msg[index++] = ((req_code >> 8) & 0xff); - msg[index++] = (req_code & 0xff); - - if( !req_nargs ) { - return index; - } - - /* reserve a byte for the argument count */ - if( (msg_len -= 1) < 0 ) - return( -1 ); - l1_argno_byte = index++; - l1_argno = 0; - - /* copy additional arguments */ - va_start( al, req_nargs ); - while( argno < req_nargs ) { - l1_argno++; - l1_arg_t = va_arg( al, int ); argno++; - switch( l1_arg_t ) - { - case L1_ARG_INT: - if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_INT; - buf32 = (unsigned)va_arg( al, int ); argno++; - COPY_INT_TO_BUFFER(msg, index, buf32); - break; - - case L1_ARG_ASCII: - bufptr = va_arg( al, char* ); argno++; - if( (msg_len -= (strlen( bufptr ) + 2)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_ASCII; - strcpy( (char *)&(msg[index]), (char *)bufptr ); - index += (strlen( bufptr ) + 1); /* include terminating null */ - break; - - case L1_ARG_UNKNOWN: - { - int arglen; - - arglen = va_arg( al, int ); argno++; - bufptr = va_arg( al, void* ); argno++; - if( (msg_len -= (arglen + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_UNKNOWN | arglen; - BCOPY( bufptr, &(msg[index]), arglen ); - index += arglen; - break; - } - - default: /* unhandled argument type */ - return -1; - } - } - - va_end( al ); - msg[l1_argno_byte] = l1_argno; - - return index; -} - - - -/* sc_interpret_resp verifies an L1 response to a bedrock request, and - * breaks the response data up into the constituent parts. If the - * response message indicates error, or if a mismatch is found in the - * expected number and type of arguments, an error is returned. The - * arguments to this function work very much like the arguments to - * sc_construct_msg, above, except that L1_ARG_INTs must be followed - * by a _pointer_ to an integer that can be filled in by this function. - */ -int -sc_interpret_resp( char *resp, /* buffer received from L1 */ - int resp_nargs, /* number of _varargs_ passed in */ - ... ) -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold response field addresses */ - va_list al; /* variable argument list */ - int index; /* current index into response buffer */ - int argno; /* current position in varargs list */ - int l1_fldno; /* number of resp fields received from l1 */ - int l1_fld_t; /* field type/length */ - - index = argno = 0; - -#if defined(L1_DEBUG) -#define DUMP_RESP \ - { \ - int ix; \ - char outbuf[512]; \ - sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \ - for( ix = 0; ix < 16; ix++ ) { \ - sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] ); \ - } \ - printk( "%s\n", outbuf ); \ - } -#else -#define DUMP_RESP -#endif /* L1_DEBUG */ - - /* check response code */ - COPY_BUFFER_TO_INT(resp, index, buf32); - if( buf32 != L1_RESP_OK ) { - DUMP_RESP; - return buf32; - } - - /* get number of response fields */ - l1_fldno = resp[index++]; - - va_start( al, resp_nargs ); - - /* copy out response fields */ - while( argno < resp_nargs ) { - l1_fldno--; - l1_fld_t = va_arg( al, int ); argno++; - switch( l1_fld_t ) - { - case L1_ARG_INT: - if( resp[index++] != L1_ARG_INT ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, int* ); argno++; - COPY_BUFFER_TO_BUFFER(resp, index, bufptr); - break; - - case L1_ARG_ASCII: - if( resp[index++] != L1_ARG_ASCII ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, char* ); argno++; - strcpy( (char *)bufptr, (char *)&(resp[index]) ); - /* include terminating null */ - index += (strlen( &(resp[index]) ) + 1); - break; - - default: - if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN ) - { - int *arglen; - - arglen = va_arg( al, int* ); argno++; - bufptr = va_arg( al, void* ); argno++; - *arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff); - BCOPY( &(resp[index]), bufptr, *arglen ); - index += (*arglen); - } - - else { - /* unhandled type */ - va_end( al ); - DUMP_RESP; - return -1; - } - } - } - va_end( al ); - - if( (l1_fldno != 0) || (argno != resp_nargs) ) { - /* wrong number of arguments */ - DUMP_RESP; - return -1; - } - return 0; -} - - - - -/* sc_send takes as arguments a system controller struct, a - * buffer which contains a Bedrock<->L1 "request" message, - * the message length, and the subchannel (presumably obtained - * from an earlier invocation of sc_open) over which the - * message is to be sent. The final argument ("wait") indicates - * whether the send is to be performed synchronously or not. - * - * sc_send returns either zero or an error value. Synchronous sends - * (wait != 0) will not return until the data has actually been sent - * to the UART. Synchronous sends generally receive privileged - * treatment. The intent is that they be used sparingly, for such - * purposes as kernel printf's (the "ducons" routines). Run-of-the-mill - * console output and L1 requests should NOT use a non-zero value - * for wait. - */ -int -sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ) -{ - char type_and_subch; - int result; - - if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) { - return SC_BADSUBCH; - } - - /* Verify that this is an open subchannel - */ - if( sc->subch[ch].use == BRL1_SUBCH_FREE ) { - return SC_NOPEN; - } - - type_and_subch = (BRL1_REQUEST | ((u_char)ch)); - result = brl1_send( sc, msg, len, type_and_subch, wait ); - - /* If we sent as much as we asked to, return "ok". */ - if( result == len ) - return( SC_SUCCESS ); - - /* Or, if we sent less, than either the UART is busy or - * we're trying to send too large a packet anyway. - */ - else if( result >= 0 && result < len ) - return( SC_BUSY ); - - /* Or, if something else went wrong (result < 0), then - * return that error value. - */ - else - return( result ); -} - - - -/* subch_pull_msg pulls a message off the receive queue for subch - * and places it the buffer pointed to by msg. This routine should only - * be called when the caller already knows a message is available on the - * receive queue (and, in the kernel, only when the subchannel data lock - * is held by the caller). - */ -static void -subch_pull_msg( brl1_sch_t *subch, char *msg, int *len ) -{ - sc_cq_t *q; /* receive queue */ - int before_wrap, /* packet may be split into two different */ - after_wrap; /* pieces to accommodate queue wraparound */ - - /* pull message off the receive queue */ - q = subch->iqp; - - cq_rem( q, *len ); /* remove length byte and store */ - cq_discard( q ); /* remove type/subch byte and discard */ - - if ( *len > 0 ) - (*len)--; /* don't count type/subch byte in length returned */ - - if( (q->opos + (*len)) > BRL1_QSIZE ) { - before_wrap = BRL1_QSIZE - q->opos; - after_wrap = (*len) - before_wrap; - } - else { - before_wrap = (*len); - after_wrap = 0; - } - - BCOPY( q->buf + q->opos, msg, before_wrap ); - if( after_wrap ) { - BCOPY( q->buf, msg + before_wrap, after_wrap ); - q->opos = after_wrap; - } - else { - q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); - } - atomic_dec(&(subch->packet_arrived)); -} - - -/* sc_recv_poll can be called as a blocking or non-blocking function; - * it attempts to pull a message off of the subchannel specified - * in the argument list (ch). - * - * The "block" argument, if non-zero, is interpreted as a timeout - * delay (to avoid permanent waiting). - */ - -int -sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - rtc_time_t exp_time = rtc_time() + block; - - /* sanity check-- make sure this is an open subchannel */ - if( subch->use == BRL1_SUBCH_FREE ) - return( SC_NOPEN ); - - do { - - /* kick the next lower layer and see if it pulls anything in - */ - brl1_receive( sc, SERIAL_POLLED_MODE ); - is_msg = atomic_read(&subch->packet_arrived); - - } while( block && !is_msg && (rtc_time() < exp_time) ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - return( SC_NMSG ); - } - - SUBCH_DATA_LOCK( subch, pl ); - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - - -/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking - * or non-blocking mode. Rather than polling until an appointed timeout, - * however, sc_recv_intr sleeps on a syncrhonization variable until a - * signal from the lower layer tells us that a packet has arrived. - * - * sc_recv_intr can't be used with remote (router) L1s. - */ -int -sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - do { - SUBCH_DATA_LOCK(subch, pl); - is_msg = atomic_read(&subch->packet_arrived); - if( !is_msg && block ) { - /* wake me when you've got something */ - subch->rx_notify = sc_data_ready; - sv_wait( &(subch->arrive_sv), 0, 0); - if( subch->use == BRL1_SUBCH_FREE ) { - /* oops-- somebody closed our subchannel while we were - * sleeping! - */ - - /* no need to unlock since the channel's closed anyhow */ - return( SC_NOPEN ); - } - } - } while( !is_msg && block ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch, pl ); - return( SC_NMSG ); - } - - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - -/* sc_command implements a (blocking) combination of sc_send and sc_recv. - * It is intended to be the SN1 equivalent of SN0's "elsc_command", which - * issued a system controller command and then waited for a response from - * the system controller before returning. - * - * cmd points to the outgoing command; resp points to the buffer in - * which the response is to be stored. Both buffers are assumed to - * be the same length; if there is any doubt as to whether the - * response buffer is long enough to hold the L1's response, then - * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any - * bigger. - * - * Be careful using the same buffer for both cmd and resp; it could get - * hairy if there were ever an L1 command request that spanned multiple - * packets. (On the other hand, that would require some additional - * rewriting of the L1 command interface anyway.) - */ -#define __RETRIES 50 -#define __WAIT_SEND 1 // ( sc->uart != BRL1_LOCALHUB_UART ) -#define __WAIT_RECV 10000000 - - -int -sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else - int result; - int retries; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - retries = __RETRIES; - - while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) { - if( result == SC_BUSY ) { - retries--; - if( retries <= 0 ) - return result; - uart_delay(500); - } - else { - return result; - } - } - - /* block on sc_recv_* */ - if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) { - return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); - } - else { - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); - } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - -/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command - * used in situations where the kernel has a command that shouldn't be - * delayed until the send buffer clears. sc_command should be used instead - * under most circumstances. - */ - -int -sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else - int result; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) { - return result; - } - - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - - -/* sc_poll checks the queue corresponding to the given - * subchannel to see if there's anything available. If - * not, it kicks the brl1 layer and then checks again. - * - * Returns 1 if input is available on the given queue, - * 0 otherwise. - */ - -int -sc_poll( l1sc_t *sc, int ch ) -{ - brl1_sch_t *subch = &(sc->subch[ch]); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - brl1_receive( sc, SERIAL_POLLED_MODE ); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - return 0; -} - -/* for now, sc_init just calls brl1_init */ - -void -sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - if ( !IS_RUNNING_ON_SIMULATOR() ) - brl1_init( sc, nasid, uart ); -} - -/* sc_dispatch_env_event handles events sent from the system control - * network's environmental monitor tasks. - */ - -#if defined(LINUX_KERNEL_THREADS) - -static void -sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) -{ - int j, i = 0; - uint32_t ESPcode; - - switch( code ) { - /* for now, all codes do the same thing: grab two arguments - * and print a cmn_err_tag message */ - default: - /* check number of arguments */ - if( argc != 2 ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected 2 arguments, got %d\n", argc )); - return; - } - - /* get ESP code (integer argument) */ - if( args[i++] != L1_ARG_INT ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected integer argument\n" )); - return; - } - /* WARNING: highly endian */ - COPY_BUFFER_TO_INT(args, i, ESPcode); - - /* verify string argument */ - if( args[i++] != L1_ARG_ASCII ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected an ASCII string\n" )); - return; - } - for( j = i; j < maxlen; j++ ) { - if( args[j] == '\0' ) break; /* found string termination */ - } - if( j == maxlen ) { - j--; - L1_DBG_PRF(( "sc_dispatch_env_event: " - "message too long-- truncating\n" )); - } - - /* strip out trailing cr/lf */ - for( ; - j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); - j-- ); - args[j] = '\0'; - - /* strip out leading cr/lf */ - for( ; - i < j && ((args[i] == 0xd) || (args[i] == 0xa)); - i++ ); - } -} - - -/* sc_event waits for events to arrive from the system controller, and - * prints appropriate messages to the syslog. - */ - -static void -sc_event( l1sc_t *sc, int ch ) -{ - char event[BRL1_QSIZE]; - int i; - int result; - int event_len; - uint32_t ev_src; - uint32_t ev_code; - int ev_argc; - - while(1) { - - bzero( event, BRL1_QSIZE ); - - /* - * wait for an event - */ - result = sc_recv_intr( sc, ch, event, &event_len, 1 ); - if( result != SC_SUCCESS ) { - printk(KERN_WARNING "Error receiving sysctl event on nasid %d\n", - sc->nasid ); - } - else { - /* - * an event arrived; break it down into useful pieces - */ -#if defined(L1_DEBUG) && 0 - int ix; - printf( "Event packet received:\n" ); - for (ix = 0; ix < 64; ix++) { - printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)), - (event[ix] & ((uint64_t)0xf)) ); - if( (ix % 16) == 0xf ) printf( "\n" ); - } -#endif /* L1_DEBUG */ - - i = 0; - - /* get event source */ - COPY_BUFFER_TO_INT(event, i, ev_src); - COPY_BUFFER_TO_INT(event, i, ev_code); - - /* get arg count */ - ev_argc = (event[i++] & 0xffUL); - - /* dispatch events by task */ - switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT ) - { - case L1_ADDR_TASK_ENV: /* environmental monitor event */ - sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), - BRL1_QSIZE - i ); - break; - - default: /* unhandled task type */ - L1_DBG_PRF(( "Unhandled event type received from system " - "controllers: source task %x\n", - (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT - )); - } - } - - } -} - -/* sc_listen sets up a service thread to listen for incoming events. - */ - -void -sc_listen( l1sc_t *sc ) -{ - int result; - unsigned long pl = 0; - brl1_sch_t *subch; - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int ch; /* system controller subchannel used */ - - extern int msc_shutdown_pri; - - /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[BRL1_EVENT_SUBCH]); - if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc, pl ); - printk(KERN_WARNING "sysctl event subchannel in use! " - "Not monitoring sysctl events.\n" ); - return; - } - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = BRL1_LOCALHUB_UART; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - /* set up a thread to listen for events */ - sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri, - KT_PS, (st_func_t *) sc_event, - (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 ); - - /* signal the L1 to begin sending events */ - bzero( msg, BRL1_QSIZE ); - ch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EVENT_SUBCH, 2, - L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len )); - goto err_return; - } - - result = sc_command_kern( sc, ch, msg, msg, &len ); - if( result < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result )); - goto err_return; - } - - sc_close( sc, ch ); - - result = sc_interpret_resp( msg, 0 ); - if( result < 0 ) - { - L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result )); - goto err_return; - } - - /* everything went fine; just return */ - return; - -err_return: - /* there was a problem; complain */ - printk(KERN_WARNING "failed to set sysctl event-monitoring subchannel. " - "Sysctl events will not be monitored.\n" ); -} - -#endif /* LINUX_KERNEL_THREADS */ diff --git a/arch/ia64/sn/io/l1_command.c b/arch/ia64/sn/io/l1_command.c deleted file mode 100644 index 30d666e5c8c..00000000000 --- a/arch/ia64/sn/io/l1_command.c +++ /dev/null @@ -1,1377 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ -#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -#define hub_cpu_get() 0 - -#define LBYTE(caddr) (*(char *) caddr) - -extern char *bcopy(const char * src, char * dest, int count); - -#define LDEBUG 0 - -/* - * ELSC data is in NVRAM page 7 at the following offsets. - */ - -#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ -#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ -#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ -#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ -#define NVRAM_CFG 0x707 /* ELSC Configuration info */ -#define NVRAM_MODULE 0x708 /* system module number */ -#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ -#define NVRAM_PARTITION 0x70a /* module's partition id */ -#define NVRAM_DOMAIN 0x70b /* module's domain id */ -#define NVRAM_CLUSTER 0x70c /* module's cluster id */ -#define NVRAM_CELL 0x70d /* module's cellid */ - -#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ -#define NVRAM_SIZE 16 /* 16 bytes in nvram */ - -/* - * Declare a static ELSC NVRAM buffer to hold all data read from - * and written to NVRAM. This nvram "cache" will be used only during the - * IP27prom execution. - */ -static char elsc_nvram_buffer[NVRAM_SIZE]; - -#define SC_COMMAND sc_command - -/* - * elsc_init - * - * Initialize ELSC structure - */ - -void elsc_init(elsc_t *e, nasid_t nasid) -{ - sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART); -} - - -/* - * elsc_errmsg - * - * Given a negative error code, - * returns a corresponding static error string. - */ - -char *elsc_errmsg(int code) -{ - switch (code) { - case ELSC_ERROR_CMD_SEND: - return "Command send error"; - case ELSC_ERROR_CMD_CHECKSUM: - return "Command packet checksum error"; - case ELSC_ERROR_CMD_UNKNOWN: - return "Unknown command"; - case ELSC_ERROR_CMD_ARGS: - return "Invalid command argument(s)"; - case ELSC_ERROR_CMD_PERM: - return "Permission denied"; - case ELSC_ERROR_RESP_TIMEOUT: - return "System controller response timeout"; - case ELSC_ERROR_RESP_CHECKSUM: - return "Response packet checksum error"; - case ELSC_ERROR_RESP_FORMAT: - return "Response format error"; - case ELSC_ERROR_RESP_DIR: - return "Response direction error"; - case ELSC_ERROR_MSG_LOST: - return "Message lost because queue is full"; - case ELSC_ERROR_LOCK_TIMEOUT: - return "Timed out getting ELSC lock"; - case ELSC_ERROR_DATA_SEND: - return "Error sending data"; - case ELSC_ERROR_NIC: - return "NIC protocol error"; - case ELSC_ERROR_NVMAGIC: - return "Bad magic number in NVRAM"; - case ELSC_ERROR_MODULE: - return "Module location protocol error"; - default: - return "Unknown error"; - } -} - -/* - * elsc_nvram_init - * - * Initializes reads and writes to NVRAM. This will perform a single - * read to NVRAM, getting all data at once. When the PROM tries to - * read NVRAM, it returns the data from the buffer being read. If the - * PROM tries to write out to NVRAM, the write is done, and the internal - * buffer is updated. - */ - -void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data) -{ - /* This might require implementation of multiple-packet request/responses - * if it's to provide the same behavior that was available in SN0. - */ - nasid = nasid; - elsc_nvram_data = elsc_nvram_data; -} - -/* - * elsc_nvram_copy - * - * Copies the content of a buffer into the static buffer in this library. - */ - -void elsc_nvram_copy(uchar_t *elsc_nvram_data) -{ - memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE); -} - -/* - * elsc_nvram_write - * - * Copies bytes from 'buf' into NVRAM, starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. - */ - -int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len) -{ - /* Here again, we might need to work out the details of a - * multiple-packet protocol. - */ - - /* For now, pretend it worked. */ - e = e; - addr = addr; - buf = buf; - return (len < 0 ? -len : len); -} - -/* - * elsc_nvram_read - * - * Copies bytes from NVRAM into 'buf', starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. NOTE: This method is no longer supported. - * It was never used in the first place. - */ - -int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len) -{ - /* multiple packets? */ - e = e; - addr = addr; - buf = buf; - len = len; - return -1; -} - - -/* - * Command Set - */ - -int elsc_version(elsc_t *e, char *result) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} - -int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2) -{ - /* shush compiler */ - e = e; - byte1 = byte1; - byte2 = byte2; - - /* fill in a buffer with the opcode & params; call sc_command */ - - return 0; -} - -int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int dbg_sw; /* holds debug switch settings */ - int len; /* number of msg buffer bytes used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RDBG, 0 ) ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* copy out debug switch settings (last two bytes of the - * integer response) - */ - *byte1 = ((dbg_sw >> 8) & 0xFF); - *byte2 = (dbg_sw & 0xFF); - - return 0; -} - - -/* - * elsc_rack_bay_get fills in the two int * arguments with the - * rack number and bay number of the L1 being addressed - */ -int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRACK, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close(e, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -/* elsc_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - /* convert brick_type to lower case */ - *brick_type = *brick_type - 'A' + 'a'; - - return 0; -} - - -int elsc_module_get(elsc_t *e) -{ - extern char brick_types[]; - uint rnum, rack, bay, bricktype, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { - return ret; - } - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == bricktype ) - return RBT_TO_MODULE(rack, bay, t); - } - - return ELSC_ERROR_MODULE; -} - -int elsc_partition_set(elsc_t *e, int partition) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_SET, 2, - L1_ARG_INT, partition )) < 0 ) - { - - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( 0 ); -} - -int elsc_partition_get(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t partition_id; /* used to copy partition id out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_GET, 0 )) < 0 ) - - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( partition_id ); -} - - -/* - * elsc_cons_subch selects the "active" console subchannel for this node - * (i.e., the one that will currently receive input) - */ -int elsc_cons_subch(elsc_t *e, uint ch) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_SUBCH, 2, - L1_ARG_INT, ch)) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* - * elsc_cons_node should only be executed by one node. It declares to - * the system controller that the node from which it is called will be - * the owner of the system console. - */ -int elsc_cons_node(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_NODE, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_line writes up to 12 characters to either the top or bottom - * line of the L1 display. line points to a buffer containing the message - * to be displayed. The zero-based line number is specified by lnum (so - * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). - * Lines longer than 12 characters, or line numbers not less than - * L1_DISPLAY_LINES, cause elsc_display_line to return an error. - */ -int elsc_display_line(elsc_t *e, char *line, int lnum) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - - /* argument sanity checking */ - if( !(lnum < L1_DISPLAY_LINES) ) - return( ELSC_ERROR_CMD_ARGS ); - if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) ) - return( ELSC_ERROR_CMD_ARGS ); - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - (L1_REQ_DISP1+lnum), 2, - L1_ARG_ASCII, line )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_mesg silently drops message characters beyond the 12th. - */ -int elsc_display_mesg(elsc_t *e, char *chr) -{ - - char line[L1_DISPLAY_LINE_LENGTH+1]; - int numlines, i; - int result; - - numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) / - L1_DISPLAY_LINE_LENGTH; - - if( numlines > L1_DISPLAY_LINES ) - numlines = L1_DISPLAY_LINES; - - for( i = 0; i < numlines; i++ ) - { - strlcpy( line, chr, sizeof(line) ); - - /* generally we want to leave the first line of the L1 display - * alone (so the L1 can manipulate it). If you need to be able - * to display to both lines (for debugging purposes), define - * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES - * to your 'defs file. - */ -#if defined(L1_DISP_2LINES) - if( (result = elsc_display_line( e, line, i )) < 0 ) -#else - if( (result = elsc_display_line( e, line, i+1 )) < 0 ) -#endif - - return result; - - chr += L1_DISPLAY_LINE_LENGTH; - } - - return 0; -} - - -int elsc_password_set(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -int elsc_password_get(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* - * sc_portspeed_get - * - * retrieve the current portspeed setting for the bedrock II - */ -int sc_portspeed_get(l1sc_t *sc) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int portspeed_a, portspeed_b; - /* ioport clock rates */ - - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PORTSPEED, - 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, - L1_ARG_INT, &portspeed_a, - L1_ARG_INT, &portspeed_b ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* for the c-brick, we ignore the portspeed_b value */ - return (portspeed_a ? 600 : 400); -} - -/* - * elsc_power_query - * - * To be used after system reset, this command returns 1 if the reset - * was the result of a power-on, 0 otherwise. - * - * The power query status is cleared to 0 after it is read. - */ - -int elsc_power_query(elsc_t *e) -{ - e = e; /* shush the compiler */ - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 1; -} - -int elsc_rpwr_query(elsc_t *e, int is_master) -{ - /* shush the compiler */ - e = e; - is_master = is_master; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -/* - * elsc_power_down - * - * Sets up system to shut down in "sec" seconds (or modifies the - * shutdown time if one is already in effect). Use 0 to power - * down immediately. - */ - -int elsc_power_down(elsc_t *e, int sec) -{ - /* shush compiler */ - e = e; - sec = sec; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -int elsc_system_reset(elsc_t *e) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - int result; - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RESET, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( (result = sc_command( e, subch, msg, msg, &len )) ) { - sc_close( e, subch ); - if( result == SC_NMSG ) { - /* timeout is OK. We've sent the reset. Now it's just - * a matter of time... - */ - return( 0 ); - } - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -int elsc_power_cycle(elsc_t *e) -{ - /* shush compiler */ - e = e; - - /* fill in buffer with the opcode & params; call sc_command */ - - return 0; -} - - -/* - * L1 Support for reading - * cbrick uid. - */ - -int elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose) -{ - /* this parameter included only for SN0 compatibility */ - verbose = verbose; - - /* We don't go straight to the bedrock/L1 protocol on this one, but let - * the eeprom layer prepare the eeprom data as we would like it to - * appear to the caller - */ - return cbrick_uid_get( e->nasid, nic ); -} - - -int _elsc_hbt(elsc_t *e, int ival, int rdly) -{ - e = e; - ival = ival; - rdly = rdly; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* send a command string to an L1 */ -int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay, - char *cmd ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - l1addr_t target; /* target system controller for command */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - - L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); - subch = sc_open( sc, target ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, - L1_ARG_ASCII, cmd )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - -/* - * sc_power_down - * - * Shuts down the c-brick associated with sc, and any attached I/O bricks - * or other c-bricks (won't go through r-bricks). - */ - -int sc_power_down(l1sc_t *sc) -{ - return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); -} - - -/* - * sc_power_down_all - * - * Works similarly to sc_power_down, except that the request is sent to the - * closest L2 and EVERYBODY gets turned off. - */ - -int sc_power_down_all(l1sc_t *sc) -{ - if( nodepda->num_routers > 0 ) { - return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); - } - else { - return sc_power_down( sc ); - } -} - - -/* - * Routines for reading the R-brick's L1 - */ - -int router_module_get( nasid_t nasid, net_vec_t path ) -{ - uint rnum, rack, bay, t; - int ret; - l1sc_t sc; - - /* prepare l1sc_t struct */ - sc_init( &sc, nasid, path ); - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_get(&sc, &rnum, &bay)) < 0) - return ret; - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - ret = RBT_TO_MODULE(rack, bay, MODULE_RBRICK); - return ret; -} - - -/* - * iobrick routines - */ - -/* iobrick_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -int iobrick_module_get(l1sc_t *sc) -{ - uint rnum, rack, bay, brick_type, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) - return ret; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - switch( brick_type ) { - case 'I': - brick_type = MODULE_IBRICK; break; - case 'P': - brick_type = MODULE_PBRICK; break; - case 'X': - brick_type = MODULE_XBRICK; break; - } - - ret = RBT_TO_MODULE(rack, bay, brick_type); - - return ret; -} - -/* iobrick_get_sys_snum asks the attached iobrick for the system - * serial number. This function will only be relevant to the master - * cbrick (the one attached to the bootmaster ibrick); other nodes - * may call the function, but the value returned to the master node - * will be the one used as the system serial number by the kernel. - */ - -int -iobrick_get_sys_snum( l1sc_t *sc, char *snum_str ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SYS_SERIAL, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) ); -} - - -/* - * The following functions apply (or cut off) power to the specified - * pci bus or slot. - */ - -int -iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) -{ -#if 0 /* The "bedrock request" method of performing this function - * seems to be broken in the L1, so for now use the command- - * interpreter method - */ - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - req_code, 4, - L1_ARG_INT, bus, - L1_ARG_INT, slot )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; - -#else - char cmd[64]; - char *fxn; - - switch( req_code ) - { - case L1_REQ_PCI_UP: - fxn = "u"; - break; - case L1_REQ_PCI_DOWN: - fxn = "d"; - break; - case L1_REQ_PCI_RESET: - fxn = "rst"; - break; - default: - return( ELSC_ERROR_CMD_ARGS ); - } - - if( slot == -1 ) - sprintf( cmd, "pci %d %s", bus, fxn ); - else - sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); - - return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, - L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); -#endif -} - -int -iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) -{ - return iobrick_pci_pwr( sc, bus, slot, up ); -} - -int -iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) -{ - return iobrick_pci_pwr( sc, bus, -1, up ); -} - - -int -iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) -{ - return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); -} - -int -iobrick_pci_bus_rst( l1sc_t *sc, int bus ) -{ - return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); -} - - -/* get the L1 firmware version for an iobrick */ -int -iobrick_sc_version( l1sc_t *sc, char *result ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} diff --git a/arch/ia64/sn/io/machvec/Makefile b/arch/ia64/sn/io/machvec/Makefile new file mode 100644 index 00000000000..238f3e1c5fd --- /dev/null +++ b/arch/ia64/sn/io/machvec/Makefile @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += pci.o pci_dma.o pci_bus_cvlink.o iomv.o diff --git a/arch/ia64/sn/kernel/sn2/iomv.c b/arch/ia64/sn/io/machvec/iomv.c similarity index 94% rename from arch/ia64/sn/kernel/sn2/iomv.c rename to arch/ia64/sn/io/machvec/iomv.c index 4dd53594f5c..e69d0b81d95 100644 --- a/arch/ia64/sn/kernel/sn2/iomv.c +++ b/arch/ia64/sn/io/machvec/iomv.c @@ -65,7 +65,7 @@ EXPORT_SYMBOL(sn_io_addr); void sn_mmiob (void) { - while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != + while ((((volatile unsigned long) (*pda->pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) udelay(1); } diff --git a/arch/ia64/sn/io/machvec/pci.c b/arch/ia64/sn/io/machvec/pci.c new file mode 100644 index 00000000000..c525614bf0c --- /dev/null +++ b/arch/ia64/sn/io/machvec/pci.c @@ -0,0 +1,135 @@ +/* + * + * SNI64 specific PCI support for SNI IO. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1997, 1998, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_CONFIG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + + +#ifdef CONFIG_PCI + +extern vertex_hdl_t pci_bus_to_vertex(unsigned char); +extern vertex_hdl_t devfn_to_vertex(unsigned char bus, unsigned char devfn); + +int sn_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) +{ + unsigned long res = 0; + vertex_hdl_t device_vertex; + + device_vertex = devfn_to_vertex(bus->number, devfn); + res = pciio_config_get(device_vertex, (unsigned) where, size); + *val = (unsigned int) res; + return PCIBIOS_SUCCESSFUL; +} + +int sn_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) +{ + vertex_hdl_t device_vertex; + + device_vertex = devfn_to_vertex(bus->number, devfn); + pciio_config_set( device_vertex, (unsigned)where, size, (uint64_t) val); + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sn_pci_ops = { + .read = sn_read_config, + .write = sn_write_config +}; + +/* + * sn_pci_find_bios - SNIA64 pci_find_bios() platform specific code. + */ +void __init +sn_pci_find_bios(void) +{ + extern struct pci_ops *pci_root_ops; + /* + * Go initialize our IO Infrastructure .. + */ + extern void sgi_master_io_infr_init(void); + + sgi_master_io_infr_init(); + + /* sn_io_infrastructure_init(); */ + pci_root_ops = &sn_pci_ops; +} + +void +pci_fixup_ioc3(struct pci_dev *d) +{ + int i; + unsigned int size; + + /* IOC3 only decodes 0x20 bytes of the config space, reading + * beyond that is relatively benign but writing beyond that + * (especially the base address registers) will shut down the + * pci bus...so avoid doing so. + * NOTE: this means we can't program the intr_pin into the device, + * currently we hack this with special code in + * sgi_pci_intr_support() + */ + DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); + + /* I happen to know from the spec that the ioc3 needs only 0xfffff + * The standard pci trick of writing ~0 to the baddr and seeing + * what comes back doesn't work with the ioc3 + */ + size = 0xfffff; + d->resource[0].end = (unsigned long) d->resource[0].start + (unsigned long) size; + + /* + * Zero out the resource structure .. because we did not go through + * the normal PCI Infrastructure Init, garbbage are left in these + * fileds. + */ + for (i = 1; i <= PCI_ROM_RESOURCE; i++) { + d->resource[i].start = 0UL; + d->resource[i].end = 0UL; + d->resource[i].flags = 0UL; + } + + d->subsystem_vendor = 0; + d->subsystem_device = 0; + +} + +#else +void sn_pci_find_bios(void) {} +void pci_fixup_ioc3(struct pci_dev *d) {} +struct list_head pci_root_buses; +struct list_head pci_root_buses; +struct list_head pci_devices; + +#endif /* CONFIG_PCI */ diff --git a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c similarity index 66% rename from arch/ia64/sn/io/sn2/pci_bus_cvlink.c rename to arch/ia64/sn/io/machvec/pci_bus_cvlink.c index 3b80e91135f..51e53d0d419 100644 --- a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c +++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -15,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -38,23 +36,24 @@ #include #include #include +#include extern int bridge_rev_b_data_check_disable; -devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; +vertex_hdl_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; unsigned char num_bridges; -static int done_probing = 0; +static int done_probing; +extern irqpda_t *irqpdaindr; -static int pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid); -devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); +static int pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid); +vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); -extern unsigned char Is_pic_on_this_nasid[512]; - -extern void sn_init_irq_desc(void); extern void register_pcibr_intr(int irq, pcibr_intr_t intr); +void sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot); + /* * For the given device, initialize whether it is a PIC device. @@ -78,7 +77,7 @@ pci_bus_cvlink_init(void) extern void ioconfig_bus_init(void); - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(vertex_hdl_t) * MAX_PCI_XWIDGET); memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); @@ -92,11 +91,11 @@ pci_bus_cvlink_init(void) * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated * pci bus vertex from the SGI IO Infrastructure. */ -devfs_handle_t +vertex_hdl_t pci_bus_to_vertex(unsigned char busnum) { - devfs_handle_t pci_bus = NULL; + vertex_hdl_t pci_bus = NULL; /* @@ -110,15 +109,15 @@ pci_bus_to_vertex(unsigned char busnum) * devfn_to_vertex() - returns the vertex of the device given the bus, slot, * and function numbers. */ -devfs_handle_t +vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn) { int slot = 0; int func = 0; char name[16]; - devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = (devfs_handle_t)NULL; + vertex_hdl_t pci_bus = NULL; + vertex_hdl_t device_vertex = (vertex_hdl_t)NULL; /* * Go get the pci bus vertex. @@ -126,9 +125,9 @@ devfn_to_vertex(unsigned char busnum, unsigned int devfn) pci_bus = pci_bus_to_vertex(busnum); if (!pci_bus) { /* - * During probing, the Linux pci code invents non existant + * During probing, the Linux pci code invents non-existent * bus numbers and pci_dev structures and tries to access - * them to determine existance. Don't crib during probing. + * them to determine existence. Don't crib during probing. */ if (done_probing) printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); @@ -219,6 +218,199 @@ printk("set_flush_addresses: xbow_buf_sync\n"); } +struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; + +// Initialize the data structures for flushing write buffers after a PIO read. +// The theory is: +// Take an unused int. pin and associate it with a pin that is in use. +// After a PIO read, force an interrupt on the unused pin, forcing a write buffer flush +// on the in use pin. This will prevent the race condition between PIO read responses and +// DMA writes. +void +sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot) { + nasid_t nasid; + unsigned long dnasid; + int wid_num; + int bus; + struct sn_flush_device_list *p; + bridge_t *b; + bridgereg_t dev_sel; + extern int isIO9(int); + int bwin; + int i; + + nasid = NASID_GET(start); + wid_num = SWIN_WIDGETNUM(start); + bus = (start >> 23) & 0x1; + bwin = BWIN_WINDOWNUM(start); + + if (flush_nasid_list[nasid].widget_p == NULL) { + flush_nasid_list[nasid].widget_p = (struct sn_flush_device_list **)kmalloc((HUB_WIDGET_ID_MAX+1) * + sizeof(struct sn_flush_device_list *), GFP_KERNEL); + memset(flush_nasid_list[nasid].widget_p, 0, (HUB_WIDGET_ID_MAX+1) * sizeof(struct sn_flush_device_list *)); + } + if (bwin > 0) { + bwin--; + switch (bwin) { + case 0: + flush_nasid_list[nasid].iio_itte1 = HUB_L(IIO_ITTE_GET(nasid, 0)); + wid_num = ((flush_nasid_list[nasid].iio_itte1) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte1 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 1: + flush_nasid_list[nasid].iio_itte2 = HUB_L(IIO_ITTE_GET(nasid, 1)); + wid_num = ((flush_nasid_list[nasid].iio_itte2) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte2 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 2: + flush_nasid_list[nasid].iio_itte3 = HUB_L(IIO_ITTE_GET(nasid, 2)); + wid_num = ((flush_nasid_list[nasid].iio_itte3) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte3 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 3: + flush_nasid_list[nasid].iio_itte4 = HUB_L(IIO_ITTE_GET(nasid, 3)); + wid_num = ((flush_nasid_list[nasid].iio_itte4) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte4 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 4: + flush_nasid_list[nasid].iio_itte5 = HUB_L(IIO_ITTE_GET(nasid, 4)); + wid_num = ((flush_nasid_list[nasid].iio_itte5) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte5 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 5: + flush_nasid_list[nasid].iio_itte6 = HUB_L(IIO_ITTE_GET(nasid, 5)); + wid_num = ((flush_nasid_list[nasid].iio_itte6) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte6 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 6: + flush_nasid_list[nasid].iio_itte7 = HUB_L(IIO_ITTE_GET(nasid, 6)); + wid_num = ((flush_nasid_list[nasid].iio_itte7) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte7 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + } + } + + // if it's IO9, bus 1, we don't care about slots 1, 3, and 4. This is + // because these are the IOC4 slots and we don't flush them. + if (isIO9(nasid) && bus == 0 && (slot == 1 || slot == 4)) { + return; + } + if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) { + flush_nasid_list[nasid].widget_p[wid_num] = (struct sn_flush_device_list *)kmalloc( + DEV_PER_WIDGET * sizeof (struct sn_flush_device_list), GFP_KERNEL); + memset(flush_nasid_list[nasid].widget_p[wid_num], 0, + DEV_PER_WIDGET * sizeof (struct sn_flush_device_list)); + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + for (i=0; ibus = -1; + p->pin = -1; + p++; + } + } + + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + for (i=0;ipin == pin && p->bus == bus) break; + if (p->pin < 0) { + p->pin = pin; + p->bus = bus; + break; + } + p++; + } + + for (i=0; ibar_list[i].start == 0) { + p->bar_list[i].start = start; + p->bar_list[i].end = end; + break; + } + } + b = (bridge_t *)(NODE_SWIN_BASE(nasid, wid_num) | (bus << 23) ); + + // If it's IO9, then slot 2 maps to slot 7 and slot 6 maps to slot 8. + // To see this is non-trivial. By drawing pictures and reading manuals and talking + // to HW guys, we can see that on IO9 bus 1, slots 7 and 8 are always unused. + // Further, since we short-circuit slots 1, 3, and 4 above, we only have to worry + // about the case when there is a card in slot 2. A multifunction card will appear + // to be in slot 6 (from an interrupt point of view) also. That's the most we'll + // have to worry about. A four function card will overload the interrupt lines in + // slot 2 and 6. + // We also need to special case the 12160 device in slot 3. Fortunately, we have + // a spare intr. line for pin 4, so we'll use that for the 12160. + // All other buses have slot 3 and 4 and slots 7 and 8 unused. Since we can only + // see slots 1 and 2 and slots 5 and 6 coming through here for those buses (this + // is true only on Pxbricks with 2 physical slots per bus), we just need to add + // 2 to the slot number to find an unused slot. + // We have convinced ourselves that we will never see a case where two different cards + // in two different slots will ever share an interrupt line, so there is no need to + // special case this. + + if (isIO9(nasid) && wid_num == 0xc && bus == 0) { + if (slot == 2) { + p->force_int_addr = (unsigned long)&b->b_force_always[6].intr; + dev_sel = b->b_int_device; + dev_sel |= (1<<18); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[6] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } else if (slot == 3) { /* 12160 SCSI device in IO9 */ + p->force_int_addr = (unsigned long)&b->b_force_always[4].intr; + dev_sel = b->b_int_device; + dev_sel |= (2<<12); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[4] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } else { /* slot == 6 */ + p->force_int_addr = (unsigned long)&b->b_force_always[7].intr; + dev_sel = b->b_int_device; + dev_sel |= (5<<21); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[7] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } + } else { + p->force_int_addr = (unsigned long)&b->b_force_always[pin + 2].intr; + dev_sel = b->b_int_device; + dev_sel |= ((slot - 1) << ( pin * 3) ); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[pin + 2] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } +} + /* * Most drivers currently do not properly tell the arch specific pci dma * interfaces whether they can handle A64. Here is where we privately @@ -264,37 +456,22 @@ sn_pci_fixup(int arg) struct sn_device_sysdata *device_sysdata; pciio_intr_t intr_handle; int cpuid, bit; - devfs_handle_t device_vertex; + vertex_hdl_t device_vertex; pciio_intr_line_t lines; extern void sn_pci_find_bios(void); extern int numnodes; int cnode; - extern void io_sh_swapper(int, int); - - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 0); - } if (arg == 0) { #ifdef CONFIG_PROC_FS extern void register_sn_procfs(void); #endif - sn_init_irq_desc(); sn_pci_find_bios(); for (cnode = 0; cnode < numnodes; cnode++) { extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); intr_init_vecblk(NODEPDA(cnode), cnode, 0); } - - /* - * When we return to generic Linux, Swapper is always on .. - */ - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 1); - } #ifdef CONFIG_PROC_FS register_sn_procfs(); #endif @@ -323,13 +500,19 @@ sn_pci_fixup(int arg) ioport_resource.end = 0xcfffffffffffffff; /* + * Set the root start and end for Mem Resource. + */ + iomem_resource.start = 0; + iomem_resource.end = 0xffffffffffffffff; + + /* * Initialize the device vertex in the pci_dev struct. */ while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { unsigned int irq; int idx; u16 cmd; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; unsigned long size; extern int bit_pos_to_irq(int); @@ -423,15 +606,36 @@ sn_pci_fixup(int arg) device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; device_vertex = device_sysdata->vhdl; + irqpdaindr->current = device_dev; intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); - bit = intr_handle->pi_irq; + irq = intr_handle->pi_irq; + irqpdaindr->device_dev[irq] = device_dev; cpuid = intr_handle->pi_cpu; - irq = bit; - irq = irq + (cpuid << 8); pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0); device_dev->irq = irq; register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); + + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + int ibits = ((pcibr_intr_t)intr_handle)->bi_ibits; + int i; + + size = device_dev->resource[idx].end - + device_dev->resource[idx].start; + if (size == 0) continue; + + for (i=0; i<8; i++) { + if (ibits & (1 << i) ) { + sn_dma_flush_init(device_dev->resource[idx].start, + device_dev->resource[idx].end, + idx, + i, + PCI_SLOT(device_dev->devfn)); + } + } + } + + } #ifdef ajmtestintr { int slot = PCI_SLOT(device_dev->devfn); @@ -448,13 +652,6 @@ sn_pci_fixup(int arg) request_irq(irq, intr_test_handle_intr,0,NULL, NULL); } #endif - - } - - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 1); - } } /* @@ -506,18 +703,20 @@ linux_bus_cvlink(void) * */ static int -pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid) +pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid) { - devfs_handle_t master_node_vertex = NULL; - devfs_handle_t xwidget = NULL; - devfs_handle_t pci_bus = NULL; + vertex_hdl_t master_node_vertex = NULL; + vertex_hdl_t xwidget = NULL; + vertex_hdl_t pci_bus = NULL; hubinfo_t hubinfo = NULL; xwidgetnum_t widgetnum; char pathname[128]; graph_error_t rv; int bus; int basebus_num; + extern void ioconfig_get_busnum(char *, int *); + int bus_number; /* @@ -666,12 +865,14 @@ int pci_bus_to_hcl_cvlink(void) { - devfs_handle_t devfs_hdl = NULL; - devfs_handle_t xtalk = NULL; + vertex_hdl_t devfs_hdl = NULL; + vertex_hdl_t xtalk = NULL; int rv = 0; char name[256]; char tmp_name[256]; - int i, ii; + int i, ii, j; + char *brick_name; + extern void ioconfig_bus_new_entries(void); /* * Figure out which IO Brick is connected to the Compute Bricks. @@ -695,18 +896,28 @@ pci_bus_to_hcl_cvlink(void) } } - devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); + devfs_hdl = hwgraph_path_to_vertex("hw/module"); for (i = 0; i < nummodules ; i++) { + for ( j = 0; j < 3; j++ ) { + if ( j == 0 ) + brick_name = EDGE_LBL_PBRICK; + else if ( j == 1 ) + brick_name = EDGE_LBL_PXBRICK; + else + brick_name = EDGE_LBL_IXBRICK; + for ( ii = 0; ii < 2 ; ii++ ) { memset(name, 0, 256); memset(tmp_name, 0, 256); format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - sprintf(tmp_name, "/slab/%d/Pbrick/xtalk", geo_slab(modules[i]->geoid[ii])); + sprintf(tmp_name, "/slab/%d/%s/xtalk", geo_slab(modules[i]->geoid[ii]), brick_name); strcat(name, tmp_name); xtalk = NULL; rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); + if ( rv == 0 ) + pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); } + } } /* diff --git a/arch/ia64/sn/io/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c similarity index 72% rename from arch/ia64/sn/io/pci_dma.c rename to arch/ia64/sn/io/machvec/pci_dma.c index 837da01be05..948685c69f6 100644 --- a/arch/ia64/sn/io/pci_dma.c +++ b/arch/ia64/sn/io/machvec/pci_dma.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. * * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for * a description of how these routines should be used. @@ -35,14 +35,15 @@ /* * For ATE allocations */ -pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); void free_pciio_dmamap(pcibr_dmamap_t); static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); +void sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* * Toplogy stuff */ -extern devfs_handle_t busnum_to_pcibr_vhdl[]; +extern vertex_hdl_t busnum_to_pcibr_vhdl[]; extern nasid_t busnum_to_nid[]; extern void * busnum_to_atedmamaps[]; @@ -54,7 +55,7 @@ extern void * busnum_to_atedmamaps[]; * by @pci_bus. */ pciio_dmamap_t -get_free_pciio_dmamap(devfs_handle_t pci_bus) +get_free_pciio_dmamap(vertex_hdl_t pci_bus) { int i; struct sn_dma_maps_s *sn_dma_map = NULL; @@ -122,50 +123,6 @@ find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) } /** - * sn_dma_sync - try to flush DMA buffers into the coherence domain - * @hwdev: device to flush - * - * This routine flushes all DMA buffers for the device into the II of - * the destination hub. - * - * NOTE!: this does not mean that the data is in the "coherence domain", - * but it is very close. In other words, this routine *does not work* - * as advertised due to hardware bugs. That said, it should be good enough for - * most situations. - */ -void -sn_dma_sync(struct pci_dev *hwdev) -{ - -#ifdef SN_DMA_SYNC - - struct sn_device_sysdata *device_sysdata; - volatile unsigned long dummy; - - /* - * A DMA sync is supposed to ensure that - * all the DMA from a particular device - * is complete and coherent. We - * try to do this by - * 1. flushing the write wuffers from Bridge - * 2. flushing the Xbow port. - * Unfortunately, this only gets the DMA transactions 'very close' to - * the coherence domain, but not quite in it. - */ - device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; - dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync; - - /* - * For the Xbow port flush, we may be denied the request because - * someone else may be flushing the port .. try again. - */ - while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) { - udelay(2); - } -#endif -} - -/** * sn_pci_alloc_consistent - allocate memory for coherent DMA * @hwdev: device to allocate for * @size: size of the region @@ -188,7 +145,7 @@ void * sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *cpuaddr; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; struct sn_device_sysdata *device_sysdata; unsigned long phys_addr; pciio_dmamap_t dma_map = 0; @@ -227,38 +184,22 @@ sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_hand * device on the same bus is already mapped with different * attributes or to a different memory region. */ -#ifdef CONFIG_IA64_SGI_SN1 - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); -#elif defined(CONFIG_IA64_SGI_SN2) *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_CMD); -#else -#error unsupported platform -#endif /* * It is a 32 bit card and we cannot do direct mapping, * so we try to use an ATE. */ if (!(*dma_handle)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); -#elif defined(CONFIG_IA64_SGI_SN2) dma_map = pciio_dmamap_alloc(vhdl, NULL, size, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_CMD); -#else -#error unsupported platform -#endif if (!dma_map) { printk(KERN_ERR "sn_pci_alloc_consistent: Unable to " "allocate anymore 32 bit page map entries.\n"); - BUG(); + return 0; } *dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr, size); @@ -316,11 +257,12 @@ sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire { int i; - devfs_handle_t vhdl; - dma_addr_t dma_addr; + vertex_hdl_t vhdl; unsigned long phys_addr; struct sn_device_sysdata *device_sysdata; pciio_dmamap_t dma_map; + struct sn_dma_maps_s *sn_dma_map; + struct scatterlist *saved_sg = sg; /* can't go anywhere w/o a direction in life */ if (direction == PCI_DMA_NONE) @@ -337,40 +279,20 @@ sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire * scatterlist. */ for (i = 0; i < nents; i++, sg++) { - /* this catches incorrectly written drivers that - attempt to map scatterlists that they have - previously mapped. we print a warning and - continue, but the driver should be fixed */ - switch (((u64)sg->dma_address) >> 60) { - case 0xa: - case 0xb: -#ifdef DEBUG -/* This needs to be cleaned up at some point. */ - NAG("A PCI driver (for device at%8s) has attempted to " - "map a scatterlist that was previously mapped at " - "%p - this is currently being worked around.\n", - hwdev->slot_name, (void *)sg->dma_address); - phys_addr = (u64)sg->dma_address & TO_PHYS_MASK; - break; -#endif - default: /* not previously mapped, get the phys. addr */ - phys_addr = __pa(sg->dma_address); - break; - } - sg->page = NULL; - dma_addr = 0; + phys_addr = __pa(sg->dma_address ? sg->dma_address : + page_address(sg->page) + sg->offset); /* * Handle the most common case: 64 bit cards. This * call should always succeed. */ if (IS_PCIA64(hwdev)) { - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr, sg->length, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_DATA | PCIIO_DMA_A64); - sg->dma_address = (char *)dma_addr; + sg->dma_length = sg->length; continue; } @@ -378,24 +300,15 @@ sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire * Handle 32-63 bit cards via direct mapping */ if (IS_PCI32G(hwdev)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr, sg->length, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif + sg->dma_length = sg->length; /* * See if we got a direct map entry */ - if (dma_addr) { - sg->dma_address = (char *)dma_addr; + if (sg->dma_address) { continue; } @@ -405,27 +318,25 @@ sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int dire * It is a 32 bit card and we cannot do direct mapping, * so we use an ATE. */ - dma_map = 0; -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif if (!dma_map) { printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " "anymore 32 bit page map entries.\n"); - BUG(); + /* + * We will need to free all previously allocated entries. + */ + if (i > 0) { + sn_pci_unmap_sg(hwdev, saved_sg, i, direction); + } + return (0); } - dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length); - sg->dma_address = (char *)dma_addr; - sg->page = (struct page *)dma_map; - + + sg->dma_address = pciio_dmamap_addr(dma_map, phys_addr, sg->length); + sg->dma_length = sg->length; + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = sg->dma_address; } return nents; @@ -453,20 +364,21 @@ sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int di if (direction == PCI_DMA_NONE) BUG(); - for (i = 0; i < nents; i++, sg++) - if (sg->page) { - /* - * We maintain the DMA Map pointer in sg->page if - * it is ever allocated. - */ - sg->dma_address = 0; - sn_dma_map = (struct sn_dma_maps_s *)sg->page; - pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); - sn_dma_map->dma_addr = 0; - sg->page = 0; - } + for (i = 0; i < nents; i++, sg++){ + if (IS_PCI32_MAPPED(sg->dma_address)) { + sn_dma_map = NULL; + sn_dma_map = find_sn_dma_map(sg->dma_address, hwdev->bus->number); + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; + } + } + + sg->dma_address = (dma_addr_t)NULL; + sg->dma_length = 0; + } } /** @@ -492,7 +404,7 @@ sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int di dma_addr_t sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; dma_addr_t dma_addr; unsigned long phys_addr; struct sn_device_sysdata *device_sysdata; @@ -534,17 +446,9 @@ sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) * First try to get a 32 bit direct map register. */ if (IS_PCI32G(hwdev)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif if (dma_addr) return dma_addr; } @@ -554,21 +458,14 @@ sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) * let's use the PMU instead. */ dma_map = NULL; -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) dma_map = pciio_dmamap_alloc(vhdl, NULL, size, ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif if (!dma_map) { printk(KERN_ERR "pci_map_single: Unable to allocate anymore " "32 bit page map entries.\n"); - BUG(); + return 0; } dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size); @@ -620,17 +517,14 @@ sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int * @direction: DMA direction * * This routine is supposed to sync the DMA region specified - * by @dma_handle into the 'coherence domain'. See sn_dma_sync() - * above for more information. Also known as - * platform_pci_dma_sync_single() by the IA64 machvec code. + * by @dma_handle into the 'coherence domain'. We do not need to do + * anything on our platform. */ void sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { - if (direction == PCI_DMA_NONE) - BUG(); + return; - sn_dma_sync(hwdev); } /** @@ -641,30 +535,14 @@ sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size * @direction: DMA direction * * This routine is supposed to sync the DMA regions specified - * by @sg into the 'coherence domain'. See sn_dma_sync() - * above for more information. Also known as - * platform_pci_dma_sync_sg() by the IA64 machvec code. + * by @sg into the 'coherence domain'. We do not need to do anything + * on our platform. */ void sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { - if (direction == PCI_DMA_NONE) - BUG(); - - sn_dma_sync(hwdev); -} + return; -/** - * sn_dma_address - get the DMA address for the first entry of a scatterlist - * @sg: sg to look at - * - * Gets the DMA address for the scatterlist @sg. Also known as - * platform_dma_address() by the IA64 machvec code. - */ -unsigned long -sn_dma_address(struct scatterlist *sg) -{ - return ((unsigned long)sg->dma_address); } /** @@ -688,6 +566,134 @@ sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) return 1; } +#ifdef CONFIG_PCI + +/* + * New generic DMA routines just wrap sn2 PCI routines until we + * support other bus types (if ever). + */ + +int +sn_dma_supported(struct device *dev, u64 mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_dma_supported(to_pci_dev(dev), mask); +} +EXPORT_SYMBOL(sn_dma_supported); + +int +sn_dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +} +EXPORT_SYMBOL(sn_dma_set_mask); + +void * +sn_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + int flag) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); +} +EXPORT_SYMBOL(sn_dma_alloc_coherent); + +void +sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); +} +EXPORT_SYMBOL(sn_dma_free_coherent); + +dma_addr_t +sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_single); + +void +sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_single); + +dma_addr_t +sn_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_page); + +void +sn_dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_page); + +int +sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_sg); + +void +sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_sg); + +void +sn_dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_single); + +void +sn_dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_sg); + +#endif /* CONFIG_PCI */ + EXPORT_SYMBOL(sn_pci_unmap_single); EXPORT_SYMBOL(sn_pci_map_single); EXPORT_SYMBOL(sn_pci_dma_sync_single); @@ -695,6 +701,5 @@ EXPORT_SYMBOL(sn_pci_map_sg); EXPORT_SYMBOL(sn_pci_unmap_sg); EXPORT_SYMBOL(sn_pci_alloc_consistent); EXPORT_SYMBOL(sn_pci_free_consistent); -EXPORT_SYMBOL(sn_dma_address); EXPORT_SYMBOL(sn_pci_dma_supported); diff --git a/arch/ia64/sn/io/ml_SN_init.c b/arch/ia64/sn/io/ml_SN_init.c deleted file mode 100644 index d6bfddc90f9..00000000000 --- a/arch/ia64/sn/io/ml_SN_init.c +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int numcpus; -extern char arg_maxnodes[]; -extern cpuid_t master_procid; -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif - -extern int hasmetarouter; - -int maxcpus; -cpumask_t boot_cpumask; -hubreg_t region_mask = 0; - - -extern xwidgetnum_t hub_widget_id(nasid_t); - -extern int valid_icache_reasons; /* Reasons to flush the icache */ -extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern u_char miniroot; -extern volatile int need_utlbmiss_patch; -extern void iograph_early_init(void); - -nasid_t master_nasid = INVALID_NASID; - - -/* - * mlreset(int slave) - * very early machine reset - at this point NO interrupts have been - * enabled; nor is memory, tlb, p0, etc setup. - * - * slave is zero when mlreset is called for the master processor and - * is nonzero thereafter. - */ - - -void -mlreset(int slave) -{ - if (!slave) { - /* - * We are the master cpu and node. - */ - master_nasid = get_nasid(); - set_master_bridge_base(); - - /* We're the master processor */ - master_procid = smp_processor_id(); - master_nasid = cpuid_to_nasid(master_procid); - - /* - * master_nasid we get back better be same as one from - * get_nasid() - */ - ASSERT_ALWAYS(master_nasid == get_nasid()); - - /* early initialization of iograph */ - iograph_early_init(); - - /* Initialize Hub Pseudodriver Management */ - hubdev_init(); - - } else { /* slave != 0 */ - /* - * This code is performed ONLY by slave processors. - */ - - } -} - - -/* XXX - Move the meat of this to intr.c ? */ -/* - * Set up the platform-dependent fields in the nodepda. - */ -void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) -{ - hubinfo_t hubinfo; -#ifdef CONFIG_IA64_SGI_SN1 - int sn; -#endif - - extern void router_map_init(nodepda_t *); - extern void router_queue_init(nodepda_t *,cnodeid_t); - extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); - - /* Allocate per-node platform-dependent data */ - hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); - - npda->pdinfo = (void *)hubinfo; - hubinfo->h_nodepda = npda; - hubinfo->h_cnodeid = node; - hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); - - spin_lock_init(&hubinfo->h_crblock); - - hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); - npda->xbow_peer = INVALID_NASID; - - /* - * Initialize the linked list of - * router info pointers to the dependent routers - */ - npda->npda_rip_first = NULL; - - /* - * npda_rip_last always points to the place - * where the next element is to be inserted - * into the list - */ - npda->npda_rip_last = &npda->npda_rip_first; - npda->module_id = INVALID_MODULE; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Initialize the interrupts. - * On sn2, this is done at pci init time, - * because sn2 needs the cpus checked in - * when it initializes interrupts. This is - * so we don't see all the nodes as headless. - */ - for (sn=0; snxbow_sema); /* init it locked? */ - -#ifdef LATER - - /* Setup the (module,slot) --> nic mapping for all the routers - * in the system. This is useful during error handling when - * there is no shared memory. - */ - router_map_init(npda); - - /* Allocate memory for the per-node router traversal queue */ - router_queue_init(npda,node); - npda->sbe_info = alloc_bootmem_node(NODE_DATA(node), sizeof (sbe_info_t)); - ASSERT(npda->sbe_info); - -#endif /* LATER */ -} - -/* XXX - Move the interrupt stuff to intr.c ? */ -/* - * Set up the platform-dependent fields in the processor pda. - * Must be done _after_ init_platform_nodepda(). - * If we need a lock here, something else is wrong! - */ -void init_platform_pda(cpuid_t cpu) -{ -#if defined(CONFIG_IA64_SGI_SN1) - hub_intmasks_t *intmasks; - int i, subnode; - cnodeid_t cnode; - synergy_da_t *sda; - int which_synergy; - - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - intmasks = &sda->s_intmasks; - - /* Clear INT_PEND0 masks. */ - for (i = 0; i < N_INTPEND0_MASKS; i++) - intmasks->intpend0_masks[i] = 0; - - /* Set up pointer to the vector block in the nodepda. */ - /* (Cant use SUBNODEPDA - not working yet) */ - subnode = cpuid_to_subnode(cpu); - intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; - if (intmasks->dispatch0 != &SUBNODEPDA(cnode, subnode)->intr_dispatch0 || - intmasks->dispatch1 != &SUBNODEPDA(cnode, subnode)->intr_dispatch1) - panic("xxx"); - intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0; - intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1; - - /* Clear INT_PEND1 masks. */ - for (i = 0; i < N_INTPEND1_MASKS; i++) - intmasks->intpend1_masks[i] = 0; -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -update_node_information(cnodeid_t cnodeid) -{ - nodepda_t *npda = NODEPDA(cnodeid); - nodepda_router_info_t *npda_rip; - - /* Go through the list of router info - * structures and copy some frequently - * accessed info from the info hanging - * off the corresponding router vertices - */ - npda_rip = npda->npda_rip_first; - while(npda_rip) { - if (npda_rip->router_infop) { - npda_rip->router_portmask = - npda_rip->router_infop->ri_portmask; - npda_rip->router_slot = - npda_rip->router_infop->ri_slotnum; - } else { - /* No router, no ports. */ - npda_rip->router_portmask = 0; - } - npda_rip = npda_rip->router_next; - } -} diff --git a/arch/ia64/sn/io/ml_iograph.c b/arch/ia64/sn/io/ml_iograph.c deleted file mode 100644 index eb6e3e60bf8..00000000000 --- a/arch/ia64/sn/io/ml_iograph.c +++ /dev/null @@ -1,1570 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IOGRAPH_DEBUG */ -#ifdef IOGRAPH_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* IOGRAPH_DEBUG */ - -/* #define PROBE_TEST */ - -/* At most 2 hubs can be connected to an xswitch */ -#define NUM_XSWITCH_VOLUNTEER 2 - -/* - * Track which hubs have volunteered to manage devices hanging off of - * a Crosstalk Switch (e.g. xbow). This structure is allocated, - * initialized, and hung off the xswitch vertex early on when the - * xswitch vertex is created. - */ -typedef struct xswitch_vol_s { - mutex_t xswitch_volunteer_mutex; - int xswitch_volunteer_count; - devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; -} *xswitch_vol_t; - -void -xswitch_vertex_init(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - mutex_init(&xvolinfo->xswitch_volunteer_mutex); - xvolinfo->xswitch_volunteer_count = 0; - rc = hwgraph_info_add_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t)xvolinfo); - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -} - - -/* - * When assignment of hubs to widgets is complete, we no longer need the - * xswitch volunteer structure hanging around. Destroy it. - */ -static void -xswitch_volunteer_delete(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - rc = hwgraph_info_remove_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); -#ifdef LATER - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -#endif - - kfree(xvolinfo); -} -/* - * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. - */ -/* ARGSUSED */ -static void -volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) -{ - xswitch_vol_t xvolinfo = NULL; - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(master)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "volunteer for widgets: vertex %v has no info label", - xswitch); -#else - printk(KERN_WARNING "volunteer for widgets: vertex 0x%x has no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - mutex_lock(&xvolinfo->xswitch_volunteer_mutex); - ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); - xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; - xvolinfo->xswitch_volunteer_count++; - mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); -} - -extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); - -/* - * Assign all the xwidgets hanging off the specified xswitch to the - * Crosstalk masters that have volunteered for xswitch duty. - */ -/* ARGSUSED */ -static void -assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) -{ - int curr_volunteer, num_volunteer; - xwidgetnum_t widgetnum; - xswitch_info_t xswitch_info; - xswitch_vol_t xvolinfo = NULL; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - xswitch_info = xswitch_info_get(xswitch); - ASSERT(xswitch_info != NULL); - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(hubv)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has " - " no info label", - xswitch); -#else - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has " - " no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - num_volunteer = xvolinfo->xswitch_volunteer_count; - ASSERT(num_volunteer > 0); - curr_volunteer = 0; - - /* Assign master hub for xswitch itself. */ - if (HUB_WIDGET_ID_MIN > 0) { - hubv = xvolinfo->xswitch_volunteer[0]; - xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); - } - - /* - * TBD: Use administrative information to alter assignment of - * widgets to hubs. - */ - for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - - /* - * Ignore disabled/empty ports. - */ - if (!xbow_port_io_enabled(nasid, widgetnum)) - continue; - - /* - * If this is the master IO board, assign it to the same - * hub that owned it in the prom. - */ - if (is_master_nasid_widget(nasid, widgetnum)) { - int i; - - for (i=0; ixswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (nasid == get_console_nasid()) - goto do_assignment; - } -#ifdef LATER - PRINT_PANIC("Nasid == %d, console nasid == %d", - nasid, get_console_nasid()); -#endif - } - - - /* - * Do a round-robin assignment among the volunteer nodes. - */ - hubv = xvolinfo->xswitch_volunteer[curr_volunteer]; - curr_volunteer = (curr_volunteer + 1) % num_volunteer; - /* fall through */ - -do_assignment: - /* - * At this point, we want to make hubv the master of widgetnum. - */ - xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); - } - - xswitch_volunteer_delete(xswitch); -} - -/* - * Early iograph initialization. Called by master CPU in mlreset(). - * Useful for including iograph.o in kernel.o. - */ -void -iograph_early_init(void) -{ -/* - * Need new way to get this information .. - */ - cnodeid_t cnode; - nasid_t nasid; - lboard_t *board; - - /* - * Init. the board-to-hwgraph link early, so FRU analyzer - * doesn't trip on leftover values if we panic early on. - */ - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - DBG("iograph_early_init: Found board 0x%p\n", board); - - /* Check out all the board info stored on a node */ - while(board) { - board->brd_graph_link = GRAPH_VERTEX_NONE; - board = KLCF_NEXT(board); - DBG("iograph_early_init: Found board 0x%p\n", board); - - - } - } - - hubio_init(); -} - -#ifdef LINUX_KERNEL_THREADS -static struct semaphore io_init_sema; -#endif - -/* - * Let boot processor know that we're done initializing our node's IO - * and then exit. - */ -/* ARGSUSED */ -static void -io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) -{ - /* Let boot processor know that we're done. */ -#ifdef LINUX_KERNEL_THREADS - up(&io_init_sema); -#endif -#ifdef LATER - /* This is for the setnoderun done when the io_init thread - * started - */ - restorenoderun(c); - sthread_exit(); -#endif -} - -/* - * Probe to see if this hub's xtalk link is active. If so, - * return the Crosstalk Identification of the widget that we talk to. - * This is called before any of the Crosstalk infrastructure for - * this hub is set up. It's usually called on the node that we're - * probing, but not always. - * - * TBD: Prom code should actually do this work, and pass through - * hwid for our use. - */ -static void -early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) -{ - hubreg_t llp_csr_reg; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - /* - * If link is up, read the widget's part number. - * A direct connect widget must respond to widgetnum=0. - */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { - /* TBD: Put hub into "indirect" mode */ - /* - * We're able to read from a widget because our hub's - * WIDGET_ID was set up earlier. - */ - widgetreg_t widget_id = *(volatile widgetreg_t *) - (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); - - DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, - (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); - - hwid->part_num = XWIDGET_PART_NUM(widget_id); - hwid->rev_num = XWIDGET_REV_NUM(widget_id); - hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); - - /* TBD: link reset */ - } else { - - hwid->part_num = XWIDGET_PART_NUM_NONE; - hwid->rev_num = XWIDGET_REV_NUM_NONE; - hwid->mfg_num = XWIDGET_MFG_NUM_NONE; - } - -} - -/* Add inventory information to the widget vertex - * Right now (module,slot,revision) is being - * added as inventory information. - */ -static void -xwidget_inventory_add(devfs_handle_t widgetv, - lboard_t *board, - struct xwidget_hwid_s hwid) -{ - if (!board) - return; - /* Donot add inventory information for the baseio - * on a speedo with an xbox. It has already been - * taken care of in SN00_vmc. - * Speedo with xbox's baseio comes in at slot io1 (widget 9) - */ - device_inventory_add(widgetv,INV_IOBD,board->brd_type, - board->brd_module, - SLOTNUM_GETSLOT(board->brd_slot), - hwid.rev_num); -} - -/* - * io_xswitch_widget_init - * - */ - -/* defined in include/linux/ctype.h */ -/* #define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) */ - -void -io_xswitch_widget_init(devfs_handle_t xswitchv, - devfs_handle_t hubv, - xwidgetnum_t widgetnum, - async_attach_t aa) -{ - xswitch_info_t xswitch_info; - xwidgetnum_t hub_widgetid; - devfs_handle_t widgetv; - cnodeid_t cnode; - widgetreg_t widget_id; - nasid_t nasid, peer_nasid; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - /*REFERENCED*/ - int rc; - char slotname[SLOTNUM_MAXLENGTH]; - char pathname[128]; - char new_name[64]; - moduleid_t module; - slotid_t slot; - lboard_t *board = NULL; - char buffer[16]; - slotid_t get_widget_slotnum(int xbow, int widget); - - DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); - /* - * Verify that xswitchv is indeed an attached xswitch. - */ - xswitch_info = xswitch_info_get(xswitchv); - ASSERT(xswitch_info != NULL); - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - cnode = NASID_TO_COMPACT_NODEID(nasid); - hub_widgetid = hubinfo->h_widgetid; - - - /* Who's the other guy on out crossbow (if anyone) */ - peer_nasid = NODEPDA(cnode)->xbow_peer; - if (peer_nasid == INVALID_NASID) - /* If I don't have a peer, use myself. */ - peer_nasid = nasid; - - - /* Check my xbow structure and my peer's */ - if (!xbow_port_io_enabled(nasid, widgetnum) && - !xbow_port_io_enabled(peer_nasid, widgetnum)) { - return; - } - - if (xswitch_info_link_ok(xswitch_info, widgetnum)) { - char name[4]; - /* - * If the current hub is not supposed to be the master - * for this widgetnum, then skip this widget. - */ - if (xswitch_info_master_assignment_get(xswitch_info, - widgetnum) != hubv) { - return; - } - - module = NODEPDA(cnode)->module_id; -#ifdef XBRIDGE_REGS_SIM - /* hardwire for now...could do this with something like: - * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl); - * xbow_t xbow = soft->base; - * xbowreg_t xwidget_id = xbow->xb_wid_id; - * but I don't feel like figuring out vhdl right now.. - * and I know for a fact the answer is 0x2d000049 - */ - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module_class( - (lboard_t *)KL_CONFIG_INFO(nasid), - module, - KLTYPE_IOBRICK); - -DBG("io_xswitch_widget_init: Board 0x%p\n", board); -{ - lboard_t dummy; - - - if (board) { - DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); - } else { - DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); - board = &dummy; - } - -} - - /* - * Make sure we really want to say xbrick, pbrick, - * etc. rather than XIO, graphics, etc. - */ - -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - "%cbrick" "/%s/%d", - NODEPDA(cnode)->module_id, - -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - "%cbrick" "/%s/%d", - buffer, -#endif - - (board->brd_type == KLTYPE_IBRICK) ? 'I' : - (board->brd_type == KLTYPE_PBRICK) ? 'P' : - (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', - EDGE_LBL_XTALK, widgetnum); - } - - DBG("io_xswitch_widget_init: path= %s\n", pathname); - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - - ASSERT(rc == GRAPH_SUCCESS); - - /* This is needed to let the user programs to map the - * module,slot numbers to the corresponding widget numbers - * on the crossbow. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - /* If we are looking at the global master io6 - * then add information about the version of - * the io6prom as a part of "detailed inventory" - * information. - */ - if (is_master_baseio(nasid, - NODEPDA(cnode)->module_id, - get_widget_slotnum(0,widgetnum))) { - extern void klhwg_baseio_inventory_add(devfs_handle_t, - cnodeid_t); - module = NODEPDA(cnode)->module_id; - -#ifdef XBRIDGE_REGS_SIM - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(nasid), - module); - /* - * Change iobrick to correct i/o brick - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" -#else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif - "iobrick" "/%s/%d", - NODEPDA(cnode)->module_id, - EDGE_LBL_XTALK, widgetnum); - } else { - slot = get_widget_slotnum(0, widgetnum); - board = get_board_name(nasid, module, slot, - new_name); - /* - * Create the vertex for the widget, - * using the decimal - * widgetnum as the name of the primary edge. - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - EDGE_LBL_SLOT "/%s/%s", - NODEPDA(cnode)->module_id, - slotname, new_name); -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - EDGE_LBL_SLOT "/%s/%s", - buffer, - slotname, new_name); -#endif - } - - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); - /* - * This is a weird ass code needed for error injection - * purposes. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - klhwg_baseio_inventory_add(widgetv,cnode); - } - sprintf(name, "%d", widgetnum); - DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); - rc = hwgraph_edge_add(xswitchv, widgetv, name); - - /* - * crosstalk switch code tracks which - * widget is attached to each link. - */ - xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); - - /* - * Peek at the widget to get its crosstalk part and - * mfgr numbers, then present it to the generic xtalk - * bus provider to have its driver attach routine - * called (or not). - */ -#ifdef XBRIDGE_REGS_SIM - widget_id = 0x2d000049; - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); -#else - widget_id = XWIDGET_ID_READ(nasid, widgetnum); -#endif /* XBRIDGE_REGS_SIM */ - hwid.part_num = XWIDGET_PART_NUM(widget_id); - hwid.rev_num = XWIDGET_REV_NUM(widget_id); - hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); - /* Store some inventory information about - * the xwidget in the hardware graph. - */ - xwidget_inventory_add(widgetv,board,hwid); - - (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid, - aa); - -#ifdef SN0_USE_BTE - bte_bpush_war(cnode, (void *)board); -#endif - } - -} - - -static void -io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) -{ - xwidgetnum_t widgetnum; - async_attach_t aa; - - aa = async_attach_new(); - - DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum, aa); - } - /* - * Wait for parallel attach threads, if any, to complete. - */ - async_attach_waitall(aa); - async_attach_free(aa); -} - -/* - * For each PCI bridge connected to the xswitch, add a link from the - * board's klconfig info to the bridge's hwgraph vertex. This lets - * the FRU analyzer find the bridge without traversing the hardware - * graph and risking hangs. - */ -static void -io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) -{ - xwidgetnum_t widgetnum; - char pathname[128]; - devfs_handle_t vhdl; - nasid_t nasid, peer_nasid; - lboard_t *board; - - - - /* And its connected hub's nasids */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - peer_nasid = NODEPDA(cnodeid)->xbow_peer; - - /* - * Look for paths matching "/pci" under xswitchv. - * For every widget, init. its lboard's hwgraph link. If the - * board has a PCI bridge, point the link to it. - */ - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - sprintf(pathname, "%d", widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) != - GRAPH_SUCCESS) - continue; - - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), - NODEPDA(cnodeid)->module_id); - if (board == NULL && peer_nasid != INVALID_NASID) { - /* - * Try to find the board on our peer - */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(peer_nasid), - NODEPDA(cnodeid)->module_id); - } - if (board == NULL) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "Could not find PROM info for vertex %v, " - "FRU analyzer may fail", - vhdl); -#else - printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " - "FRU analyzer may fail", - (void *)vhdl); -#endif - return; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == - GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else - board->brd_graph_link = GRAPH_VERTEX_NONE; - } -} - -/* - * Initialize all I/O on the specified node. - */ -static void -io_init_node(cnodeid_t cnodeid) -{ - /*REFERENCED*/ - devfs_handle_t hubv, switchv, widgetv; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - int is_xswitch; - nodepda_t *npdap; - struct semaphore *peer_sema = 0; - uint32_t widget_partnum; - nodepda_router_info_t *npda_rip; - cpu_cookie_t c = 0; - extern int hubdev_docallouts(devfs_handle_t); - -#ifdef LATER - /* Try to execute on the node that we're initializing. */ - c = setnoderun(cnodeid); -#endif - npdap = NODEPDA(cnodeid); - - /* - * Get the "top" vertex for this node's hardware - * graph; it will carry the per-hub hub-specific - * data, and act as the crosstalk provider master. - * It's canonical path is probably something of the - * form /hw/module/%M/slot/%d/node - */ - hubv = cnodeid_to_vertex(cnodeid); - DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); - - ASSERT(hubv != GRAPH_VERTEX_NONE); - - hubdev_docallouts(hubv); - - /* - * Set up the dependent routers if we have any. - */ - npda_rip = npdap->npda_rip_first; - - while(npda_rip) { - /* If the router info has not been initialized - * then we need to do the router initialization - */ - if (!npda_rip->router_infop) { - router_init(cnodeid,0,npda_rip); - } - npda_rip = npda_rip->router_next; - } - - /* - * Read mfg info on this hub - */ -#ifdef LATER - printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n"); - HUB_VERTEX_MFG_INFO(hubv); -#endif /* LATER */ - - /* - * If nothing connected to this hub's xtalk port, we're done. - */ - early_probe_for_widget(hubv, &hwid); - if (hwid.part_num == XWIDGET_PART_NUM_NONE) { -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 600; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - - DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - return; - /* NOTREACHED */ - } - - /* - * attach our hub_provider information to hubv, - * so we can use it as a crosstalk provider "master" - * vertex. - */ - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); - - /* - * Create a vertex to represent the crosstalk bus - * attached to this hub, and a vertex to be used - * as the connect point for whatever is out there - * on the other side of our crosstalk connection. - * - * Crosstalk Switch drivers "climb up" from their - * connection point to try and take over the switch - * point. - * - * Of course, the edges and verticies may already - * exist, in which case our net effect is just to - * associate the "xtalk_" driver with the connection - * point for the device. - */ - - (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - - DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); - - ASSERT(switchv != GRAPH_VERTEX_NONE); - - (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - - DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); - - /* - * We need to find the widget id and update the basew_id field - * accordingly. In particular, SN00 has direct connected bridge, - * and hence widget id is Not 0. - */ - - widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - - if (widget_partnum == BRIDGE_WIDGET_PART_NUM || - widget_partnum == XBRIDGE_WIDGET_PART_NUM){ - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); - - } else if (widget_partnum == XBOW_WIDGET_PART_NUM || - widget_partnum == XXBOW_WIDGET_PART_NUM) { - /* - * Xbow control register does not have the widget ID field. - * So, hard code the widget ID to be zero. - */ - DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); - npdap->basew_id = 0; - - } else if (widget_partnum == XG_WIDGET_PART_NUM) { - /* - * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock??? - * So, hard code the widget ID to be zero? - */ - npdap->basew_id = 0; - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - } else { - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); - - /*NOTREACHED*/ - } - { - char widname[10]; - sprintf(widname, "%x", npdap->basew_id); - (void)hwgraph_path_add(switchv, widname, &widgetv); - DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); - ASSERT(widgetv != GRAPH_VERTEX_NONE); - } - - nodepda->basew_xc = widgetv; - - is_xswitch = xwidget_hwid_is_xswitch(&hwid); - - /* - * Try to become the master of the widget. If this is an xswitch - * with multiple hubs connected, only one will succeed. Mastership - * of an xswitch is used only when touching registers on that xswitch. - * The slave xwidgets connected to the xswitch can be owned by various - * masters. - */ - if (device_master_set(widgetv, hubv) == 0) { - - /* Only one hub (thread) per Crosstalk device or switch makes - * it to here. - */ - - /* - * Initialize whatever xwidget is hanging off our hub. - * Whatever it is, it's accessible through widgetnum 0. - */ - hubinfo_get(hubv, &hubinfo); - - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); - - if (!is_xswitch) { - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - /* NOTREACHED */ - } - - /* - * Special handling for Crosstalk Switches (e.g. xbow). - * We need to do things in roughly the following order: - * 1) Initialize xswitch hardware (done above) - * 2) Determine which hubs are available to be widget masters - * 3) Discover which links are active from the xswitch - * 4) Assign xwidgets hanging off the xswitch to hubs - * 5) Initialize all xwidgets on the xswitch - */ - - volunteer_for_widgets(switchv, hubv); - - /* If there's someone else on this crossbow, recognize him */ - if (npdap->xbow_peer != INVALID_NASID) { - nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); - peer_sema = &peer_npdap->xbow_sema; - volunteer_for_widgets(switchv, peer_npdap->node_vertex); - } - - assign_widgets_to_volunteers(switchv, hubv); - - /* Signal that we're done */ - if (peer_sema) { - mutex_unlock(peer_sema); - } - - } - else { - /* Wait 'til master is done assigning widgets. */ - mutex_lock(&npdap->xbow_sema); - } - -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 500; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* Now both nodes can safely inititialize widgets */ - io_init_xswitch_widgets(switchv, cnodeid); - io_link_xswitch_widgets(switchv, cnodeid); - - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - - DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); -} - - -#define IOINIT_STKSZ (16 * 1024) - -#define __DEVSTR1 "/../.master/" -#define __DEVSTR2 "/target/" -#define __DEVSTR3 "/lun/0/disk/partition/" -#define __DEVSTR4 "/../ef" - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * Currently, we need to allow for 5 IBrick slots with 1 FC each - * plus an internal 1394. - * - * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. - */ -#define NUM_BASE_IO_SCSI_CTLR 6 -#else -#define NUM_BASE_IO_SCSI_CTLR 6 -#endif -/* - * This tells ioconfig where it can start numbering scsi controllers. - * Below this base number, platform-specific handles the numbering. - * XXX Irix legacy..controller numbering should be part of devfsd's job - */ -int num_base_io_scsi_ctlr = 2; /* used by syssgi */ -devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; -static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; - -/* - * Put the logical controller number information in the - * scsi controller vertices for each scsi controller that - * is in a "fixed position". - */ -static void -scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) -{ - { - int i; - - num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; - - /* Initialize base_io_scsi_ctlr_vhdl array */ - for (i=0; i -devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; - -/* Define the system critical vertices and connect them through - * a canonical parent-child relationships for easy traversal - * during io error handling. - */ -static void -sys_critical_graph_init(void) -{ - devfs_handle_t bridge_vhdl,master_node_vhdl; - devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; - extern devfs_handle_t hwgraph_root; - devfs_handle_t pci_slot_conn; - int slot; - devfs_handle_t baseio_console_conn; - - DBG("sys_critical_graph_init: FIXME.\n"); - baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); - - if (baseio_console_conn == NULL) { - return; - } - - /* Get the vertex handle for the baseio bridge */ - bridge_vhdl = device_master_get(baseio_console_conn); - - /* Get the master node of the baseio card */ - master_node_vhdl = cnodeid_to_vertex( - master_node_get(baseio_console_vhdl)); - - /* Add the "root->node" part of the system critical graph */ - - sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); - - /* Check if we have a crossbow */ - if (hwgraph_traverse(master_node_vhdl, - EDGE_LBL_XTALK"/0", - &xbow_vhdl) == GRAPH_SUCCESS) { - /* We have a crossbow.Add "node->xbow" part of the system - * critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); - - /* Add "xbow->baseio bridge" of the system critical graph */ - sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); - - hwgraph_vertex_unref(xbow_vhdl); - } else - /* We donot have a crossbow. Add "node->baseio_bridge" - * part of the system critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); - - /* Add all the populated PCI slot vertices to the system critical - * graph with the bridge vertex as the parent. - */ - for (slot = 0 ; slot < 8; slot++) { - char slot_edge[10]; - - sprintf(slot_edge,"%d",slot); - if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) - != GRAPH_SUCCESS) - continue; - sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); - hwgraph_vertex_unref(pci_slot_conn); - } - - hwgraph_vertex_unref(bridge_vhdl); - - /* Add the "ioc3 pci connection point -> console ioc3" part - * of the system critical graph - */ - - if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_console_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "ethernet pci connection point -> base ethernet" part of - * the system critical graph - */ - if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_enet_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "scsi controller pci connection point -> base scsi - * controller" part of the system critical graph - */ - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[0]); - hwgraph_vertex_unref(pci_slot_conn); - } - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[1]); - hwgraph_vertex_unref(pci_slot_conn); - } - hwgraph_vertex_unref(baseio_console_conn); - -} - -static void -baseio_ctlr_num_set(void) -{ - char name[MAXDEVNAME]; - devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - devfs_handle_t ioc3_console_vhdl_get(void); - - - DBG("baseio_ctlr_num_set; FIXME\n"); - console_vhdl = ioc3_console_vhdl_get(); - if (console_vhdl == GRAPH_VERTEX_NONE) - return; - /* Useful for setting up the system critical graph */ - baseio_console_vhdl = console_vhdl; - - vertex_to_name(console_vhdl,name,MAXDEVNAME); - - strcat(name,__DEVSTR1); - pci_vhdl = hwgraph_path_to_vertex(name); - scsi_ctlr_nums_add(pci_vhdl); - /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(pci_vhdl); - - vertex_to_name(console_vhdl, name, MAXDEVNAME); - strcat(name, __DEVSTR4); - enet_vhdl = hwgraph_path_to_vertex(name); - - /* Useful for setting up the system critical graph */ - baseio_enet_vhdl = enet_vhdl; - - device_controller_num_set(enet_vhdl, 0); - /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(enet_vhdl); -} -/* #endif */ - -void -sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list) -{ - /* REFERENCED */ - int rtn_val; - - /* - ** sn00 population: errb orrb - ** 0- ql 3+? - ** 1- ql 2 - ** 2- ioc3 ethernet 2+? - ** 3- ioc3 secondary 1 - ** 4- 0 - ** 5- PCI slot - ** 6- PCI slot - ** 7- PCI slot - */ - - /* The following code implements this heuristic for getting - * maximum usage out of the rrbs - * - * constraints: - * 8 bit ql1 needs 1+1 - * ql0 or ql5,6,7 wants 1+2 - * ethernet wants 2 or more - * - * rules for even rrbs: - * if nothing in slot 6 - * 4 rrbs to 0 and 2 (0xc8889999) - * else - * 3 2 3 to slots 0 2 6 (0xc8899bbb) - * - * rules for odd rrbs - * if nothing in slot 5 or 7 (0xc8889999) - * 4 rrbs to 1 and 3 - * else if 1 thing in 5 or 7 (0xc8899aaa) or (0xc8899bbb) - * 3 2 3 to slots 1 3 5|7 - * else - * 2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this - * (0xc89aaabb) may short what it wants therefore the - * rule should be to plug pci slots in order) - */ - - - if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) { - /* something in slot 6 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0); - } - else { - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); - - if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && - (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { - /* soemthing in slot 5 and 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0); - } - else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 5 but not 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0); - } - else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 7 but not 5 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0); - } - else { - /* nothing in slot 5 or 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -} - - -/* - * Initialize all I/O devices. Starting closest to nodes, probe and - * initialize outward. - */ -void -init_all_devices(void) -{ - /* Governor on init threads..bump up when safe - * (beware many devfs races) - */ -#ifdef LATER - int io_init_node_threads = 2; -#endif - cnodeid_t cnodeid, active; - -#ifdef LINUX_KERNEL_THREADS - sema_init(&io_init_sema, 0); -#endif - - active = 0; - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { -#ifdef LINUX_KERNEL_THREADS - char thread_name[16]; - extern int io_init_pri; - - /* - * Spawn a service thread for each node to initialize all - * I/O on that node. Each thread attempts to bind itself - * to the node whose I/O it's initializing. - */ - sprintf(thread_name, "IO_init[%d]", cnodeid); - - (void)sthread_create(thread_name, 0, IOINIT_STKSZ, 0, - io_init_pri, KT_PS, (st_func_t *)io_init_node, - (void *)(long)cnodeid, 0, 0, 0); -#else - DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); - io_init_node(cnodeid); - - DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - -#endif /* LINUX_KERNEL_THREADS */ - -#ifdef LINUX_KERNEL_THREADS - /* Limit how many nodes go at once, to not overload hwgraph */ - /* TBD: Should timeout */ - DBG("started thread for cnode %d\n", cnodeid); - active++; - if (io_init_node_threads && - active >= io_init_node_threads) { - down(&io_init_sema); - active--; - } -#endif /* LINUX_KERNEL_THREADS */ - } - -#ifdef LINUX_KERNEL_THREADS - /* Wait until all IO_init threads are done */ - - while (active > 0) { -#ifdef AA_DEBUG - DBG("waiting, %d still active\n", active); -#endif - down(&io_init_sema); - active--; - } - -#endif /* LINUX_KERNEL_THREADS */ - - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) - /* - * Update information generated by IO init. - */ - update_node_information(cnodeid); - - baseio_ctlr_num_set(); - /* Setup the system critical graph (which is a subgraph of the - * main hwgraph). This information is useful during io error - * handling. - */ - sys_critical_graph_init(); - -#if HWG_PRINT - hwgraph_print(); -#endif - -} - -#define toint(x) ((int)(x) - (int)('0')) - -void -devnamefromarcs(char *devnm) -{ - int val; - char tmpnm[MAXDEVNAME]; - char *tmp1, *tmp2; - - val = strncmp(devnm, "dks", 3); - if (val != 0) - return; - tmp1 = devnm + 3; - if (!isdigit(*tmp1)) - return; - - val = 0; - while (isdigit(*tmp1)) { - val = 10*val+toint(*tmp1); - tmp1++; - } - - if(*tmp1 != 'd') - return; - else - tmp1++; - - if ((val < 0) || (val >= NUM_BASE_IO_SCSI_CTLR)) { - int i; - int viable_found = 0; - - DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); - DBG("prom \"root\" variables of the form dksXdXsX.\n"); - DBG("To use another disk you must use the full hardware graph path\n\n"); - DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); - for (i=0; i XBOW_PORT_F) - return 0; - - /* Find "brick" in the path name */ - bp = strstr(hw_path_name, "brick"); - if (bp == NULL) - return 0; - - /* Find preceding slash */ - sp = bp; - while (sp > hw_path_name) { - sp--; - if (*sp == '/') - break; - } - - /* Invalid if no preceding slash */ - if (!sp) - return 0; - - /* Bump slash pointer to "brick" prefix */ - sp++; - /* - * Verify "brick" prefix length; valid exaples: - * 'I' from "/Ibrick" - * 'P' from "/Pbrick" - * 'X' from "/Xbrick" - */ - if ((bp - sp) != 1) - return 0; - - return (io_brick_map_widget(*sp, widget_num)); - -} diff --git a/arch/ia64/sn/io/module.c b/arch/ia64/sn/io/module.c deleted file mode 100644 index b53648a9101..00000000000 --- a/arch/ia64/sn/io/module.c +++ /dev/null @@ -1,312 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* #define LDEBUG 1 */ - -#ifdef LDEBUG -#define DPRINTF printk -#define printf printk -#else -#define DPRINTF(x...) -#endif - -module_t *modules[MODULE_MAX]; -int nummodules; - -#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 -#define SN0_SERIAL_FUDGE 0x6e - -void -encode_int_serial(uint64_t src,uint64_t *dest) -{ - uint64_t val; - int i; - - val = src + SN00_SERIAL_FUDGE; - - - for (i = 0; i < sizeof(long long); i++) { - ((char*)dest)[i] = - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; - } -} - - -void -decode_int_serial(uint64_t src, uint64_t *dest) -{ - uint64_t val; - int i; - - for (i = 0; i < sizeof(long long); i++) { - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = - ((char*)&src)[i]; - } - - *dest = val - SN00_SERIAL_FUDGE; -} - - -void -encode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - - dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + - SN0_SERIAL_FUDGE; - } -} - -void -decode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - dest[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - - SN0_SERIAL_FUDGE; - } -} - - -module_t *module_lookup(moduleid_t id) -{ - int i; - - for (i = 0; i < nummodules; i++) - if (modules[i]->id == id) { - DPRINTF("module_lookup: found m=0x%p\n", modules[i]); - return modules[i]; - } - - return NULL; -} - -/* - * module_add_node - * - * The first time a new module number is seen, a module structure is - * inserted into the module list in order sorted by module number - * and the structure is initialized. - * - * The node number is added to the list of nodes in the module. - */ - -module_t *module_add_node(moduleid_t id, cnodeid_t n) -{ - module_t *m; - int i; - char buffer[16]; - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, id, MODULE_FORMAT_BRIEF); - DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); -#endif - - if ((m = module_lookup(id)) == 0) { -#ifdef LATER - m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); -#else - m = kmalloc(sizeof (module_t), GFP_KERNEL); - memset(m, 0 , sizeof(module_t)); -#endif - ASSERT_ALWAYS(m); - - m->id = id; - spin_lock_init(&m->lock); - - mutex_init_locked(&m->thdcnt); - -// set_elsc(&m->elsc); - elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); - spin_lock_init(&m->elsclock); - - /* Insert in sorted order by module number */ - - for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--) - modules[i] = modules[i - 1]; - - modules[i] = m; - nummodules++; - } - - m->nodes[m->nodecnt++] = n; - - DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); - - return m; -} - -int module_probe_snum(module_t *m, nasid_t nasid) -{ - lboard_t *board; - klmod_serial_num_t *comp; - char * bcopy(const char * src, char * dest, int count); - char serial_number[16]; - - /* - * record brick serial number - */ - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - { -#if LDEBUG - printf ("module_probe_snum: no IP35 board found!\n"); -#endif - return 0; - } - - board_serial_number_get( board, serial_number ); - if( serial_number[0] != '\0' ) { - encode_str_serial( serial_number, m->snum.snum_str ); - m->snum_valid = 1; - } -#if LDEBUG - else { - printf("module_probe_snum: brick serial number is null!\n"); - } - printf("module_probe_snum: brick serial number == %s\n", serial_number); -#endif /* DEBUG */ - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_IOBRICK_XBOW); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - return 0; - - comp = GET_SNUM_COMP(board); - - if (comp) { -#if LDEBUG - int i; - - printf("********found module with id %x and string", m->id); - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) - printf(" %x ", comp->snum.snum_str[i]); - - printf("\n"); /* Fudged string is not ASCII */ -#endif - - if (comp->snum.snum_str[0] != '\0') { - bcopy(comp->snum.snum_str, - m->sys_snum, - MAX_SERIAL_NUM_SIZE); - m->sys_snum_valid = 1; - } - } - - if (m->sys_snum_valid) - return 1; - else { - DPRINTF("Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); - return 0; - } -} - -void -io_module_init(void) -{ - cnodeid_t node; - lboard_t *board; - nasid_t nasid; - int nserial; - module_t *m; - - DPRINTF("*******module_init\n"); - - nserial = 0; - - for (node = 0; node < numnodes; node++) { - nasid = COMPACT_TO_NASID_NODEID(node); - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(board); - - m = module_add_node(board->brd_module, node); - - if (! m->snum_valid && module_probe_snum(m, nasid)) - nserial++; - } - - DPRINTF("********found total of %d serial numbers in the system\n", - nserial); - - if (nserial == 0) - printk(KERN_WARNING "io_module_init: No serial number found.\n"); -} - -elsc_t *get_elsc(void) -{ - return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; -} - -int -get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) -{ - int i; - - if (cmod < 0 || cmod >= nummodules) - return EINVAL; - - if (! modules[cmod]->snum_valid) - return ENXIO; - - mod_info->mod_num = modules[cmod]->id; - { - char temp[MAX_SERIAL_NUM_SIZE]; - - decode_str_serial(modules[cmod]->snum.snum_str, temp); - - /* if this is an invalid serial number return an error */ - if (temp[0] != 'K') - return ENXIO; - - mod_info->serial_num = 0; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) { - mod_info->serial_num <<= 4; - mod_info->serial_num |= (temp[i] & 0xf); - - mod_info->serial_str[i] = temp[i]; - } - - mod_info->serial_str[i] = '\0'; - } - - return 0; -} diff --git a/arch/ia64/sn/io/pci.c b/arch/ia64/sn/io/pci.c deleted file mode 100644 index 974272d7216..00000000000 --- a/arch/ia64/sn/io/pci.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * SNI64 specific PCI support for SNI IO. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 1997, 1998, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG_CONFIG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - - - -#ifdef CONFIG_PCI - -extern devfs_handle_t pci_bus_to_vertex(unsigned char); -extern devfs_handle_t devfn_to_vertex(unsigned char bus, unsigned char devfn); - -/* - * snia64_read_config_byte - Read a byte from the config area of the device. - */ -static int snia64_read_config_byte (struct pci_dev *dev, - int where, unsigned char *val) -{ - unsigned long res = 0; - unsigned size = 1; - devfs_handle_t device_vertex; - - if ( (dev == (struct pci_dev *)0) || (val == (unsigned char *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned char) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_read_config_word - Read 2 bytes from the config area of the device. - */ -static int snia64_read_config_word (struct pci_dev *dev, - int where, unsigned short *val) -{ - unsigned long res = 0; - unsigned size = 2; /* 2 bytes */ - devfs_handle_t device_vertex; - - if ( (dev == (struct pci_dev *)0) || (val == (unsigned short *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned short) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_read_config_dword - Read 4 bytes from the config area of the device. - */ -static int snia64_read_config_dword (struct pci_dev *dev, - int where, unsigned int *val) -{ - unsigned long res = 0; - unsigned size = 4; /* 4 bytes */ - devfs_handle_t device_vertex; - - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( (dev == (struct pci_dev *)0) || (val == (unsigned int *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned int) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_byte - Writes 1 byte to the config area of the device. - */ -static int snia64_write_config_byte (struct pci_dev *dev, - int where, unsigned char val) -{ - devfs_handle_t device_vertex; - - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3 ) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 1, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_word - Writes 2 bytes to the config area of the device. - */ -static int snia64_write_config_word (struct pci_dev *dev, - int where, unsigned short val) -{ - devfs_handle_t device_vertex = NULL; - - if (where & 1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 2, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_dword - Writes 4 bytes to the config area of the device. - */ -static int snia64_write_config_dword (struct pci_dev *dev, - int where, unsigned int val) -{ - devfs_handle_t device_vertex; - - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 4, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops snia64_pci_ops = { - snia64_read_config_byte, - snia64_read_config_word, - snia64_read_config_dword, - snia64_write_config_byte, - snia64_write_config_word, - snia64_write_config_dword -}; - -/* - * snia64_pci_find_bios - SNIA64 pci_find_bios() platform specific code. - */ -void __init -sn_pci_find_bios(void) -{ - extern struct pci_ops *pci_root_ops; - /* - * Go initialize our IO Infrastructure .. - */ - extern void sgi_master_io_infr_init(void); - - sgi_master_io_infr_init(); - - /* sn_io_infrastructure_init(); */ - pci_root_ops = &snia64_pci_ops; -} - -void -pci_fixup_ioc3(struct pci_dev *d) -{ - int i; - unsigned int size; - - /* IOC3 only decodes 0x20 bytes of the config space, reading - * beyond that is relatively benign but writing beyond that - * (especially the base address registers) will shut down the - * pci bus...so avoid doing so. - * NOTE: this means we can't program the intr_pin into the device, - * currently we hack this with special code in - * sgi_pci_intr_support() - */ - DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); - - /* I happen to know from the spec that the ioc3 needs only 0xfffff - * The standard pci trick of writing ~0 to the baddr and seeing - * what comes back doesn't work with the ioc3 - */ - size = 0xfffff; - d->resource[0].end = (unsigned long) d->resource[0].start + (unsigned long) size; - - /* - * Zero out the resource structure .. because we did not go through - * the normal PCI Infrastructure Init, garbbage are left in these - * fileds. - */ - for (i = 1; i <= PCI_ROM_RESOURCE; i++) { - d->resource[i].start = 0UL; - d->resource[i].end = 0UL; - d->resource[i].flags = 0UL; - } - -#ifdef CONFIG_IA64_SGI_SN1 - *(volatile u32 *)0xc0000a000f000220 |= 0x90000; -#endif - d->subsystem_vendor = 0; - d->subsystem_device = 0; - -} - -#else -void sn_pci_find_bios(void) {} -void pci_fixup_ioc3(struct pci_dev *d) {} -struct list_head pci_root_buses; -struct list_head pci_root_buses; -struct list_head pci_devices; - -#endif /* CONFIG_PCI */ diff --git a/arch/ia64/sn/io/pci_bus_cvlink.c b/arch/ia64/sn/io/pci_bus_cvlink.c deleted file mode 100644 index dd417cd82ec..00000000000 --- a/arch/ia64/sn/io/pci_bus_cvlink.c +++ /dev/null @@ -1,737 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int bridge_rev_b_data_check_disable; - -devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; -nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; -void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; -unsigned char num_bridges; -static int done_probing = 0; - -static int pci_bus_map_create(devfs_handle_t xtalk); -devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -#define SN1_IOPORTS_UNIT 256 -#define MAX_IOPORTS 0xffff -#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT) -struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; -unsigned long sn1_allocate_ioports(unsigned long pci_address); - -extern void sn1_init_irq_desc(void); - - - -/* - * pci_bus_cvlink_init() - To be called once during initialization before - * SGI IO Infrastructure init is called. - */ -void -pci_bus_cvlink_init(void) -{ - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); - memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); - - memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); - - memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); - - num_bridges = 0; -} - -/* - * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated - * pci bus vertex from the SGI IO Infrastructure. - */ -devfs_handle_t -pci_bus_to_vertex(unsigned char busnum) -{ - - devfs_handle_t pci_bus = NULL; - - - /* - * First get the xwidget vertex. - */ - pci_bus = busnum_to_pcibr_vhdl[busnum]; - return(pci_bus); -} - -/* - * devfn_to_vertex() - returns the vertex of the device given the bus, slot, - * and function numbers. - */ -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn) -{ - - int slot = 0; - int func = 0; - char name[16]; - devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = (devfs_handle_t)NULL; - - /* - * Go get the pci bus vertex. - */ - pci_bus = pci_bus_to_vertex(busnum); - if (!pci_bus) { - /* - * During probing, the Linux pci code invents non-existent - * bus numbers and pci_dev structures and tries to access - * them to determine existence. Don't crib during probing. - */ - if (done_probing) - printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); - return(NULL); - } - - - /* - * Go get the slot&function vertex. - * Should call pciio_slot_func_to_name() when ready. - */ - slot = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); - - /* - * For a NON Multi-function card the name of the device looks like: - * ../pci/1, ../pci/2 .. - */ - if (func == 0) { - sprintf(name, "%d", slot); - if (hwgraph_traverse(pci_bus, name, &device_vertex) == - GRAPH_SUCCESS) { - if (device_vertex) { - return(device_vertex); - } - } - } - - /* - * This maybe a multifunction card. It's names look like: - * ../pci/1a, ../pci/1b, etc. - */ - sprintf(name, "%d%c", slot, 'a'+func); - if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { - if (!device_vertex) { - return(NULL); - } - } - - return(device_vertex); -} - -/* - * For the given device, initialize the addresses for both the Device(x) Flush - * Write Buffer register and the Xbow Flush Register for the port the PCI bus - * is connected. - */ -static void -set_flush_addresses(struct pci_dev *device_dev, - struct sn1_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - device_sysdata->dma_buf_sync = (volatile unsigned int *) - &(bridge->b_wr_req_buf[pciio_slot].reg); - device_sysdata->xbow_buf_sync = (volatile unsigned int *) - XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), - pcibr_soft->bs_xid); -#ifdef DEBUG - - printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", - device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); - - while((volatile unsigned int )*device_sysdata->dma_buf_sync); - while((volatile unsigned int )*device_sysdata->xbow_buf_sync); -#endif - -} - -/* - * Most drivers currently do not properly tell the arch specific pci dma - * interfaces whether they can handle A64. Here is where we privately - * keep track of this. - */ -static void __init -set_sn1_pci64(struct pci_dev *dev) -{ - unsigned short vendor = dev->vendor; - unsigned short device = dev->device; - - if (vendor == PCI_VENDOR_ID_QLOGIC) { - if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || - (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { - SET_PCIA64(dev); - return; - } - } - - if (vendor == PCI_VENDOR_ID_SGI) { - if (device == PCI_DEVICE_ID_SGI_IOC3) { - SET_PCIA64(dev); - return; - } - } - -} - -/* - * sn1_allocate_ioports() - This routine provides the allocation and - * mappings between Linux style IOPORTs management. - * - * For simplicity sake, SN1 will allocate IOPORTs in chunks of - * 256bytes .. irrespective of what the card desires. This may - * have to change when we understand how to deal with legacy ioports - * which are hardcoded in some drivers e.g. SVGA. - * - * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. - * It will remain so. The IO Infrastructure will continue to map - * IO Resource just like IRIX. When this is done, we map IOPORT - * chunks to these resources. The Linux drivers will see and use real - * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. - * does the munging of these IOPORT numbers to make a Uncache Virtual - * Address. This address via the tlb entries generates the PCI Address - * allocated by the SN1 IO Infrastructure Layer. - */ -static unsigned long sn1_ioport_num = 0x1000; /* Reserve room for Legacy stuff */ -unsigned long -sn1_allocate_ioports(unsigned long pci_address) -{ - - unsigned long ioport_index; - - /* - * Just some idiot checking .. - */ - if ( sn1_ioport_num > 0xffff ) { - printk("sn1_allocate_ioports: No more IO PORTS available\n"); - return(-1); - } - - /* - * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's - * Manual for details. - */ - ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT; - - ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ - ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */ - ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/ - ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/ - ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */ - ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/ - ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/ - ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */ - ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ - ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ - - /* printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */ - - sn1_ioport_num += SN1_IOPORTS_UNIT; - - return(sn1_ioport_num - SN1_IOPORTS_UNIT); -} - -/* - * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is - * invoked at the end of pcibios_init() to link the Linux pci - * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c - * - * Other platform specific fixup can also be done here. - */ -void -sn1_pci_fixup(int arg) -{ - struct list_head *ln; - struct pci_bus *pci_bus = NULL; - struct pci_dev *device_dev = NULL; - struct sn1_widget_sysdata *widget_sysdata; - struct sn1_device_sysdata *device_sysdata; -#ifdef SN1_IOPORTS - unsigned long ioport; -#endif - pciio_intr_t intr_handle; - int cpuid, bit; - devfs_handle_t device_vertex; - pciio_intr_line_t lines; - extern void sn1_pci_find_bios(void); -#ifdef CONFIG_IA64_SGI_SN2 - extern int numnodes; - int cnode; -#endif /* CONFIG_IA64_SGI_SN2 */ - - - if (arg == 0) { - sn1_init_irq_desc(); - sn1_pci_find_bios(); -#ifdef CONFIG_IA64_SGI_SN2 - for (cnode = 0; cnode < numnodes; cnode++) { - extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); - intr_init_vecblk(NODEPDA(cnode), cnode, 0); - } -#endif /* CONFIG_IA64_SGI_SN2 */ - return; - } - -#if 0 -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} -#endif - done_probing = 1; - - /* - * Initialize the pci bus vertex in the pci_bus struct. - */ - for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - pci_bus = pci_bus_b(ln); - widget_sysdata = kmalloc(sizeof(struct sn1_widget_sysdata), - GFP_KERNEL); - widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); - pci_bus->sysdata = (void *)widget_sysdata; - } - - /* - * set the root start and end so that drivers calling check_region() - * won't see a conflict - */ -#ifdef SN1_IOPORTS - ioport_resource.start = sn1_ioport_num; - ioport_resource.end = 0xffff; -#else -#if defined(CONFIG_IA64_SGI_SN1) - if ( IS_RUNNING_ON_SIMULATOR() ) { - /* - * IDE legacy IO PORTs are supported in Medusa. - * Just open up IO PORTs from 0 .. ioport_resource.end. - */ - ioport_resource.start = 0; - } else { - /* - * We do not support Legacy IO PORT numbers. - */ - ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET; - } - ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET; -#else - // Need something here for sn2.... ZXZXZX -#endif -#endif - - /* - * Initialize the device vertex in the pci_dev struct. - */ - while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { - unsigned int irq; - int idx; - u16 cmd; - devfs_handle_t vhdl; - unsigned long size; - extern int bit_pos_to_irq(int); - - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { - extern void pci_fixup_ioc3(struct pci_dev *d); - pci_fixup_ioc3(device_dev); - } - - /* Set the device vertex */ - - device_sysdata = kmalloc(sizeof(struct sn1_device_sysdata), - GFP_KERNEL); - device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); - device_sysdata->isa64 = 0; - /* - * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush - * register addresses. - */ - (void) set_flush_addresses(device_dev, device_sysdata); - - device_dev->sysdata = (void *) device_sysdata; - set_sn1_pci64(device_dev); - pci_read_config_word(device_dev, PCI_COMMAND, &cmd); - - /* - * Set the resources address correctly. The assumption here - * is that the addresses in the resource structure has been - * read from the card and it was set in the card by our - * Infrastructure .. - */ - vhdl = device_sysdata->vhdl; - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - size = 0; - size = device_dev->resource[idx].end - - device_dev->resource[idx].start; - if (size) { - device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; - } - else - continue; - - device_dev->resource[idx].end = - device_dev->resource[idx].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Adjust the addresses to go to the SWIZZLE .. - */ - device_dev->resource[idx].start = - device_dev->resource[idx].start & 0xfffff7ffffffffff; - device_dev->resource[idx].end = - device_dev->resource[idx].end & 0xfffff7ffffffffff; -#endif - - if (device_dev->resource[idx].flags & IORESOURCE_IO) { - cmd |= PCI_COMMAND_IO; -#ifdef SN1_IOPORTS - ioport = sn1_allocate_ioports(device_dev->resource[idx].start); - if (ioport < 0) { - printk("sn1_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number); - continue; - } - pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff))); - -printk("sn1_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff))); - - device_dev->resource[idx].start = ioport; - device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT; -#endif - } - if (device_dev->resource[idx].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - /* - * Now handle the ROM resource .. - */ - size = device_dev->resource[PCI_ROM_RESOURCE].end - - device_dev->resource[PCI_ROM_RESOURCE].start; - - if (size) { - device_dev->resource[PCI_ROM_RESOURCE].start = - (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, - size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; - device_dev->resource[PCI_ROM_RESOURCE].end = - device_dev->resource[PCI_ROM_RESOURCE].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * go through synergy swizzled space - */ - device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; - device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; -#endif - - } - - /* - * Update the Command Word on the Card. - */ - cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ - /* bit gets dropped .. no harm */ - pci_write_config_word(device_dev, PCI_COMMAND, cmd); - - pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { - lines = 1; - } - - device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata; - device_vertex = device_sysdata->vhdl; - - intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); - - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; -#ifdef CONFIG_IA64_SGI_SN1 - irq = bit_pos_to_irq(bit); -#else /* SN2 */ - irq = bit; -#endif - irq = irq + (cpuid << 8); - pciio_intr_connect(intr_handle); - device_dev->irq = irq; -#ifdef ajmtestintr - { - int slot = PCI_SLOT(device_dev->devfn); - static int timer_set = 0; - pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - extern void intr_test_handle_intr(int, void*, struct pt_regs *); - - if (!timer_set) { - intr_test_set_timer(); - timer_set = 1; - } - intr_test_register_irq(irq, pcibr_soft, slot); - request_irq(irq, intr_test_handle_intr,0,NULL, NULL); - } -#endif - - } - -#if 0 - -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} - -printk("testing Big Window: 0xC0000200c0000000 %p\n", *( (volatile uint64_t *)0xc0000200a0000000)); -printk("testing Big Window: 0xC0000200c0000008 %p\n", *( (volatile uint64_t *)0xc0000200a0000008)); - -#endif - -} - -/* - * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. - * - * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to - * HUB_WIDGET_ID_MIN: - * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. - * - * Given 2 modules 001c01 and 001c02 we get the following mappings: - * 001c01, widgetnum 15 = Bus number 0 - * 001c01, widgetnum 14 = Bus number 1 - * 001c02, widgetnum 15 = Bus number 3 - * 001c02, widgetnum 14 = Bus number 4 - * etc. - * - * The rational for starting Bus Number 0 with Widget number 15 is because - * the system boot disks are always connected via Widget 15 Slot 0 of the - * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 - * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest - * module id(Master Cnode) of the system. - * - */ -static int -pci_bus_map_create(devfs_handle_t xtalk) -{ - - devfs_handle_t master_node_vertex = NULL; - devfs_handle_t xwidget = NULL; - devfs_handle_t pci_bus = NULL; - hubinfo_t hubinfo = NULL; - xwidgetnum_t widgetnum; - char pathname[128]; - graph_error_t rv; - - /* - * Loop throught this vertex and get the Xwidgets .. - */ - for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { -#if 0 - { - int pos; - char dname[256]; - pos = devfs_generate_path(xtalk, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) - continue; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) - continue; - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - num_bridges++; - busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; - - /* - * Get the master node and from there get the NASID. - */ - master_node_vertex = device_master_get(xwidget); - if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); - } - - hubinfo_get(master_node_vertex, &hubinfo); - if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); - return(1); - } else { - busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; - } - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct sn1_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct sn1_dma_maps_s) * MAX_ATE_MAPS); - - } - - return(0); -} - -/* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between Xbridge - * and logical pci bus numbers. We also set up the NASID for each of these - * xbridges. - * - * Must be called before pci_init() is invoked. - */ -int -pci_bus_to_hcl_cvlink(void) -{ - - devfs_handle_t devfs_hdl = NULL; - devfs_handle_t xtalk = NULL; - int rv = 0; - char name[256]; - int master_iobrick; - int i; - - /* - * Iterate throught each xtalk links in the system .. - * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 - * - * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15 - * - * What if it is not pci? - */ - devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); - - /* - * To provide consistent(not persistent) device naming, we need to start - * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 - * with an attached I-Brick. Find the master_iobrick. - */ - master_iobrick = -1; - for (i = 0; i < nummodules; i++) { - moduleid_t iobrick_id; - iobrick_id = iobrick_module_get(&modules[i]->elsc); - if (iobrick_id > 0) { /* Valid module id */ - if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { - master_iobrick = i; - break; - } - } - } - - /* - * The master_iobrick gets bus 0 and 1. - */ - if (master_iobrick >= 0) { - memset(name, 0, 256); - format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - /* - * Now go do the rest of the modules, starting from the C-Brick with the lowest - * module id, remembering to skip the master_iobrick, which was done above. - */ - for (i = 0; i < nummodules; i++) { - if (i == master_iobrick) { - continue; /* Did the master_iobrick already. */ - } - - memset(name, 0, 256); - format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - return(0); -} diff --git a/arch/ia64/sn/io/pciba.c b/arch/ia64/sn/io/pciba.c deleted file mode 100644 index 437b309e92d..00000000000 --- a/arch/ia64/sn/io/pciba.c +++ /dev/null @@ -1,950 +0,0 @@ -/* - * arch/ia64/sn/io/pciba.c - * - * IRIX PCIBA-inspired user mode PCI interface - * - * requires: devfs - * - * device nodes show up in /dev/pci/BB/SS.F (where BB is the bus the - * device is on, SS is the slot the device is in, and F is the - * device's function on a multi-function card). - * - * when compiled into the kernel, it will only be initialized by the - * sgi sn1 specific initialization code. in this case, device nodes - * are under /dev/hw/..../ - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of - * this archive for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * 03262001 - Initial version by Chad Talbott - */ - - -/* jesse's beefs: - - register_pci_device should be documented - - grossness with do_swap should be documented - - big, gross union'ized node_data should be replaced with independent - structures - - replace global list of nodes with global lists of resources. could - use object oriented approach of allocating and cleaning up - resources. - -*/ - - -#include -#ifndef CONFIG_DEVFS_FS -# error PCIBA requires devfs -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -MODULE_DESCRIPTION("User mode PCI interface"); -MODULE_AUTHOR("Chad Talbott"); - - -#undef DEBUG_PCIBA -/* #define DEBUG_PCIBA */ - -#undef TRACE_PCIBA -/* #define TRACE_PCIBA */ - -#if defined(DEBUG_PCIBA) -# define DPRINTF(x...) printk(KERN_DEBUG x) -#else -# define DPRINTF(x...) -#endif - -#if defined(TRACE_PCIBA) -# if defined(__GNUC__) -# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ - __FILE__, __LINE__, __FUNCTION__) -# else -# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) -# endif -#else -# define TRACE() -#endif - - -typedef enum { failure, success } status; -typedef enum { false, true } boolean; - - -/* major data structures: - - struct node_data - - - one for each file registered with devfs. contains everything - that any file's fops would need to know about. - - struct dma_allocation - - - a single DMA allocation. only the 'dma' nodes care about - these. they are there primarily to allow the driver to look - up the kernel virtual address of dma buffers allocated by - pci_alloc_consistent, as the application is only given the - physical address (to program the device's dma, presumably) and - cannot supply the kernel virtual address when freeing the - buffer. - - it's also useful to maintain a list of buffers allocated - through a specific node to allow some sanity checking by this - driver. this prevents (for example) a broken application from - freeing buffers that it didn't allocate, or buffers allocated - on another node. - - global_node_list - - - a list of all nodes allocated. this allows the driver to free - all the memory it has 'kmalloc'd in case of an error, or on - module removal. - - global_dma_list - - - a list of all dma buffers allocated by this driver. this - allows the driver to 'pci_free_consistent' all buffers on - module removal or error. - -*/ - - -struct node_data { - /* flat list of all the device nodes. makes it easy to free - them all when we're unregistered */ - struct list_head global_node_list; - devfs_handle_t devfs_handle; - - void (* cleanup)(struct node_data *); - - union { - struct { - struct pci_dev * dev; - struct list_head dma_allocs; - boolean mmapped; - } dma; - struct { - struct pci_dev * dev; - u32 saved_rom_base_reg; - boolean mmapped; - } rom; - struct { - struct resource * res; - } base; - struct { - struct pci_dev * dev; - } config; - } u; -}; - -struct dma_allocation { - struct list_head list; - - dma_addr_t handle; - void * va; - size_t size; -}; - - -static LIST_HEAD(global_node_list); -static LIST_HEAD(global_dma_list); - - -/* module entry points */ -int __init pciba_init(void); -void __exit pciba_exit(void); - -static status __init register_with_devfs(void); -static void __exit unregister_with_devfs(void); - -static status __init register_pci_device(devfs_handle_t device_dir_handle, - struct pci_dev * dev); - -/* file operations */ -static int generic_open(struct inode * inode, struct file * file); -static int rom_mmap(struct file * file, struct vm_area_struct * vma); -static int rom_release(struct inode * inode, struct file * file); -static int base_mmap(struct file * file, struct vm_area_struct * vma); -static int config_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg); -static int dma_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg); -static int dma_mmap(struct file * file, struct vm_area_struct * vma); - -/* support routines */ -static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va); -static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va); - -#ifdef DEBUG_PCIBA -static void dump_nodes(struct list_head * nodes); -static void dump_allocations(struct list_head * dalp); -#endif - -/* file operations for each type of node */ -static struct file_operations rom_fops = { - owner: THIS_MODULE, - mmap: rom_mmap, - open: generic_open, - release: rom_release -}; - - -static struct file_operations base_fops = { - owner: THIS_MODULE, - mmap: base_mmap, - open: generic_open -}; - - -static struct file_operations config_fops = { - owner: THIS_MODULE, - ioctl: config_ioctl, - open: generic_open -}; - -static struct file_operations dma_fops = { - owner: THIS_MODULE, - ioctl: dma_ioctl, - mmap: dma_mmap, - open: generic_open -}; - - -module_init(pciba_init); -module_exit(pciba_exit); - - -int __init -pciba_init(void) -{ - TRACE(); - - if (register_with_devfs() == failure) - return 1; /* failure */ - - printk("PCIBA (a user mode PCI interface) initialized.\n"); - - return 0; /* success */ -} - - -void __exit -pciba_exit(void) -{ - TRACE(); - - /* FIXME: should also free all that memory that we allocated - ;) */ - unregister_with_devfs(); -} - - -# if 0 -static void __exit -free_nodes(void) -{ - struct node_data * nd; - - TRACE(); - - list_for_each(nd, &node_list) { - kfree(list_entry(nd, struct nd, node_list)); - } -} -#endif - -#if !defined(CONFIG_IA64_SGI_SN1) - -static status __init -register_with_devfs(void) -{ - struct pci_dev * dev = NULL; - devfs_handle_t device_dir_handle; - char devfs_path[40]; - - TRACE(); - - if (!devfs_mk_dir(NULL, "pci", NULL)) - return failure; - - /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ - - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - sprintf(devfs_path, "pci/%02x/%02x.%x", - dev->bus->number, - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - - device_dir_handle = - devfs_mk_dir(NULL, devfs_path, NULL); - if (device_dir_handle == NULL) - return failure; - - if (register_pci_device(device_dir_handle, dev) == failure) { - devfs_remove("pci"); - return failure; - } - } - - return success; -} - -#else - -extern devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -static status __init -register_with_devfs(void) -{ - struct pci_dev * dev = NULL; - devfs_handle_t device_dir_handle; - - TRACE(); - - /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */ - - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - device_dir_handle = devfn_to_vertex(dev->bus->number, - dev->devfn); - if (device_dir_handle == NULL) - return failure; - - if (register_pci_device(device_dir_handle, dev) == failure) { - devfs_remove("pci"); - return failure; - } - } - - return success; -} - -static void __exit -unregister_with_devfs(void) -{ - struct list_head * lhp; - struct node_data * nd; - - TRACE(); - - list_for_each(lhp, &global_node_list) { - nd = list_entry(lhp, struct node_data, global_node_list); - devfs_unregister(nd->devfs_handle); - } - -} - - -struct node_data * new_node(void) -{ - struct node_data * node; - - TRACE(); - - node = kmalloc(sizeof(struct node_data), GFP_KERNEL); - if (node == NULL) - return NULL; - list_add(&node->global_node_list, &global_node_list); - return node; -} - - -void dma_cleanup(struct node_data * dma_node) -{ - TRACE(); - - /* FIXME: should free these allocations */ -#ifdef DEBUG_PCIBA - dump_allocations(&dma_node->u.dma.dma_allocs); -#endif - devfs_unregister(dma_node->devfs_handle); -} - - -void init_dma_node(struct node_data * node, - struct pci_dev * dev, devfs_handle_t dh) -{ - TRACE(); - - node->devfs_handle = dh; - node->u.dma.dev = dev; - node->cleanup = dma_cleanup; - INIT_LIST_HEAD(&node->u.dma.dma_allocs); -} - - -void rom_cleanup(struct node_data * rom_node) -{ - TRACE(); - - if (rom_node->u.rom.mmapped) - pci_write_config_dword(rom_node->u.rom.dev, - PCI_ROM_ADDRESS, - rom_node->u.rom.saved_rom_base_reg); - devfs_unregister(rom_node->devfs_handle); -} - - -void init_rom_node(struct node_data * node, - struct pci_dev * dev, devfs_handle_t dh) -{ - TRACE(); - - node->devfs_handle = dh; - node->u.rom.dev = dev; - node->cleanup = rom_cleanup; - node->u.rom.mmapped = false; -} - - -static status __init -register_pci_device(devfs_handle_t device_dir_handle, struct pci_dev * dev) -{ - struct node_data * nd; - char devfs_path[20]; - devfs_handle_t node_devfs_handle; - int ri; - - TRACE(); - - - /* register nodes for all the device's base address registers */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (pci_resource_len(dev, ri) != 0) { - sprintf(devfs_path, "base/%d", ri); - if (devfs_register(device_dir_handle, devfs_path, - DEVFS_FL_NONE, - 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - } - } - - /* register a node corresponding to the first MEM resource on - the device */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (dev->resource[ri].flags & IORESOURCE_MEM && - pci_resource_len(dev, ri) != 0) { - if (devfs_register(device_dir_handle, "mem", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - break; - } - } - - /* also register a node corresponding to the first IO resource - on the device */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (dev->resource[ri].flags & IORESOURCE_IO && - pci_resource_len(dev, ri) != 0) { - if (devfs_register(device_dir_handle, "io", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - break; - } - } - - /* register a node corresponding to the device's ROM resource, - if present */ - if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) { - nd = new_node(); - if (nd == NULL) - return failure; - node_devfs_handle = devfs_register(device_dir_handle, "rom", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR, - &rom_fops, nd); - if (node_devfs_handle == NULL) - return failure; - init_rom_node(nd, dev, node_devfs_handle); - } - - /* register a node that allows ioctl's to read and write to - the device's config space */ - if (devfs_register(device_dir_handle, "config", DEVFS_FL_NONE, - 0, 0, S_IFREG | S_IRUSR | S_IWUSR, - &config_fops, dev) == NULL) - return failure; - - - /* finally, register a node that allows ioctl's to allocate - and free DMA buffers, as well as memory map those - buffers. */ - nd = new_node(); - if (nd == NULL) - return failure; - node_devfs_handle = - devfs_register(device_dir_handle, "dma", DEVFS_FL_NONE, - 0, 0, S_IFREG | S_IRUSR | S_IWUSR, - &dma_fops, nd); - if (node_devfs_handle == NULL) - return failure; - init_dma_node(nd, dev, node_devfs_handle); - -#ifdef DEBUG_PCIBA - dump_nodes(&global_node_list); -#endif - - return success; -} - - -static int -generic_open(struct inode * inode, struct file * file) -{ - TRACE(); - - /* FIXME: should check that they're not trying to open the ROM - writable */ - - return 0; /* success */ -} - - -static int -rom_mmap(struct file * file, struct vm_area_struct * vma) -{ - unsigned long pci_pa; - struct node_data * nd; - - TRACE(); - - nd = (struct node_data * )file->private_data; - - pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE); - - if (!nd->u.rom.mmapped) { - nd->u.rom.mmapped = true; - DPRINTF("Enabling ROM address decoder.\n"); - DPRINTF( -"rom_mmap: FIXME: some cards do not allow both ROM and memory addresses to\n" -"rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.\n"); - pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - &nd->u.rom.saved_rom_base_reg); - DPRINTF("ROM base address contains %x\n", - nd->u.rom.saved_rom_base_reg); - pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - nd->u.rom.saved_rom_base_reg | - PCI_ROM_ADDRESS_ENABLE); - } - - return mmap_pci_address(vma, pci_pa); -} - - -static int -rom_release(struct inode * inode, struct file * file) -{ - struct node_data * nd; - - TRACE(); - - nd = (struct node_data * )file->private_data; - - if (nd->u.rom.mmapped) { - nd->u.rom.mmapped = false; - DPRINTF("Disabling ROM address decoder.\n"); - pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - nd->u.rom.saved_rom_base_reg); - } - return 0; /* indicate success */ -} - - -static int -base_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct resource * resource; - - TRACE(); - - resource = (struct resource *)file->private_data; - - return mmap_pci_address(vma, resource->start); -} - - -static int -config_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct pci_dev * dev; - - union cfg_data { - uint8_t byte; - uint16_t word; - uint32_t dword; - } read_data, write_data; - - int dir, size, offset; - - TRACE(); - - DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)\n", - cmd, - _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); - DPRINTF("arg = %lx\n", arg); - - dev = (struct pci_dev *)file->private_data; - - /* PCIIOCCFG{RD,WR}: read and/or write PCI configuration - space. If both, the read happens first (this becomes a swap - operation, atomic with respect to other updates through - this path). */ - - dir = _IOC_DIR(cmd); - -#define do_swap(suffix, type) \ - do { \ - if (dir & _IOC_READ) { \ - pci_read_config_##suffix(dev, _IOC_NR(cmd), \ - &read_data.suffix); \ - } \ - if (dir & _IOC_WRITE) { \ - get_user(write_data.suffix, (type)arg); \ - pci_write_config_##suffix(dev, _IOC_NR(cmd), \ - write_data.suffix); \ - } \ - if (dir & _IOC_READ) { \ - put_user(read_data.suffix, (type)arg); \ - } \ - } while (0) - - size = _IOC_SIZE(cmd); - offset = _IOC_NR(cmd); - - DPRINTF("sanity check\n"); - if (((size > 0) || (size <= 4)) && - ((offset + size) <= 256) && - (dir & (_IOC_READ | _IOC_WRITE))) { - - switch (size) - { - case 1: - do_swap(byte, uint8_t *); - break; - case 2: - do_swap(word, uint16_t *); - break; - case 4: - do_swap(dword, uint32_t *); - break; - default: - DPRINTF("invalid ioctl\n"); - return -EINVAL; - } - } else - return -EINVAL; - - return 0; -} - - -#ifdef DEBUG_PCIBA -static void -dump_allocations(struct list_head * dalp) -{ - struct dma_allocation * dap; - struct list_head * p; - - printk("{\n"); - list_for_each(p, dalp) { - dap = list_entry(p, struct dma_allocation, - list); - printk(" handle = %lx, va = %p\n", - dap->handle, dap->va); - } - printk("}\n"); -} - -static void -dump_nodes(struct list_head * nodes) -{ - struct node_data * ndp; - struct list_head * p; - - printk("{\n"); - list_for_each(p, nodes) { - ndp = list_entry(p, struct node_data, - global_node_list); - printk(" %p\n", (void *)ndp); - } - printk("}\n"); -} - - -#if 0 -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) - -static void -test_list(void) -{ - u64 i; - LIST_HEAD(the_list); - - for (i = 0; i < 5; i++) { - struct dma_allocation * new_alloc; - NEW(new_alloc); - new_alloc->va = (void *)i; - new_alloc->handle = 5*i; - printk("%d - the_list->next = %lx\n", i, the_list.next); - list_add(&new_alloc->list, &the_list); - } - dump_allocations(&the_list); -} -#endif -#endif - - -static LIST_HEAD(dma_buffer_list); - - -static int -dma_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct node_data * nd; - uint64_t argv; - int result; - struct dma_allocation * dma_alloc; - struct list_head * iterp; - - TRACE(); - - DPRINTF("cmd = %x\n", cmd); - DPRINTF("arg = %lx\n", arg); - - nd = (struct node_data *)file->private_data; - -#ifdef DEBUG_PCIBA - DPRINTF("at dma_ioctl entry\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - - switch (cmd) { - case PCIIOCDMAALLOC: - /* PCIIOCDMAALLOC: allocate a chunk of physical memory - and set it up for DMA. Return the PCI address that - gets to it. */ - DPRINTF("case PCIIOCDMAALLOC (%lx)\n", PCIIOCDMAALLOC); - - if ( (result = get_user(argv, (uint64_t *)arg)) ) - return result; - DPRINTF("argv (size of buffer) = %lx\n", argv); - - dma_alloc = (struct dma_allocation *) - kmalloc(sizeof(struct dma_allocation), GFP_KERNEL); - if (dma_alloc == NULL) - return -ENOMEM; - - dma_alloc->size = (size_t)argv; - dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev, - dma_alloc->size, - &dma_alloc->handle); - DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lx\n", - dma_alloc->va, dma_alloc->handle); - if (dma_alloc->va == NULL) { - kfree(dma_alloc); - return -ENOMEM; - } - - list_add(&dma_alloc->list, &nd->u.dma.dma_allocs); - if ( (result = put_user((uint64_t)dma_alloc->handle, - (uint64_t *)arg)) ) { - DPRINTF("put_user failed\n"); - pci_free_consistent(nd->u.dma.dev, (size_t)argv, - dma_alloc->va, dma_alloc->handle); - kfree(dma_alloc); - return result; - } - -#ifdef DEBUG_PCIBA - DPRINTF("after insertion\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - break; - - case PCIIOCDMAFREE: - DPRINTF("case PCIIOCDMAFREE (%lx)\n", PCIIOCDMAFREE); - - if ( (result = get_user(argv, (uint64_t *)arg)) ) { - DPRINTF("get_user failed\n"); - return result; - } - - DPRINTF("argv (physical address of DMA buffer) = %lx\n", argv); - list_for_each(iterp, &nd->u.dma.dma_allocs) { - struct dma_allocation * da = - list_entry(iterp, struct dma_allocation, list); - if (da->handle == argv) { - pci_free_consistent(nd->u.dma.dev, da->size, - da->va, da->handle); - list_del(&da->list); - kfree(da); -#ifdef DEBUG_PCIBA - DPRINTF("after deletion\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - return 0; /* success */ - } - } - /* previously allocated dma buffer wasn't found */ - DPRINTF("attempt to free invalid dma handle\n"); - return -EINVAL; - - default: - DPRINTF("undefined ioctl\n"); - return -EINVAL; - } - - DPRINTF("success\n"); - return 0; -} - - -static int -dma_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct node_data * nd; - struct list_head * iterp; - int result; - - TRACE(); - - nd = (struct node_data *)file->private_data; - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - DPRINTF("offset = %lx\n", vma->vm_pgoff); - - /* get kernel virtual address for the dma buffer (necessary - * for the mmap). */ - list_for_each(iterp, &nd->u.dma.dma_allocs) { - struct dma_allocation * da = - list_entry(iterp, struct dma_allocation, list); - /* why does mmap shift its offset argument? */ - if (da->handle == vma->vm_pgoff << PAGE_SHIFT) { - DPRINTF("found dma handle\n"); - if ( (result = mmap_kernel_address(vma, - da->va)) ) { - return result; /* failure */ - } else { - /* it seems like at least one of these - should show up in user land.... - I'm missing something */ - *(char *)da->va = 0xaa; - strncpy(da->va, " Toastie!", da->size); - if (put_user(0x18badbeeful, - (u64 *)vma->vm_start)) - DPRINTF("put_user failed?!\n"); - return 0; /* success */ - } - - } - } - DPRINTF("attempt to mmap an invalid dma handle\n"); - return -EINVAL; -} - - -static int -mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va) -{ - unsigned long pci_pa; - - TRACE(); - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - - /* the size of the vma doesn't necessarily correspond to the - size specified in the mmap call. So we can't really do any - kind of sanity check here. This is a dangerous driver, and - it's very easy for a user process to kill the machine. */ - - DPRINTF("PCI base at virtual address %lx\n", pci_va); - /* the __pa macro is intended for region 7 on IA64, so it - doesn't work for region 6 */ - /* pci_pa = __pa(pci_va); */ - /* should be replaced by __tpa or equivalent (preferably a - generic equivalent) */ - pci_pa = pci_va & ~0xe000000000000000ul; - DPRINTF("PCI base at physical address %lx\n", pci_pa); - - /* there are various arch-specific versions of this function - defined in linux/drivers/char/mem.c, but it would be nice - if all architectures put it in pgtable.h. it's defined - there for ia64.... */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - - return io_remap_page_range(vma->vm_start, pci_pa, - vma->vm_end-vma->vm_start, - vma->vm_page_prot); -} - - -static int -mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va) -{ - unsigned long kernel_pa; - - TRACE(); - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - - /* the size of the vma doesn't necessarily correspond to the - size specified in the mmap call. So we can't really do any - kind of sanity check here. This is a dangerous driver, and - it's very easy for a user process to kill the machine. */ - - DPRINTF("mapping virtual address %p\n", kernel_va); - kernel_pa = __pa(kernel_va); - DPRINTF("mapping physical address %lx\n", kernel_pa); - - vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - - return remap_page_range(vma->vm_start, kernel_pa, - vma->vm_end-vma->vm_start, - vma->vm_page_prot); -} diff --git a/arch/ia64/sn/io/pciio.c b/arch/ia64/sn/io/pciio.c deleted file mode 100644 index a6f130e702c..00000000000 --- a/arch/ia64/sn/io/pciio.c +++ /dev/null @@ -1,1507 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#define USRPCI 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Must be before iograph.h to get MAX_PORT_NUM */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_PCIIO -#undef DEBUG_PCIIO /* turn this on for yet more console output */ - - -#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DO_DEL(ptr) (kfree(ptr)) - -char pciio_info_fingerprint[] = "pciio_info"; - -cdl_p pciio_registry = NULL; - -int -badaddr_val(volatile void *addr, int len, volatile void *ptr) -{ - int ret = 0; - volatile void *new_addr; - - switch (len) { - case 4: - new_addr = (void *)(((u64) addr)^4); - ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); - break; - default: - printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); - } - - if (ret < 0) - panic("badaddr_val: unexpected status (%d) in probing", ret); - return(ret); - -} - - -nasid_t -get_console_nasid(void) -{ - extern nasid_t console_nasid; - if (console_nasid < 0) { - console_nasid = ia64_sn_get_console_nasid(); - if (console_nasid < 0) { -// ZZZ What do we do if we don't get a console nasid on the hardware???? - if (IS_RUNNING_ON_SIMULATOR() ) - console_nasid = master_nasid; - } - } - return console_nasid; -} - -int -hub_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return(0); -} - -int -hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) -{ - return(0); -} - -void -ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) -{ -} - -/****** - ****** end hack defines ...... - ******/ - - - - -/* ===================================================================== - * PCI Generic Bus Provider - * Implement PCI provider operations. The pciio* layer provides a - * platform-independent interface for PCI devices. This layer - * switches among the possible implementations of a PCI adapter. - */ - -/* ===================================================================== - * Provider Function Location SHORTCUT - * - * On platforms with only one possible PCI provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * For the moment, we will assume that IP27 - * only use Bridge ASICs to provide PCI support. - */ -#include -#define DEV_FUNC(dev,func) pcibr_##func -#define CAST_PIOMAP(x) ((pcibr_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x)) -#define CAST_INTR(x) ((pcibr_intr_t)(x)) -#endif /* CONFIG_IA64_SGI_SN1 */ - -/* ===================================================================== - * Function Table of Contents - */ - -#if !defined(DEV_FUNC) -static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); -#endif - -pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pciio_piomap_free(pciio_piomap_t); -caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); - -void pciio_piomap_done(pciio_piomap_t); -caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); - -iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); -void pciio_dmamap_done(pciio_dmamap_t); -iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pciio_dmamap_drain(pciio_dmamap_t); -void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pciio_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); - -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pciio_intr_free(pciio_intr_t); -int pciio_intr_connect(pciio_intr_t); -void pciio_intr_disconnect(pciio_intr_t); -devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); - -void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); - -void pciio_provider_startup(devfs_handle_t); -void pciio_provider_shutdown(devfs_handle_t); - -pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); -devfs_handle_t pciio_intr_dev_get(pciio_intr_t); - -devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); -pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); -pciio_space_t pciio_pio_space_get(pciio_piomap_t); -iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); -ulong pciio_pio_mapsz_get(pciio_piomap_t); -caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); - -devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); -pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); - -pciio_info_t pciio_info_chk(devfs_handle_t); -pciio_info_t pciio_info_get(devfs_handle_t); -void pciio_info_set(devfs_handle_t, pciio_info_t); -devfs_handle_t pciio_info_dev_get(pciio_info_t); -pciio_slot_t pciio_info_slot_get(pciio_info_t); -pciio_function_t pciio_info_function_get(pciio_info_t); -pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); -pciio_device_id_t pciio_info_device_id_get(pciio_info_t); -devfs_handle_t pciio_info_master_get(pciio_info_t); -arbitrary_info_t pciio_info_mfast_get(pciio_info_t); -pciio_provider_t *pciio_info_pops_get(pciio_info_t); -error_handler_f *pciio_info_efunc_get(pciio_info_t); -error_handler_arg_t *pciio_info_einfo_get(pciio_info_t); -pciio_space_t pciio_info_bar_space_get(pciio_info_t, int); -iopaddr_t pciio_info_bar_base_get(pciio_info_t, int); -size_t pciio_info_bar_size_get(pciio_info_t, int); -iopaddr_t pciio_info_rom_base_get(pciio_info_t); -size_t pciio_info_rom_size_get(pciio_info_t); - -void pciio_init(void); -int pciio_attach(devfs_handle_t); - -void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); -void pciio_provider_unregister(devfs_handle_t); -pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); - -int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); -void pciio_driver_unregister(char *driver_prefix); - -devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); - -void pciio_device_unregister(devfs_handle_t); -pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -void pciio_device_info_free(pciio_info_t); -devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); -void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t, int); -int pciio_device_detach(devfs_handle_t, int); -void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); - -int pciio_reset(devfs_handle_t); -int pciio_write_gather_flush(devfs_handle_t); -int pciio_slot_inuse(devfs_handle_t); - -/* ===================================================================== - * Provider Function Location - * - * If there is more than one possible provider for - * this platform, we need to examine the master - * vertex of the current vertex for a provider - * function structure, and indirect through the - * appropriately named member. - */ - -#if !defined(DEV_FUNC) - -static pciio_provider_t * -pciio_to_provider_fns(devfs_handle_t dev) -{ - pciio_info_t card_info; - pciio_provider_t *provider_fns; - - /* - * We're called with two types of vertices, one is - * the bridge vertex (ends with "pci") and the other is the - * pci slot vertex (ends with "pci/[0-8]"). For the first type - * we need to get the provider from the PFUNCS label. For - * the second we get it from fastinfo/c_pops. - */ - provider_fns = pciio_provider_fns_get(dev); - if (provider_fns == NULL) { - card_info = pciio_info_get(dev); - if (card_info != NULL) { - provider_fns = pciio_info_pops_get(card_info); - } - } - - if (provider_fns == NULL) -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_PANIC("%v: provider_fns == NULL", dev); -#else - PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); -#endif - - return provider_fns; - -} - -#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) -#define CAST_INTR(x) ((pciio_intr_t)(x)) -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) -#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * pciio space on a specified card - */ - -pciio_piomap_t -pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* lowest address (or offset in window) */ - size_t byte_count, /* size of region containing our mappings */ - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); -} - -void -pciio_piomap_free(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_free) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ - iopaddr_t pciio_addr, /* map for this pciio address */ - size_t byte_count) -{ /* map this many bytes */ - pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) - (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); - - return pciio_piomap->pp_kvaddr; -} - -void -pciio_piomap_done(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_done) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, space, addr, byte_count, flags); -} - -caddr_t -pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - pciio_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - pciio_piomap_t map = 0; - int errfree = 0; - caddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_piotrans_addr - (dev, dev_desc, space, addr, byte_count, flags); - if (res) - return res; /* pciio_piotrans worked */ - - if (!map) { - map = pciio_piomap_alloc - (dev, dev_desc, space, addr, byte_count, byte_count, flags); - if (!map) - return res; /* pciio_piomap_alloc failed */ - errfree = 1; - } - - res = pciio_piomap_addr - (map, addr, byte_count); - if (!res) { - if (errfree) - pciio_piomap_free(map); - return res; /* pciio_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_piomap_addr succeeded */ -} - -iopaddr_t -pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ - device_desc_t dev_desc, /* Device descriptor */ - pciio_space_t space, /* MEM32/MEM64/IO */ - size_t byte_count, /* Size of mapping */ - size_t align) -{ /* Alignment needed */ - if (align < NBPP) - align = NBPP; - return DEV_FUNC(dev, piospace_alloc) - (dev, dev_desc, space, byte_count, align); -} - -void -pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ - pciio_space_t space, /* Type of space */ - iopaddr_t pciaddr, /* starting address */ - size_t byte_count) -{ /* Range of address */ - DEV_FUNC(dev, piospace_free) - (dev, space, pciaddr, byte_count); -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from pci space to system - * physical space. - */ - -pciio_dmamap_t -pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -alenlist_t -pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(pciio_dmamap, dmamap_list) - (CAST_DMAMAP(pciio_dmamap), alenlist, flags); -} - -void -pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -alenlist_t -pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -iopaddr_t -pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - pciio_dmamap_t *mapp, /* map to use, then map we used */ - unsigned flags) -{ /* PIO flags */ - pciio_dmamap_t map = 0; - int errfree = 0; - iopaddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_dmatrans_addr - (dev, dev_desc, paddr, byte_count, flags); - if (res) - return res; /* pciio_dmatrans worked */ - - if (!map) { - map = pciio_dmamap_alloc - (dev, dev_desc, byte_count, flags); - if (!map) - return res; /* pciio_dmamap_alloc failed */ - errfree = 1; - } - - res = pciio_dmamap_addr - (map, paddr, byte_count); - if (!res) { - if (errfree) - pciio_dmamap_free(map); - return res; /* pciio_dmamap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_dmamap_addr succeeded */ -} - -void -pciio_dmamap_drain(pciio_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -pciio_intr_t -pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_intr_line_t lines, /* INTR line(s) to attach */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, lines, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -pciio_intr_free(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - -/* - * Associate resources allocated with a previous pciio_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -pciio_intr_connect(pciio_intr_t intr_hdl) /* pciio intr resource handle */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl)); -} - -/* - * Disassociate handler with the specified interrupt. - */ -void -pciio_intr_disconnect(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -pciio_intr_cpu_get(pciio_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - -void -pciio_slot_func_to_name(char *name, - pciio_slot_t slot, - pciio_function_t func) -{ - /* - * standard connection points: - * - * PCIIO_SLOT_NONE: .../pci/direct - * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 - * multifunction: .../pci/ ie. .../pci/3c - */ - - if (slot == PCIIO_SLOT_NONE) - sprintf(name, "direct"); - else if (func == PCIIO_FUNC_NONE) - sprintf(name, "%d", slot); - else - sprintf(name, "%d%c", slot, 'a'+func); -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -pciio_provider_startup(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_startup) - (pciio_provider); -} - -/* - * Shutdown a crosstalk provider - */ -void -pciio_provider_shutdown(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_shutdown) - (pciio_provider); -} - -/* - * Specify endianness constraints. The driver tells us what the device - * does and how it would like to see things in memory. We reply with - * how things will actually appear in memory. - */ -pciio_endian_t -pciio_endian_set(devfs_handle_t dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); - ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); - -#if DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#else - printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#endif -#endif - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -/* - * Specify PCI arbitration priority. - */ -pciio_priority_t -pciio_priority_set(devfs_handle_t dev, - pciio_priority_t device_prio) -{ - ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); - - return DEV_FUNC(dev, priority_set) - (dev, device_prio); -} - -/* - * Read value of configuration register - */ -uint64_t -pciio_config_get(devfs_handle_t dev, - unsigned reg, - unsigned size) -{ - uint64_t value = 0; - unsigned shift = 0; - - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - value |= DEV_FUNC(dev, config_get) - (dev, reg, biw) << shift; - - shift += 8*biw; - reg += biw; - size -= biw; - } - return value; -} - -/* - * Change value of configuration register - */ -void -pciio_config_set(devfs_handle_t dev, - unsigned reg, - unsigned size, - uint64_t value) -{ - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - DEV_FUNC(dev, config_set) - (dev, reg, biw, value); - reg += biw; - size -= biw; - value >>= biw * 8; - } -} - -/* ===================================================================== - * GENERIC PCI SUPPORT FUNCTIONS - */ - -/* - * Issue a hardware reset to a card. - */ -int -pciio_reset(devfs_handle_t dev) -{ - return DEV_FUNC(dev, reset) (dev); -} - -/* - * flush write gather buffers - */ -int -pciio_write_gather_flush(devfs_handle_t dev) -{ - return DEV_FUNC(dev, write_gather_flush) (dev); -} - -devfs_handle_t -pciio_intr_dev_get(pciio_intr_t pciio_intr) -{ - return (pciio_intr->pi_dev); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -pciio_pio_dev_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_dev); -} - -pciio_slot_t -pciio_pio_slot_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_slot); -} - -pciio_space_t -pciio_pio_space_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_space); -} - -iopaddr_t -pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_pciaddr); -} - -ulong -pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_mapsz); -} - -caddr_t -pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_kvaddr); -} - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_dev); -} - -pciio_slot_t -pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_slot); -} - -/****** Generic pci slot information interfaces ******/ - -pciio_info_t -pciio_info_chk(devfs_handle_t pciio) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); - return (pciio_info_t) ainfo; -} - -pciio_info_t -pciio_info_get(devfs_handle_t pciio) -{ - pciio_info_t pciio_info; - - pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); - -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pciio, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { - - return((pciio_info_t)-1); /* Should panic .. */ - } - - - return pciio_info; -} - -void -pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) -{ - if (pciio_info != NULL) - pciio_info->c_fingerprint = pciio_info_fingerprint; - hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); - - /* Also, mark this vertex as a PCI slot - * and use the pciio_info, so pciio_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, - (arbitrary_info_t) pciio_info); -} - -devfs_handle_t -pciio_info_dev_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vertex); -} - -/*ARGSUSED*/ -pciio_bus_t -pciio_info_bus_get(pciio_info_t pciio_info) -{ - /* XXX for now O2 always gets back bus 0 */ - return (pciio_bus_t)0; -} - -pciio_slot_t -pciio_info_slot_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_slot); -} - -pciio_function_t -pciio_info_function_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_func); -} - -pciio_vendor_id_t -pciio_info_vendor_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vendor); -} - -pciio_device_id_t -pciio_info_device_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_device); -} - -devfs_handle_t -pciio_info_master_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_master); -} - -arbitrary_info_t -pciio_info_mfast_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_mfast); -} - -pciio_provider_t * -pciio_info_pops_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_pops); -} - -error_handler_f * -pciio_info_efunc_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_efunc); -} - -error_handler_arg_t * -pciio_info_einfo_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_einfo); -} - -pciio_space_t -pciio_info_bar_space_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_space; -} - -iopaddr_t -pciio_info_bar_base_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_base; -} - -size_t -pciio_info_bar_size_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_size; -} - -iopaddr_t -pciio_info_rom_base_get(pciio_info_t info) -{ - return info->c_rbase; -} - -size_t -pciio_info_rom_size_get(pciio_info_t info) -{ - return info->c_rsize; -} - - -/* ===================================================================== - * GENERIC PCI INITIALIZATION FUNCTIONS - */ - -/* - * pciioinit: called once during device driver - * initializtion if this driver is configured into - * the system. - */ -void -pciio_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("pciio_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (pciio_registry == NULL) { - cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); - if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(pciio_registry != NULL); -} - -/* - * pciioattach: called for each vertex in the graph - * that is a PCI provider. - */ -/*ARGSUSED */ -int -pciio_attach(devfs_handle_t pciio) -{ -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("%v: pciio_attach\n", pciio); -#else - printk("0x%x: pciio_attach\n", pciio); -#endif -#endif - return 0; -} - -/* - * Associate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) -{ - hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); -} - -/* - * Disassociate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_unregister(devfs_handle_t provider) -{ - arbitrary_info_t ainfo; - - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -} - -/* - * Obtain a pointer to the pciio_provider functions for a specified Crosstalk - * provider. - */ -pciio_provider_t * -pciio_provider_fns_get(devfs_handle_t provider) -{ - arbitrary_info_t ainfo = 0; - - (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); - return (pciio_provider_t *) ainfo; -} - -/*ARGSUSED4 */ -int -pciio_driver_register( - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine might call - * pciio_driver_register before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - return cdl_add_driver(pciio_registry, - vendor_id, device_id, - driver_prefix, flags, NULL); -} - -/* - * Remove an initialization function. - */ -void -pciio_driver_unregister( - char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called register; so - * we can assume we have a registry here. - */ - ASSERT(pciio_registry != NULL); - - cdl_del_driver(pciio_registry, driver_prefix, NULL); -} - -/* - * Set the slot status for a device supported by the - * driver being registered. - */ -void -pciio_driver_reg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Set the slot status for a device supported by the - * driver being unregistered. - */ -void -pciio_driver_unreg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -pciio_iterate(char *driver_prefix, - pciio_iter_f * func) -{ - /* a driver's init routine might call - * pciio_iterate before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - ASSERT(pciio_registry != NULL); - - cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); -} - -devfs_handle_t -pciio_device_register( - devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ - devfs_handle_t master, /* card's master ASIC (PCI provider) */ - pciio_slot_t slot, /* card's slot */ - pciio_function_t func, /* card's func */ - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - return pciio_device_info_register - (connectpt, pciio_device_info_new (NULL, master, slot, func, - vendor_id, device_id)); -} - -void -pciio_device_unregister(devfs_handle_t pconn) -{ - DEV_FUNC(pconn,device_unregister)(pconn); -} - -pciio_info_t -pciio_device_info_new( - pciio_info_t pciio_info, - devfs_handle_t master, - pciio_slot_t slot, - pciio_function_t func, - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - if (!pciio_info) - GET_NEW(pciio_info); - ASSERT(pciio_info != NULL); - - pciio_info->c_slot = slot; - pciio_info->c_func = func; - pciio_info->c_vendor = vendor_id; - pciio_info->c_device = device_id; - pciio_info->c_master = master; - pciio_info->c_mfast = hwgraph_fastinfo_get(master); - pciio_info->c_pops = pciio_provider_fns_get(master); - pciio_info->c_efunc = 0; - pciio_info->c_einfo = 0; - - return pciio_info; -} - -void -pciio_device_info_free(pciio_info_t pciio_info) -{ - /* NOTE : pciio_info is a structure within the pcibr_info - * and not a pointer to memory allocated on the heap !! - */ - BZERO((char *)pciio_info,sizeof(pciio_info)); -} - -devfs_handle_t -pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ - pciio_info_t pciio_info) /* details about the connectpt */ -{ - char name[32]; - devfs_handle_t pconn; - int device_master_set(devfs_handle_t, devfs_handle_t); - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - if (GRAPH_SUCCESS != - hwgraph_path_add(connectpt, name, &pconn)) - return pconn; - - pciio_info->c_vertex = pconn; - pciio_info_set(pconn, pciio_info); -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pconn, dname, 256); - printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - /* - * create link to our pci provider - */ - - device_master_set(pconn, pciio_info->c_master); - -#if USRPCI - /* - * Call into usrpci provider to let it initialize for - * the given slot. - */ - if (pciio_info->c_slot != PCIIO_SLOT_NONE) - usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); -#endif - - return pconn; -} - -void -pciio_device_info_unregister(devfs_handle_t connectpt, - pciio_info_t pciio_info) -{ - char name[32]; - devfs_handle_t pconn; - - if (!pciio_info) - return; - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - hwgraph_edge_remove(connectpt,name,&pconn); - pciio_info_set(pconn,0); - - /* Remove the link to our pci provider */ - hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); - - - hwgraph_vertex_unref(pconn); - hwgraph_vertex_destroy(pconn); - -} -/* Add the pci card inventory information to the hwgraph - */ -static void -pciio_device_inventory_add(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - - /* Donot add inventory for non-existent devices */ - if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || - (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) - return; - device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, - pciio_info->c_vendor,pciio_info->c_device, - pciio_info->c_slot); -} - -static void -pciio_device_inventory_remove(devfs_handle_t pconn_vhdl) -{ -#ifdef LATER - hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1); -#endif -} - -/*ARGSUSED */ -int -pciio_device_attach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - - pciio_device_inventory_add(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); -} - -int -pciio_device_detach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - pciio_device_inventory_remove(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_del_connpt(pciio_registry, vendor_id, device_id, - pconn, drv_flags)); - -} - -/* - * pciio_error_register: - * arrange for a function to be called with - * a specified first parameter plus other - * information when an error is encountered - * and traced to the pci slot corresponding - * to the connection point pconn. - * - * may also be called with a null function - * pointer to "unregister" the error handler. - * - * NOTE: subsequent calls silently overwrite - * previous data for this vertex. We assume that - * cooperating drivers, well, cooperate ... - */ -void -pciio_error_register(devfs_handle_t pconn, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - pciio_info_t pciio_info; - - pciio_info = pciio_info_get(pconn); - ASSERT(pciio_info != NULL); - pciio_info->c_efunc = efunc; - pciio_info->c_einfo = einfo; -} - -/* - * Check if any device has been found in this slot, and return - * true or false - * vhdl is the vertex for the slot - */ -int -pciio_slot_inuse(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - if (pciio_info->c_vendor) { - /* - * Non-zero value for vendor indicate - * a board being found in this slot. - */ - return 1; - } - return 0; -} - -int -pciio_dma_enabled(devfs_handle_t pconn_vhdl) -{ - return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); -} - -/* - * These are complementary Linux interfaces that takes in a pci_dev * as the - * first arguement instead of devfs_handle_t. - */ -iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); -pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); -void snia_pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -void snia_pciio_dmamap_done(pciio_dmamap_t); -pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, - pciio_endian_t desired_end); - -#include -EXPORT_SYMBOL(snia_pciio_dmatrans_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_alloc); -EXPORT_SYMBOL(snia_pciio_dmamap_free); -EXPORT_SYMBOL(snia_pciio_dmamap_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_done); -EXPORT_SYMBOL(snia_pciio_endian_set); - -pciio_endian_t -snia_pciio_endian_set(struct pci_dev *pci_dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -iopaddr_t -snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -pciio_dmamap_t -snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -void -snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - diff --git a/arch/ia64/sn/io/platform_init/Makefile b/arch/ia64/sn/io/platform_init/Makefile new file mode 100644 index 00000000000..05ffc316269 --- /dev/null +++ b/arch/ia64/sn/io/platform_init/Makefile @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += sgi_io_init.o irix_io_init.o diff --git a/arch/ia64/sn/io/platform_init/irix_io_init.c b/arch/ia64/sn/io/platform_init/irix_io_init.c new file mode 100644 index 00000000000..25dbcef02d3 --- /dev/null +++ b/arch/ia64/sn/io/platform_init/irix_io_init.c @@ -0,0 +1,88 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void init_all_devices(void); +extern void klhwg_add_all_modules(vertex_hdl_t); +extern void klhwg_add_all_nodes(vertex_hdl_t); + +extern vertex_hdl_t hwgraph_root; +extern void io_module_init(void); +extern int pci_bus_to_hcl_cvlink(void); +extern void mlreset(void); + +/* #define DEBUG_IO_INIT 1 */ +#ifdef DEBUG_IO_INIT +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_IO_INIT */ + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +irix_io_init(void) +{ + cnodeid_t cnode; + + /* + * This is the Master CPU. Emulate mlsetup and main.c in Irix. + */ + mlreset(); + + /* + * Initialize platform-dependent vertices in the hwgraph: + * module + * node + * cpu + * memory + * slot + * hub + * router + * xbow + */ + + io_module_init(); /* Use to be called module_init() .. */ + klhwg_add_all_modules(hwgraph_root); + klhwg_add_all_nodes(hwgraph_root); + + for (cnode = 0; cnode < numnodes; cnode++) { + extern void per_hub_init(cnodeid_t); + per_hub_init(cnode); + } + + /* We can do headless hub cnodes here .. */ + + /* + * + * Our IO Infrastructure drivers are in place .. + * Initialize the whole IO Infrastructure .. xwidget/device probes. + * + */ + init_all_devices(); + pci_bus_to_hcl_cvlink(); +} diff --git a/arch/ia64/sn/io/platform_init/sgi_io_init.c b/arch/ia64/sn/io/platform_init/sgi_io_init.c new file mode 100644 index 00000000000..3583456b1cc --- /dev/null +++ b/arch/ia64/sn/io/platform_init/sgi_io_init.c @@ -0,0 +1,109 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int init_hcl(void); + +/* + * per_hub_init + * + * This code is executed once for each Hub chip. + */ +void +per_hub_init(cnodeid_t cnode) +{ + nasid_t nasid; + nodepda_t *npdap; + ii_icmr_u_t ii_icmr; + ii_ibcr_u_t ii_ibcr; + ii_ilcsr_u_t ii_ilcsr; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + ASSERT(nasid != INVALID_NASID); + ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); + + npdap = NODEPDA(cnode); + + /* Disable the request and reply errors. */ + REMOTE_HUB_S(nasid, IIO_IWEIM, 0xC000); + + /* + * Set the total number of CRBs that can be used. + */ + ii_icmr.ii_icmr_regval= 0x0; + ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; + if (enable_shub_wars_1_1() ) { + // Set bit one of ICMR to prevent II from sending interrupt for II bug. + ii_icmr.ii_icmr_regval |= 0x1; + } + REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); + + /* + * Set the number of CRBs that both of the BTEs combined + * can use minus 1. + */ + ii_ibcr.ii_ibcr_regval= 0x0; + ii_ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(nasid, IIO_LLP_CSR); + if (ii_ilcsr.ii_ilcsr_fld_s.i_llp_stat & LNK_STAT_WORKING) { + ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; + } else { + /* + * if the LLP is down, there is no attached I/O, so + * give BTE all the CRBs. + */ + ii_ibcr.ii_ibcr_fld_s.i_count = 0x14; + } + REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); + + /* + * Set CRB timeout to be 10ms. + */ + REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff ); + REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); + + /* Initialize error interrupts for this hub. */ + hub_error_init(cnode); +} + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +sgi_master_io_infr_init(void) +{ + extern void irix_io_init(void); + + init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ + irix_io_init(); /* Do IRIX Compatibility IO Init */ + +#ifdef CONFIG_KDB + { + extern void kdba_io_init(void); + kdba_io_init(); + } +#endif + +} diff --git a/arch/ia64/sn/io/sgi_if.c b/arch/ia64/sn/io/sgi_if.c index 2303cba48f3..a4d65390113 100644 --- a/arch/ia64/sn/io/sgi_if.c +++ b/arch/ia64/sn/io/sgi_if.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -20,8 +20,6 @@ #include #include -unsigned char Is_pic_on_this_nasid[512]; /* non-0 when this is a pic shub */ - void * snia_kmem_zalloc(size_t size, int flag) { @@ -37,13 +35,6 @@ snia_kmem_free(void *ptr, size_t size) kfree(ptr); } -int -nic_vertex_info_match(devfs_handle_t v, char *s) -{ - /* we don't support this */ - return(0); -} - /* * the alloc/free_node routines do a simple kmalloc for now .. */ @@ -104,34 +95,6 @@ atoi(register char *p) return (neg ? n : -n); } -char * -strtok_r(char *string, const char *sepset, char **lasts) -{ - register char *q, *r; - - /*first or subsequent call*/ - if (string == NULL) - string = *lasts; - - if(string == 0) /* return if no tokens remaining */ - return(NULL); - - q = string + strspn(string, sepset); /* skip leading separators */ - - if(*q == '\0') { /* return if no tokens remaining */ - *lasts = 0; /* indicate this is last token */ - return(NULL); - } - - if((r = strpbrk(q, sepset)) == NULL) /* move past token */ - *lasts = 0; /* indicate this is last token */ - else { - *r = '\0'; - *lasts = r+1; - } - return(q); -} - /* * print_register() allows formatted printing of bit fields. individual * bit fields are described by a struct reg_desc, multiple bit fields within diff --git a/arch/ia64/sn/io/sgi_io_init.c b/arch/ia64/sn/io/sgi_io_init.c deleted file mode 100644 index c984fe6b711..00000000000 --- a/arch/ia64/sn/io/sgi_io_init.c +++ /dev/null @@ -1,308 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void mlreset(int ); -extern int init_hcl(void); -extern void klgraph_hack_init(void); -extern void hubspc_init(void); -extern void pciio_init(void); -extern void pcibr_init(void); -extern void xtalk_init(void); -extern void xbow_init(void); -extern void xbmon_init(void); -extern void pciiox_init(void); -extern void usrpci_init(void); -extern void ioc3_init(void); -extern void initialize_io(void); -#if defined(CONFIG_IA64_SGI_SN1) -extern void intr_clear_all(nasid_t); -#endif -extern void klhwg_add_all_modules(devfs_handle_t); -extern void klhwg_add_all_nodes(devfs_handle_t); - -void sn_mp_setup(void); -extern devfs_handle_t hwgraph_root; -extern void io_module_init(void); -extern void pci_bus_cvlink_init(void); -extern void temp_hack(void); - -extern int pci_bus_to_hcl_cvlink(void); - -/* #define DEBUG_IO_INIT */ -#ifdef DEBUG_IO_INIT -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_IO_INIT */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - npdap = NODEPDA(cnode); - -#if defined(CONFIG_IA64_SGI_SN1) - /* initialize per-node synergy perf instrumentation */ - npdap->synergy_perf_enabled = 0; /* off by default */ - npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; - npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; - npdap->synergy_inactive_intervals = 0; - npdap->synergy_active_intervals = 0; - npdap->synergy_perf_data = NULL; - npdap->synergy_perf_first = NULL; -#endif /* CONFIG_IA64_SGI_SN1 */ - - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - - -#if defined(CONFIG_IA64_SGI_SN1) - /* Reserve all of the hardwired interrupt levels. */ - intr_reserve_hardwired(cnode); -#endif - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn1_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn1_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void -sgi_master_io_infr_init(void) -{ - int cnode; - - /* - * Do any early init stuff .. einit_tbl[] etc. - */ - DBG("--> sgi_master_io_infr_init: calling init_hcl().\n"); - init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ - - /* - * initialize the Linux PCI to xwidget vertexes .. - */ - DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n"); - pci_bus_cvlink_init(); - -#ifdef BRINGUP -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Hack to provide statically initialzed klgraph entries. - */ - DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); - klgraph_hack_init(); -#endif /* CONFIG_IA64_SGI_SN1 */ -#endif /* BRINGUP */ - - /* - * This is the Master CPU. Emulate mlsetup and main.c in Irix. - */ - DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n"); - mlreset(0); /* Master .. */ - - /* - * allowboot() is called by kern/os/main.c in main() - * Emulate allowboot() ... - * per_cpu_init() - only need per_hub_init() - * cpu_io_setup() - Nothing to do. - * - */ - DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n"); - sn_mp_setup(); - - DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - for (cnode = 0; cnode < numnodes; cnode++) { - per_hub_init(cnode); - } - - /* We can do headless hub cnodes here .. */ - - /* - * io_init[] stuff. - * - * Get SGI IO Infrastructure drivers to init and register with - * each other etc. - */ - - DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n"); - hubspc_init(); - - DBG("--> sgi_master_io_infr_init: calling pciio_init()\n"); - pciio_init(); - - DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n"); - pcibr_init(); - - DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n"); - xtalk_init(); - - DBG("--> sgi_master_io_infr_init: calling xbow_init()\n"); - xbow_init(); - - DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n"); - xbmon_init(); - - DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n"); - pciiox_init(); - - DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n"); - usrpci_init(); - - DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n"); - ioc3_init(); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n"); - initialize_io(); - - DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n"); - pci_bus_to_hcl_cvlink(); - -#ifdef CONFIG_PCIBA - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); - pciba_init(); -#endif - - DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n"); -} - -/* - * sgi_slave_io_infr_init - This routine must be called on all cpus except - * the Master CPU. - */ -void -sgi_slave_io_infr_init(void) -{ - /* Emulate cboot() .. */ - mlreset(1); /* This is a slave cpu */ - - // per_hub_init(0); /* Need to get and send in actual cnode number */ - - /* Done */ -} - -/* - * One-time setup for MP SN. - * Allocate per-node data, slurp prom klconfig information and - * convert it to hwgraph information. - */ -void -sn_mp_setup(void) -{ - cnodeid_t cnode; - cpuid_t cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - DBG("sn_mp_io_setup: calling io_module_init()\n"); - io_module_init(); /* Use to be called module_init() .. */ - - DBG("sn_mp_setup: calling klhwg_add_all_modules()\n"); - klhwg_add_all_modules(hwgraph_root); - DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); - klhwg_add_all_nodes(hwgraph_root); - - - for (cnode = 0; cnode < numnodes; cnode++) { - - /* - * This routine clears the Hub's Interrupt registers. - */ - /* - * We need to move this intr_clear_all() routine - * from SN/intr.c to a more appropriate file. - * Talk to Al Mayer. - */ -#if defined(CONFIG_IA64_SGI_SN1) - intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); -#endif - /* now init the hub */ - // per_hub_init(cnode); - - } - -#if defined(CONFIG_IA64_SGI_SN1) - synergy_perf_init(); -#endif - -} diff --git a/arch/ia64/sn/io/sgi_io_sim.c b/arch/ia64/sn/io/sgi_io_sim.c index ba119a2cd8e..056fb53d09a 100644 --- a/arch/ia64/sn/io/sgi_io_sim.c +++ b/arch/ia64/sn/io/sgi_io_sim.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -15,18 +15,11 @@ #include #include #include -#include #include -cpuid_t master_procid = 0; +cpuid_t master_procid; char arg_maxnodes[4]; -extern void init_all_devices(void); - -#if defined(CONFIG_IA64_SGI_SN1) -synergy_da_t *Synergy_da_indr[MAX_COMPACT_NODES * 2]; -#endif - /* * Return non-zero if the given variable was specified */ @@ -36,44 +29,12 @@ is_specified(char *s) return (strlen(s) != 0); } -void xbmon_init(void) -{ - FIXME("xbmon_init : no-op\n"); - -} - -void pciiox_init(void) -{ - FIXME("pciiox_init : no-op\n"); - -} - -void usrpci_init(void) -{ - FIXME("usrpci_init : no-op\n"); - -} - -void ioc3_init(void) -{ - FIXME("ioc3_init : no-op\n"); - -} - -void initialize_io(void) -{ - - init_all_devices(); -} - /* * Routines provided by ml/SN/promif.c. */ -static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; +static __psunsigned_t master_bridge_base; nasid_t console_nasid = (nasid_t)-1; -#if !defined(CONFIG_IA64_SGI_SN1) char master_baseio_wid; -#endif static char console_wid; static char console_pcislot; @@ -95,27 +56,6 @@ check_nasid_equiv(nasid_t nasida, nasid_t nasidb) return 0; } -#if defined(CONFIG_IA64_SGI_SN1) -int -is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) -{ - - /* - * If the widget numbers are different, we're not the master. - */ - if (test_wid != (xwidgetnum_t)console_wid) - return 0; - - /* - * If the NASIDs are the same or equivalent, we're the master. - */ - if (check_nasid_equiv(test_nasid, console_nasid)) { - return 1; - } else { - return 0; - } -} -#else int is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) { @@ -137,14 +77,3 @@ is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) return 0; } } -#endif /* CONFIG_IA64_SGI_SN1 */ - -/* - * Routines provided by ml/SN/nvram.c - */ -void -nvram_baseinit(void) -{ - FIXME("nvram_baseinit : no-op\n"); - -} diff --git a/arch/ia64/sn/io/sn1/hub_intr.c b/arch/ia64/sn/io/sn1/hub_intr.c deleted file mode 100644 index 474f6c6b285..00000000000 --- a/arch/ia64/sn/io/sn1/hub_intr.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $Id: hub_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern xtalk_provider_t hub_provider; - -/* ARGSUSED */ -void -hub_intr_init(devfs_handle_t hubv) -{ -} - -/* - * hub_device_desc_update - * Update the passed in device descriptor with the actual the - * target cpu number and interrupt priority level. - * NOTE : These might be the same as the ones passed in thru - * the descriptor. - */ -static void -hub_device_desc_update(device_desc_t dev_desc, - ilvl_t intr_swlevel, - cpuid_t cpu) -{ -} - -int allocate_my_bit = INTRCONNECT_ANYBIT; - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -static hub_intr_t -do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev, /* owner of this interrupt, if known */ - int uncond_nothread) /* unconditionally non-threaded */ -{ - cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ - int cpupicked = 0; - int bit; /* interrupt vector */ - /*REFERENCED*/ - int intr_resflags = 0; - hub_intr_t intr_hdl; - cnodeid_t nodeid; /* node to receive interrupt */ - /*REFERENCED*/ - nasid_t nasid; /* nasid to receive interrupt */ - struct xtalk_intr_s *xtalk_info; - iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */ - xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */ - char *intr_name = NULL; - ilvl_t intr_swlevel = (ilvl_t)0; - extern int default_intr_pri; - extern void synergy_intr_alloc(int, int); - - - if (dev_desc) { - if (dev_desc->flags & D_INTR_ISERR) { - intr_resflags = II_ERRORINT; - } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { - intr_resflags = II_THREADED; - } else { - /* Neither an error nor a thread. */ - intr_resflags = 0; - } - } else { - intr_swlevel = default_intr_pri; - if (!uncond_nothread) - intr_resflags = II_THREADED; - } - - /* XXX - Need to determine if the interrupt should be threaded. */ - - /* If the cpu has not been picked already then choose a candidate - * interrupt target and reserve the interrupt bit - */ - if (!cpupicked) { - cpu = intr_heuristic(dev,dev_desc,allocate_my_bit, - intr_resflags,owner_dev, - intr_name,&bit); - } - - /* At this point we SHOULD have a valid cpu */ - if (cpu == CPU_NONE) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v hub_intr_alloc could not allocate interrupt\n", - owner_dev); -#else - printk(KERN_WARNING "%p hub_intr_alloc could not allocate interrupt\n", - (void *)owner_dev); -#endif - return(0); - - } - - /* If the cpu has been picked already (due to the bridge data - * corruption bug) then try to reserve an interrupt bit . - */ - if (cpupicked) { - bit = intr_reserve_level(cpu, allocate_my_bit, - intr_resflags, - owner_dev, intr_name); - if (bit < 0) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " - " %d and dev %v\n", - cpu,owner_dev); -#else - printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " - " %d and dev %p\n", - (int)cpu, (void *)owner_dev); -#endif - - return(0); - } - } - - nodeid = cpuid_to_cnodeid(cpu); - nasid = cpuid_to_nasid(cpu); - xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu))); - - /* - * Allocate an interrupt handle, and fill it in. There are two - * pieces to an interrupt handle: the piece needed by generic - * xtalk code which is used by crosstalk device drivers, and - * the piece needed by low-level IP27 hardware code. - */ - intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid); - ASSERT_ALWAYS(intr_hdl); - - /* - * Fill in xtalk information for generic xtalk interfaces that - * operate on xtalk_intr_hdl's. - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = dev; - xtalk_info->xi_vector = bit; - xtalk_info->xi_addr = xtalk_addr; - - /* - * Regardless of which CPU we ultimately interrupt, a given crosstalk - * widget always handles interrupts (and PIO and DMA) through its - * designated "master" crosstalk provider. - */ - xwidget_info = xwidget_info_get(dev); - if (xwidget_info) - xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); - - /* Fill in low level hub information for hub_* interrupt interface */ - intr_hdl->i_swlevel = intr_swlevel; - intr_hdl->i_cpuid = cpu; - intr_hdl->i_bit = bit; - intr_hdl->i_flags = HUB_INTR_IS_ALLOCED; - - /* Store the actual interrupt priority level & interrupt target - * cpu back in the device descriptor. - */ - hub_device_desc_update(dev_desc, intr_swlevel, cpu); - synergy_intr_alloc((int)bit, (int)cpu); - return(intr_hdl); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Uncondtionally request non-threaded, regardless of what the device - * descriptor might say. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -hub_intr_free(hub_intr_t intr_hdl) -{ - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_t xtalk_info; - - if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { - /* Setting the following fields in the xtalk interrupt info - * clears the interrupt target register in the xtalk user - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = NODEV; - xtalk_info->xi_vector = 0; - xtalk_info->xi_addr = 0; - hub_intr_disconnect(intr_hdl); - } - - if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) - kfree(intr_hdl); - - intr_unreserve_level(cpu, bit); -} - - -/* - * Associate resources allocated with a previous hub_intr_alloc call with the - * described handler, arg, name, etc. - */ -/*ARGSUSED*/ -int -hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - extern int synergy_intr_connect(int, int); - - ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); - - rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, NULL); - if (rv < 0) - return(rv); - - intr_hdl->i_xtalk_info.xi_setfunc = setfunc; - intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; - - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; - return(synergy_intr_connect((int)bit, (int)cpu)); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -hub_intr_disconnect(hub_intr_t intr_hdl) -{ - /*REFERENCED*/ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_setfunc_t setfunc; - - setfunc = intr_hdl->i_xtalk_info.xi_setfunc; - - /* TBD: send disconnected interrupts somewhere harmless */ - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - rv = intr_disconnect_level(cpu, bit); - ASSERT(rv == 0); - intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl) -{ - cpuid_t cpuid = intr_hdl->i_cpuid; - ASSERT(cpuid != CPU_NONE); - - return(cpuid_to_vertex(cpuid)); -} diff --git a/arch/ia64/sn/io/sn1/hubcounters.c b/arch/ia64/sn/io/sn1/hubcounters.c deleted file mode 100644 index 0d3717fb69b..00000000000 --- a/arch/ia64/sn/io/sn1/hubcounters.c +++ /dev/null @@ -1,283 +0,0 @@ -/* $Id: hubcounters.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. - * All rights reserved. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_error_handler(char *, int); /* huberror.c */ - -static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -struct file_operations hub_mon_fops = { - ioctl: hubstats_ioctl, -}; - -#define HUB_CAPTURE_TICKS (2 * HZ) - -#define HUB_ERR_THRESH 500 -#define USEC_PER_SEC 1000000 -#define NSEC_PER_SEC USEC_PER_SEC*1000 - -volatile int hub_print_usecs = 600 * USEC_PER_SEC; - -/* Return success if the hub's crosstalk link is working */ -int -hub_xtalk_link_up(nasid_t nasid) -{ - hubreg_t llp_csr_reg; - - /* Read the IO LLP control status register */ - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - - /* Check if the xtalk link is working */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) - return(1); - - return(0); - - -} - -static char *error_flag_to_type(unsigned char error_flag) -{ - switch(error_flag) { - case 0x1: return ("NI retries"); - case 0x2: return ("NI SN errors"); - case 0x4: return ("NI CB errors"); - case 0x8: return ("II CB errors"); - case 0x10: return ("II SN errors"); - default: return ("Errors"); - } -} - -int -print_hub_error(hubstat_t *hsp, hubreg_t reg, - int64_t delta, unsigned char error_flag) -{ - int64_t rate; - - reg *= hsp->hs_per_minute; /* Convert to minutes */ - rate = reg / delta; - - if (rate > HUB_ERR_THRESH) { - - if(hsp->hs_maint & error_flag) - { - printk( "Excessive %s (%ld/min) on %s", - error_flag_to_type(error_flag), rate, hsp->hs_name); - } - else - { - hsp->hs_maint |= error_flag; - printk( "Excessive %s (%ld/min) on %s", - error_flag_to_type(error_flag), rate, hsp->hs_name); - } - return 1; - } else { - return 0; - } -} - - -int -check_hub_error_rates(hubstat_t *hsp) -{ - int64_t delta = hsp->hs_timestamp - hsp->hs_timebase; - int printed = 0; - - printed += print_hub_error(hsp, hsp->hs_ni_retry_errors, - delta, 0x1); - -#if 0 - printed += print_hub_error(hsp, hsp->hs_ni_sn_errors, - delta, 0x2); -#endif - - printed += print_hub_error(hsp, hsp->hs_ni_cb_errors, - delta, 0x4); - - - /* If the hub's xtalk link is not working there is - * no need to print the "Excessive..." warning - * messages - */ - if (!hub_xtalk_link_up(hsp->hs_nasid)) - return(printed); - - - printed += print_hub_error(hsp, hsp->hs_ii_cb_errors, - delta, 0x8); - - printed += print_hub_error(hsp, hsp->hs_ii_sn_errors, - delta, 0x10); - - return printed; -} - - -void -capture_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) -{ - nasid_t nasid; - hubstat_t *hsp = &(npda->hubstats); - hubreg_t port_error; - ii_illr_u_t illr; - int count; - int overflow = 0; - - /* - * If our link wasn't up at boot time, don't worry about error rates. - */ - if (!(hsp->hs_ni_port_status & NPS_LINKUP_MASK)) { - printk("capture_hub_stats: cnode=%d hs_ni_port_status=0x%016lx : link is not up\n", - cnodeid, hsp->hs_ni_port_status); - return; - } - - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - - hsp->hs_timestamp = GET_RTC_COUNTER(); - - port_error = REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); - count = ((port_error & NPE_RETRYCOUNT_MASK) >> NPE_RETRYCOUNT_SHFT); - hsp->hs_ni_retry_errors += count; - if (count == NPE_COUNT_MAX) - overflow = 1; - count = ((port_error & NPE_SNERRCOUNT_MASK) >> NPE_SNERRCOUNT_SHFT); - hsp->hs_ni_sn_errors += count; - if (count == NPE_COUNT_MAX) - overflow = 1; - count = ((port_error & NPE_CBERRCOUNT_MASK) >> NPE_CBERRCOUNT_SHFT); - hsp->hs_ni_cb_errors += count; - if (overflow || count == NPE_COUNT_MAX) - hsp->hs_ni_overflows++; - - if (port_error & NPE_FATAL_ERRORS) { -#ifdef ajm - hubni_error_handler("capture_hub_stats", 1); -#else - printk("Error: hubni_error_handler in capture_hub_stats"); -#endif - } - - illr.ii_illr_regval = REMOTE_HUB_L(nasid, IIO_LLP_LOG); - REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); - - hsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt; - hsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt; - if ((illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) || - (illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX)) - hsp->hs_ii_overflows++; - - if (hsp->hs_print) { - if (check_hub_error_rates(hsp)) { - hsp->hs_last_print = GET_RTC_COUNTER(); - hsp->hs_print = 0; - } - } else { - if ((GET_RTC_COUNTER() - - hsp->hs_last_print) > hub_print_usecs) - hsp->hs_print = 1; - } - - npda->hubticks = HUB_CAPTURE_TICKS; -} - - -void -init_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) -{ - hubstat_t *hsp = &(npda->hubstats); - nasid_t nasid = cnodeid_to_nasid(cnodeid); - bzero(&(npda->hubstats), sizeof(hubstat_t)); - - hsp->hs_version = HUBSTAT_VERSION; - hsp->hs_cnode = cnodeid; - hsp->hs_nasid = nasid; - hsp->hs_timebase = GET_RTC_COUNTER(); - hsp->hs_ni_port_status = REMOTE_HUB_L(nasid, NI_PORT_STATUS); - - /* Clear the II error counts. */ - REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); - - /* Clear the NI counts. */ - REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); - - hsp->hs_per_minute = (long long)RTC_CYCLES_PER_SEC * 60LL; - - npda->hubticks = HUB_CAPTURE_TICKS; - - /* XX should use kmem_alloc_node */ - hsp->hs_name = (char *)kmalloc(MAX_HUB_PATH, GFP_KERNEL); - ASSERT_ALWAYS(hsp->hs_name); - - sprintf(hsp->hs_name, "/dev/hw/" EDGE_LBL_MODULE "/%03d/" - EDGE_LBL_NODE "/" EDGE_LBL_HUB, - npda->module_id); - - hsp->hs_last_print = 0; - hsp->hs_print = 1; - - hub_print_usecs = hub_print_usecs; - -#if 0 - printk("init_hub_stats: cnode=%d nasid=%d hs_version=%d hs_ni_port_status=0x%016lx\n", - cnodeid, nasid, hsp->hs_version, hsp->hs_ni_port_status); -#endif -} - -static int -hubstats_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - cnodeid_t cnode; - nodepda_t *npdap; - uint64_t longarg; - devfs_handle_t d; - - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; - cnode = (cnodeid_t)hwgraph_fastinfo_get(d); - npdap = NODEPDA(cnode); - - if (npdap->hubstats.hs_version != HUBSTAT_VERSION) { - init_hub_stats(cnode, npdap); - } - - switch (cmd) { - case SNDRV_GET_INFOSIZE: - longarg = sizeof(hubstat_t); - if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { - return -EFAULT; - } - break; - - case SNDRV_GET_HUBINFO: - /* refresh npda->hubstats */ - capture_hub_stats(cnode, npdap); - if (copy_to_user((void *)arg, &npdap->hubstats, sizeof(hubstat_t))) { - return -EFAULT; - } - break; - - default: - return -EINVAL; - } - - return 0; -} diff --git a/arch/ia64/sn/io/sn1/huberror.c b/arch/ia64/sn/io/sn1/huberror.c deleted file mode 100644 index 67780a759e6..00000000000 --- a/arch/ia64/sn/io/sn1/huberror.c +++ /dev/null @@ -1,228 +0,0 @@ -/* $Id: huberror.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_eint_init(cnodeid_t cnode); -extern void hubii_eint_init(cnodeid_t cnode); -extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - -extern int maxcpus; - -#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ - - -void -hub_error_clear(nasid_t nasid) -{ - int i; - hubreg_t idsr; - int sn; - - for(sn=0; snh_cnodeid == cnode); - - ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); - - if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { - /* - * HUB II link is not up. - * Just disable LLP, and don't connect any interrupts. - */ - ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); - return; - } - /* Select a possible interrupt target where there is a free interrupt - * bit and also reserve the interrupt bit for this IO error interrupt - */ - intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, - "HUB IO error interrupt",&bit); - if (intr_cpu == CPU_NONE) { - printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); - return; - } - - rv = intr_connect_level(intr_cpu, bit, 0, NULL); - synergy_intr_connect(bit, intr_cpu); - request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); - ASSERT_ALWAYS(rv >= 0); - hubio_eint.ii_iidsr_regval = 0; - hubio_eint.ii_iidsr_fld_s.i_enable = 1; - hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ - hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); - hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); - -} - -void -hubni_eint_init(cnodeid_t cnode) -{ - int intr_bit; - cpuid_t targ; - - - if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) - return; - - /* The prom chooses which cpu gets these interrupts, but we - * don't know which one it chose. We will register all of the - * cpus to be sure. This only costs us an irqaction per cpu. - */ - for (; targ < CPUS_PER_NODE; targ++) { - if (!cpu_enabled(targ) ) continue; - /* connect the INTEND1 bits. */ - for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { - intr_connect_level(targ, intr_bit, II_ERRORINT, NULL); - } - request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, "SN hub error", NULL); - /* synergy masks are initialized in the prom to enable all interrupts. */ - /* We'll just leave them that way, here, for these interrupts. */ - } -} - - -/*ARGSUSED*/ -void -hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) -{ - - panic("Hubii interrupt\n"); -} diff --git a/arch/ia64/sn/io/sn1/ip37.c b/arch/ia64/sn/io/sn1/ip37.c deleted file mode 100644 index 2ec567d5498..00000000000 --- a/arch/ia64/sn/io/sn1/ip37.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * ip37.c - * Support for IP35/IP37 machines - */ - -#include - -#include -#include -#include -#include /* for bridge_t */ - - -xwidgetnum_t -hub_widget_id(nasid_t nasid) -{ - hubii_wcr_t ii_wcr; /* the control status register */ - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - - return ii_wcr.wcr_fields_s.wcr_widget_id; -} - -int -is_fine_dirmode(void) -{ - return (((LOCAL_HUB_L(LB_REV_ID) & LRI_SYSTEM_SIZE_MASK) - >> LRI_SYSTEM_SIZE_SHFT) == SYSTEM_SIZE_SMALL); - -} - - -void -ni_reset_port(void) -{ - LOCAL_HUB_S(NI_RESET_ENABLE, NRE_RESETOK); - LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); -} diff --git a/arch/ia64/sn/io/sn1/mem_refcnt.c b/arch/ia64/sn/io/sn1/mem_refcnt.c deleted file mode 100644 index c39f6d22497..00000000000 --- a/arch/ia64/sn/io/sn1/mem_refcnt.c +++ /dev/null @@ -1,220 +0,0 @@ -/* $Id: mem_refcnt.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// From numa_hw.h - -#define MIGR_COUNTER_MAX_GET(nodeid) \ - (NODEPDA_MCD((nodeid))->migr_system_kparms.migr_threshold_reference) -/* - * Get the Absolute Theshold - */ -#define MIGR_THRESHOLD_ABS_GET(nodeid) ( \ - MD_MIG_VALUE_THRESH_GET(COMPACT_TO_NASID_NODEID(nodeid))) -/* - * Get the current Differential Threshold - */ -#define MIGR_THRESHOLD_DIFF_GET(nodeid) \ - (NODEPDA_MCD(nodeid)->migr_as_kparms.migr_base_threshold) - -#define NUM_OF_HW_PAGES_PER_SW_PAGE() (NBPP / MD_PAGE_SIZE) - -// #include "migr_control.h" - -int -mem_refcnt_attach(devfs_handle_t hub) -{ -#if 0 - devfs_handle_t refcnt_dev; - - hwgraph_char_device_add(hub, - "refcnt", - "hubspc_", - &refcnt_dev); - device_info_set(refcnt_dev, (void*)(ulong)HUBSPC_REFCOUNTERS); -#endif - - return (0); -} - - -/*ARGSUSED*/ -int -mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) -{ - cnodeid_t node; - - node = master_node_get(*devp); - - ASSERT( (node >= 0) && (node < numnodes) ); - - if (NODEPDA(node)->migr_refcnt_counterbuffer == NULL) { - return (ENODEV); - } - - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != (size_t)0 ); - - return (0); -} - -/*ARGSUSED*/ -int -mem_refcnt_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED*/ -int -mem_refcnt_mmap(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - cnodeid_t node; - int errcode; - char* buffer; - size_t blen; - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - /* - * XXXX deal with prot's somewhere around here.... - */ - - buffer = NODEPDA(node)->migr_refcnt_counterbuffer; - blen = NODEPDA(node)->migr_refcnt_cbsize; - - /* - * Force offset to be a multiple of sizeof(refcnt_t) - * We round up. - */ - - off = (((off - 1)/sizeof(refcnt_t)) + 1) * sizeof(refcnt_t); - - if ( ((buffer + blen) - (buffer + off + len)) < 0 ) { - return (EPERM); - } - - errcode = v_mapphys(vt, - buffer + off, - len); - - return errcode; -} - -/*ARGSUSED*/ -int -mem_refcnt_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* ARGSUSED */ -int -mem_refcnt_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int mode, - cred_t *cred_p, - int *rvalp) -{ - cnodeid_t node; - int errcode; - extern int numnodes; - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - errcode = 0; - - switch (cmd) { - case RCB_INFO_GET: - { - rcb_info_t rcb; - - rcb.rcb_len = NODEPDA(node)->migr_refcnt_cbsize; - - rcb.rcb_sw_sets = NODEPDA(node)->migr_refcnt_numsets; - rcb.rcb_sw_counters_per_set = numnodes; - rcb.rcb_sw_counter_size = sizeof(refcnt_t); - - rcb.rcb_base_pages = NODEPDA(node)->migr_refcnt_numsets / - NUM_OF_HW_PAGES_PER_SW_PAGE(); - rcb.rcb_base_page_size = NBPP; - rcb.rcb_base_paddr = ctob(slot_getbasepfn(node, 0)); - - rcb.rcb_cnodeid = node; - rcb.rcb_granularity = MD_PAGE_SIZE; -#ifdef LATER - rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); - rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); -#endif - rcb.rcb_abs_threshold = MIGR_THRESHOLD_ABS_GET(node); - rcb.rcb_num_slots = MAX_MEM_SLOTS; - - if (COPYOUT(&rcb, arg, sizeof(rcb_info_t))) { - errcode = EFAULT; - } - - break; - } - case RCB_SLOT_GET: - { - rcb_slot_t slot[MAX_MEM_SLOTS]; - int s; - int nslots; - - nslots = MAX_MEM_SLOTS; - ASSERT(nslots <= MAX_MEM_SLOTS); - for (s = 0; s < nslots; s++) { - slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); -#ifdef LATER - slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); -#else - slot[s].size = (uint64_t)1; -#endif - } - if (COPYOUT(&slot[0], arg, nslots * sizeof(rcb_slot_t))) { - errcode = EFAULT; - } - - *rvalp = nslots; - break; - } - - default: - errcode = EINVAL; - break; - - } - - return errcode; -} diff --git a/arch/ia64/sn/io/sn1/ml_SN_intr.c b/arch/ia64/sn/io/sn1/ml_SN_intr.c deleted file mode 100644 index 510069248a3..00000000000 --- a/arch/ia64/sn/io/sn1/ml_SN_intr.c +++ /dev/null @@ -1,1154 +0,0 @@ -/* $Id: ml_SN_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * intr.c- - * This file contains all of the routines necessary to set up and - * handle interrupts on an IP27 board. - */ - -#ident "$Revision: 1.1 $" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if DEBUG_INTR_TSTAMP_DEBUG -#include -#include -#include -void do_splx_log(int, int); -void spldebug_log_event(int); -#endif - -#ifdef CONFIG_SMP -extern unsigned long cpu_online_map; -#endif -#define cpu_allows_intr(cpu) (1) -// If I understand what's going on with this, 32 should work. -// physmem_maxradius seems to be the maximum number of router -// hops to get from one end of the system to the other. With -// a maximally configured machine, with the dumbest possible -// topology, we would make 32 router hops. For what we're using -// it for, the dumbest possible should suffice. -#define physmem_maxradius() 32 - -#define SUBNODE_ANY (-1) - -extern int nmied; -extern int hub_intr_wakeup_cnt; -extern synergy_da_t *Synergy_da_indr[]; -extern cpuid_t master_procid; - -extern cnodeid_t master_node_get(devfs_handle_t vhdl); - -extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - - -#define INTR_LOCK(vecblk) \ - (s = mutex_spinlock(&(vecblk)->vector_lock)) -#define INTR_UNLOCK(vecblk) \ - mutex_spinunlock(&(vecblk)->vector_lock, s) - -/* - * REACT/Pro - */ - - - -/* - * Find first bit set - * Used outside this file also - */ -int ms1bit(unsigned long x) -{ - int b; - - if (x >> 32) b = 32, x >>= 32; - else b = 0; - if (x >> 16) b += 16, x >>= 16; - if (x >> 8) b += 8, x >>= 8; - if (x >> 4) b += 4, x >>= 4; - if (x >> 2) b += 2, x >>= 2; - - return b + (int) (x >> 1); -} - -/* ARGSUSED */ -void -intr_stray(void *lvl) -{ - printk(KERN_WARNING "Stray Interrupt - level %ld to cpu %d", (long)lvl, smp_processor_id()); -} - -#if defined(DEBUG) - -/* Infrastructure to gather the device - target cpu mapping info */ -#define MAX_DEVICES 1000 /* Reasonable large number . Need not be - * the exact maximum # devices possible. - */ -#define MAX_NAME 100 -typedef struct { - dev_t dev; /* device */ - cpuid_t cpuid; /* target cpu */ - cnodeid_t cnodeid;/* node on which the target cpu is present */ - int bit; /* intr bit reserved */ - char intr_name[MAX_NAME]; /* name of the interrupt */ -} intr_dev_targ_map_t; - -intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; -uint64_t intr_dev_targ_map_size; -spinlock_t intr_dev_targ_map_lock; - -/* Print out the device - target cpu mapping. - * This routine is used only in the idbg command - * "intrmap" - */ -void -intr_dev_targ_map_print(cnodeid_t cnodeid) -{ - int i,j,size = 0; - int print_flag = 0,verbose = 0; - char node_name[10]; - - if (cnodeid != CNODEID_NONE) { - nodepda_t *npda; - - npda = NODEPDA(cnodeid); - for (j=0; jintr_dispatch0.info[i].ii_flags); - qprintf("\n INT_PEND1: "); - for(i = 0 ; i < N_INTPEND_BITS ; i++) - qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags); - } - verbose = 1; - } - qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n", - (verbose ? "All" : "Non-hardwired"), - (cnodeid == CNODEID_NONE) ? "s: All" : node_name); - - qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n"); - for (i = 0 ; i < intr_dev_targ_map_size ; i++) { - - print_flag = 0; - if (verbose) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } else { - if (intr_dev_targ_map[i].dev != 0) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == - intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } - } - if (print_flag) { - size++; - qprintf("%d\t%d\t%d\t%d\t%s\n", - intr_dev_targ_map[i].dev, - intr_dev_targ_map[i].cpuid, - intr_dev_targ_map[i].cnodeid, - intr_dev_targ_map[i].bit, - intr_dev_targ_map[i].intr_name); - } - - } - qprintf("\nTotal : %d\n",size); -} -#endif /* DEBUG */ - -/* - * The spinlocks have already been initialized. Now initialize the interrupt - * vectors. One processor on each hub does the work. - */ -void -intr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn) -{ - int i, ip=0; - intr_vecblk_t *vecblk; - subnode_pda_t *snpda; - - - snpda = SNPDA(npda,sn); - do { - if (ip == 0) { - vecblk = &snpda->intr_dispatch0; - } else { - vecblk = &snpda->intr_dispatch1; - } - - /* Initialize this vector. */ - for (i = 0; i < N_INTPEND_BITS; i++) { - vecblk->vectors[i].iv_func = intr_stray; - vecblk->vectors[i].iv_prefunc = NULL; - vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i); - - vecblk->info[i].ii_owner_dev = 0; - strcpy(vecblk->info[i].ii_name, "Unused"); - vecblk->info[i].ii_flags = 0; /* No flags */ - vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */ - - } - - mutex_spinlock_init(&vecblk->vector_lock); - - vecblk->vector_count = 0; - for (i = 0; i < CPUS_PER_SUBNODE; i++) - vecblk->cpu_count[i] = 0; - - vecblk->vector_state = VECTOR_UNINITED; - - } while (++ip < 2); - -} - - -/* - * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - * devfs_handle_t owner_dev, char *name) - * Internal work routine to reserve or unreserve an interrupt level. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to reserve. -1 means any level - * resflags should include II_ERRORINT if this is an - * error interrupt, II_THREADED if the interrupt handler - * will be threaded, or 0 otherwise. - * reserve should be set to II_RESERVE or II_UNRESERVE - * to get or clear a reservation. - * owner_dev is the device that "owns" this interrupt, if supplied - * name is a human-readable name for this interrupt, if supplied - * intr_reserve_level returns the bit reserved or -1 to indicate an error - */ -static int -do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - devfs_handle_t owner_dev, char *name) -{ - intr_vecblk_t *vecblk; - hub_intmasks_t *hub_intmasks; - unsigned long s; - int rv = 0; - int ip; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - // if (pdaindr[cpu].pda == NULL) return -1; - if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) { - vecblk = hub_intmasks->dispatch0; - ip = 0; - } else { - ASSERT((bit >= N_INTPEND_BITS) || (bit == -1)); - bit -= N_INTPEND_BITS; /* Get position relative to INT_PEND1 reg. */ - vecblk = hub_intmasks->dispatch1; - ip = 1; - } - - INTR_LOCK(vecblk); - - if (bit <= -1) { - bit = 0; - ASSERT(reserve == II_RESERVE); - /* Choose any available level */ - for (; bit < N_INTPEND_BITS; bit++) { - if (!(vecblk->info[bit].ii_flags & II_RESERVE)) { - rv = bit; - break; - } - } - - /* Return -1 if all interrupt levels int this register are taken. */ - if (bit == N_INTPEND_BITS) - rv = -1; - - } else { - /* Reserve a particular level if it's available. */ - if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) { - /* Can't (un)reserve a level that's already (un)reserved. */ - rv = -1; - } else { - rv = bit; - } - } - - /* Reserve the level and bump the count. */ - if (rv != -1) { - if (reserve) { - vecblk->info[bit].ii_flags |= (II_RESERVE | resflags); - vecblk->info[bit].ii_owner_dev = owner_dev; - /* Copy in the name. */ - if (name) - strlcpy(vecblk->info[bit].ii_name, name, - sizeof(vecblk->info[bit].ii_name)); - else - vecblk->info[bit].ii_name[0] = '\0'; - vecblk->vector_count++; - } else { - vecblk->info[bit].ii_flags = 0; /* Clear all the flags */ - vecblk->info[bit].ii_owner_dev = 0; - /* Clear the name. */ - vecblk->info[bit].ii_name[0] = '\0'; - vecblk->vector_count--; - } - } - - INTR_UNLOCK(vecblk); - -#if defined(DEBUG) - if (rv >= 0) { - /* Gather this device - target cpu mapping information - * in a table which can be used later by the idbg "intrmap" - * command - */ - s = mutex_spinlock(&intr_dev_targ_map_lock); - if (intr_dev_targ_map_size < MAX_DEVICES) { - intr_dev_targ_map_t *p; - - p = &intr_dev_targ_map[intr_dev_targ_map_size]; - p->dev = owner_dev; - p->cpuid = cpu; - p->cnodeid = cpuid_to_cnodeid(cpu); - p->bit = ip * N_INTPEND_BITS + rv; - if (name) - strlcpy(p->intr_name, name, sizeof(p->intr_name)); - else - p->intr_name[0] = '\0'; - intr_dev_targ_map_size++; - } - mutex_spinunlock(&intr_dev_targ_map_lock,s); - } -#endif /* DEBUG */ - - return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ; -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Reserve an interrupt level. - */ -int -intr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name) -{ - return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name)); -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Unreserve an interrupt level. - */ -void -intr_unreserve_level(cpuid_t cpu, int bit) -{ - (void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL); -} - -/* - * Get values that vary depending on which CPU and bit we're operating on - */ -static hub_intmasks_t * -intr_get_ptrs(cpuid_t cpu, int bit, - int *new_bit, /* Bit relative to the register */ - hubreg_t **intpend_masks, /* Masks for this register */ - intr_vecblk_t **vecblk, /* Vecblock for this interrupt */ - int *ip) /* Which intpend register */ -{ - hub_intmasks_t *hub_intmasks; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - if (bit < N_INTPEND_BITS) { - *intpend_masks = hub_intmasks->intpend0_masks; - *vecblk = hub_intmasks->dispatch0; - *ip = 0; - *new_bit = bit; - } else { - *intpend_masks = hub_intmasks->intpend1_masks; - *vecblk = hub_intmasks->dispatch1; - *ip = 1; - *new_bit = bit - N_INTPEND_BITS; - } - - return hub_intmasks; -} - - -/* - * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, - * intr_func_t intr_func, void *intr_arg); - * This is the lowest-level interface to the interrupt code. It shouldn't - * be called from outside the ml/SN directory. - * intr_connect_level hooks up an interrupt to a particular bit in - * the INT_PEND0/1 masks. Returns 0 on success. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to connect to - * intr_swlevel tells which software level to use - * intr_func is the interrupt handler - * intr_arg is an arbitrary argument interpreted by the handler - * intr_prefunc is a prologue function, to be called - * with interrupts disabled, to disable - * the interrupt at source. It is called - * with the same argument. Should be NULL for - * typical interrupts, which can be masked - * by the infrastructure at the level bit. - * intr_connect_level returns 0 on success or nonzero on an error - */ -/* ARGSUSED */ -int -intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, intr_func_t intr_prefunc) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - int rv = 0; - int ip; - unsigned long s; - - ASSERT(bit < N_INTPEND_BITS * 2); - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & II_INUSE) || - (!(vecblk->info[bit].ii_flags & II_RESERVE))) { - /* Can't assign to a level that's in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_prefunc = intr_prefunc; - vecblk->info[bit].ii_flags |= II_INUSE; - } - - /* Now stuff the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - // nasid_t nasid = COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)); - nasid_t nasid = cpuid_to_nasid(cpu); - int subnode = cpuid_to_subnode(cpu); - - /* Make sure it's not already pending when we connect it. */ - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS); - - if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { - intpend_masks[0] |= (1ULL << (uint64_t)bit); - } - - lslice = cpuid_to_localslice(cpu); - vecblk->cpu_count[lslice]++; -#if SN1 - /* - * On SN1, there are 8 interrupt mask registers per node: - * PI_0 MASK_0 A - * PI_0 MASK_1 A - * PI_0 MASK_0 B - * PI_0 MASK_1 B - * PI_1 MASK_0 A - * PI_1 MASK_1 A - * PI_1 MASK_0 B - * PI_1 MASK_1 B - */ -#endif - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice); - } - - HUB_S(mask_reg, intpend_masks[0]); - } - - INTR_UNLOCK(vecblk); - - return rv; -} - - -/* - * intr_disconnect_level(cpuid_t cpu, int bit) - * - * This is the lowest-level interface to the interrupt code. It should - * not be called from outside the ml/SN directory. - * intr_disconnect_level removes a particular bit from an interrupt in - * the INT_PEND0/1 masks. Returns 0 on success or nonzero on failure. - */ -int -intr_disconnect_level(cpuid_t cpu, int bit) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - unsigned long s; - int rv = 0; - int ip; - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) != - ((II_RESERVE | II_INUSE))) { - /* Can't remove a level that's not in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_func = (intr_func_t)NULL; - vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL; - vecblk->vectors[bit].iv_arg = 0; - vecblk->info[bit].ii_flags &= ~II_INUSE; -#ifdef BASE_ITHRTEAD - vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */ -#endif - } - - /* Now clear the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - lslice = cpuid_to_localslice(cpu); - vecblk->cpu_count[lslice]--; - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), - ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A); - mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg + - (PI_INT_MASK_OFFSET * lslice)); - *mask_reg = intpend_masks[0]; - } - - INTR_UNLOCK(vecblk); - - return rv; -} - -/* - * Actually block or unblock an interrupt - */ -void -do_intr_block_bit(cpuid_t cpu, int bit, int block) -{ - intr_vecblk_t *vecblk; - int ip; - unsigned long s; - hubreg_t *intpend_masks; - volatile hubreg_t mask_value; - volatile hubreg_t *mask_reg; - - intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip); - - INTR_LOCK(vecblk); - - if (block) - /* Block */ - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - else - /* Unblock */ - intpend_masks[0] |= (1ULL << (uint64_t)bit); - - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK0_A); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK1_A); - } - - HUB_S(mask_reg, intpend_masks[0]); - - /* - * Wait for it to take effect. (One read should suffice.) - * This is only necessary when blocking an interrupt - */ - if (block) - while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0]) - ; - - INTR_UNLOCK(vecblk); -} - - -/* - * Block a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_block_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 1); -} - - -/* - * Unblock a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_unblock_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 0); -} - - -/* verifies that the specified CPUID is on the specified SUBNODE (if any) */ -#define cpu_on_subnode(cpuid, which_subnode) \ - (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode))) - - -/* - * Choose one of the CPUs on a specified node or subnode to receive - * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu. - * - * Among all acceptable CPUs, the CPU that has the fewest total number - * of interrupts targetted towards it is chosen. Note that we never - * consider how frequent each of these interrupts might occur, so a rare - * hardware error interrupt is weighted equally with a disk interrupt. - */ -static cpuid_t -do_intr_cpu_choose(cnodeid_t cnode, int which_subnode) -{ - cpuid_t cpu, best_cpu = CPU_NONE; - int slice, min_count=1000; - - min_count = 1000; - for (slice=0; slice < CPUS_PER_NODE; slice++) { - intr_vecblk_t *vecblk0, *vecblk1; - int total_intrs_to_slice; - subnode_pda_t *snpda; - int local_cpu_num; - - cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) - continue; - - /* If this cpu isn't enabled for interrupts, skip it */ - if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu)) - continue; - - /* If this isn't the right subnode, skip it */ - if (!cpu_on_subnode(cpu, which_subnode)) - continue; - - /* OK, this one's a potential CPU for interrupts */ - snpda = SUBNODEPDA(cnode,SUBNODE(slice)); - vecblk0 = &snpda->intr_dispatch0; - vecblk1 = &snpda->intr_dispatch1; - local_cpu_num = LOCALCPU(slice); - total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] + - vecblk1->cpu_count[local_cpu_num]; - - if (min_count > total_intrs_to_slice) { - min_count = total_intrs_to_slice; - best_cpu = cpu; - } - } - return best_cpu; -} - -/* - * Choose an appropriate interrupt target CPU on a specified node. - * If which_subnode is SUBNODE_ANY, then subnode is not considered. - * Otherwise, the chosen CPU must be on the specified subnode. - */ -static cpuid_t -intr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode) -{ - return(do_intr_cpu_choose(cnode, which_subnode)); -} - - -/* Make it easy to identify subnode vertices in the hwgraph */ -void -mark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode) -{ - graph_error_t rv; - - ASSERT(0 <= which_subnode); - ASSERT(which_subnode < NUM_SUBNODES); - - rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); - - rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t)); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); -} - - -/* - * Given a device descriptor, extract interrupt target information and - * choose an appropriate CPU. Return CPU_NONE if we can't make sense - * out of the target information. - * TBD: Should this be considered platform-independent code? - */ - - -/* - * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags, - * owner_dev,intr_name,*resp_bit) - * Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but - * not both. - * 1. If cpuid is specified, this routine tests if this cpu can be a valid - * interrupt target candidate. - * 2. If cnodeid is specified, this routine tests if there is a cpu on - * this node which can be a valid interrupt target candidate. - * 3. If a valid interrupt target cpu candidate is found then an attempt at - * reserving an interrupt bit on the corresponding cnode is made. - * - * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid - * interrupt target cpu then routine returns CPU_NONE (failure) - * Otherwise routine returns cpuid of interrupt target (success) - */ -static cpuid_t -intr_bit_reserve_test(cpuid_t cpuid, - int favor_subnode, - cnodeid_t cnodeid, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - - ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE)); - - if (cnodeid != CNODEID_NONE) { - /* Try to choose a interrupt cpu candidate */ - cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode); - } - - if (cpuid != CPU_NONE) { - /* Try to reserve an interrupt bit on the hub - * corresponding to the canidate cnode. If we - * are successful then we got a cpu which can - * act as an interrupt target for the io device. - * Otherwise we need to continue the search - * further. - */ - *resp_bit = do_intr_reserve_level(cpuid, - req_bit, - intr_resflags, - II_RESERVE, - owner_dev, - intr_name); - - if (*resp_bit >= 0) - /* The interrupt target specified was fine */ - return(cpuid); - } - return(CPU_NONE); -} -/* - * intr_heuristic(dev_t dev,device_desc_t dev_desc, - * int req_bit,int intr_resflags,dev_t owner_dev, - * char *intr_name,int *resp_bit) - * - * Choose an interrupt destination for an interrupt. - * dev is the device for which the interrupt is being set up - * dev_desc is a description of hardware and policy that could - * help determine where this interrupt should go - * req_bit is the interrupt bit requested - * (can be INTRCONNECT_ANY_BIT in which the first available - * interrupt bit is used) - * intr_resflags indicates whether we want to (un)reserve bit - * owner_dev is the owner device - * intr_name is the readable interrupt name - * resp_bit indicates whether we succeeded in getting the required - * action { (un)reservation} done - * negative value indicates failure - * - */ -/* ARGSUSED */ -cpuid_t -intr_heuristic(devfs_handle_t dev, - device_desc_t dev_desc, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - cpuid_t cpuid; /* possible intr targ*/ - cnodeid_t candidate; /* possible canidate */ - int which_subnode = SUBNODE_ANY; - -/* SN1 + pcibr Addressing Limitation */ - { - devfs_handle_t pconn_vhdl; - pcibr_soft_t pcibr_soft; - - /* - * This combination of SN1 and Bridge hardware has an odd "limitation". - * Due to the choice of addresses for PI0 and PI1 registers on SN1 - * and historical limitations in Bridge, Bridge is unable to - * send interrupts to both PI0 CPUs and PI1 CPUs -- we have - * to choose one set or the other. That choice is implicitly - * made when Bridge first attaches its error interrupt. After - * that point, all subsequent interrupts are restricted to the - * same PI number (though it's possible to send interrupts to - * the same PI number on a different node). - * - * Since neither SN1 nor Bridge designers are willing to admit a - * bug, we can't really call this a "workaround". It's a permanent - * solution for an SN1-specific and Bridge-specific hardware - * limitation that won't ever be lifted. - */ - if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && - ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) { - /* - * We "know" that the error interrupt is the first - * interrupt set up by pcibr_attach. Send all interrupts - * on this bridge to the same subnode number. - */ - if (pcibr_soft->bsi_err_intr) { - which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid); - } - } - } - - /* Check if we can find a valid interrupt target candidate on - * the master node for the device. - */ - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - master_node_get(dev), - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); /* got a valid interrupt target */ - else - intr_unreserve_level(cpuid, *resp_bit); - } - - printk(KERN_WARNING "Cannot target interrupts to closest node(%d): (0x%lx)\n", - master_node_get(dev),(unsigned long)owner_dev); - - /* Fall through into the default algorithm - * (exhaustive-search-for-the-nearest-possible-interrupt-target) - * for finding the interrupt target - */ - - { - /* - * Do a stupid round-robin assignment of the node. - * (Should do a "nearest neighbor" but not for SN1. - */ - static cnodeid_t last_node = -1; - - if (last_node >= numnodes) last_node = 0; - for (candidate = last_node + 1; candidate != last_node; candidate++) { - if (candidate == numnodes) candidate = 0; - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - candidate, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) { - last_node = candidate; - return(cpuid); /* got a valid interrupt target */ - } - else - intr_unreserve_level(cpuid, *resp_bit); - } - } - last_node = candidate; - } - - printk(KERN_WARNING "Cannot target interrupts to any close node: %ld (0x%lx)\n", - (long)owner_dev, (unsigned long)owner_dev); - - /* In the worst case try to allocate interrupt bits on the - * master processor's node. We may get here during error interrupt - * allocation phase when the topology matrix is not yet setup - * and hence cannot do an exhaustive search. - */ - ASSERT(cpu_allows_intr(master_procid)); - cpuid = intr_bit_reserve_test(master_procid, - which_subnode, - CNODEID_NONE, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); - else - intr_unreserve_level(cpuid, *resp_bit); - } - - printk(KERN_WARNING "Cannot target interrupts: (0x%lx)\n", - (unsigned long)owner_dev); - - return(CPU_NONE); /* Should never get here */ -} - -struct hardwired_intr_s { - signed char level; - int flags; - char *name; -} const hardwired_intr[] = { - { INT_PEND0_BASELVL + RESERVED_INTR, 0, "Reserved" }, - { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, - { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, - { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, - { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, - { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, - { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, - { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, - { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, - { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, - { INT_PEND1_BASELVL + MD_COR_ERR_INTR, II_ERRORINT, "MD Correct. Error" }, - { INT_PEND1_BASELVL + NI_ERROR_INTR, II_ERRORINT, "NI Error" }, - { INT_PEND1_BASELVL + NI_BRDCAST_ERR_A, II_ERRORINT, "Remote NI Error"}, - { INT_PEND1_BASELVL + NI_BRDCAST_ERR_B, II_ERRORINT, "Remote NI Error"}, - { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, - { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, - { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, - { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, - { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, - { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, - { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, - { -1, 0, (char *)NULL}, -}; - -/* - * Reserve all of the hardwired interrupt levels so they're not used as - * general purpose bits later. - */ -void -intr_reserve_hardwired(cnodeid_t cnode) -{ - cpuid_t cpu; - int level; - int i; - char subnode_done[NUM_SUBNODES]; - - // cpu = cnodetocpu(cnode); - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - if (cpuid_to_cnodeid(cpu) == cnode) { - break; - } - } - if (cpu == smp_num_cpus) cpu = CPU_NONE; - if (cpu == CPU_NONE) { - printk("Node %d has no CPUs", cnode); - return; - } - - for (i=0; iii_name, - vector->iv_func, vector->iv_arg, vector->iv_prefunc); - pf(" vertex 0x%x %s%s", - info->ii_owner_dev, - ((info->ii_flags) & II_RESERVE) ? "R" : "U", - ((info->ii_flags) & II_INUSE) ? "C" : "-"); - pf("%s%s%s%s", - ip & value ? "P" : "-", - ima & value ? "A" : "-", - imb & value ? "B" : "-", - ((info->ii_flags) & II_ERRORINT) ? "E" : "-"); - pf("\n"); -} - - -/* - * Dump information about interrupt vector assignment. - */ -void -intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)) -{ - nodepda_t *npda; - int ip, sn, bit; - intr_vecblk_t *dispatch; - hubreg_t ipr, ima, imb; - nasid_t nasid; - - if ((cnode < 0) || (cnode >= numnodes)) { - pf("intr_dumpvec: cnodeid out of range: %d\n", cnode); - return ; - } - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - if (nasid == INVALID_NASID) { - pf("intr_dumpvec: Bad cnodeid: %d\n", cnode); - return ; - } - - - npda = NODEPDA(cnode); - - for (sn = 0; sn < NUM_SUBNODES; sn++) { - for (ip = 0; ip < 2; ip++) { - dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0); - ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0); - ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A); - imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B); - - pf("Node %d INT_PEND%d:\n", cnode, ip); - - if (dispatch->ithreads_enabled) - pf(" Ithreads enabled\n"); - else - pf(" Ithreads disabled\n"); - pf(" vector_count = %d, vector_state = %d\n", - dispatch->vector_count, - dispatch->vector_state); - pf(" CPU A count %d, CPU B count %d\n", - dispatch->cpu_count[0], - dispatch->cpu_count[1]); - pf(" &vector_lock = 0x%x\n", - &(dispatch->vector_lock)); - for (bit = 0; bit < N_INTPEND_BITS; bit++) { - if ((dispatch->info[bit].ii_flags & II_RESERVE) || - (ipr & (1L << bit))) { - dump_vector(&(dispatch->info[bit]), - &(dispatch->vectors[bit]), - bit, ipr, ima, imb, pf); - } - } - pf("\n"); - } - } -} - diff --git a/arch/ia64/sn/io/sn1/pcibr.c b/arch/ia64/sn/io/sn1/pcibr.c deleted file mode 100644 index 92594ce11da..00000000000 --- a/arch/ia64/sn/io/sn1/pcibr.c +++ /dev/null @@ -1,7704 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -int NeedXbridgeSwap = 0; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - -extern boolean_t is_sys_critical_vertex(devfs_handle_t); - -#undef PCIBR_ATE_DEBUG - -#if 0 -#define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ -#endif -#define PCI_DEBUG 1 -#define ATTACH_DEBUG 1 -#define PCIBR_SOFT_LIST 1 - -#ifndef LOCAL -#define LOCAL static -#endif - -/* - * Macros related to the Lucent USS 302/312 usb timeout workaround. It - * appears that if the lucent part can get into a retry loop if it sees a - * DAC on the bus during a pio read retry. The loop is broken after about - * 1ms, so we need to set up bridges holding this part to allow at least - * 1ms for pio. - */ - -#define USS302_TIMEOUT_WAR - -#ifdef USS302_TIMEOUT_WAR -#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 -#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 -#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 -#define USS302_BRIDGE_TIMEOUT_HLD 4 -#endif - -#define PCIBR_LLP_CONTROL_WAR -#if defined (PCIBR_LLP_CONTROL_WAR) -int pcibr_llp_control_war_cnt; -#endif /* PCIBR_LLP_CONTROL_WAR */ - -int pcibr_devflag = D_MP; - -#ifdef LATER -#define F(s,n) { 1l<<(s),-(s), n } - -struct reg_desc bridge_int_status_desc[] = -{ - F(31, "MULTI_ERR"), - F(30, "PMU_ESIZE_EFAULT"), - F(29, "UNEXPECTED_RESP"), - F(28, "BAD_XRESP_PACKET"), - F(27, "BAD_XREQ_PACKET"), - F(26, "RESP_XTALK_ERROR"), - F(25, "REQ_XTALK_ERROR"), - F(24, "INVALID_ADDRESS"), - F(23, "UNSUPPORTED_XOP"), - F(22, "XREQ_FIFO_OFLOW"), - F(21, "LLP_REC_SNERROR"), - F(20, "LLP_REC_CBERROR"), - F(19, "LLP_RCTY"), - F(18, "LLP_TX_RETRY"), - F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), - F(15, "PCI_ABORT"), - F(14, "PCI_PARITY"), - F(13, "PCI_SERR"), - F(12, "PCI_PERR"), - F(11, "PCI_MASTER_TOUT"), - F(10, "PCI_RETRY_CNT"), - F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), - F(7, "INT7"), - F(6, "INT6"), - F(5, "INT5"), - F(4, "INT4"), - F(3, "INT3"), - F(2, "INT2"), - F(1, "INT1"), - F(0, "INT0"), - {0} -}; - -struct reg_values space_v[] = -{ - {PCIIO_SPACE_NONE, "none"}, - {PCIIO_SPACE_ROM, "ROM"}, - {PCIIO_SPACE_IO, "I/O"}, - {PCIIO_SPACE_MEM, "MEM"}, - {PCIIO_SPACE_MEM32, "MEM(32)"}, - {PCIIO_SPACE_MEM64, "MEM(64)"}, - {PCIIO_SPACE_CFG, "CFG"}, - {PCIIO_SPACE_WIN(0), "WIN(0)"}, - {PCIIO_SPACE_WIN(1), "WIN(1)"}, - {PCIIO_SPACE_WIN(2), "WIN(2)"}, - {PCIIO_SPACE_WIN(3), "WIN(3)"}, - {PCIIO_SPACE_WIN(4), "WIN(4)"}, - {PCIIO_SPACE_WIN(5), "WIN(5)"}, - {PCIIO_SPACE_BAD, "BAD"}, - {0} -}; - -struct reg_desc space_desc[] = -{ - {0xFF, 0, "space", 0, space_v}, - {0} -}; - -#if DEBUG -#define device_desc device_bits -LOCAL struct reg_desc device_bits[] = -{ - {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, - {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, - {BRIDGE_DEV_FORCE_PCI_PAR, 0, "FORCE_PCI_PAR"}, - {BRIDGE_DEV_VIRTUAL_EN, 0, "VIRTUAL_EN"}, - {BRIDGE_DEV_PMU_WRGA_EN, 0, "PMU_WRGA_EN"}, - {BRIDGE_DEV_DIR_WRGA_EN, 0, "DIR_WRGA_EN"}, - {BRIDGE_DEV_DEV_SIZE, 0, "DEV_SIZE"}, - {BRIDGE_DEV_RT, 0, "RT"}, - {BRIDGE_DEV_SWAP_PMU, 0, "SWAP_PMU"}, - {BRIDGE_DEV_SWAP_DIR, 0, "SWAP_DIR"}, - {BRIDGE_DEV_PREF, 0, "PREF"}, - {BRIDGE_DEV_PRECISE, 0, "PRECISE"}, - {BRIDGE_DEV_COH, 0, "COH"}, - {BRIDGE_DEV_BARRIER, 0, "BARRIER"}, - {BRIDGE_DEV_GBR, 0, "GBR"}, - {BRIDGE_DEV_DEV_SWAP, 0, "DEV_SWAP"}, - {BRIDGE_DEV_DEV_IO_MEM, 0, "DEV_IO_MEM"}, - {BRIDGE_DEV_OFF_MASK, BRIDGE_DEV_OFF_ADDR_SHFT, "DEV_OFF", "%x"}, - {0} -}; -#endif /* DEBUG */ - -#ifdef SUPPORT_PRINTING_R_FORMAT -LOCAL struct reg_values xio_cmd_pactyp[] = -{ - {0x0, "RdReq"}, - {0x1, "RdResp"}, - {0x2, "WrReqWithResp"}, - {0x3, "WrResp"}, - {0x4, "WrReqNoResp"}, - {0x5, "Reserved(5)"}, - {0x6, "FetchAndOp"}, - {0x7, "Reserved(7)"}, - {0x8, "StoreAndOp"}, - {0x9, "Reserved(9)"}, - {0xa, "Reserved(a)"}, - {0xb, "Reserved(b)"}, - {0xc, "Reserved(c)"}, - {0xd, "Reserved(d)"}, - {0xe, "SpecialReq"}, - {0xf, "SpecialResp"}, - {0} -}; - -LOCAL struct reg_desc xio_cmd_bits[] = -{ - {WIDGET_DIDN, -28, "DIDN", "%x"}, - {WIDGET_SIDN, -24, "SIDN", "%x"}, - {WIDGET_PACTYP, -20, "PACTYP", 0, xio_cmd_pactyp}, - {WIDGET_TNUM, -15, "TNUM", "%x"}, - {WIDGET_COHERENT, 0, "COHERENT"}, - {WIDGET_DS, 0, "DS"}, - {WIDGET_GBR, 0, "GBR"}, - {WIDGET_VBPM, 0, "VBPM"}, - {WIDGET_ERROR, 0, "ERROR"}, - {WIDGET_BARRIER, 0, "BARRIER"}, - {0} -}; -#endif /* SUPPORT_PRINTING_R_FORMAT */ - -#if PCIBR_FREEZE_TIME || PCIBR_ATE_DEBUG -LOCAL struct reg_desc ate_bits[] = -{ - {0xFFFF000000000000ull, -48, "RMF", "%x"}, - {~(IOPGSIZE - 1) & /* may trim off some low bits */ - 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, - {0x0000000000000F00ull, -8, "port", "%x"}, - {0x0000000000000010ull, 0, "Barrier"}, - {0x0000000000000008ull, 0, "Prefetch"}, - {0x0000000000000004ull, 0, "Precise"}, - {0x0000000000000002ull, 0, "Coherent"}, - {0x0000000000000001ull, 0, "Valid"}, - {0} -}; -#endif - -#if PCIBR_ATE_DEBUG -LOCAL struct reg_values ssram_sizes[] = -{ - {BRIDGE_CTRL_SSRAM_512K, "512k"}, - {BRIDGE_CTRL_SSRAM_128K, "128k"}, - {BRIDGE_CTRL_SSRAM_64K, "64k"}, - {BRIDGE_CTRL_SSRAM_1K, "1k"}, - {0} -}; - -LOCAL struct reg_desc control_bits[] = -{ - {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, - {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, - {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, - {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, - {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, - {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, - {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, - {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, - {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, - {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, - {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, - {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, - {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, - {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, - {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, - {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, - {BRIDGE_CTRL_MAX_TRANS_MASK, -4, "MAX_TRANS", "%d"}, - {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, - {0} -}; -#endif -#endif /* LATER */ - -/* kbrick widgetnum-to-bus layout */ -int p_busnum[MAX_PORT_NUM] = { /* widget# */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 2, /* 0x8 */ - 1, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 5, /* 0xc */ - 6, /* 0xd */ - 4, /* 0xe */ - 3, /* 0xf */ -}; - -/* - * Additional PIO spaces per slot are - * recorded in this structure. - */ -struct pciio_piospace_s { - pciio_piospace_t next; /* another space for this device */ - char free; /* 1 if free, 0 if in use */ - pciio_space_t space; /* Which space is in use */ - iopaddr_t start; /* Starting address of the PIO space */ - size_t count; /* size of PIO space */ -}; - -#if PCIBR_SOFT_LIST -pcibr_list_p pcibr_list = 0; -#endif - -#define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" - -#define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) -#define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) - -#define PCIBR_VALID_SLOT(s) (s < 8) - -#ifdef SN_XXX -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); -#endif -extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); -extern void free_pciio_dmamap(pcibr_dmamap_t); - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - -extern devfs_handle_t hwgraph_root; -extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); -extern int cap_able(uint64_t x); -extern uint64_t rmalloc(struct map *mp, size_t size); -extern void rmfree(struct map *mp, size_t size, uint64_t a); -extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); -extern long atoi(register char *p); -extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr); -extern struct map *rmallocmap(uint64_t mapsiz); -extern void rmfreemap(struct map *mp); -extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); -extern int io_path_map_widget(devfs_handle_t vertex); - - - -/* ===================================================================== - * Function Table of Contents - * - * The order of functions in this file has stopped - * making much sense. We might want to take a look - * at it some time and bring back some sanity, or - * perhaps bust this file into smaller chunks. - */ - -LOCAL void do_pcibr_rrb_clear(bridge_t *, int); -LOCAL void do_pcibr_rrb_flush(bridge_t *, int); -LOCAL int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); -LOCAL int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); - -LOCAL void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); - -int pcibr_wrb_flush(devfs_handle_t); -int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); -void pcibr_rrb_flush(devfs_handle_t); - -LOCAL int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); -void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); - -LOCAL void pcibr_clearwidint(bridge_t *); -LOCAL void pcibr_setwidint(xtalk_intr_t); -LOCAL int pcibr_probe_slot(bridge_t *, cfg_p, unsigned *); - -void pcibr_init(void); -int pcibr_attach(devfs_handle_t); -int pcibr_detach(devfs_handle_t); -int pcibr_open(devfs_handle_t *, int, int, cred_t *); -int pcibr_close(devfs_handle_t, int, int, cred_t *); -int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int pcibr_unmap(devfs_handle_t, vhandl_t *); -int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); - -LOCAL int pcibr_init_ext_ate_ram(bridge_t *); -LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); -LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); - -LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); -LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); - -pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pcibr_piomap_free(pcibr_piomap_t); -caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); -void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -LOCAL iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); -LOCAL bridge_ate_t pcibr_flags_to_ate(unsigned); - -pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pcibr_dmamap_free(pcibr_dmamap_t); -LOCAL bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -LOCAL iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); -iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); -void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); -iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); - -static unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); -pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pcibr_intr_free(pcibr_intr_t); -LOCAL void pcibr_setpciint(xtalk_intr_t); -int pcibr_intr_connect(pcibr_intr_t); -void pcibr_intr_disconnect(pcibr_intr_t); - -devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); -void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_func(intr_arg_t); - -void pcibr_provider_startup(devfs_handle_t); -void pcibr_provider_shutdown(devfs_handle_t); - -int pcibr_reset(devfs_handle_t); -pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); -int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); - -LOCAL cfg_p pcibr_config_addr(devfs_handle_t, unsigned); -uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -LOCAL uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); -void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -LOCAL void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); - -LOCAL pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -void pcibr_hints_fix_rrbs(devfs_handle_t); -void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); - -LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); - -#ifdef LATER -LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, - pcibr_slot_info_resp_t); -LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, - pcibr_slot_func_info_resp_t); -#endif /* LATER */ - -LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); -LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, - pciio_slot_t, int); -LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, - pciio_slot_t, int); - -LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); -LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); -#ifdef LATER -LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); -#endif - -/* ===================================================================== - * RRB management - */ - -#define LSBIT(word) ((word) &~ ((word)-1)) - -#define PCIBR_RRB_SLOT_VIRTUAL 8 - -LOCAL void -do_pcibr_rrb_clear(bridge_t *bridge, int rrb) -{ - bridgereg_t status; - - /* bridge_lock must be held; - * this RRB must be disabled. - */ - - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } -} - -LOCAL void -do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) -{ - reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; - bridgereg_t rrbv; - int shft = 4 * (rrbn >> 1); - unsigned ebit = BRIDGE_RRB_EN << shft; - - rrbv = *rrbp; - if (rrbv & ebit) - *rrbp = rrbv & ~ebit; - - do_pcibr_rrb_clear(bridge, rrbn); - - if (rrbv & ebit) - *rrbp = rrbv; -} - -/* - * pcibr_rrb_count_valid: count how many RRBs are - * marked valid for the specified PCI slot on this - * bridge. - * - * NOTE: The "slot" parameter for all pcibr_rrb - * management routines must include the "virtual" - * bit; when manageing both the normal and the - * virtual channel, separate calls to these - * routines must be made. To denote the virtual - * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot - * number. - * - * IMPL NOTE: The obvious algorithm is to iterate - * through the RRB fields, incrementing a count if - * the RRB is valid and matches the slot. However, - * it is much simpler to use an algorithm derived - * from the "partitioned add" idea. First, XOR in a - * pattern such that the fields that match this - * slot come up "all ones" and all other fields - * have zeros in the mismatching bits. Then AND - * together the bits in the field, so we end up - * with one bit turned on for each field that - * matched. Now we need to count these bits. This - * can be done either with a series of shift/add - * instructions or by using "tmp % 15"; I expect - * that the cascaded shift/add will be faster. - */ - -LOCAL int -do_pcibr_rrb_count_valid(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp ^= 0x11111111 * (7 - slot / 2); - tmp &= (0xCCCCCCCC & tmp) >> 2; - tmp &= (0x22222222 & tmp) >> 1; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_count_avail: count how many RRBs are - * available to be allocated for the specified slot. - * - * IMPL NOTE: similar to the above, except we are - * just counting how many fields have the valid bit - * turned off. - */ -LOCAL int -do_pcibr_rrb_count_avail(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~tmp) >> 3; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_alloc: allocate some additional RRBs - * for the specified slot. Returns -1 if there were - * insufficient free RRBs to satisfy the request, - * or 0 if the request was fulfilled. - * - * Note that if a request can be partially filled, - * it will be, even if we return failure. - * - * IMPL NOTE: again we avoid iterating across all - * the RRBs; instead, we form up a word containing - * one bit for each free RRB, then peel the bits - * off from the low end. - */ -LOCAL int -do_pcibr_rrb_alloc(bridge_t *bridge, - pciio_slot_t slot, - int more) -{ - int rv = 0; - bridgereg_t reg, tmp, bit; - - reg = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~reg) >> 3; - while (more-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); - } - bridge->b_rrb_map[slot & 1].reg = reg; - return rv; -} - -/* - * do_pcibr_rrb_free: release some of the RRBs that - * have been allocated for the specified - * slot. Returns zero for success, or negative if - * it was unable to free that many RRBs. - * - * IMPL NOTE: We form up a bit for each RRB - * allocated to the slot, aligned with the VALID - * bitfield this time; then we peel bits off one at - * a time, releasing the corresponding RRB. - */ -LOCAL int -do_pcibr_rrb_free(bridge_t *bridge, - pciio_slot_t slot, - int less) -{ - int rv = 0; - bridgereg_t reg, tmp, clr, bit; - int i; - - clr = 0; - reg = bridge->b_rrb_map[slot & 1].reg; - - /* This needs to be done otherwise the rrb's on the virtual channel - * for this slot won't be freed !! - */ - tmp = reg & 0xbbbbbbbb; - - tmp ^= (0x11111111 * (7 - slot / 2)); - tmp &= (0x33333333 & tmp) << 2; - tmp &= (0x44444444 & tmp) << 1; - while (less-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg &= ~bit; - clr |= bit; - } - bridge->b_rrb_map[slot & 1].reg = reg; - - for (i = 0; i < 8; i++) - if (clr & (8 << (4 * i))) - do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); - - return rv; -} - -LOCAL void -do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, - int slot, - int more_rrbs) -{ - bridge_t *bridge = pcibr_soft->bs_base; - int got; - - for (got = 0; got < more_rrbs; ++got) { - if (pcibr_soft->bs_rrb_res[slot & 7] > 0) - pcibr_soft->bs_rrb_res[slot & 7]--; - else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) - pcibr_soft->bs_rrb_avail[slot & 1]--; - else - break; - if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) - break; -#if PCIBR_RRB_DEBUG - printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n", - slot & 7, slot & 8 ? "v" : ""); -#endif - pcibr_soft->bs_rrb_valid[slot]++; - } -#if PCIBR_RRB_DEBUG - printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (slot = 0; slot < 8; ++slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif -} - -/* - * Device driver interface to flush the write buffers for a specified - * device hanging off the bridge. - */ -int -pcibr_wrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - volatile bridgereg_t *wrb_flush; - - wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); - while (*wrb_flush); - - return(0); -} -/* - * Device driver interface to request RRBs for a specified device - * hanging off a Bridge. The driver requests the total number of - * RRBs it would like for the normal channel (vchan0) and for the - * "virtual channel" (vchan1). The actual number allocated to each - * channel is returned. - * - * If we cannot allocate at least one RRB to a channel that needs - * at least one, return -1 (failure). Otherwise, satisfy the request - * as best we can and return 0. - */ -int -pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - int desired_vchan0; - int desired_vchan1; - int orig_vchan0; - int orig_vchan1; - int delta_vchan0; - int delta_vchan1; - int final_vchan0; - int final_vchan1; - int avail_rrbs; - unsigned long s; - int error; - - /* - * TBD: temper request with admin info about RRB allocation, - * and according to demand from other devices on this Bridge. - * - * One way of doing this would be to allocate two RRBs - * for each device on the bus, before any drivers start - * asking for extras. This has the weakness that one - * driver might not give back an "extra" RRB until after - * another driver has already failed to get one that - * it wanted. - */ - - s = pcibr_lock(pcibr_soft); - - /* How many RRBs do we own? */ - orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; - orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - /* How many RRBs do we want? */ - desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; - desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; - - /* How many RRBs are free? */ - avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot]; - - /* Figure desired deltas */ - delta_vchan0 = desired_vchan0 - orig_vchan0; - delta_vchan1 = desired_vchan1 - orig_vchan1; - - /* Trim back deltas to something - * that we can actually meet, by - * decreasing the ending allocation - * for whichever channel wants - * more RRBs. If both want the same - * number, cut the second channel. - * NOTE: do not change the allocation for - * a channel that was passed as NULL. - */ - while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { - if (count_vchan0 && - (!count_vchan1 || - ((orig_vchan0 + delta_vchan0) > - (orig_vchan1 + delta_vchan1)))) - delta_vchan0--; - else - delta_vchan1--; - } - - /* Figure final RRB allocations - */ - final_vchan0 = orig_vchan0 + delta_vchan0; - final_vchan1 = orig_vchan1 + delta_vchan1; - - /* If either channel wants RRBs but our actions - * would leave it with none, declare an error, - * but DO NOT change any RRB allocations. - */ - if ((desired_vchan0 && !final_vchan0) || - (desired_vchan1 && !final_vchan1)) { - - error = -1; - - } else { - - /* Commit the allocations: free, then alloc. - */ - if (delta_vchan0 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); - if (delta_vchan1 < 0) - (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); - - if (delta_vchan0 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); - if (delta_vchan1 > 0) - (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); - - /* Return final values to caller. - */ - if (count_vchan0) - *count_vchan0 = final_vchan0; - if (count_vchan1) - *count_vchan1 = final_vchan1; - - /* prevent automatic changes to this slot's RRBs - */ - pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; - - /* Track the actual allocations, release - * any further reservations, and update the - * number of available RRBs. - */ - - pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot] - - delta_vchan0 - - delta_vchan1; - pcibr_soft->bs_rrb_res[pciio_slot] = 0; - -#if PCIBR_RRB_DEBUG - printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", - pciio_slot, final_vchan0, final_vchan1, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[pciio_slot]); - printk("\n"); -#endif - - error = 0; - } - - pcibr_unlock(pcibr_soft, s); - return error; -} - -/* - * Device driver interface to check the current state - * of the RRB allocations. - * - * pconn_vhdl is your PCI connection point (specifies which - * PCI bus and which slot). - * - * count_vchan0 points to where to return the number of RRBs - * assigned to the primary DMA channel, used by all DMA - * that does not explicitly ask for the alternate virtual - * channel. - * - * count_vchan1 points to where to return the number of RRBs - * assigned to the secondary DMA channel, used when - * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. - * - * count_reserved points to where to return the number of RRBs - * that have been automatically reserved for your device at - * startup, but which have not been assigned to a - * channel. RRBs must be assigned to a channel to be used; - * this can be done either with an explicit pcibr_rrb_alloc - * call, or automatically by the infrastructure when a DMA - * translation is constructed. Any call to pcibr_rrb_alloc - * will release any unassigned reserved RRBs back to the - * free pool. - * - * count_pool points to where to return the number of RRBs - * that are currently unassigned and unreserved. This - * number can (and will) change as other drivers make calls - * to pcibr_rrb_alloc, or automatically allocate RRBs for - * DMA beyond their initial reservation. - * - * NULL may be passed for any of the return value pointers - * the caller is not interested in. - * - * The return value is "0" if all went well, or "-1" if - * there is a problem. Additionally, if the wrong vertex - * is passed in, one of the subsidiary support functions - * could panic with a "bad pciio fingerprint." - */ - -int -pcibr_rrb_check(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1, - int *count_reserved, - int *count_pool) -{ - pciio_info_t pciio_info; - pciio_slot_t pciio_slot; - pcibr_soft_t pcibr_soft; - unsigned long s; - int error = -1; - - if ((pciio_info = pciio_info_get(pconn_vhdl)) && - (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && - ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { - - s = pcibr_lock(pcibr_soft); - - if (count_vchan0) - *count_vchan0 = - pcibr_soft->bs_rrb_valid[pciio_slot]; - - if (count_vchan1) - *count_vchan1 = - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - if (count_reserved) - *count_reserved = - pcibr_soft->bs_rrb_res[pciio_slot]; - - if (count_pool) - *count_pool = - pcibr_soft->bs_rrb_avail[pciio_slot & 1]; - - error = 0; - - pcibr_unlock(pcibr_soft, s); - } - return error; -} - -/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities - * requested for each of the devies. The evn_odd argument indicates whether - * allcoation for the odd or even rrbs is requested and next group of four pairse - * are the amount to assign to each device (they should sum to <= 8) and - * whether to set the viritual bit for that device (1 indictaes yes, 0 indicates no) - * the devices in order are either 0, 2, 4, 6 or 1, 3, 5, 7 - * if even_odd is even we alloc even rrbs else we allocate odd rrbs - * returns 0 if no errors else returns -1 - */ - -int -pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, - int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, - int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) -{ - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft = NULL; - bridge_t *bridge = NULL; - - uint32_t rrb_setting = 0; - int rrb_shift = 7; - uint32_t cur_rrb; - int dev_rrbs[4]; - int virt[4]; - int i, j; - unsigned long s; - - if (GRAPH_SUCCESS == - hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) - bridge = pcibr_soft->bs_base; - hwgraph_vertex_unref(pcibr_vhdl); - } - if (bridge == NULL) - bridge = (bridge_t *) xtalk_piotrans_addr - (vhdl, NULL, 0, sizeof(bridge_t), 0); - - even_odd &= 1; - - dev_rrbs[0] = dev_1_rrbs; - dev_rrbs[1] = dev_2_rrbs; - dev_rrbs[2] = dev_3_rrbs; - dev_rrbs[3] = dev_4_rrbs; - - virt[0] = virt1; - virt[1] = virt2; - virt[2] = virt3; - virt[3] = virt4; - - if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { - return -1; - } - if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { - return -1; - } - /* walk through rrbs */ - for (i = 0; i < 4; i++) { - if (virt[i]) { - cur_rrb = i | 0xc; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - dev_rrbs[i] = dev_rrbs[i] - 1; - } - for (j = 0; j < dev_rrbs[i]; j++) { - cur_rrb = i | 0x8; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - } - } - - if (pcibr_soft) - s = pcibr_lock(pcibr_soft); - - bridge->b_rrb_map[even_odd].reg = rrb_setting; - - if (pcibr_soft) { - - pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; - - /* since we've "FIXED" the allocations - * for these slots, we probably can dispense - * with tracking avail/res/valid data, but - * keeping it up to date helps debugging. - */ - - pcibr_soft->bs_rrb_avail[even_odd] = - 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); - - pcibr_soft->bs_rrb_res[even_odd + 0] = 0; - pcibr_soft->bs_rrb_res[even_odd + 2] = 0; - pcibr_soft->bs_rrb_res[even_odd + 4] = 0; - pcibr_soft->bs_rrb_res[even_odd + 6] = 0; - - pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; - - pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; - - pcibr_unlock(pcibr_soft, s); - } - return 0; -} - -/* - * pcibr_rrb_flush: chase down all the RRBs assigned - * to the specified connection point, and flush - * them. - */ -void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - unsigned long s; - reg_p rrbp; - unsigned rrbm; - int i; - int rrbn; - unsigned sval; - unsigned mask; - - sval = BRIDGE_RRB_EN | (pciio_slot >> 1); - mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; - rrbn = pciio_slot & 1; - rrbp = &bridge->b_rrb_map[rrbn].reg; - - s = pcibr_lock(pcibr_soft); - rrbm = *rrbp; - for (i = 0; i < 8; ++i) { - if ((rrbm & mask) == sval) - do_pcibr_rrb_flush(bridge, rrbn); - rrbm >>= 4; - rrbn += 2; - } - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Device(x) register management - */ - -/* pcibr_try_set_device: attempt to modify Device(x) - * for the specified slot on the specified bridge - * as requested in flags, limited to the specified - * bits. Returns which BRIDGE bits were in conflict, - * or ZERO if everything went OK. - * - * Caller MUST hold pcibr_lock when calling this function. - */ -LOCAL int -pcibr_try_set_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - unsigned flags, - bridgereg_t mask) -{ - bridge_t *bridge; - pcibr_soft_slot_t slotp; - bridgereg_t old; - bridgereg_t new; - bridgereg_t chg; - bridgereg_t bad; - bridgereg_t badpmu; - bridgereg_t badd32; - bridgereg_t badd64; - bridgereg_t fix; - unsigned long s; - bridgereg_t xmask; - - xmask = mask; - if (pcibr_soft->bs_xbridge) { - if (mask == BRIDGE_DEV_PMU_BITS) - xmask = XBRIDGE_DEV_PMU_BITS; - if (mask == BRIDGE_DEV_D64_BITS) - xmask = XBRIDGE_DEV_D64_BITS; - } - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - bridge = pcibr_soft->bs_base; - - old = slotp->bss_device; - - /* figure out what the desired - * Device(x) bits are based on - * the flags specified. - */ - - new = old; - - /* Currently, we inherit anything that - * the new caller has not specified in - * one way or another, unless we take - * action here to not inherit. - * - * This is needed for the "swap" stuff, - * since it could have been set via - * pcibr_endian_set -- altho note that - * any explicit PCIBR_BYTE_STREAM or - * PCIBR_WORD_VALUES will freely override - * the effect of that call (and vice - * versa, no protection either way). - * - * I want to get rid of pcibr_endian_set - * in favor of tracking DMA endianness - * using the flags specified when DMA - * channels are created. - */ - -#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) -#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) - - /* Do not use Barrier, Write Gather, - * or Prefetch unless asked. - * Leave everything else as it - * was from the last time. - */ - new = new - & ~BRIDGE_DEV_BARRIER - & ~BRIDGE_DEV_WRGA_BITS - & ~BRIDGE_DEV_PREF - ; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { - new = (new - & ~BRIDGE_DEV_BARRIER) /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ - - } - if (flags & PCIIO_DMA_CMD) { - new = ((new - & ~BRIDGE_DEV_PREF) /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ - } - /* Generic detail flags - */ - if (flags & PCIIO_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIIO_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIIO_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIBR_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_BYTE_STREAM) - new |= (pcibr_soft->bs_xbridge) ? - BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; - if (flags & PCIIO_WORD_VALUES) - new &= (pcibr_soft->bs_xbridge) ? - ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; - - /* Provider-specific flags - */ - if (flags & PCIBR_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - new |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - new &= ~BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - new |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - new &= ~BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - new |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - new &= ~BRIDGE_DEV_DEV_SIZE; - - chg = old ^ new; /* what are we changing, */ - chg &= xmask; /* of the interesting bits */ - - if (chg) { - - badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; - if (pcibr_soft->bs_xbridge) { - badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; - } else { - badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; - } - bad = badpmu | badd32 | badd64; - - if (bad) { - - /* some conflicts can be resolved by - * forcing the bit on. this may cause - * some performance degredation in - * the stream(s) that want the bit off, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) ){ - bad &= ~fix; - /* don't change these bits if - * they are already set in "old" - */ - chg &= ~(fix & old); - } - /* some conflicts can be resolved by - * forcing the bit off. this may cause - * some performance degredation in - * the stream(s) that want the bit on, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ) { - bad &= ~fix; - /* don't change these bits if - * we wanted to turn them on. - */ - chg &= ~(fix & new); - } - /* conflicts in other bits mean - * we can not establish this DMA - * channel while the other(s) are - * still present. - */ - if (bad) { - pcibr_unlock(pcibr_soft, s); -#if (DEBUG && PCIBR_DEV_DEBUG) - printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); -#endif - return bad; - } - } - } - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr++; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr++; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr++; - - /* the value we want to write is the - * original value, with the bits for - * our selected changes flipped, and - * with any disabled features turned off. - */ - new = old ^ chg; /* only change what we want to change */ - - if (slotp->bss_device == new) { - pcibr_unlock(pcibr_soft, s); - return 0; - } - bridge->b_device[slot].reg = new; - slotp->bss_device = new; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); -#endif - - return 0; -} - -void -pcibr_release_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - bridgereg_t mask) -{ - pcibr_soft_slot_t slotp; - unsigned long s; - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr--; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr--; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr--; - - pcibr_unlock(pcibr_soft, s); -} - -/* - * flush write gather buffer for slot - */ -LOCAL void -pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - bridge_t *bridge; - unsigned long s; - volatile uint32_t wrf; - s = pcibr_lock(pcibr_soft); - bridge = pcibr_soft->bs_base; - wrf = bridge->b_wr_req_buf[slot].reg; - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Bridge (pcibr) "Device Driver" entry points - */ - -/* - * pcibr_probe_slot: read a config space word - * while trapping any errors; reutrn zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -LOCAL int -pcibr_probe_slot(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) -{ - int rv; - bridgereg_t old_enable, new_enable; - int badaddr_val(volatile void *, int, volatile void *); - - - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - - bridge->b_int_enable = new_enable; - - /* - * The xbridge doesn't clear b_err_int_view unless - * multi-err is cleared... - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) cfg, 4, valp); - - /* - * The xbridge doesn't set master timeout in b_int_status - * here. Fortunately it's in error_interrupt_view. - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ - } - - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - return rv; -} - -/* - * pcibr_init: called once during system startup or - * when a loadable driver is loaded. - * - * The driver_register function should normally - * be in _reg, not _init. But the pcibr driver is - * required by devinit before the _reg routines - * are called, so this is an exception. - */ -void -pcibr_init(void) -{ -#if DEBUG && ATTACH_DEBUG - printk("pcibr_init\n"); -#endif - - xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, - XBRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); - xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, - BRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); -} - -/* - * open/close mmap/munmap interface would be used by processes - * that plan to map the PCI bridge, and muck around with the - * registers. This is dangerous to do, and will be allowed - * to a select brand of programs. Typically these are - * diagnostics programs, or some user level commands we may - * write to do some weird things. - * To start with expect them to have root priveleges. - * We will ask for more later. - */ -/* ARGSUSED */ -int -pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - int error; - devfs_handle_t vhdl = dev_to_vhdl(dev); - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - ASSERT(pcibr_soft); - len = ctob(btoc(len)); /* Make len page aligned */ - error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); - - /* - * If the offset being mapped corresponds to the flash prom - * base, and if the mapping succeeds, and if the user - * has requested the protections to be WRITE, enable the - * flash prom to be written. - * - * XXX- deprecate this in favor of using the - * real flash driver ... - */ - if (!error && - ((off == BRIDGE_EXTERNAL_FLASH) || - (len > BRIDGE_EXTERNAL_FLASH))) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return error; -} - -/*ARGSUSED */ -int -pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return 0; -} - -/* This is special case code used by grio. There are plans to make - * this a bit more general in the future, but till then this should - * be sufficient. - */ -pciio_slot_t -pcibr_device_slot_get(devfs_handle_t dev_vhdl) -{ - char devname[MAXDEVNAME]; - devfs_handle_t tdev; - pciio_info_t pciio_info; - pciio_slot_t slot = PCIIO_SLOT_NONE; - - vertex_to_name(dev_vhdl, devname, MAXDEVNAME); - - /* run back along the canonical path - * until we find a PCI connection point. - */ - tdev = hwgraph_connectpt_get(dev_vhdl); - while (tdev != GRAPH_VERTEX_NONE) { - pciio_info = pciio_info_chk(tdev); - if (pciio_info) { - slot = pciio_info_slot_get(pciio_info); - break; - } - hwgraph_vertex_unref(tdev); - tdev = hwgraph_connectpt_get(tdev); - } - hwgraph_vertex_unref(tdev); - - return slot; -} - -/*========================================================================== - * BRIDGE PCI SLOT RELATED IOCTLs - */ -char *pci_space_name[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - - -/*ARGSUSED */ -int -pcibr_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef LATER - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); -#endif - int error = 0; - - hwgraph_vertex_unref(pcibr_vhdl); - - switch (cmd) { -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); - break; - } - - case PCIBR_SLOT_POWERUP: - { - pciio_slot_t slot; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_SHUTDOWN: - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_QUERY: - { - struct pcibr_slot_info_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_query(pcibr_vhdl, &req); - break; - } -#endif /* LATER */ - default: - break; - - } - - return error; -} - -void -pcibr_freeblock_sub(iopaddr_t *free_basep, - iopaddr_t *free_lastp, - iopaddr_t base, - size_t size) -{ - iopaddr_t free_base = *free_basep; - iopaddr_t free_last = *free_lastp; - iopaddr_t last = base + size - 1; - - if ((last < free_base) || (base > free_last)); /* free block outside arena */ - - else if ((base <= free_base) && (last >= free_last)) - /* free block contains entire arena */ - *free_basep = *free_lastp = 0; - - else if (base <= free_base) - /* free block is head of arena */ - *free_basep = last + 1; - - else if (last >= free_last) - /* free block is tail of arena */ - *free_lastp = base - 1; - - /* - * We are left with two regions: the free area - * in the arena "below" the block, and the free - * area in the arena "above" the block. Keep - * the one that is bigger. - */ - - else if ((base - free_base) > (free_last - last)) - *free_lastp = base - 1; /* keep lower chunk */ - else - *free_basep = last + 1; /* keep upper chunk */ -} - -/* Convert from ssram_bits in control register to number of SSRAM entries */ -#define ATE_NUM_ENTRIES(n) _ate_info[n] - -/* Possible choices for number of ATE entries in Bridge's SSRAM */ -LOCAL int _ate_info[] = -{ - 0, /* 0 entries */ - 8 * 1024, /* 8K entries */ - 16 * 1024, /* 16K entries */ - 64 * 1024 /* 64K entries */ -}; - -#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) -#define ATE_PROBE_VALUE 0x0123456789abcdefULL - -/* - * Determine the size of this bridge's external mapping SSRAM, and set - * the control register appropriately to reflect this size, and initialize - * the external SSRAM. - */ -LOCAL int -pcibr_init_ext_ate_ram(bridge_t *bridge) -{ - int largest_working_size = 0; - int num_entries, entry; - int i, j; - bridgereg_t old_enable, new_enable; - int s; - - /* Probe SSRAM to determine its size. */ - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - - for (i = 1; i < ATE_NUM_SIZES; i++) { - /* Try writing a value */ - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - - /* Guard against wrap */ - for (j = 1; j < i; j++) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; - - /* See if value was written */ - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - - s = splhi(); - bridge->b_wid_control = (bridge->b_wid_control - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - - num_entries = ATE_NUM_ENTRIES(largest_working_size); - -#if PCIBR_ATE_DEBUG - if (num_entries) - printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); - else - printk("bridge at 0x%x: no externa9422l ATE RAM found\n", bridge); -#endif - - /* Initialize external mapping entries */ - for (entry = 0; entry < num_entries; entry++) - bridge->b_ext_ate_ram[entry] = 0; - - return (num_entries); -} - -/* - * Allocate "count" contiguous Bridge Address Translation Entries - * on the specified bridge to be used for PCI to XTALK mappings. - * Indices in rm map range from 1..num_entries. Indicies returned - * to caller range from 0..num_entries-1. - * - * Return the start index on success, -1 on failure. - */ -LOCAL int -pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) -{ - int index = 0; - - index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); -/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ - - if (!index && pcibr_soft->bs_ext_ate_map) - index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); - - /* rmalloc manages resources in the 1..n - * range, with 0 being failure. - * pcibr_ate_alloc manages resources - * in the 0..n-1 range, with -1 being failure. - */ - return index - 1; -} - -LOCAL void -pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) -/* Who says there's no such thing as a free meal? :-) */ -{ - /* note the "+1" since rmalloc handles 1..n but - * we start counting ATEs at zero. - */ -/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ - - rmfree((index < pcibr_soft->bs_int_ate_size) - ? pcibr_soft->bs_int_ate_map - : pcibr_soft->bs_ext_ate_map, - count, index + 1); -} - -LOCAL pcibr_info_t -pcibr_info_get(devfs_handle_t vhdl) -{ - return (pcibr_info_t) pciio_info_get(vhdl); -} - -pcibr_info_t -pcibr_device_info_new( - pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pciio_function_t rfunc, - pciio_vendor_id_t vendor, - pciio_device_id_t device) -{ - pcibr_info_t pcibr_info; - pciio_function_t func; - int ibit; - - func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; - - NEW(pcibr_info); - pciio_device_info_new(&pcibr_info->f_c, - pcibr_soft->bs_vhdl, - slot, rfunc, - vendor, device); - - if (slot != PCIIO_SLOT_NONE) { - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - * - * XXX- allow pcibr_hints to override default - * XXX- allow ADMIN to override pcibr_hints - */ - for (ibit = 0; ibit < 4; ++ibit) - pcibr_info->f_ibit[ibit] = - (slot + 4 * ibit) & 7; - - /* - * Record the info in the sparse func info space. - */ - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) - pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; - } - return pcibr_info; -} - -void -pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info_t pcibr_info; - pciio_function_t func; - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; - int nfunc = slotp->bss_ninfo; - - - for (func = 0; func < nfunc; func++) { - pcibr_info = slotp->bss_infos[func]; - - if (!pcibr_info) - continue; - - slotp->bss_infos[func] = 0; - pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); - pciio_device_info_free(&pcibr_info->f_c); - DEL(pcibr_info); - } - - /* Clear the DEVIO(x) for this slot */ - slotp->bss_devio.bssd_space = PCIIO_SPACE_NONE; - slotp->bss_devio.bssd_base = PCIBR_D32_BASE_UNSET; - slotp->bss_device = 0; - - - /* Reset the mapping usage counters */ - slotp->bss_pmu_uctr = 0; - slotp->bss_d32_uctr = 0; - slotp->bss_d64_uctr = 0; - - /* Clear the Direct translation info */ - slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; - slotp->bss_d64_flags = 0; - slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; - slotp->bss_d32_flags = 0; - - /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = ATOMIC_INIT(0); - slotp->bss_cmd_pointer = 0; - slotp->bss_cmd_shadow = 0; - -} - -/* - * PCI_ADDR_SPACE_LIMITS_LOAD - * Gets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_LOAD() \ - pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ - pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ - pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ - pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ - pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ - pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; -/* - * PCI_ADDR_SPACE_LIMITS_STORE - * Sets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_STORE() \ - pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ - pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ - pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ - pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ - pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ - pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; - -#define PCI_ADDR_SPACE_LIMITS_PRINT() \ - printf("+++++++++++++++++++++++\n" \ - "IO base 0x%x last 0x%x\n" \ - "SWIN base 0x%x last 0x%x\n" \ - "MEM base 0x%x last 0x%x\n" \ - "+++++++++++++++++++++++\n", \ - pcibr_soft->bs_spinfo.pci_io_base, \ - pcibr_soft->bs_spinfo.pci_io_last, \ - pcibr_soft->bs_spinfo.pci_swin_base, \ - pcibr_soft->bs_spinfo.pci_swin_last, \ - pcibr_soft->bs_spinfo.pci_mem_base, \ - pcibr_soft->bs_spinfo.pci_mem_last); - -/* - * pcibr_slot_info_init - * Probe for this slot and see if it is populated. - * If it is populated initialize the generic PCI infrastructural - * information associated with this particular PCI device. - */ -int -pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - cfg_p cfgw; - unsigned idword; - unsigned pfail; - unsigned idwords[8]; - pciio_vendor_id_t vendor; - pciio_device_id_t device; - unsigned htype; - cfg_p wptr; - int win; - pciio_space_t space; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - int nfunc; - pciio_function_t rfunc; - int func; - devfs_handle_t conn_vhdl; - pcibr_soft_slot_t slotp; - - /* Get the basic software information required to proceed */ - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization - * is done by the host slot then we are done. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - /* Check for a slot with any system critical functions */ - if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - /* Load the current values of allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - /* Try to read the device-id/vendor-id from the config space */ - cfgw = bridge->b_type0_cfg_dev[slot].l; - - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(ENODEV); - - slotp = &pcibr_soft->bs_slot[slot]; - slotp->slot_status |= SLOT_POWER_UP; - - vendor = 0xFFFF & idword; - /* If the vendor id is not valid then the slot is not populated - * and we are done. - */ - if (vendor == 0xFFFF) - return(ENODEV); - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - - nfunc = 1; - rfunc = PCIIO_FUNC_NONE; - pfail = 0; - - /* NOTE: if a card claims to be multifunction - * but only responds to config space 0, treat - * it as a unifunction card. - */ - - if (htype & 0x80) { /* MULTIFUNCTION */ - for (func = 1; func < 8; ++func) { - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { - pfail |= 1 << func; - continue; - } - vendor = 0xFFFF & idwords[func]; - if (vendor == 0xFFFF) { - pfail |= 1 << func; - continue; - } - nfunc = func + 1; - rfunc = 0; - } - cfgw = bridge->b_type0_cfg_dev[slot].l; - } - NEWA(pcibr_infoh, nfunc); - - pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - for (func = 0; func < nfunc; ++func) { - unsigned cmd_reg; - - if (func) { - if (pfail & (1 << func)) - continue; - - idword = idwords[func]; - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - rfunc = func; - } - htype &= 0x7f; - if (htype != 0x00) { - printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", - pcibr_soft->bs_name, slot, func, htype); - continue; - } -#if DEBUG && ATTACH_DEBUG - printk(KERN_NOTICE - "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", - pcibr_soft->bs_name, slot, func, vendor, device); -#endif - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, rfunc, vendor, device); - conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); - if (func == 0) - slotp->slot_conn = conn_vhdl; - -#ifdef LITTLE_ENDIAN - cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4]; -#else - cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; -#endif - - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { - iopaddr_t base, mask, code; - size_t size; - - /* - * GET THE BASE & SIZE OF THIS WINDOW: - * - * The low two or four bits of the BASE register - * determines which address space we are in; the - * rest is a base address. BASE registers - * determine windows that are power-of-two sized - * and naturally aligned, so we can get the size - * of a window by writing all-ones to the - * register, reading it back, and seeing which - * bits are used for decode; the least - * significant nonzero bit is also the size of - * the window. - * - * WARNING: someone may already have allocated - * some PCI space to this window, and in fact - * PIO may be in process at this very moment - * from another processor (or even from this - * one, if we get interrupted)! So, if the BASE - * already has a nonzero address, be generous - * and use the LSBit of that address as the - * size; this could overstate the window size. - * Usually, when one card is set up, all are set - * up; so, since we don't bitch about - * overlapping windows, we are ok. - * - * UNFORTUNATELY, some cards do not clear their - * BASE registers on reset. I have two heuristics - * that can detect such cards: first, if the - * decode enable is turned off for the space - * that the window uses, we can disregard the - * initial value. second, if the address is - * outside the range that we use, we can disregard - * it as well. - * - * This is looking very PCI generic. Except for - * knowing how many slots and where their config - * spaces are, this window loop and the next one - * could probably be shared with other PCI host - * adapters. It would be interesting to see if - * this could be pushed up into pciio, when we - * start supporting more PCI providers. - */ -#ifdef LITTLE_ENDIAN - base = wptr[((win*4)^4)/4]; -#else - base = wptr[win]; -#endif - - if (base & PCI_BA_IO_SPACE) { - /* BASE is in I/O space. */ - space = PCIIO_SPACE_IO; - mask = -4; - code = base & 3; - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { - base = 0; /* decode not enabled */ - } - } else { - /* BASE is in MEM space. */ - space = PCIIO_SPACE_MEM; - mask = -16; - code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { - base = 0; /* decode not enabled */ - } else if (base & 0xC0000000) { - base = 0; /* outside permissable range */ - } else if ((code == PCI_BA_MEM_64BIT) && -#ifdef LITTLE_ENDIAN - (wptr[(((win + 1)*4)^4)/4] != 0)) { -#else - (wptr[win + 1] != 0)) { -#endif /* LITTLE_ENDIAN */ - base = 0; /* outside permissable range */ - } - } - - if (base != 0) { /* estimate size */ - size = base & -base; - } else { /* calculate size */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ - size = wptr[((win*4)^4)/4]; /* get stored bits */ -#else - wptr[win] = ~0; /* turn on all bits */ - size = wptr[win]; /* get stored bits */ -#endif /* LITTLE_ENDIAN */ - size &= mask; /* keep addr */ - size &= -size; /* keep lsbit */ - if (size == 0) - continue; - } - - pcibr_info->f_window[win].w_space = space; - pcibr_info->f_window[win].w_base = base; - pcibr_info->f_window[win].w_size = size; - - /* - * If this window already has PCI space - * allocated for it, "subtract" that space from - * our running freeblocks. Don't worry about - * overlaps in existing allocated windows; we - * may be overstating their sizes anyway. - */ - - if (base && size) { - if (space == PCIIO_SPACE_IO) { - pcibr_freeblock_sub(&pci_io_fb, - &pci_io_fl, - base, size); - } else { - pcibr_freeblock_sub(&pci_lo_fb, - &pci_lo_fl, - base, size); - pcibr_freeblock_sub(&pci_hi_fb, - &pci_hi_fl, - base, size); - } - } -#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) - /* - * IOC3 BASE_ADDR* BUG WORKAROUND - * - - * If we write to BASE1 on the IOC3, the - * data in BASE0 is replaced. The - * original workaround was to remember - * the value of BASE0 and restore it - * when we ran off the end of the BASE - * registers; however, a later - * workaround was added (I think it was - * rev 1.44) to avoid setting up - * anything but BASE0, with the comment - * that writing all ones to BASE1 set - * the enable-parity-error test feature - * in IOC3's SCR bit 14. - * - * So, unless we defer doing any PCI - * space allocation until drivers - * attach, and set up a way for drivers - * (the IOC3 in paricular) to tell us - * generically to keep our hands off - * BASE registers, we gotta "know" about - * the IOC3 here. - * - * Too bad the PCI folks didn't reserve the - * all-zero value for 'no BASE here' (it is a - * valid code for an uninitialized BASE in - * 32-bit PCI memory space). - */ - - if ((vendor == IOC3_VENDOR_ID_NUM) && - (device == IOC3_DEVICE_ID_NUM)) - break; -#endif - if (code == PCI_BA_MEM_64BIT) { - win++; /* skip upper half */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = 0; /* which must be zero */ -#else - wptr[win] = 0; /* which must be zero */ -#endif /* LITTLE_ENDIAN */ - } - } /* next win */ - } /* next func */ - - /* Store back the values for allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_info_free - * Remove all the PCI infrastructural information associated - * with a particular PCI device. - */ -int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - int nfunc; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - - pcibr_device_info_free(pcibr_vhdl, slot); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - DELA(pcibr_infoh,nfunc); - pcibr_soft->bs_slot[slot].bss_ninfo = 0; - - return(0); -} - -int as_debug = 0; -/* - * pcibr_slot_addr_space_init - * Reserve chunks of PCI address space as required by - * the base registers in the card. - */ -int -pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - size_t align; - iopaddr_t mask; - int nbars; - int nfunc; - int func; - int win; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* Get the current values for the allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - if (as_debug) -#ifdef LATER - PCI_ADDR_SPACE_LIMITS_PRINT(); -#endif - /* allocate address space, - * for windows that have not been - * previously assigned. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - if (nfunc < 1) - return(EINVAL); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - if (!pcibr_infoh) - return(EINVAL); - - /* - * Try to make the DevIO windows not - * overlap by pushing the "io" and "hi" - * allocation areas up to the next one - * or two megabyte bound. This also - * keeps them from being zero. - * - * DO NOT do this with "pci_lo" since - * the entire "lo" area is only a - * megabyte, total ... - */ - align = (slot < 2) ? 0x200000 : 0x100000; - mask = -align; - pci_io_fb = (pci_io_fb + align - 1) & mask; - pci_hi_fb = (pci_hi_fb + align - 1) & mask; - - for (func = 0; func < nfunc; ++func) { - cfg_p cfgw; - cfg_p wptr; - pciio_space_t space; - iopaddr_t base; - size_t size; - cfg_p pci_cfg_cmd_reg_p; - unsigned pci_cfg_cmd_reg; - unsigned pci_cfg_cmd_reg_add = 0; - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - nbars = PCI_CFG_BASE_ADDRS; - - for (win = 0; win < nbars; ++win) { - - space = pcibr_info->f_window[win].w_space; - base = pcibr_info->f_window[win].w_base; - size = pcibr_info->f_window[win].w_size; - - if (size < 1) - continue; - - if (base >= size) { -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", - slot, func, win, space, base, base + size - 1); -#endif - continue; /* already allocated */ - } - align = size; /* ie. 0x00001000 */ - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ - mask = -align; /* ie. 0xFFFFC000 */ - - switch (space) { - case PCIIO_SPACE_IO: - base = (pci_io_fb + align - 1) & mask; - if ((base + size) > pci_io_fl) { - base = 0; - break; - } - pci_io_fb = base + size; - break; - - case PCIIO_SPACE_MEM: -#ifdef LITTLE_ENDIAN - if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == -#else - if ((wptr[win] & PCI_BA_MEM_LOCATION) == -#endif /* LITTLE_ENDIAN */ - PCI_BA_MEM_1MEG) { - /* allocate from 20-bit PCI space */ - base = (pci_lo_fb + align - 1) & mask; - if ((base + size) > pci_lo_fl) { - base = 0; - break; - } - pci_lo_fb = base + size; - } else { - /* allocate from 32-bit or 64-bit PCI space */ - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) { - base = 0; - break; - } - pci_hi_fb = base + size; - } - break; - - default: - base = 0; -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d window %d had bad space code %d\n", - slot, win, space); -#endif - } - pcibr_info->f_window[win].w_base = base; -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = base; -#if DEBUG && PCI_DEBUG - printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); -#endif -#else - wptr[win] = base; -#endif /* LITTLE_ENDIAN */ - -#if DEBUG && PCI_DEBUG - if (base >= size) - printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", - slot, func, win, space, base, base + size - 1); - else - printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", - slot, func, win, size, space); -#endif - } /* next base */ - - /* - * Allocate space for the EXPANSION ROM - * NOTE: DO NOT DO THIS ON AN IOC3, - * as it blows the system away. - */ - base = size = 0; - if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || - (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { - - wptr = cfgw + PCI_EXPANSION_ROM / 4; -#ifdef LITTLE_ENDIAN - wptr[1] = 0xFFFFF000; - mask = wptr[1]; -#else - *wptr = 0xFFFFF000; - mask = *wptr; -#endif /* LITTLE_ENDIAN */ - if (mask & 0xFFFFF000) { - size = mask & -mask; - align = size; - if (align < _PAGESZ) - align = _PAGESZ; - mask = -align; - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) - base = size = 0; - else { - pci_hi_fb = base + size; -#ifdef LITTLE_ENDIAN - wptr[1] = base; -#else - *wptr = base; -#endif /* LITTLE_ENDIAN */ -#if DEBUG && PCI_DEBUG - printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", - pcibr_soft->bs_name, slot, - base, base + size - 1); -#endif - } - } - } - pcibr_info->f_rbase = base; - pcibr_info->f_rsize = size; - - /* - * if necessary, update the board's - * command register to enable decoding - * in the windows we added. - * - * There are some bits we always want to - * be sure are set. - */ - pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - - /* - * The Adaptec 1160 FC Controller WAR #767995: - * The part incorrectly ignores the upper 32 bits of a 64 bit - * address when decoding references to its registers so to - * keep it from responding to a bus cycle that it shouldn't - * we only use I/O space to get at it's registers. Don't - * enable memory space accesses on that PCI device. - */ - #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ - #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ - - if ((pcibr_info->f_vendor != FCADP_VENDID) || - (pcibr_info->f_device != FCADP_DEVID)) - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; - - pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - - pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; - pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; -#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ - if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) - fast_back_to_back_enable = 0; -#endif - pci_cfg_cmd_reg &= 0xFFFF; - if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; - - } /* next func */ - - /* Now that we have allocated new chunks of PCI address spaces to this - * card we need to update the bookkeeping values which indicate - * the current PCI address space allocations. - */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_device_init - * Setup the device register in the bridge for this PCI slot. - */ -int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - bridgereg_t devreg; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* - * Adjustments to Device(x) - * and init of bss_device shadow - */ - devreg = bridge->b_device[slot].reg; - devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; - devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; -#ifdef LITTLE_ENDIAN - devreg |= BRIDGE_DEV_DEV_SWAP; -#endif - pcibr_soft->bs_slot[slot].bss_device = devreg; - bridge->b_device[slot].reg = devreg; - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); -#endif - -#if DEBUG && PCI_DEBUG - printk("pcibr: PCI space allocation done.\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_guest_info_init - * Setup the host/guest relations for a PCI slot. - */ -int -pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - pcibr_soft_slot_t slotp; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - slotp = &pcibr_soft->bs_slot[slot]; - - /* create info and verticies for guest slots; - * for compatibilitiy macros, create info - * for even unpopulated slots (but do not - * build verticies for them). - */ - if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { - NEWA(pcibr_infoh, 1); - pcibr_soft->bs_slot[slot].bss_ninfo = 1; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - - if (pcibr_soft->bs_slot[slot].has_host) { - slotp->slot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - } - } - - /* generate host/guest relations - */ - if (pcibr_soft->bs_slot[slot].has_host) { - int host = pcibr_soft->bs_slot[slot].host_slot; - pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; - - hwgraph_edge_add(slotp->slot_conn, - host_slotp->slot_conn, - EDGE_LBL_HOST); - - /* XXX- only gives us one guest edge per - * host. If/when we have a host with more than - * one guest, we will need to figure out how - * the host finds all its guests, and sorts - * out which one is which. - */ - hwgraph_edge_add(host_slotp->slot_conn, - slotp->slot_conn, - EDGE_LBL_GUEST); - } - - return(0); -} - -/* - * pcibr_slot_initial_rrb_alloc - * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation - * strategy routine defined per platform. - */ - -int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - int c0, c1; - int r; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* How may RRBs are on this slot? - */ - c0 = do_pcibr_rrb_count_valid(bridge, slot); - c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); - -#if PCIBR_RRB_DEBUG - printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); -#endif - - /* Do we really need any? - */ - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - pcibr_info = pcibr_infoh[0]; - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - if (c0 > 0) - do_pcibr_rrb_free(bridge, slot, c0); - if (c1 > 0) - do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); - pcibr_soft->bs_rrb_valid[slot] = 0x1000; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(ENODEV); - } - - pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; - pcibr_soft->bs_rrb_valid[slot] = c0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; - - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); - - r = 3 - (c0 + c1); - - if (r > 0) { - pcibr_soft->bs_rrb_res[slot] = r; - pcibr_soft->bs_rrb_avail[slot & 1] -= r; - } - -#if PCIBR_RRB_DEBUG - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - async_attach_t aa = NULL; - int func; - devfs_handle_t xconn_vhdl,conn_vhdl; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - - if (pcibr_soft->bs_slot[slot].has_host) { - return(EPERM); - } - - xconn_vhdl = pcibr_soft->bs_conn; - aa = async_attach_get_info(xconn_vhdl); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - -#ifdef LATER - /* - * Activate if and when we support cdl. - */ - if (aa) - async_attach_add_info(conn_vhdl, aa); -#endif /* LATER */ - - error_func = pciio_device_attach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; - } else { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int func; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_soft->bs_slot[slot].has_host) - return(EPERM); - - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - - error_func = pciio_device_detach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; - } else { - if (conn_vhdl != GRAPH_VERTEX_NONE) - pcibr_device_unregister(conn_vhdl); - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. - */ -int -pcibr_slot_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - int error; - - /* Call the device detach function */ - error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); - return (error); - -} - -/* - * pcibr_is_slot_sys_critical - * Check slot for any functions that are system critical. - * Return 1 if any are system critical or 0 otherwise. - * - * This function will always return 0 when called by - * pcibr_attach() because the system critical vertices - * have not yet been set in the hwgraph. - */ -int -pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int func; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(0); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - if (is_sys_critical_vertex(conn_vhdl)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); -#else - printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); -#endif - return(1); - } - - } - - return(0); -} - -/* - * pcibr_device_unregister - * This frees up any hardware resources reserved for this PCI device - * and removes any PCI infrastructural information setup for it. - * This is usually used at the time of shutting down of the PCI card. - */ -int -pcibr_device_unregister(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - int error_call; - int error = 0; - - pciio_info = pciio_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Clear all the hardware xtalk resources for this device */ - xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); - - /* Flush all the rrbs */ - pcibr_rrb_flush(pconn_vhdl); - - /* Free the rrbs allocated to this slot */ - error_call = do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]); - - if (error_call) - error = ERANGE; - - pcibr_soft->bs_rrb_valid[slot] = 0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; - pcibr_soft->bs_rrb_res[slot] = 0; - - /* Flush the write buffers !! */ - error_call = pcibr_wrb_flush(pconn_vhdl); - - if (error_call) - error = error_call; - - /* Clear the information specific to the slot */ - error_call = pcibr_slot_info_free(pcibr_vhdl, slot); - - if (error_call) - error = error_call; - - return(error); - -} - -/* - * build a convenience link path in the - * form of "...//bus/" - * - * returns 1 on success, 0 otherwise - * - * depends on hwgraph separator == '/' - */ -int -pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) -{ - char dst[MAXDEVNAME]; - char *dp = dst; - char *cp, *xp; - int widgetnum; - char pcibus[8]; - devfs_handle_t nvtx, svtx; - int rv; - -#if DEBUG - printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", - slot, f_c); - { - int pos; - char dname[256]; - pos = devfs_generate_path(f_c, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) - return 0; - - /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ - - /* find the widget number */ - xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); - if (xp == NULL) - return 0; - widgetnum = atoi(xp+7); - if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) - return 0; - - /* remove "/pci/direct" from path */ - cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); - if (cp == NULL) - return 0; - *cp = (char)NULL; - - /* get the vertex for the widget */ - if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) - return 0; - - *xp = (char)NULL; /* remove "/xtalk/..." from path */ - - /* dst example now == /hw/module/001c02/Pbrick */ - - /* get the bus number */ - strcat(dst, "/bus"); - sprintf(pcibus, "%d", p_busnum[widgetnum]); - - /* link to bus to widget */ - rv = hwgraph_path_add(NULL, dp, &nvtx); - if (GRAPH_SUCCESS == rv) - rv = hwgraph_edge_add(nvtx, svtx, pcibus); - - return (rv == GRAPH_SUCCESS); -} - - -/* - * pcibr_attach: called every time the crosstalk - * infrastructure is asked to initialize a widget - * that matches the part number we handed to the - * registration routine above. - */ -/*ARGSUSED */ -int -pcibr_attach(devfs_handle_t xconn_vhdl) -{ - /* REFERENCED */ - graph_error_t rc; - devfs_handle_t pcibr_vhdl; - devfs_handle_t ctlr_vhdl; - bridge_t *bridge = NULL; - bridgereg_t id; - int rev; - pcibr_soft_t pcibr_soft; - pcibr_info_t pcibr_info; - xwidget_info_t info; - xtalk_intr_t xtalk_intr; - device_desc_t dev_desc = (device_desc_t)0; - int slot; - int ibit; - devfs_handle_t noslot_conn; - char devnm[MAXDEVNAME], *s; - pcibr_hints_t pcibr_hints; - bridgereg_t b_int_enable; - unsigned rrb_fixed = 0; - - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - - int spl_level; -#ifdef LATER - char *nicinfo = (char *)0; -#endif - -#if PCI_FBBE - int fast_back_to_back_enable; -#endif - l1sc_t *scp; - nasid_t nasid; - - async_attach_t aa = NULL; - - aa = async_attach_get_info(xconn_vhdl); - -#if DEBUG && ATTACH_DEBUG - printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); - { - int pos; - char dname[256]; - pos = devfs_generate_path(xconn_vhdl, dname, 256); - printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif - - /* Setup the PRB for the bridge in CONVEYOR BELT - * mode. PRBs are setup in default FIRE-AND-FORGET - * mode during the initialization. - */ - hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); - - bridge = (bridge_t *) - xtalk_piotrans_addr(xconn_vhdl, NULL, - 0, sizeof(bridge_t), 0); - -#ifndef MEDUSA_HACK - if ((bridge->b_wid_stat & BRIDGE_STAT_PCI_GIO_N) == 0) - return -1; /* someone else handles GIO bridges. */ -#endif - - if (XWIDGET_PART_REV_NUM(bridge->b_wid_id) == XBRIDGE_PART_REV_A) - NeedXbridgeSwap = 1; - - /* - * Create the vertex for the PCI bus, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); - - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - - ASSERT(ctlr_vhdl != NULL); - - /* - * decode the nic, and hang its stuff off our - * connection point where other drivers can get - * at it. - */ -#ifdef LATER - nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); -#endif - - /* - * Get the hint structure; if some NIC callback - * marked this vertex as "hands-off" then we - * just return here, before doing anything else. - */ - pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); - - if (pcibr_hints && pcibr_hints->ph_hands_off) - return -1; /* generic operations disabled */ - - id = bridge->b_wid_id; - rev = XWIDGET_PART_REV_NUM(id); - - hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); - - /* - * allocate soft state structure, fill in some - * fields, and hook it up to our vertex. - */ - NEW(pcibr_soft); - BZERO(pcibr_soft, sizeof *pcibr_soft); - pcibr_soft_set(pcibr_vhdl, pcibr_soft); - - pcibr_soft->bs_conn = xconn_vhdl; - pcibr_soft->bs_vhdl = pcibr_vhdl; - pcibr_soft->bs_base = bridge; - pcibr_soft->bs_rev_num = rev; - pcibr_soft->bs_intr_bits = pcibr_intr_bits; - if (is_xbridge(bridge)) { - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 1; - } else { - pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 0; - } - - nasid = NASID_GET(bridge); - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - pcibr_soft->bs_l1sc = scp; - pcibr_soft->bs_moduleid = iobrick_module_get(scp); - pcibr_soft->bsi_err_intr = 0; - - /* Bridges up through REV C - * are unable to set the direct - * byteswappers to BYTE_STREAM. - */ - if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { - pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; - pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; - } -#if PCIBR_SOFT_LIST - { - pcibr_list_p self; - - NEW(self); - self->bl_soft = pcibr_soft; - self->bl_vhdl = pcibr_vhdl; - self->bl_next = pcibr_list; - pcibr_list = self; - } -#endif - - /* - * get the name of this bridge vertex and keep the info. Use this - * only where it is really needed now: like error interrupts. - */ - s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); - pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(pcibr_soft->bs_name, s); - -#if SHOW_REVS || DEBUG -#if !DEBUG - if (kdebug) -#endif - printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", - is_xbridge(bridge) ? "X" : "", - (rev == BRIDGE_PART_REV_A) ? "A" : - (rev == BRIDGE_PART_REV_B) ? "B" : - (rev == BRIDGE_PART_REV_C) ? "C" : - (rev == BRIDGE_PART_REV_D) ? "D" : - (rev == XBRIDGE_PART_REV_A) ? "A" : - (rev == XBRIDGE_PART_REV_B) ? "B" : - "unknown", - rev, pcibr_soft->bs_name); -#endif - - info = xwidget_info_get(xconn_vhdl); - pcibr_soft->bs_xid = xwidget_info_id_get(info); - pcibr_soft->bs_master = xwidget_info_master_get(info); - pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); - - /* - * Init bridge lock. - */ - spin_lock_init(&pcibr_soft->bs_lock); - - /* - * If we have one, process the hints structure. - */ - if (pcibr_hints) { - rrb_fixed = pcibr_hints->ph_rrb_fixed; - - pcibr_soft->bs_rrb_fixed = rrb_fixed; - - if (pcibr_hints->ph_intr_bits) - pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; - - for (slot = 0; slot < 8; ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; - - if (hslot < 0) { - pcibr_soft->bs_slot[slot].host_slot = slot; - } else { - pcibr_soft->bs_slot[slot].has_host = 1; - pcibr_soft->bs_slot[slot].host_slot = hslot; - } - } - } - /* - * set up initial values for state fields - */ - for (slot = 0; slot < 8; ++slot) { - pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); - } - - for (ibit = 0; ibit < 8; ++ibit) { - pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = - &(bridge->b_int_status); - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; - } - - /* - * Initialize various Bridge registers. - */ - - /* - * On pre-Rev.D bridges, set the PCI_RETRY_CNT - * to zero to avoid dropping stores. (#475347) - */ - if (rev < BRIDGE_PART_REV_D) - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; - - /* - * Clear all pending interrupts. - */ - bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); - - /* - * Until otherwise set up, - * assume all interrupts are - * from slot 7. - */ - bridge->b_int_device = (uint32_t) 0xffffffff; - - { - bridgereg_t dirmap; - paddr_t paddr; - iopaddr_t xbase; - xwidgetnum_t xport; - iopaddr_t offset; - int num_entries = 0; - int entry; - cnodeid_t cnodeid; - nasid_t nasid; - - /* Set the Bridge's 32-bit PCI to XTalk - * Direct Map register to the most useful - * value we can determine. Note that we - * must use a single xid for all of: - * direct-mapped 32-bit DMA accesses - * direct-mapped 64-bit DMA accesses - * DMA accesses through the PMU - * interrupts - * This is the only way to guarantee that - * completion interrupts will reach a CPU - * after all DMA data has reached memory. - * (Of course, there may be a few special - * drivers/controlers that explicitly manage - * this ordering problem.) - */ - - cnodeid = 0; /* default node id */ - /* - * Determine the base address node id to be used for all 32-bit - * Direct Mapping I/O. The default is node 0, but this can be changed - * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE - * attribute in the irix.sm config file. A device driver can obtain - * this node value via a call to pcibr_get_dmatrans_node(). - */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - paddr = NODE_OFFSET(nasid) + 0; - - /* currently, we just assume that if we ask - * for a DMA mapping to "zero" the XIO - * host will transmute this into a request - * for the lowest hunk of memory. - */ - xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, - paddr, _PAGESZ, 0); - - if (xbase != XIO_NOWHERE) { - if (XIO_PACKED(xbase)) { - xport = XIO_PORT(xbase); - xbase = XIO_ADDR(xbase); - } else - xport = pcibr_soft->bs_mxid; - - offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); - xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; - - dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; - - if (xbase) - dirmap |= BRIDGE_DIRMAP_OFF & xbase; - else if (offset >= (512 << 20)) - dirmap |= BRIDGE_DIRMAP_ADD512; - - bridge->b_dir_map = dirmap; - } - /* - * Set bridge's idea of page size according to the system's - * idea of "IO page size". TBD: The idea of IO page size - * should really go away. - */ - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - spl_level = splhi(); -#if IOPGSIZE == 4096 - bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; -#elif IOPGSIZE == 16384 - bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; -#else - <<>>; -#endif - bridge->b_wid_control; /* inval addr bug war */ - splx(spl_level); - - /* Initialize internal mapping entries */ - for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) - bridge->b_int_ate_ram[entry].wr = 0; - - /* - * Determine if there's external mapping SSRAM on this - * bridge. Set up Bridge control register appropriately, - * inititlize SSRAM, and set software up to manage RAM - * entries as an allocatable resource. - * - * Currently, we just use the rm* routines to manage ATE - * allocation. We should probably replace this with a - * Best Fit allocator. - * - * For now, if we have external SSRAM, avoid using - * the internal ssram: we can't turn PREFETCH on - * when we use the internal SSRAM; and besides, - * this also guarantees that no allocation will - * straddle the internal/external line, so we - * can increment ATE write addresses rather than - * recomparing against BRIDGE_INTERNAL_ATES every - * time. - */ - if (is_xbridge(bridge)) - num_entries = 0; - else - num_entries = pcibr_init_ext_ate_ram(bridge); - - /* we always have 128 ATEs (512 for Xbridge) inside the chip - * even if disabled for debugging. - */ - pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); - pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); -#endif - - if (num_entries > pcibr_soft->bs_int_ate_size) { -#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ - printk("pcibr_attach: disabling internal ATEs.\n"); - pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); -#endif - pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); - pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, - num_entries - pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d EXTERNAL ATEs\n", - num_entries - pcibr_soft->bs_int_ate_size); -#endif - } - } - - { - bridgereg_t dirmap; - iopaddr_t xbase; - - /* - * now figure the *real* xtalk base address - * that dirmap sends us to. - */ - dirmap = bridge->b_dir_map; - if (dirmap & BRIDGE_DIRMAP_OFF) - xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) - << BRIDGE_DIRMAP_OFF_ADDRSHFT; - else if (dirmap & BRIDGE_DIRMAP_ADD512) - xbase = 512 << 20; - else - xbase = 0; - - pcibr_soft->bs_dir_xbase = xbase; - - /* it is entirely possible that we may, at this - * point, have our dirmap pointing somewhere - * other than our "master" port. - */ - pcibr_soft->bs_dir_xport = - (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; - } - - /* pcibr sources an error interrupt; - * figure out where to send it. - * - * If any interrupts are enabled in bridge, - * then the prom set us up and our interrupt - * has already been reconnected in mlreset - * above. - * - * Need to set the D_INTR_ISERR flag - * in the dev_desc used for allocating the - * error interrupt, so our interrupt will - * be properly routed and prioritized. - * - * If our crosstalk provider wants to - * fix widget error interrupts to specific - * destinations, D_INTR_ISERR is how it - * knows to do this. - */ - - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); - ASSERT(xtalk_intr != NULL); - - pcibr_soft->bsi_err_intr = xtalk_intr; - - /* - * On IP35 with XBridge, we do some extra checks in pcibr_setwidint - * in order to work around some addressing limitations. In order - * for that fire wall to work properly, we need to make sure we - * start from a known clean state. - */ - pcibr_clearwidint(bridge); - - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); - - /* - * now we can start handling error interrupts; - * enable all of them. - * NOTE: some PCI ints may already be enabled. - */ - b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; - - - bridge->b_int_enable = b_int_enable; - bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ - - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * Depending on the rev of bridge, disable certain features. - * Easiest way seems to be to force the PCIBR_NOwhatever - * flag to be on for all DMA calls, which overrides any - * PCIBR_whatever flag or even the setting of whatever - * from the PCIIO_DMA_class flags (or even from the other - * PCIBR flags, since NO overrides YES). - */ - pcibr_soft->bs_dma_flags = 0; - - /* PREFETCH: - * Always completely disabled for REV.A; - * at "pcibr_prefetch_enable_rev", anyone - * asking for PCIIO_PREFETCH gets it. - * Between these two points, you have to ask - * for PCIBR_PREFETCH, which promises that - * your driver knows about known Bridge WARs. - */ - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) - pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; - else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - - /* WRITE_GATHER: - * Disabled up to but not including the - * rev number in pcibr_wg_enable_rev. There - * is no "WAR range" as with prefetch. - */ - if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; - - pciio_provider_register(pcibr_vhdl, &pcibr_provider); - pciio_provider_startup(pcibr_vhdl); - - pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ - pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ - - pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ - pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ - - pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ - pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ - - - PCI_ADDR_SPACE_LIMITS_STORE(); - - /* build "no-slot" connection point - */ - pcibr_info = pcibr_device_info_new - (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - noslot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - - /* Remember the no slot connection point info for tearing it - * down during detach. - */ - pcibr_soft->bs_noslot_conn = noslot_conn; - pcibr_soft->bs_noslot_info = pcibr_info; -#if PCI_FBBE - fast_back_to_back_enable = 1; -#endif - -#if PCI_FBBE - if (fast_back_to_back_enable) { - /* - * All devices on the bus are capable of fast back to back, so - * we need to set the fast back to back bit in all devices on - * the bus that are capable of doing such accesses. - */ - } -#endif - -#ifdef LATER - /* If the bridge has been reset then there is no need to reset - * the individual PCI slots. - */ - for (slot = 0; slot < 8; ++slot) - /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl, slot); -#endif - - for (slot = 0; slot < 8; ++slot) - /* Find out what is out there */ - (void)pcibr_slot_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Set up the address space for this slot in the pci land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - -#ifndef __ia64 - for (slot = 0; slot < 8; ++slot) - /* Set up convenience links */ - if (is_xbridge(bridge)) - if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ - pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); -#endif - - for (slot = 0; slot < 8; ++slot) - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Initial RRB management */ - (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); - - /* driver attach routines should be called out from generic linux code */ - for (slot = 0; slot < 8; ++slot) - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); - - /* - * Each Pbrick PCI bus only has slots 1 and 2. Similarly for - * widget 0xe on Ibricks. Allocate RRB's accordingly. - */ - if (pcibr_soft->bs_moduleid > 0) { - switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { - case 'p': /* Pbrick */ - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - break; - case 'i': /* Ibrick */ - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); - } - break; - } /* switch */ - } - -#ifdef LATER - if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); -#if PCIBR_RRB_DEBUG - printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); - - printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", - pcibr_vhdl, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - - for (slot = 0; slot < 8; ++slot) - printf("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - - printf("\n"); -#endif - } -#else - FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif - - if (aa) - async_attach_add_info(noslot_conn, aa); - - pciio_device_attach(noslot_conn, 0); - - - /* - * Tear down pointer to async attach info -- async threads for - * bridge's descendants may be running but the bridge's work is done. - */ - if (aa) - async_attach_del_info(xconn_vhdl); - - return 0; -} -/* - * pcibr_detach: - * Detach the bridge device from the hwgraph after cleaning out all the - * underlying vertices. - */ -int -pcibr_detach(devfs_handle_t xconn) -{ - pciio_slot_t slot; - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - - /* Get the bridge vertex from its xtalk connection point */ - if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) - return(1); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Disable the interrupts from the bridge */ - bridge->b_int_enable = 0; - - /* Detach all the PCI devices talking to this bridge */ - for(slot = 0; slot < 8; slot++) { -#ifdef DEBUG - printk("pcibr_device_detach called for %p/%d\n", - pcibr_vhdl,slot); -#endif - pcibr_slot_detach(pcibr_vhdl, slot, 0); - } - - /* Unregister the no-slot connection point */ - pciio_device_info_unregister(pcibr_vhdl, - &(pcibr_soft->bs_noslot_info->f_c)); - - spin_lock_destroy(&pcibr_soft->bs_lock); - kfree(pcibr_soft->bs_name); - - /* Error handler gets unregistered when the widget info is - * cleaned - */ - /* Free the soft ATE maps */ - if (pcibr_soft->bs_int_ate_map) - rmfreemap(pcibr_soft->bs_int_ate_map); - if (pcibr_soft->bs_ext_ate_map) - rmfreemap(pcibr_soft->bs_ext_ate_map); - - /* Disconnect the error interrupt and free the xtalk resources - * associated with it. - */ - xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); - xtalk_intr_free(pcibr_soft->bsi_err_intr); - - /* Clear the software state maintained by the bridge driver for this - * bridge. - */ - DEL(pcibr_soft); - /* Remove the Bridge revision labelled info */ - (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); - /* Remove the character device associated with this bridge */ - (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); - /* Remove the PCI bridge vertex */ - (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); - - return(0); -} - -int -pcibr_asic_rev(devfs_handle_t pconn_vhdl) -{ - devfs_handle_t pcibr_vhdl; - arbitrary_info_t ainfo; - - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) - return -1; - - if (GRAPH_SUCCESS != - hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) - return -1; - - return (int) ainfo; -} - -int -pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t slot; - slot = pciio_info_slot_get(pciio_info); - pcibr_device_write_gather_flush(pcibr_soft, slot); - return 0; -} - -/* ===================================================================== - * PIO MANAGEMENT - */ - -LOCAL iopaddr_t -pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, - pciio_slot_t slot, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - unsigned bar; /* which BASE reg on device is decoding */ - iopaddr_t xio_addr = XIO_NOWHERE; - - pciio_space_t wspace; /* which space device is decoding */ - iopaddr_t wbase; /* base of device decode on PCI */ - size_t wsize; /* size of device decode on PCI */ - - int try; /* DevIO(x) window scanning order control */ - int win; /* which DevIO(x) window is being used */ - pciio_space_t mspace; /* target space for devio(x) register */ - iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ - size_t msize; /* size of devio(x) mapped area on PCI */ - size_t mmask; /* addr bits stored in Device(x) */ - - unsigned long s; - - s = pcibr_lock(pcibr_soft); - - if (pcibr_soft->bs_slot[slot].has_host) { - slot = pcibr_soft->bs_slot[slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; - } - if (space == PCIIO_SPACE_NONE) - goto done; - - if (space == PCIIO_SPACE_CFG) { - /* - * Usually, the first mapping - * established to a PCI device - * is to its config space. - * - * In any case, we definitely - * do NOT need to worry about - * PCI BASE registers, and - * MUST NOT attempt to point - * the DevIO(x) window at - * this access ... - */ - if (((flags & PCIIO_BYTE_STREAM) == 0) && - ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) - xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); - - goto done; - } - if (space == PCIIO_SPACE_ROM) { - /* PIO to the Expansion Rom. - * Driver is responsible for - * enabling and disabling - * decodes properly. - */ - wbase = pcibr_info->f_rbase; - wsize = pcibr_info->f_rsize; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - pci_addr += wbase; - space = PCIIO_SPACE_MEM; - } - /* - * reduce window mappings to raw - * space mappings (maybe allocating - * windows), and try for DevIO(x) - * usage (setting it if it is available). - */ - bar = space - PCIIO_SPACE_WIN0; - if (bar < 6) { - wspace = pcibr_info->f_window[bar].w_space; - if (wspace == PCIIO_SPACE_NONE) - goto done; - - /* get PCI base and size */ - wbase = pcibr_info->f_window[bar].w_base; - wsize = pcibr_info->f_window[bar].w_size; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - /* shift from window relative to - * decoded space relative. - */ - pci_addr += wbase; - space = wspace; - } else - bar = -1; - - /* Scan all the DevIO(x) windows twice looking for one - * that can satisfy our request. The first time through, - * only look at assigned windows; the second time, also - * look at PCIIO_SPACE_NONE windows. Arrange the order - * so we always look at our own window first. - * - * We will not attempt to satisfy a single request - * by concatinating multiple windows. - */ - for (try = 0; try < 16; ++try) { - bridgereg_t devreg; - unsigned offset; - - win = (try + slot) % 8; - - /* If this DevIO(x) mapping area can provide - * a mapping to this address, use it. - */ - msize = (win < 2) ? 0x200000 : 0x100000; - mmask = -msize; - if (space != PCIIO_SPACE_IO) - mmask &= 0x3FFFFFFF; - - offset = pci_addr & (msize - 1); - - /* If this window can't possibly handle that request, - * go on to the next window. - */ - if (((pci_addr & (msize - 1)) + req_size) > msize) - continue; - - devreg = pcibr_soft->bs_slot[win].bss_device; - - /* Is this window "nailed down"? - * If not, maybe we can use it. - * (only check this the second time through) - */ - mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; - if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { - - /* If this is the primary DevIO(x) window - * for some other device, skip it. - */ - if ((win != slot) && - (PCIIO_VENDOR_ID_NONE != - pcibr_soft->bs_slot[win].bss_vendor_id)) - continue; - - /* It's a free window, and we fit in it. - * Set up Device(win) to our taste. - */ - mbase = pci_addr & mmask; - - /* check that we would really get from - * here to there. - */ - if ((mbase | offset) != pci_addr) - continue; - - devreg &= ~BRIDGE_DEV_OFF_MASK; - if (space != PCIIO_SPACE_IO) - devreg |= BRIDGE_DEV_DEV_IO_MEM; - else - devreg &= ~BRIDGE_DEV_DEV_IO_MEM; - devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; - - /* default is WORD_VALUES. - * if you specify both, - * operation is undefined. - */ - if (flags & PCIIO_BYTE_STREAM) - devreg |= BRIDGE_DEV_DEV_SWAP; - else - devreg &= ~BRIDGE_DEV_DEV_SWAP; - - if (pcibr_soft->bs_slot[win].bss_device != devreg) { - bridge->b_device[win].reg = devreg; - pcibr_soft->bs_slot[win].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); -#endif - } - pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; - pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", - __FUNCTION__, __LINE__, space, space_desc, - pci_addr, pci_addr + req_size - 1, - slot, win, devreg); -#endif - - goto done; - } /* endif DevIO(x) not pointed */ - mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; - - /* Now check for request incompat with DevIO(x) - */ - if ((mspace != space) || - (pci_addr < mbase) || - ((pci_addr + req_size) > (mbase + msize)) || - ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || - (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) - continue; - - /* DevIO(x) window is pointed at PCI space - * that includes our target. Calculate the - * final XIO address, release the lock and - * return. - */ - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", - __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); -#endif - goto done; - } - - switch (space) { - /* - * Accesses to device decode - * areas that do a not fit - * within the DevIO(x) space are - * modified to be accesses via - * the direct mapping areas. - * - * If necessary, drivers can - * explicitly ask for mappings - * into these address spaces, - * but this should never be needed. - */ - case PCIIO_SPACE_MEM: /* "mem space" */ - case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; - break; - - case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; - break; - - case PCIIO_SPACE_IO: /* "i/o space" */ - /* Bridge Hardware Bug WAR #482741: - * The 4G area that maps directly from - * XIO space to PCI I/O space is busted - * until Bridge Rev D. - */ - if ((pcibr_soft->bs_rev_num > BRIDGE_PART_REV_C) && - ((pci_addr + BRIDGE_PCI_IO_BASE + req_size - 1) <= - BRIDGE_PCI_IO_LIMIT)) - xio_addr = pci_addr + BRIDGE_PCI_IO_BASE; - break; - } - - /* Check that "Direct PIO" byteswapping matches, - * try to change it if it does not. - */ - if (xio_addr != XIO_NOWHERE) { - unsigned bst; /* nonzero to set bytestream */ - unsigned *bfp; /* addr of record of how swapper is set */ - unsigned swb; /* which control bit to mung */ - unsigned bfo; /* current swapper setting */ - unsigned bfn; /* desired swapper setting */ - - bfp = ((space == PCIIO_SPACE_IO) - ? (&pcibr_soft->bs_pio_end_io) - : (&pcibr_soft->bs_pio_end_mem)); - - bfo = *bfp; - - bst = flags & PCIIO_BYTE_STREAM; - - bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; - - if (bfn == bfo) { /* we already match. */ - ; - } else if (bfo != 0) { /* we have a conflict. */ -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", - space, - bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - xio_addr = XIO_NOWHERE; - } else { /* OK to make the change. */ - bridgereg_t octl, nctl; - - swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; - octl = bridge->b_wid_control; - nctl = bst ? octl | swb : octl & ~swb; - - if (octl != nctl) /* make the change if any */ - bridge->b_wid_control = nctl; - - *bfp = bfn; /* record the assignment */ - -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", - space, - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - } - } - done: - pcibr_unlock(pcibr_soft, s); - return xio_addr; -} - -/*ARGSUSED6 */ -pcibr_piomap_t -pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - size_t req_size_max, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - pcibr_piomap_t *mapptr; - pcibr_piomap_t maplist; - pcibr_piomap_t pcibr_piomap; - iopaddr_t xio_addr; - xtalk_piomap_t xtalk_piomap; - unsigned long s; - - /* Make sure that the req sizes are non-zero */ - if ((req_size < 1) || (req_size_max < 1)) - return NULL; - - /* - * Code to translate slot/space/addr - * into xio_addr is common between - * this routine and pcibr_piotrans_addr. - */ - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - /* Check the piomap list to see if there is already an allocated - * piomap entry but not in use. If so use that one. Otherwise - * allocate a new piomap entry and add it to the piomap list - */ - mapptr = &(pcibr_info->f_piomap); - - s = pcibr_lock(pcibr_soft); - for (pcibr_piomap = *mapptr; - pcibr_piomap != NULL; - pcibr_piomap = pcibr_piomap->bp_next) { - if (pcibr_piomap->bp_mapsz == 0) - break; - } - - if (pcibr_piomap) - mapptr = NULL; - else { - pcibr_unlock(pcibr_soft, s); - NEW(pcibr_piomap); - } - - pcibr_piomap->bp_dev = pconn_vhdl; - pcibr_piomap->bp_slot = pciio_slot; - pcibr_piomap->bp_flags = flags; - pcibr_piomap->bp_space = space; - pcibr_piomap->bp_pciaddr = pci_addr; - pcibr_piomap->bp_mapsz = req_size; - pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); - - if (mapptr) { - s = pcibr_lock(pcibr_soft); - maplist = *mapptr; - pcibr_piomap->bp_next = maplist; - *mapptr = pcibr_piomap; - } - pcibr_unlock(pcibr_soft, s); - - - if (pcibr_piomap) { - xtalk_piomap = - xtalk_piomap_alloc(xconn_vhdl, 0, - xio_addr, - req_size, req_size_max, - flags & PIOMAP_FLAGS); - if (xtalk_piomap) { - pcibr_piomap->bp_xtalk_addr = xio_addr; - pcibr_piomap->bp_xtalk_pio = xtalk_piomap; - } else { - pcibr_piomap->bp_mapsz = 0; - pcibr_piomap = 0; - } - } - return pcibr_piomap; -} - -/*ARGSUSED */ -void -pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); - pcibr_piomap->bp_xtalk_pio = 0; - pcibr_piomap->bp_mapsz = 0; -} - -/*ARGSUSED */ -caddr_t -pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, - iopaddr_t pci_addr, - size_t req_size) -{ - return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, - pcibr_piomap->bp_xtalk_addr + - pci_addr - pcibr_piomap->bp_pciaddr, - req_size); -} - -/*ARGSUSED */ -void -pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); -} - -/*ARGSUSED */ -caddr_t -pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - iopaddr_t xio_addr; - - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); -} - -/* - * PIO Space allocation and management. - * Allocate and Manage the PCI PIO space (mem and io space) - * This routine is pretty simplistic at this time, and - * does pretty trivial management of allocation and freeing.. - * The current scheme is prone for fragmentation.. - * Change the scheme to use bitmaps. - */ - -/*ARGSUSED */ -iopaddr_t -pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - size_t req_size, - size_t alignment) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - pciio_piospace_t piosp; - unsigned long s; - - iopaddr_t *pciaddr, *pcilast; - iopaddr_t start_addr; - size_t align_mask; - - /* - * Check for proper alignment - */ - ASSERT(alignment >= NBPP); - ASSERT((alignment & (alignment - 1)) == 0); - - align_mask = alignment - 1; - s = pcibr_lock(pcibr_soft); - - /* - * First look if a previously allocated chunk exists. - */ - if ((piosp = pcibr_info->f_piospace)) { - /* - * Look through the list for a right sized free chunk. - */ - do { - if (piosp->free && - (piosp->space == space) && - (piosp->count >= req_size) && - !(piosp->start & align_mask)) { - piosp->free = 0; - pcibr_unlock(pcibr_soft, s); - return piosp->start; - } - piosp = piosp->next; - } while (piosp); - } - ASSERT(!piosp); - - switch (space) { - case PCIIO_SPACE_IO: - pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; - pcilast = &pcibr_soft->bs_spinfo.pci_io_last; - break; - case PCIIO_SPACE_MEM: - case PCIIO_SPACE_MEM32: - pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; - pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; - break; - default: - ASSERT(0); - pcibr_unlock(pcibr_soft, s); - return 0; - } - - start_addr = *pciaddr; - - /* - * Align start_addr. - */ - if (start_addr & align_mask) - start_addr = (start_addr + align_mask) & ~align_mask; - - if ((start_addr + req_size) > *pcilast) { - /* - * If too big a request, reject it. - */ - pcibr_unlock(pcibr_soft, s); - return 0; - } - *pciaddr = (start_addr + req_size); - - NEW(piosp); - piosp->free = 0; - piosp->space = space; - piosp->start = start_addr; - piosp->count = req_size; - piosp->next = pcibr_info->f_piospace; - pcibr_info->f_piospace = piosp; - - pcibr_unlock(pcibr_soft, s); - return start_addr; -} - -/*ARGSUSED */ -void -pcibr_piospace_free(devfs_handle_t pconn_vhdl, - pciio_space_t space, - iopaddr_t pciaddr, - size_t req_size) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - pciio_piospace_t piosp; - unsigned long s; - char name[1024]; - - /* - * Look through the bridge data structures for the pciio_piospace_t - * structure corresponding to 'pciaddr' - */ - s = pcibr_lock(pcibr_soft); - piosp = pcibr_info->f_piospace; - while (piosp) { - /* - * Piospace free can only be for the complete - * chunk and not parts of it.. - */ - if (piosp->start == pciaddr) { - if (piosp->count == req_size) - break; - /* - * Improper size passed for freeing.. - * Print a message and break; - */ - hwgraph_vertex_name_get(pconn_vhdl, name, 1024); - printk(KERN_WARNING "pcibr_piospace_free: error"); - printk(KERN_WARNING "Device %s freeing size (0x%lx) different than allocated (0x%lx)", - name, req_size, piosp->count); - printk(KERN_WARNING "Freeing 0x%lx instead", piosp->count); - break; - } - piosp = piosp->next; - } - - if (!piosp) { - printk(KERN_WARNING - "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", - pciaddr, req_size); - pcibr_unlock(pcibr_soft, s); - return; - } - piosp->free = 1; - pcibr_unlock(pcibr_soft, s); - return; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * The Bridge ASIC provides three methods of doing - * DMA: via a "direct map" register available in - * 32-bit PCI space (which selects a contiguous 2G - * address space on some other widget), via - * "direct" addressing via 64-bit PCI space (all - * destination information comes from the PCI - * address, including transfer attributes), and via - * a "mapped" region that allows a bunch of - * different small mappings to be established with - * the PMU. - * - * For efficiency, we most prefer to use the 32-bit - * direct mapping facility, since it requires no - * resource allocations. The advantage of using the - * PMU over the 64-bit direct is that single-cycle - * PCI addressing can be used; the advantage of - * using 64-bit direct over PMU addressing is that - * we do not have to allocate entries in the PMU. - */ - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Direct Map attribute bits. - */ -LOCAL iopaddr_t -pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) -{ - iopaddr_t attributes = 0; - - /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef LATER - ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); -#endif - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ - attributes |= PCI64_ATTR_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= PCI64_ATTR_BAR; /* barrier bit on */ - attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - /* the swap bit is in the address attributes for xbridge */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - attributes |= PCI64_ATTR_SWAP; - if (flags & PCIIO_WORD_VALUES) - attributes &= ~PCI64_ATTR_SWAP; - } - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= PCI64_ATTR_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~PCI64_ATTR_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= PCI64_ATTR_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~PCI64_ATTR_PREC; - - if (flags & PCIBR_VCHAN1) - attributes |= PCI64_ATTR_VIRTUAL; - if (flags & PCIBR_VCHAN0) - attributes &= ~PCI64_ATTR_VIRTUAL; - - return (attributes); -} - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Address Translation Entry attribute bits. - */ -LOCAL bridge_ate_t -pcibr_flags_to_ate(unsigned flags) -{ - bridge_ate_t attributes; - - /* default if nothing specified: - * NOBARRIER - * NOPREFETCH - * NOPRECISE - * COHERENT - * Plus the valid bit - */ - attributes = ATE_CO | ATE_V; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~ATE_BAR; /* no barrier */ - attributes |= ATE_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= ATE_BAR; /* barrier bit on */ - attributes &= ~ATE_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~ATE_PREF; - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= ATE_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~ATE_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~ATE_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= ATE_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~ATE_PREC; - - return (attributes); -} - -/*ARGSUSED */ -pcibr_dmamap_t -pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - size_t req_size_max, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t slot; - xwidgetnum_t xio_port; - - xtalk_dmamap_t xtalk_dmamap; - pcibr_dmamap_t pcibr_dmamap; - int ate_count; - int ate_index; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - -#ifdef IRIX - NEWf(pcibr_dmamap, flags); -#else - /* - * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() - * can be called within an interrupt thread. - */ - pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); -#endif - - if (!pcibr_dmamap) - return 0; - - xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, - flags & DMAMAP_FLAGS); - if (!xtalk_dmamap) { -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); -#endif -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; - } - xio_port = pcibr_soft->bs_mxid; - slot = pciio_info_slot_get(pciio_info); - - pcibr_dmamap->bd_dev = pconn_vhdl; - pcibr_dmamap->bd_slot = slot; - pcibr_dmamap->bd_soft = pcibr_soft; - pcibr_dmamap->bd_xtalk = xtalk_dmamap; - pcibr_dmamap->bd_max_size = req_size_max; - pcibr_dmamap->bd_xio_port = xio_port; - - if (flags & PCIIO_DMA_A64) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { - iopaddr_t pci_addr; - int have_rrbs; - int min_rrbs; - - /* Device is capable of A64 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - */ - - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_pci_addr = pci_addr; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - if (flags & PCIBR_VCHAN1) - slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct64\n"); -#endif - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct64\n"); -#endif - flags &= ~PCIIO_DMA_A64; - } - if (flags & PCIIO_FIXED) { - /* warning: mappings may fail later, - * if direct32 can't get to the address. - */ - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { - /* User desires DIRECT A32 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - * Mapping calls may fail if target - * is outside the direct32 range. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct32\n"); -#endif - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; - pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct32\n"); -#endif - /* If the user demands FIXED and we can't - * give it to him, fail. - */ - xtalk_dmamap_free(xtalk_dmamap); -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; - } - /* - * Allocate Address Translation Entries from the mapping RAM. - * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, - * the maximum number of ATEs is based on the worst-case - * scenario, where the requested target is in the - * last byte of an ATE; thus, mapping IOPGSIZE+2 - * does end up requiring three ATEs. - */ - if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { - ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ - +req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } else { /* assume requested target is page aligned */ - ate_count = IOPG(req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } - - ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); - - if (ate_index != -1) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { - bridge_ate_t ate_proto; - int have_rrbs; - int min_rrbs; - -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using PMU\n"); -#endif - - ate_proto = pcibr_flags_to_ate(flags); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_pci_addr = - PCI32_MAPPED_BASE + IOPGSIZE * ate_index; - /* - * for xbridge the byte-swap bit == bit 29 of PCI address - */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - /* - * If swap was set in bss_device in pcibr_endian_set() - * we need to change the address bit. - */ - if (pcibr_soft->bs_slot[slot].bss_device & - BRIDGE_DEV_SWAP_PMU) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - if (flags & PCIIO_WORD_VALUES) - ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); - } - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); - pcibr_dmamap->bd_ate_index = ate_index; - pcibr_dmamap->bd_ate_count = ate_count; - pcibr_dmamap->bd_ate_proto = ate_proto; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (ate_proto & ATE_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } - if (ate_index >= pcibr_soft->bs_int_ate_size && - !pcibr_soft->bs_xbridge) { - bridge_t *bridge = pcibr_soft->bs_base; - volatile unsigned *cmd_regp; - unsigned cmd_reg; - unsigned long s; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; - - s = pcibr_lock(pcibr_soft); - cmd_regp = &(bridge-> - b_type0_cfg_dev[slot]. - l[PCI_CFG_COMMAND / 4]); - cmd_reg = *cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; - pcibr_unlock(pcibr_soft, s); - } - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use PMU\n"); -#endif - pcibr_ate_free(pcibr_soft, ate_index, ate_count); - } - /* total failure: sorry, you just can't - * get from here to there that way. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: complete failure.\n"); -#endif - xtalk_dmamap_free(xtalk_dmamap); -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - pciio_slot_t slot = pcibr_dmamap->bd_slot; - - unsigned flags = pcibr_dmamap->bd_flags; - - /* Make sure that bss_ext_ates_active - * is properly kept up to date. - */ - - if (PCIBR_DMAMAP_BUSY & flags) - if (PCIBR_DMAMAP_SSRAM & flags) - atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); - - xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); - - if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); - } - if (pcibr_dmamap->bd_ate_count) { - pcibr_ate_free(pcibr_dmamap->bd_soft, - pcibr_dmamap->bd_ate_index, - pcibr_dmamap->bd_ate_count); - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); - } -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif -} - -/* - * Setup an Address Translation Entry as specified. Use either the Bridge - * internal maps or the external map RAM, as appropriate. - */ -LOCAL bridge_ate_p -pcibr_ate_addr(pcibr_soft_t pcibr_soft, - int ate_index) -{ - bridge_t *bridge = pcibr_soft->bs_base; - - return (ate_index < pcibr_soft->bs_int_ate_size) - ? &(bridge->b_int_ate_ram[ate_index].wr) - : &(bridge->b_ext_ate_ram[ate_index]); -} - -/* - * pcibr_addr_xio_to_pci: given a PIO range, hand - * back the corresponding base PCI MEM address; - * this is used to short-circuit DMA requests that - * loop back onto this PCI bus. - */ -LOCAL iopaddr_t -pcibr_addr_xio_to_pci(pcibr_soft_t soft, - iopaddr_t xio_addr, - size_t req_size) -{ - iopaddr_t xio_lim = xio_addr + req_size - 1; - iopaddr_t pci_addr; - pciio_slot_t slot; - - if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && - (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; - return pci_addr; - } - if ((xio_addr >= BRIDGE_PCI_MEM64_BASE) && - (xio_lim <= BRIDGE_PCI_MEM64_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; - return pci_addr; - } - for (slot = 0; slot < 8; ++slot) - if ((xio_addr >= BRIDGE_DEVIO(slot)) && - (xio_lim < BRIDGE_DEVIO(slot + 1))) { - bridgereg_t dev; - - dev = soft->bs_slot[slot].bss_device; - pci_addr = dev & BRIDGE_DEV_OFF_MASK; - pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; - pci_addr += xio_addr - BRIDGE_DEVIO(slot); - return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; - } - return 0; -} - -/* We are starting to get more complexity - * surrounding writing ATEs, so pull - * the writing code into this new function. - */ - -#if PCIBR_FREEZE_TIME -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) -#else -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) -#endif - -LOCAL unsigned -ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef LATER - int dma_slot = pcibr_dmamap->bd_slot; -#endif - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - int slot; - - unsigned long s; - unsigned cmd_reg; - volatile unsigned *cmd_lwa; - unsigned cmd_lwd; - - if (!ext_ates) - return 0; - - /* Bridge Hardware Bug WAR #484930: - * Bridge can't handle updating External ATEs - * while DMA is occurring that uses External ATEs, - * even if the particular ATEs involved are disjoint. - */ - - /* need to prevent anyone else from - * unfreezing the grant while we - * are working; also need to prevent - * this thread from being interrupted - * to keep PCI grant freeze time - * at an absolute minimum. - */ - s = pcibr_lock(pcibr_soft); - -#ifdef LATER - /* just in case pcibr_dmamap_done was not called */ - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); - } -#endif /* LATER */ -#if PCIBR_FREEZE_TIME - *freeze_time_ptr = get_timestamp(); -#endif - - cmd_lwa = 0; - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - cmd_reg = pcibr_soft-> - bs_slot[slot]. - bss_cmd_shadow; - if (cmd_reg & PCI_CMD_BUS_MASTER) { - cmd_lwa = pcibr_soft-> - bs_slot[slot]. - bss_cmd_pointer; - cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; - cmd_lwa[0] = cmd_lwd; - } - cmd_regs[slot] = cmd_reg; - } else - cmd_regs[slot] = 0; - - if (cmd_lwa) { - bridge_t *bridge = pcibr_soft->bs_base; - - /* Read the last master bit that has been cleared. This PIO read - * on the PCI bus is to ensure the completion of any DMAs that - * are due to bus requests issued by PCI devices before the - * clearing of master bits. - */ - cmd_lwa[0]; - - /* Flush all the write buffers in the bridge */ - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - /* Flush the write buffer associated with this - * PCI device which might be using dma map RAM. - */ - bridge->b_wr_req_buf[slot].reg; - } - } - return s; -} - -#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) - -LOCAL void -ate_write(bridge_ate_p ate_ptr, - int ate_count, - bridge_ate_t ate) -{ - while (ate_count-- > 0) { - *ate_ptr++ = ate; - ate += IOPGSIZE; - } -} - - -#if PCIBR_FREEZE_TIME -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) -#else -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) -#endif - -LOCAL void -ate_thaw(pcibr_dmamap_t pcibr_dmamap, - int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - int dma_slot = pcibr_dmamap->bd_slot; - int slot; - bridge_t *bridge = pcibr_soft->bs_base; - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - - unsigned cmd_reg; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; - static unsigned max_freeze_time = 0; - static unsigned max_ate_total; -#endif - - if (!ext_ates) - return; - - /* restore cmd regs */ - for (slot = 0; slot < 8; ++slot) - if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) - bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; - atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - -#if PCIBR_FREEZE_TIME - freeze_time = get_timestamp() - freeze_time_start; - - if ((max_freeze_time < freeze_time) || - (max_ate_total < ate_total)) { - if (max_freeze_time < freeze_time) - max_freeze_time = freeze_time; - if (max_ate_total < ate_total) - max_ate_total = ate_total; - pcibr_unlock(pcibr_soft, s); - printk("%s: pci freeze time %d usec for %d ATEs\n" - "\tfirst ate: %R\n", - pcibr_soft->bs_name, - freeze_time * 1000 / 1250, - ate_total, - ate, ate_bits); - } else -#endif - pcibr_unlock(pcibr_soft, s); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, - paddr_t paddr, - size_t req_size) -{ - pcibr_soft_t pcibr_soft; - iopaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - unsigned flags; - - ASSERT(pcibr_dmamap != NULL); - ASSERT(req_size > 0); - ASSERT(req_size <= pcibr_dmamap->bd_max_size); - - pcibr_soft = pcibr_dmamap->bd_soft; - - flags = pcibr_dmamap->bd_flags; - - xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - /* If this DMA is to an address that - * refers back to this Bridge chip, - * reduce it back to the correct - * PCI MEM address. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - } else if (flags & PCIIO_DMA_A64) { - /* A64 DMA: - * always use 64-bit direct mapping, - * which always works. - * Device(x) was set up during - * dmamap allocation. - */ - - /* attributes are already bundled up into bd_pci_addr. - */ - pci_addr = pcibr_dmamap->bd_pci_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) - | xio_addr; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - pci_addr &= ~PCI64_ATTR_PREF; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct64):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else if (flags & PCIIO_FIXED) { - /* A32 direct DMA: - * always use 32-bit direct mapping, - * which may fail. - * Device(x) was set up during - * dmamap allocation. - */ - - if (xio_port != pcibr_soft->bs_dir_xport) - pci_addr = 0; /* wrong DIDN */ - else if (xio_addr < pcibr_dmamap->bd_xio_addr) - pci_addr = 0; /* out of range */ - else if ((xio_addr + req_size) > - (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) - pci_addr = 0; /* out of range */ - else - pci_addr = pcibr_dmamap->bd_pci_addr + - xio_addr - pcibr_dmamap->bd_xio_addr; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct32):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else { - bridge_t *bridge = pcibr_soft->bs_base; - iopaddr_t offset = IOPGOFF(xio_addr); - bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; - int ate_count = IOPG(offset + req_size - 1) + 1; - - int ate_index = pcibr_dmamap->bd_ate_index; - unsigned cmd_regs[8]; - unsigned s; - -#if PCIBR_FREEZE_TIME - int ate_total = ate_count; - unsigned freeze_time; -#endif - -#if PCIBR_ATE_DEBUG - bridge_ate_t ate_cmp; - bridge_ate_p ate_cptr; - unsigned ate_lo, ate_hi; - int ate_bad = 0; - int ate_rbc = 0; -#endif - bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; - bridge_ate_t ate; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - ate_proto &= ~ATE_PREF; - - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - - pci_addr = pcibr_dmamap->bd_pci_addr + offset; - - /* Fill in our mapping registers - * with the appropriate xtalk data, - * and hand back the PCI address. - */ - - ASSERT(ate_count > 0); - if (ate_count <= pcibr_dmamap->bd_ate_count) { - ATE_FREEZE(); - ATE_WRITE(); - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } else { - /* The number of ATE's required is greater than the number - * allocated for this map. One way this can happen is if - * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP - * flag, and then when that map is used (right now), the - * target address tells us we really did need to roundup. - * The other possibility is that the map is just plain too - * small to handle the requested target area. - */ -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_addr :\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tate_count 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - paddr, paddr + req_size - 1, - ate_count, pcibr_dmamap->bd_ate_count); -#endif - pci_addr = 0; - } - - } - return pci_addr; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, - alenlist_t palenlist, - unsigned flags) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge=NULL; - - unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - int inplace = flags & PCIIO_INPLACE; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist; - size_t length; - iopaddr_t offset; - unsigned direct64; - int ate_index = 0; - int ate_count = 0; - int ate_total = 0; - bridge_ate_p ate_ptr = (bridge_ate_p)0; - bridge_ate_t ate_proto = (bridge_ate_t)0; - bridge_ate_t ate_prev; - bridge_ate_t ate; - alenaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - alenaddr_t new_addr; - - unsigned cmd_regs[8]; - unsigned s = 0; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; -#endif - int ate_freeze_done = 0; /* To pair ATE_THAW - * with an ATE_FREEZE - */ - - pcibr_soft = pcibr_dmamap->bd_soft; - - xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; - if (!direct64) { - bridge = pcibr_soft->bs_base; - ate_ptr = pcibr_dmamap->bd_ate_ptr; - ate_index = pcibr_dmamap->bd_ate_index; - ate_proto = pcibr_dmamap->bd_ate_proto; - ATE_FREEZE(); - ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ - } - pci_addr = pcibr_dmamap->bd_pci_addr; - - ate_prev = 0; /* matches no valid ATEs */ - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &length, al_flags)) { - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - if (xio_port == pcibr_soft->bs_xid) { - new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) - goto fail; - } else if (direct64) { - new_addr = pci_addr | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - new_addr &= ~PCI64_ATTR_PREF; - - } else { - /* calculate the ate value for - * the first address. If it - * matches the previous - * ATE written (ie. we had - * multiple blocks in the - * same IOPG), then back up - * and reuse that ATE. - * - * We are NOT going to - * aggressively try to - * reuse any other ATEs. - */ - offset = IOPGOFF(xio_addr); - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - if (ate == ate_prev) { -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_list: ATE share\n"); -#endif - ate_ptr--; - ate_index--; - pci_addr -= IOPGSIZE; - } - new_addr = pci_addr + offset; - - /* Fill in the hardware ATEs - * that contain this block. - */ - ate_count = IOPG(offset + length - 1) + 1; - ate_total += ate_count; - - /* Ensure that this map contains enough ATE's */ - if (ate_total > pcibr_dmamap->bd_ate_count) { -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count); -#endif - goto fail; - } - - ATE_WRITE(); - - ate_index += ate_count; - ate_ptr += ate_count; - - ate_count <<= IOPFNSHIFT; - ate += ate_count; - pci_addr += ate_count; - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) - goto fail; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - - /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the - * changes that ATE_FREEZE has done to implement the external SSRAM - * bug workaround. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - return pciio_alenlist; - - fail: - /* There are various points of failure after doing an ATE_FREEZE - * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. - * The decision to do an ATE_THAW needs to be based on whether a - * an ATE_FREEZE was done before. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; - } - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) -{ - /* - * We could go through and invalidate ATEs here; - * for performance reasons, we don't. - * We also don't enforce the strict alternation - * between _addr/_list and _done, but Hub does. - */ - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); - } - - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); -} - - -/* - * For each bridge, the DIR_OFF value in the Direct Mapping Register - * determines the PCI to Crosstalk memory mapping to be used for all - * 32-bit Direct Mapping memory accesses. This mapping can be to any - * node in the system. This function will return that compact node id. - */ - -/*ARGSUSED */ -cnodeid_t -pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) -{ - - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - paddr_t paddr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - - xwidgetnum_t xio_port; - iopaddr_t xio_addr; - iopaddr_t pci_addr; - - int have_rrbs; - int min_rrbs; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, - flags & DMAMAP_FLAGS); - - if (!xio_addr) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - return pci_addr; - } - /* If the caller can use A64, try to - * satisfy the request with the 64-bit - * direct map. This can fail if the - * configuration bits in Device(x) - * conflict with our flags. - */ - - if (flags & PCIIO_DMA_A64) { - pci_addr = slotp->bss_d64_base; - if (!(flags & PCIBR_VCHAN1)) - flags |= PCIBR_VCHAN0; - if ((pci_addr != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - -#if DEBUG && PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_addr; - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - if (flags & PCIBR_VCHAN1) - pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ - flags = flags - & ~PCIIO_DMA_A64 - & ~PCIBR_VCHAN0 - ; - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-64\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - /* Try to satisfy the request with the 32-bit direct - * map. This can fail if the configuration bits in - * Device(x) conflict with our flags, or if the - * target address is outside where DIR_OFF points. - */ - { - size_t map_size = 1ULL << 31; - iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = req_size + offset; - - if ((req_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\txio region outside direct32 target\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } else { - pci_addr = slotp->bss_d32_base; - if ((pci_addr != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - - pci_addr |= offset; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { - - pci_addr = PCI32_DIRECT_BASE; - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_addr; - pci_addr |= offset; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (slotp->bss_device & BRIDGE_DEV_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-32\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - } - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tno acceptable PCI address found or constructable\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - - return 0; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - alenlist_t palenlist, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - xwidgetnum_t xio_port; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist = 0; - - int inplace; - unsigned direct64; - unsigned al_flags; - - iopaddr_t xio_base; - alenaddr_t xio_addr; - size_t xio_size; - - size_t map_size; - iopaddr_t pci_base; - alenaddr_t pci_addr; - - unsigned relbits = 0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - inplace = flags & PCIIO_INPLACE; - direct64 = flags & PCIIO_DMA_A64; - al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - - if (direct64) { - map_size = 1ull << 48; - xio_base = 0; - pci_base = slotp->bss_d64_base; - if ((pci_base != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D64_BITS; - pci_base = - pcibr_flags_to_d64(flags, pcibr_soft); - } - } else { - xio_base = pcibr_soft->bs_dir_xbase; - map_size = 1ull << 31; - pci_base = slotp->bss_d32_base; - if ((pci_base != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D32_BITS; - pci_base = PCI32_DIRECT_BASE; - } - } - - xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &xio_size, al_flags)) { - - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if ( (pci_addr == (alenaddr_t)NULL) ) - goto fail; - } else if (direct64) { - ASSERT(xio_port != 0); - pci_addr = pci_base | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - } else { - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = xio_size + offset; - - if ((xio_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) - goto fail; - - pci_addr = pci_base + (xio_addr - xio_base); - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) - goto fail; - } - } - - if (relbits) { - if (direct64) { - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_base; - } else { - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_base; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - return pciio_alenlist; - - fail: - if (relbits) - pcibr_release_device(pcibr_soft, pciio_slot, relbits); - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -void -pcibr_dmamap_drain(pcibr_dmamap_t map) -{ - xtalk_dmamap_drain(map->bd_xtalk); -} - -void -pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, - paddr_t paddr, - size_t bytes) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); -} - -void -pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, - alenlist_t list) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmalist_drain(xconn_vhdl, list); -} - -/* - * Get the starting PCIbus address out of the given DMA map. - * This function is supposed to be used by a close friend of PCI bridge - * since it relies on the fact that the starting address of the map is fixed at - * the allocation time in the current implementation of PCI bridge. - */ -iopaddr_t -pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) -{ - return (pcibr_dmamap->bd_pci_addr); -} - -/* - * There are end cases where a deadlock can occur if interrupt - * processing completes and the Bridge b_int_status bit is still set. - * - * One scenerio is if a second PCI interrupt occurs within 60ns of - * the previous interrupt being cleared. In this case the Bridge - * does not detect the transition, the Bridge b_int_status bit - * remains set, and because no transition was detected no interrupt - * packet is sent to the Hub/Heart. - * - * A second scenerio is possible when a b_int_status bit is being - * shared by multiple devices: - * Device #1 generates interrupt - * Bridge b_int_status bit set - * Device #2 generates interrupt - * interrupt processing begins - * ISR for device #1 runs and - * clears interrupt - * Device #1 generates interrupt - * ISR for device #2 runs and - * clears interrupt - * (b_int_status bit still set) - * interrupt processing completes - * - * Interrupt processing is now complete, but an interrupt is still - * outstanding for Device #1. But because there was no transition of - * the b_int_status bit, no interrupt packet will be generated and - * a deadlock will occur. - * - * To avoid these deadlock situations, this function is used - * to check if a specific Bridge b_int_status bit is set, and if so, - * cause the setting of the corresponding interrupt bit. - * - * On a XBridge (IP35), we do this by writing the appropriate Bridge Force - * Interrupt register. - */ -void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) -{ - unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); - - bit = wrap->iw_intr; - - if (pcibr_soft->bs_xbridge) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - REMOTE_CPU_SEND_INTR(cpu, intr_bit); - } -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - */ - -static unsigned -pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines) -{ - pciio_slot_t slot = pciio_info_slot_get(info); - unsigned bbits = 0; - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - */ - - if (slot < 8) { - if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) - bbits |= 1 << slot; - if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) - bbits |= 1 << (slot ^ 4); - } - return bbits; -} - - -/*ARGSUSED */ -pcibr_intr_t -pcibr_intr_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_intr_line_t lines, - devfs_handle_t owner_dev) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pcibr_info->f_slot; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; - int is_threaded = 0; - int thread_swlevel; - - xtalk_intr_t *xtalk_intr_p; - pcibr_intr_t *pcibr_intr_p; - pcibr_intr_list_t *intr_list_p; - - unsigned pcibr_int_bits; - unsigned pcibr_int_bit; - xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; - hub_intr_t hub_intr; - pcibr_intr_t pcibr_intr; - pcibr_intr_list_t intr_entry; - pcibr_intr_list_t intr_list; - bridgereg_t int_dev; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_alloc\n" - "%v:%s%s%s%s%s\n", - owner_dev, pconn_vhdl, - !(lines & 15) ? " No INTs?" : "", - lines & 1 ? " INTA" : "", - lines & 2 ? " INTB" : "", - lines & 4 ? " INTC" : "", - lines & 8 ? " INTD" : ""); -#endif - - NEW(pcibr_intr); - if (!pcibr_intr) - return NULL; - - if (dev_desc) { - cpuid_t intr_target_from_desc(device_desc_t, int); - } else { - extern int default_intr_pri; - - is_threaded = 1; /* PCI interrupts are threaded, by default */ - thread_swlevel = default_intr_pri; - } - - pcibr_intr->bi_dev = pconn_vhdl; - pcibr_intr->bi_lines = lines; - pcibr_intr->bi_soft = pcibr_soft; - pcibr_intr->bi_ibits = 0; /* bits will be added below */ - pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; - pcibr_intr->bi_mustruncpu = CPU_NONE; - mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); - - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); - - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ -#if DEBUG && INTR_DEBUG - printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); -#endif - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - xtalk_intr = *xtalk_intr_p; - - if (xtalk_intr == NULL) { - /* - * This xtalk_intr_alloc is constrained for two reasons: - * 1) Normal interrupts and error interrupts need to be delivered - * through a single xtalk target widget so that there aren't any - * ordering problems with DMA, completion interrupts, and error - * interrupts. (Use of xconn_vhdl forces this.) - * - * 2) On IP35, addressing constraints on IP35 and Bridge force - * us to use a single PI number for all interrupts from a - * single Bridge. (IP35-specific code forces this, and we - * verify in pcibr_setwidint.) - */ - - /* - * All code dealing with threaded PCI interrupt handlers - * is located at the pcibr level. Because of this, - * we always want the lower layers (hub/heart_intr_alloc, - * intr_level_connect) to treat us as non-threaded so we - * don't set up a duplicate threaded environment. We make - * this happen by calling a special xtalk interface. - */ - xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, - owner_dev); -#if DEBUG && INTR_DEBUG - printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); -#endif - - /* both an assert and a runtime check on this: - * we need to check in non-DEBUG kernels, and - * the ASSERT gets us more information when - * we use DEBUG kernels. - */ - ASSERT(xtalk_intr != NULL); - if (xtalk_intr == NULL) { - /* it is quite possible that our - * xtalk_intr_alloc failed because - * someone else got there first, - * and we can find their results - * in xtalk_intr_p. - */ - if (!*xtalk_intr_p) { -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_ALERT - "pcibr_intr_alloc %v: unable to get xtalk interrupt resources", - xconn_vhdl); -#else - printk(KERN_ALERT - "pcibr_intr_alloc 0x%p: unable to get xtalk interrupt resources", - (void *)xconn_vhdl); -#endif - /* yes, we leak resources here. */ - return 0; - } - } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { - /* - * now tell the bridge which slot is - * using this interrupt line. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); - bridge->b_int_device = int_dev; /* XXXMP */ - -#if DEBUG && INTR_DEBUG - printk("%v: bridge intr bit %d clears my wrb\n", - pconn_vhdl, pcibr_int_bit); -#endif - } else { - /* someone else got one allocated first; - * free the one we just created, and - * retrieve the one they allocated. - */ - xtalk_intr_free(xtalk_intr); - xtalk_intr = *xtalk_intr_p; -#if PARANOID - /* once xtalk_intr is set, we never clear it, - * so if the CAS fails above, this condition - * can "never happen" ... - */ - if (!xtalk_intr) { - printk(KERN_ALERT - "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", - xconn_vhdl); - /* yes, we leak resources here. */ - return 0; - } -#endif - } - } - - pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; - - NEW(intr_entry); - intr_entry->il_next = NULL; - intr_entry->il_intr = pcibr_intr; - intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); - intr_list_p = - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; -#if DEBUG && INTR_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("0x%x: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#else - printk("%v: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#endif -#endif - - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the first interrupt on this bridge bit. - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list = *intr_list_p; - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* first entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the new second interrupt on this bit. - */ - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - while (1) { - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* an entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* entry appended to share list - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - /* step to next record in chain - */ - intr_list = *intr_list_p; - } - } - } - -#if DEBUG && INTR_DEBUG - printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); -#endif - hub_intr = (hub_intr_t)xtalk_intr; - pcibr_intr->bi_irq = hub_intr->i_bit; - pcibr_intr->bi_cpu = hub_intr->i_cpuid; - return pcibr_intr; -} - -/*ARGSUSED */ -void -pcibr_intr_free(pcibr_intr_t pcibr_intr) -{ - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bit; - pcibr_intr_list_t intr_list; - int intr_shared; - xtalk_intr_t *xtalk_intrp; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; - intr_list != NULL; - intr_list = intr_list->il_next) - if (compare_and_swap_ptr((void **) &intr_list->il_intr, - pcibr_intr, - NULL)) { -#if DEBUG && INTR_DEBUG - printk("%s: cleared a handler from bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - } - /* If this interrupt line is not being shared between multiple - * devices release the xtalk interrupt resources. - */ - intr_shared = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; - xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - if ((!intr_shared) && (*xtalk_intrp)) { - - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_dev; - - xtalk_intr_free(*xtalk_intrp); - *xtalk_intrp = 0; - - /* Clear the PCI device interrupt to bridge interrupt pin - * mapping. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - bridge->b_int_device = int_dev; - - } - } - } - DEL(pcibr_intr); -} - -LOCAL void -pcibr_setpciint(xtalk_intr_t xtalk_intr) -{ - iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); - bridgereg_t *int_addr = (bridgereg_t *) - xtalk_intr_sfarg_get(xtalk_intr); - - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); -} - -/*ARGSUSED */ -int -pcibr_intr_connect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - bridgereg_t b_int_enable; - unsigned long s; - - if (pcibr_intr == NULL) - return -1; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_connect\n", - pcibr_intr->bi_dev); -#endif - - *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_t xtalk_intr; - - xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - /* - * If this interrupt line is being shared and the connect has - * already been done, no need to do it again. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) - continue; - - - /* - * Use the pcibr wrapper function to handle all Bridge interrupts - * regardless of whether the interrupt line is shared or not. - */ - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *)&(bridge->b_int_addr[pcibr_int_bit].addr)); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; - -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d wrapper connected\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif - } - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable |= pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - return 0; -} - -/*ARGSUSED */ -void -pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - bridgereg_t b_int_enable; - unsigned long s; - - /* Stop calling the function. Now. - */ - *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and disconnect the interrupt. - */ - - /* don't disable interrupts for lines that - * are shared between devices. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) - pcibr_int_bits &= ~(1 << pcibr_int_bit); - if (!pcibr_int_bits) - return; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - /* if the interrupt line is now shared, - * do not disconnect it. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; - -#if DEBUG && INTR_DEBUG - printk("%s: xtalk disconnect done for Bridge bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - - /* if we are sharing the interrupt line, - * connect us up; this closes the hole - * where the another pcibr_intr_alloc() - * was in progress as we disconnected. - */ - if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr)); - } -} - -/*ARGSUSED */ -devfs_handle_t -pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) - return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - return 0; -} - -/* ===================================================================== - * INTERRUPT HANDLING - */ -LOCAL void -pcibr_clearwidint(bridge_t *bridge) -{ - bridge->b_wid_int_upper = 0; - bridge->b_wid_int_lower = 0; -} - -LOCAL void -pcibr_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; - widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; - - bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); - - NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - - OLD_b_wid_int_upper = bridge->b_wid_int_upper; - OLD_b_wid_int_lower = bridge->b_wid_int_lower; - - /* Verify that all interrupts from this Bridge are using a single PI */ - if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { - /* - * Once set, these registers shouldn't change; they should - * be set multiple times with the same values. - * - * If we're attempting to change these registers, it means - * that our heuristics for allocating interrupts in a way - * appropriate for IP35 have failed, and the admin needs to - * explicitly direct some interrupts (or we need to make the - * heuristics more clever). - * - * In practice, we hope this doesn't happen very often, if - * at all. - */ - if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || - (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { - printk(KERN_WARNING "Interrupt allocation is too complex.\n"); - printk(KERN_WARNING "Use explicit administrative interrupt targetting.\n"); - printk(KERN_WARNING "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); - printk(KERN_WARNING "NEW=0x%x/0x%x OLD=0x%x/0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, - OLD_b_wid_int_upper, OLD_b_wid_int_lower); - PRINT_PANIC("PCI Bridge interrupt targetting error\n"); - } - } - - bridge->b_wid_int_upper = NEW_b_wid_int_upper; - bridge->b_wid_int_lower = NEW_b_wid_int_lower; - bridge->b_int_host_err = vect; -} - -/* - * pcibr_intr_preset: called during mlreset time - * if the platform specific code needs to route - * one of the Bridge's xtalk interrupts before the - * xtalk infrastructure is available. - */ -void -pcibr_xintr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - bridge_t *bridge = (bridge_t *) which_widget; - - if (which_widget_intr == -1) { - /* bridge widget error interrupt */ - bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - bridge->b_int_host_err = vect; - - /* turn on all interrupts except - * the PCI interrupt requests, - * at least at heart. - */ - bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; - - } else { - /* routing a PCI device interrupt. - * targ and low 38 bits of addr must - * be the same as the already set - * value for the widget error interrupt. - */ - bridge->b_int_addr[which_widget_intr].addr = - ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - /* - * now bridge can let it through; - * NB: still should be blocked at - * xtalk provider end, until the service - * function is set. - */ - bridge->b_int_enable |= 1 << vect; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ -} - - -/* - * pcibr_intr_func() - * - * This is the pcibr interrupt "wrapper" function that is called, - * in interrupt context, to initiate the interrupt handler(s) registered - * (via pcibr_intr_alloc/connect) for the occurring interrupt. Non-threaded - * handlers will be called directly, and threaded handlers will have their - * thread woken up. - */ -void -pcibr_intr_func(intr_arg_t arg) -{ - pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p wrbf; - pcibr_intr_t intr; - pcibr_intr_list_t list; - int clearit; - int do_nonthreaded = 1; - int is_threaded = 0; - int x = 0; - - /* - * If any handler is still running from a previous interrupt - * just return. If there's a need to call the handler(s) again, - * another interrupt will be generated either by the device or by - * pcibr_force_interrupt(). - */ - - if (wrap->iw_hdlrcnt) { - return; - } - - /* - * Call all interrupt handlers registered. - * First, the pcibr_intrd threads for any threaded handlers will be - * awoken, then any non-threaded handlers will be called sequentially. - */ - - clearit = 1; - while (do_nonthreaded) { - for (list = wrap->iw_list; list != NULL; list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - - /* - * This device may have initiated write - * requests since the bridge last saw - * an edge on this interrupt input; flushing - * the buffer prior to invoking the handler - * should help but may not be sufficient if we - * get more requests after the flush, followed - * by the card deciding it wants service, before - * the interrupt handler checks to see if things need - * to be done. - * - * There is a similar race condition if - * an interrupt handler loops around and - * notices further service is required. - * Perhaps we need to have an explicit - * call that interrupt handlers need to - * do between noticing that DMA to memory - * has completed, but before observing the - * contents of memory? - */ - - if ((do_nonthreaded) && (!is_threaded)) { - /* Non-threaded. - * Call the interrupt handler at interrupt level - */ - - /* Only need to flush write buffers if sharing */ - - if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { - if ((x = *wrbf)) /* write request buffer flush */ -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_ALERT "pcibr_intr_func %v: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#else - printk(KERN_ALERT "pcibr_intr_func %p: \n" - "write buffer flush failed, wrbf=0x%lx\n", - (void *)list->il_intr->bi_dev, (long) wrbf); -#endif - } - } - - clearit = 0; - } - } - - do_nonthreaded = 0; - /* - * If the non-threaded handler was the last to complete, - * (i.e., no threaded handlers still running) force an - * interrupt to avoid a potential deadlock situation. - */ - if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); - } - } - - /* If there were no handlers, - * disable the interrupt and return. - * It will get enabled again after - * a handler is connected. - * If we don't do this, we would - * sit here and spin through the - * list forever. - */ - if (clearit) { - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_int_enable; - bridgereg_t mask = 1 << wrap->iw_intr; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~mask; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - return; - } -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ -/*ARGSUSED */ -void -pcibr_provider_startup(devfs_handle_t pcibr) -{ -} - -/*ARGSUSED */ -void -pcibr_provider_shutdown(devfs_handle_t pcibr) -{ -} - -int -pcibr_reset(devfs_handle_t conn) -{ - pciio_info_t pciio_info = pciio_info_get(conn); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t ctlreg; - unsigned cfgctl[8]; - unsigned long s; - int f, nf; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int win; - - if (pcibr_soft->bs_slot[pciio_slot].has_host) { - pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; - } - if (pciio_slot < 4) { - s = pcibr_lock(pcibr_soft); - nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; - - ctlreg = bridge->b_wid_control; - bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); - /* XXX delay? */ - bridge->b_wid_control = ctlreg; - /* XXX delay? */ - - for (f = 0; f < nf; ++f) - if ((pcibr_info = pcibr_infoh[f])) - for (win = 0; win < 6; ++win) - if (pcibr_info->f_window[win].w_base != 0) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = - pcibr_info->f_window[win].w_base; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; - pcibr_unlock(pcibr_soft, s); - - return 0; - } -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_WARNING "%v: pcibr_reset unimplemented for slot %d\n", - conn, pciio_slot); -#endif - return -1; -} - -pciio_endian_t -pcibr_endian_set(devfs_handle_t pconn_vhdl, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t devreg; - unsigned long s; - - /* - * Bridge supports hardware swapping; so we can always - * arrange for the caller's desired endianness. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_end != desired_end) - devreg |= BRIDGE_DEV_SWAP_BITS; - else - devreg &= ~BRIDGE_DEV_SWAP_BITS; - - /* NOTE- if we ever put SWAP bits - * onto the disabled list, we will - * have to change the logic here. - */ - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); -#endif - - return desired_end; -} - -/* This (re)sets the GBR and REALTIME bits and also keeps track of how - * many sets are outstanding. Reset succeeds only if the number of outstanding - * sets == 1. - */ -int -pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, - pciio_slot_t pciio_slot, - pciio_priority_t device_prio) -{ - unsigned long s; - int *counter; - bridgereg_t rtbits = 0; - bridgereg_t devreg; - int rc = PRIO_SUCCESS; - - /* in dual-slot configurations, the host and the - * guest have separate DMA resources, so they - * have separate requirements for priority bits. - */ - - counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); - - /* - * Bridge supports PCI notions of LOW and HIGH priority - * arbitration rings via a "REAL_TIME" bit in the per-device - * Bridge register. The "GBR" bit controls access to the GBR - * ring on the xbow. These two bits are (re)set together. - * - * XXX- Bug in Rev B Bridge Si: - * Symptom: Prefetcher starts operating incorrectly. This happens - * due to corruption of the address storage ram in the prefetcher - * when a non-real time PCI request is pulled and a real-time one is - * put in it's place. Workaround: Use only a single arbitration ring - * on PCI bus. GBR and RR can still be uniquely used per - * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. - */ - - if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) - rtbits |= BRIDGE_DEV_RT; - - /* NOTE- if we ever put DEV_RT or DEV_GBR on - * the disabled list, we will have to take - * it into account here. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_prio == PCI_PRIO_HIGH) { - if ((++*counter == 1)) { - if (rtbits) - devreg |= rtbits; - else - rc = PRIO_FAIL; - } - } else if (device_prio == PCI_PRIO_LOW) { - if (*counter <= 0) - rc = PRIO_FAIL; - else if (--*counter == 0) - if (rtbits) - devreg &= ~rtbits; - } - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - - return rc; -} - -pciio_priority_t -pcibr_priority_set(devfs_handle_t pconn_vhdl, - pciio_priority_t device_prio) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); - - return device_prio; -} - -/* - * Interfaces to allow special (e.g. SGI) drivers to set/clear - * Bridge-specific device flags. Many flags are modified through - * PCI-generic interfaces; we don't allow them to be directly - * manipulated here. Only flags that at this point seem pretty - * Bridge-specific can be set through these special interfaces. - * We may add more flags as the need arises, or remove flags and - * create PCI-generic interfaces as the need arises. - * - * Returns 0 on failure, 1 on success - */ -int -pcibr_device_flags_set(devfs_handle_t pconn_vhdl, - pcibr_device_flags_t flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t set = 0; - bridgereg_t clr = 0; - - ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_PMU_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_PMU_WRGA_EN; - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_DIR_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_DIR_WRGA_EN; - - if (flags & PCIBR_PREFETCH) - set |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - clr |= BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - set |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - clr |= BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - set |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - clr |= BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - set |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - clr |= BRIDGE_DEV_DEV_SIZE; - - if (set || clr) { - bridgereg_t devreg; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - devreg = (devreg & ~clr) | set; - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); -#endif - } - return (1); -} - -#ifdef LITTLE_ENDIAN -/* - * on sn-ia we need to twiddle the the addresses going out - * the pci bus because we use the unswizzled synergy space - * (the alternative is to use the swizzled synergy space - * and byte swap the data) - */ -#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) -#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) -#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#else -#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) -#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) -#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) -#endif /* LITTLE_ENDIAN */ - - -LOCAL cfg_p -pcibr_config_addr(devfs_handle_t conn, - unsigned reg) -{ - pcibr_info_t pcibr_info; - pciio_slot_t pciio_slot; - pciio_function_t pciio_func; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - cfg_p cfgbase = (cfg_p)0; - - pcibr_info = pcibr_info_get(conn); - - pciio_slot = pcibr_info->f_slot; - if (pciio_slot == PCIIO_SLOT_NONE) - pciio_slot = PCI_TYPE1_SLOT(reg); - - pciio_func = pcibr_info->f_func; - if (pciio_func == PCIIO_FUNC_NONE) - pciio_func = PCI_TYPE1_FUNC(reg); - - pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - bridge = pcibr_soft->bs_base; - - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; - - return cfgbase; -} - -uint64_t -pcibr_config_get(devfs_handle_t conn, - unsigned reg, - unsigned size) -{ - return do_pcibr_config_get(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); -} - -LOCAL uint64_t -do_pcibr_config_get( - cfg_p cfgbase, - unsigned reg, - unsigned size) -{ - unsigned value; - - - value = CW(cfgbase, reg); - - if (reg & 3) - value >>= 8 * (reg & 3); - if (size < 4) - value &= (1 << (8 * size)) - 1; - - return value; -} - -void -pcibr_config_set(devfs_handle_t conn, - unsigned reg, - unsigned size, - uint64_t value) -{ - do_pcibr_config_set(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); -} - -LOCAL void -do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - switch (size) { - case 1: - CB(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; - - case 4: - CW(cfgbase, reg) = value; - break; - } -} - -pciio_provider_t pcibr_provider = -{ - (pciio_piomap_alloc_f *) pcibr_piomap_alloc, - (pciio_piomap_free_f *) pcibr_piomap_free, - (pciio_piomap_addr_f *) pcibr_piomap_addr, - (pciio_piomap_done_f *) pcibr_piomap_done, - (pciio_piotrans_addr_f *) pcibr_piotrans_addr, - (pciio_piospace_alloc_f *) pcibr_piospace_alloc, - (pciio_piospace_free_f *) pcibr_piospace_free, - - (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, - (pciio_dmamap_free_f *) pcibr_dmamap_free, - (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, - (pciio_dmamap_done_f *) pcibr_dmamap_done, - (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, - (pciio_dmamap_drain_f *) pcibr_dmamap_drain, - (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - (pciio_dmalist_drain_f *) pcibr_dmalist_drain, - - (pciio_intr_alloc_f *) pcibr_intr_alloc, - (pciio_intr_free_f *) pcibr_intr_free, - (pciio_intr_connect_f *) pcibr_intr_connect, - (pciio_intr_disconnect_f *) pcibr_intr_disconnect, - (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, - - (pciio_provider_startup_f *) pcibr_provider_startup, - (pciio_provider_shutdown_f *) pcibr_provider_shutdown, - (pciio_reset_f *) pcibr_reset, - (pciio_write_gather_flush_f *) pcibr_write_gather_flush, - (pciio_endian_set_f *) pcibr_endian_set, - (pciio_priority_set_f *) pcibr_priority_set, - (pciio_config_get_f *) pcibr_config_get, - (pciio_config_set_f *) pcibr_config_set, - - (pciio_error_devenable_f *) 0, - (pciio_error_extract_f *) 0, - -#ifdef LATER - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, -#else - (pciio_driver_reg_callback_f *) 0, - (pciio_driver_unreg_callback_f *) 0, -#endif - (pciio_device_unregister_f *) pcibr_device_unregister, - (pciio_dma_enabled_f *) pcibr_dma_enabled, -}; - -LOCAL pcibr_hints_t -pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) -{ - arbitrary_info_t ainfo = 0; - graph_error_t rv; - pcibr_hints_t hint; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (alloc && (rv != GRAPH_SUCCESS)) { - - NEW(hint); - hint->rrb_alloc_funct = NULL; - hint->ph_intr_bits = NULL; - rv = hwgraph_info_add_LBL(xconn_vhdl, - INFO_LBL_PCIBR_HINTS, - (arbitrary_info_t) hint); - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - if (ainfo != (arbitrary_info_t) hint) - goto abnormal_exit; - } - return (pcibr_hints_t) ainfo; - -abnormal_exit: -#ifdef LATER - printf("SHOULD NOT BE HERE\n"); -#endif - DEL(hint); - return(NULL); - -} - -void -pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_rrb_fixed = mask; -#if DEBUG - else - printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); -} - -void -pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, - pciio_slot_t host, - pciio_slot_t guest) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_host_slot[guest] = host + 1; -#if DEBUG - else - printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, - pcibr_intr_bits_f *xxx_intr_bits) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_intr_bits = xxx_intr_bits; -#if DEBUG - else - printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->rrb_alloc_funct = rrb_alloc_funct; -} - -void -pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_hands_off = 1; -#if DEBUG - else - printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, - pciio_slot_t slot, - uint64_t subdevs) -{ - arbitrary_info_t ainfo = 0; - char sdname[16]; - devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; - - sprintf(sdname, "pci/%d", slot); - (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); - if (pconn_vhdl == GRAPH_VERTEX_NONE) { -#if DEBUG - printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" - "\t%p (seeking %s)\n", xconn_vhdl, sdname); -#endif - return; - } - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == 0) { - uint64_t *subdevp; - - NEW(subdevp); - if (!subdevp) { -#if DEBUG - printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } - *subdevp = subdevs; - hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == (arbitrary_info_t) subdevp) - return; - DEL(subdevp); - if (ainfo == (arbitrary_info_t) NULL) { -#if DEBUG - printk("pcibr_hints_subdevs: null subdevs ptr at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } -#if DEBUG - printk("pcibr_subdevs_get: dup subdev add_LBL at\n" - "\t%p\n", pconn_vhdl); -#endif - } - *(uint64_t *) ainfo = subdevs; -} - - -#ifdef LATER - -#include -#include - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); -#endif - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_master); -#endif - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} - -#endif /* LATER */ - -int -pcibr_dma_enabled(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - - return xtalk_dma_enabled(pcibr_soft->bs_conn); -} diff --git a/arch/ia64/sn/io/sn2/Makefile b/arch/ia64/sn/io/sn2/Makefile index 106bd31b96d..f8521c8bcea 100644 --- a/arch/ia64/sn/io/sn2/Makefile +++ b/arch/ia64/sn/io/sn2/Makefile @@ -11,10 +11,9 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += pcibr/ bte_error.o geo_op.o klconflib.o klgraph.o l1.o \ - l1_command.o ml_iograph.o ml_SN_init.o ml_SN_intr.o module.o \ - pci_bus_cvlink.o pciio.o pic.o sgi_io_init.o shub.o shuberror.o \ - shub_intr.o shubio.o xbow.o xtalk.o +obj-y += pcibr/ ml_SN_intr.o shub_intr.o shuberror.o shub.o bte_error.o \ + pic.o geo_op.o l1.o l1_command.o klconflib.o klgraph.o ml_SN_init.o \ + ml_iograph.o module.o pciio.o xbow.o xtalk.o shubio.o obj-$(CONFIG_KDB) += kdba_io.o obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o diff --git a/arch/ia64/sn/io/sn2/bte_error.c b/arch/ia64/sn/io/sn2/bte_error.c dissimilarity index 85% index 8e086e1c1b4..4ab2cb0e993 100644 --- a/arch/ia64/sn/io/sn2/bte_error.c +++ b/arch/ia64/sn/io/sn2/bte_error.c @@ -1,149 +1,261 @@ -/* $Id: bte_error.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/************************************************************************ - * * - * BTE ERROR RECOVERY * - * * - * Given a BTE error, the node causing the error must do the following: * - * a) Clear all crbs relating to that BTE * - * 1) Read CRBA value for crb in question * - * 2) Mark CRB as VALID, store local physical * - * address known to be good in the address field * - * (bte_notification_targ is a known good local * - * address). * - * 3) Write CRBA * - * 4) Using ICCR, FLUSH the CRB, and wait for it to * - * complete. * - * ... BTE BUSY bit should now be clear (or at least * - * should be after ALL CRBs associated with the * - * transfer are complete. * - * * - * b) Re-enable BTE * - * 1) Write IMEM with BTE Enable + XXX bits - * 2) Write IECLR with BTE clear bits - * 3) Clear IIDSR INT_SENT bits. - * * - ************************************************************************/ - -/* - * >>> bte_crb_error_handler needs to be broken into two parts. The - * first should cleanup the CRB. The second should wait until all bte - * related CRB's are complete and then do the error reset. - */ -void -bte_crb_error_handler(devfs_handle_t hub_v, int btenum, - int crbnum, ioerror_t *ioe, int bteop) -/* - * Function: bte_crb_error_handler - * Purpose: Process a CRB for a specific HUB/BTE - * Parameters: hub_v - vertex of hub in HW graph - * btenum - bte number on hub (0 == a, 1 == b) - * crbnum - crb number being processed - * Notes: - * This routine assumes serialization at a higher level. A CRB - * should not be processed more than once. The error recovery - * follows the following sequence - if you change this, be real - * sure about what you are doing. - * - */ -{ - hubinfo_t hinfo; - icrba_t crba; - icrbb_t crbb; - nasid_t n; - hubreg_t iidsr, imem, ieclr; - - hubinfo_get(hub_v, &hinfo); - - - n = hinfo->h_nasid; - - - /* - * The following 10 lines (or so) are adapted from IRIXs - * bte_crb_error function. No clear documentation tells - * why the crb needs to complete normally in order for - * the BTE to resume normal operations. This first step - * appears vital! - */ - - /* - * Zero error and error code to prevent error_dump complaining - * about these CRBs. Copy the CRB to the notification line. - * The crb address is in shub format (physical address shifted - * right by cacheline size). - */ - crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); - crbb.b_error=0; - crbb.b_ecode=0; - REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval); - - crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); - crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3; - crba.a_valid = 1; - REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); - - REMOTE_HUB_S(n, IIO_ICCR, - IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); - - while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) - ; - - - /* Terminate the BTE. */ - /* >>> The other bte transfer will need to be restarted. */ - HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr + - IIO_IBCT0 - IIO_IBLS0))); - - imem = REMOTE_HUB_L(n, IIO_IMEM); - ieclr = REMOTE_HUB_L(n, IIO_IECLR); - if (btenum == 0) { - imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; - ieclr|= IECLR_BTE0; - } else { - imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; - ieclr|= IECLR_BTE1; - } - REMOTE_HUB_S(n, IIO_IMEM, imem); - REMOTE_HUB_S(n, IIO_IECLR, ieclr); - - iidsr = REMOTE_HUB_L(n, IIO_IIDSR); - iidsr &= ~IIO_IIDSR_SENT_MASK; - iidsr |= IIO_IIDSR_ENB_MASK; - REMOTE_HUB_S(n, IIO_IIDSR, iidsr); - - - bte_reset_nasid(n); - - *nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR; -} - +/* + * + * + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Bte error handling is done in two parts. The first captures + * any crb related errors. Since there can be multiple crbs per + * interface and multiple interfaces active, we need to wait until + * all active crbs are completed. This is the first job of the + * second part error handler. When all bte related CRBs are cleanly + * completed, it resets the interfaces and gets them ready for new + * transfers to be queued. + */ + + +void bte_error_handler(unsigned long); + + +/* + * First part error handler. This is called whenever any error CRB interrupt + * is generated by the II. + */ +void +bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, + int crbnum, ioerror_t * ioe, int bteop) +{ + hubinfo_t hinfo; + struct bteinfo_s *bte; + + + hubinfo_get(hub_v, &hinfo); + bte = &hinfo->h_nodepda->bte_if[btenum]; + + /* + * The caller has already figured out the error type, we save that + * in the bte handle structure for the thread excercising the + * interface to consume. + */ + switch (ioe->ie_errortype) { + case IIO_ICRB_ECODE_PERR: + bte->bh_error = BTEFAIL_POISON; + break; + case IIO_ICRB_ECODE_WERR: + bte->bh_error = BTEFAIL_PROT; + break; + case IIO_ICRB_ECODE_AERR: + bte->bh_error = BTEFAIL_ACCESS; + break; + case IIO_ICRB_ECODE_TOUT: + bte->bh_error = BTEFAIL_TOUT; + break; + case IIO_ICRB_ECODE_XTERR: + bte->bh_error = BTEFAIL_XTERR; + break; + case IIO_ICRB_ECODE_DERR: + bte->bh_error = BTEFAIL_DIR; + break; + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_PRERR: + /* NO BREAK */ + default: + bte->bh_error = BTEFAIL_ERROR; + } + + bte->bte_error_count++; + + BTE_PRINTK(("Got an error on cnode %d bte %d\n", + bte->bte_cnode, bte->bte_num)); + bte_error_handler((unsigned long) hinfo->h_nodepda); +} + + +/* + * Second part error handler. Wait until all BTE related CRBs are completed + * and then reset the interfaces. + */ +void +bte_error_handler(unsigned long _nodepda) +{ + struct nodepda_s *err_nodepda = (struct nodepda_s *) _nodepda; + spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; + struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; + nasid_t nasid; + int i; + int valid_crbs; + unsigned long irq_flags; + volatile u64 *notify; + bte_result_t bh_error; + ii_imem_u_t imem; /* II IMEM Register */ + ii_icrb0_d_u_t icrbd; /* II CRB Register D */ + ii_ibcr_u_t ibcr; + ii_icmr_u_t icmr; + + + BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, + smp_processor_id())); + + spin_lock_irqsave(recovery_lock, irq_flags); + + if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && + (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { + BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, + smp_processor_id())); + spin_unlock_irqrestore(recovery_lock, irq_flags); + return; + } + /* + * Lock all interfaces on this node to prevent new transfers + * from being queued. + */ + for (i = 0; i < BTES_PER_NODE; i++) { + if (err_nodepda->bte_if[i].cleanup_active) { + continue; + } + spin_lock(&err_nodepda->bte_if[i].spinlock); + BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, + smp_processor_id(), i)); + err_nodepda->bte_if[i].cleanup_active = 1; + } + + /* Determine information about our hub */ + nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); + + + /* + * A BTE transfer can use multiple CRBs. We need to make sure + * that all the BTE CRBs are complete (or timed out) before + * attempting to clean up the error. Resetting the BTE while + * there are still BTE CRBs active will hang the BTE. + * We should look at all the CRBs to see if they are allocated + * to the BTE and see if they are still active. When none + * are active, we can continue with the cleanup. + * + * We also want to make sure that the local NI port is up. + * When a router resets the NI port can go down, while it + * goes through the LLP handshake, but then comes back up. + */ + icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); + if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { + /* + * There are errors which still need to be cleaned up by + * hubiio_crb_error_handler + */ + mod_timer(recovery_timer, HZ * 5); + BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, + smp_processor_id())); + spin_unlock_irqrestore(recovery_lock, irq_flags); + return; + } + if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { + + valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; + + for (i = 0; i < IIO_NUM_CRBS; i++) { + if (!((1 << i) & valid_crbs)) { + /* This crb was not marked as valid, ignore */ + continue; + } + icrbd.ii_icrb0_d_regval = + REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); + if (icrbd.d_bteop) { + mod_timer(recovery_timer, HZ * 5); + BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", + err_nodepda, smp_processor_id(), i)); + spin_unlock_irqrestore(recovery_lock, + irq_flags); + return; + } + } + } + + + BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, + smp_processor_id())); + /* Reenable both bte interfaces */ + imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); + imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; + REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); + + /* Reinitialize both BTE state machines. */ + ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); + ibcr.ii_ibcr_fld_s.i_soft_reset = 1; + REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); + + + for (i = 0; i < BTES_PER_NODE; i++) { + bh_error = err_nodepda->bte_if[i].bh_error; + if (bh_error != BTE_SUCCESS) { + /* There is an error which needs to be notified */ + notify = err_nodepda->bte_if[i].most_rcnt_na; + BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", + err_nodepda->bte_if[i].bte_cnode, + err_nodepda->bte_if[i].bte_num, + IBLS_ERROR | (u64) bh_error)); + *notify = IBLS_ERROR | bh_error; + err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; + } + + err_nodepda->bte_if[i].cleanup_active = 0; + BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, + smp_processor_id(), i)); + spin_unlock(&pda->cpu_bte_if[i]->spinlock); + } + + del_timer(recovery_timer); + + spin_unlock_irqrestore(recovery_lock, irq_flags); +} diff --git a/arch/ia64/sn/io/sn2/kdba_io.c b/arch/ia64/sn/io/sn2/kdba_io.c new file mode 100644 index 00000000000..51f03577f8e --- /dev/null +++ b/arch/ia64/sn/io/sn2/kdba_io.c @@ -0,0 +1,76 @@ +/* + * Kernel Debugger Architecture Dependent POD functions. + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +//#include + +/** + * kdba_io - enter POD mode from kdb + * @argc: arg count + * @argv: arg values + * @envp: kdb env. vars + * @regs: current register state + * + * Enter POD mode from kdb using SGI SN specific SAL function call. + */ +static int +kdba_io(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_printf("kdba_io entered with addr 0x%p\n", (void *) regs); + + return(0); +} + +/** + * kdba_io_init - register 'io' command with kdb + * + * Register the 'io' command with kdb at load time. + */ +void +kdba_io_init(void) +{ + kdb_register("io", kdba_io, "", "Display IO Contents", 0); +} + +/** + * kdba_io_exit - unregister the 'io' command + * + * Tell kdb that the 'io' command is no longer available. + */ +static void __exit +kdba_exit(void) +{ + kdb_unregister("io"); +} diff --git a/arch/ia64/sn/io/sn2/klconflib.c b/arch/ia64/sn/io/sn2/klconflib.c index 4151c6cec7c..d3a48ada4ad 100644 --- a/arch/ia64/sn/io/sn2/klconflib.c +++ b/arch/ia64/sn/io/sn2/klconflib.c @@ -24,8 +24,6 @@ #include #include -#define printf printk -int hasmetarouter; #define LDEBUG 0 #define NIC_UNKNOWN ((nic_t) -1) @@ -37,10 +35,11 @@ int hasmetarouter; #define DBG(x...) #endif /* DEBUG_KLGRAPH */ -static void sort_nic_names(lboard_t *) ; - u64 klgraph_addr[MAX_COMPACT_NODES]; -int module_number = 0; +static int hasmetarouter; + + +char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#=012345"; lboard_t * find_lboard(lboard_t *start, unsigned char brd_type) @@ -135,23 +134,6 @@ find_lboard_module(lboard_t *start, geoid_t geoid) return (lboard_t *)NULL; } -lboard_t * -find_lboard_module_class(lboard_t *start, geoid_t geoid, - unsigned char brd_type) -{ - while (start) { - DBG("find_lboard_module_class: lboard 0x%p, start->brd_geoid 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_geoid, geoid, start->brd_type, brd_type); - - if (geo_cmp(start->brd_geoid, geoid) && - (KLCLASS(start->brd_type) == KLCLASS(brd_type))) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - /* * Convert a NIC name to a name for use in the hardware graph. */ @@ -205,63 +187,6 @@ nic_name_convert(char *old_name, char *new_name) } /* - * Find the lboard structure and get the board name. - * If we can't find the structure or it's too low a revision, - * use default name. - */ -lboard_t * -get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name) -{ - lboard_t *brd; - - brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - geoid); - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) - brd = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - geoid); - } -#endif - - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, name); - } - - /* - * PV # 540860 - * If the name is not 'baseio' - * get the lowest of all the names in the nic string. - * This is needed for boards like divo, which can have - * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio - * but it has some special case names that we would not - * like to disturb at this point. - */ - - /* gfx boards don't need any of this name scrambling */ - if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { - return(brd); - } - - if (!(!strcmp(name, "baseio") )) { - if (brd) { - sort_nic_names(brd) ; - /* Convert to small case, '-' to '_' etc */ - nic_name_convert(brd->brd_name, name) ; - } - } - - return(brd); -} - -/* * get_actual_nasid * * Completely disabled brds have their klconfig on @@ -341,12 +266,20 @@ board_to_path(lboard_t *brd, char *path) board_name = EDGE_LBL_IO; break; case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PBRICK) + if (brd->brd_type == KLTYPE_PXBRICK) + board_name = EDGE_LBL_PXBRICK; + else if (brd->brd_type == KLTYPE_IXBRICK) + board_name = EDGE_LBL_IXBRICK; + else if (brd->brd_type == KLTYPE_PBRICK) board_name = EDGE_LBL_PBRICK; else if (brd->brd_type == KLTYPE_IBRICK) board_name = EDGE_LBL_IBRICK; else if (brd->brd_type == KLTYPE_XBRICK) board_name = EDGE_LBL_XBRICK; + else if (brd->brd_type == KLTYPE_PEBRICK) + board_name = EDGE_LBL_PEBRICK; + else if (brd->brd_type == KLTYPE_CGBRICK) + board_name = EDGE_LBL_CGBRICK; else board_name = EDGE_LBL_IOBRICK; break; @@ -623,182 +556,6 @@ board_serial_number_get(lboard_t *board,char *serial_number) #include "asm/sn/sn_private.h" -xwidgetnum_t -nodevertex_widgetnum_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - return(hubinfo_p->h_widgetid); -} - -devfs_handle_t -nodevertex_xbow_peer_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - nasid_t xbow_peer_nasid; - cnodeid_t xbow_peer; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; - if(xbow_peer_nasid == INVALID_NASID) - return ( (devfs_handle_t)-1); - xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); - return(NODEPDA(xbow_peer)->node_vertex); -} - -/* NIC Sorting Support */ - -#define MAX_NICS_PER_STRING 32 -#define MAX_NIC_NAME_LEN 32 - -static char * -get_nic_string(lboard_t *lb) -{ - int i; - klinfo_t *k = NULL ; - klconf_off_t mfg_off = 0 ; - char *mfg_nic = NULL ; - - for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { - k = KLCF_COMP(lb, i) ; - switch(k->struct_type) { - case KLSTRUCT_BRI: - mfg_off = ((klbri_t *)k)->bri_mfg_nic ; - break ; - - case KLSTRUCT_HUB: - mfg_off = ((klhub_t *)k)->hub_mfg_nic ; - break ; - - case KLSTRUCT_ROU: - mfg_off = ((klrou_t *)k)->rou_mfg_nic ; - break ; - - case KLSTRUCT_GFX: - mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; - break ; - - case KLSTRUCT_TPU: - mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; - break ; - - case KLSTRUCT_GSN_A: - case KLSTRUCT_GSN_B: - mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; - break ; - - case KLSTRUCT_XTHD: - mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; - break; - - default: - mfg_off = 0 ; - break ; - } - if (mfg_off) - break ; - } - - if ((mfg_off) && (k)) - mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; - - return mfg_nic ; -} - -char * -get_first_string(char **ptrs, int n) -{ - int i ; - char *tmpptr ; - - if ((ptrs == NULL) || (n == 0)) - return NULL ; - - tmpptr = ptrs[0] ; - - if (n == 1) - return tmpptr ; - - for (i = 0 ; i < n ; i++) { - if (strcmp(tmpptr, ptrs[i]) > 0) - tmpptr = ptrs[i] ; - } - - return tmpptr ; -} - -int -get_ptrs(char *idata, char **ptrs, int n, char *label) -{ - int i = 0 ; - char *tmp = idata ; - - if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) - return 0 ; - - while ( (tmp = strstr(tmp, label)) ){ - tmp += strlen(label) ; - /* check for empty name field, and last NULL ptr */ - if ((i < (n-1)) && (*tmp != ';')) { - ptrs[i++] = tmp ; - } - } - - ptrs[i] = NULL ; - - return i ; -} - -/* - * sort_nic_names - * - * Does not really do sorting. Find the alphabetically lowest - * name among all the nic names found in a nic string. - * - * Return: - * Nothing - * - * Side Effects: - * - * lb->brd_name gets the new name found - */ - -static void -sort_nic_names(lboard_t *lb) -{ - char *nic_str ; - char *ptrs[MAX_NICS_PER_STRING] ; - char name[MAX_NIC_NAME_LEN] ; - char *tmp, *tmp1 ; - - *name = 0 ; - - /* Get the nic pointer from the lb */ - - if ((nic_str = get_nic_string(lb)) == NULL) - return ; - - tmp = get_first_string(ptrs, - get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; - - if (tmp == NULL) - return ; - - if ( (tmp1 = strchr(tmp, ';')) ) - strlcpy(name, tmp, tmp1-tmp); - else - strlcpy(name, tmp, (sizeof(name))); - - strlcpy(lb->brd_name, name, sizeof(lb->brd_name)) ; -} - - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345"; - /* * Format a module id for printing. */ @@ -811,6 +568,7 @@ format_module_id(char *buffer, moduleid_t m, int fmt) rack = MODULE_GET_RACK(m); ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); brickchar = MODULE_GET_BTCHAR(m); + position = MODULE_GET_BPOS(m); if (fmt == MODULE_FORMAT_BRIEF) { diff --git a/arch/ia64/sn/io/sn2/klgraph.c b/arch/ia64/sn/io/sn2/klgraph.c index 532a8a73693..cd513cccdad 100644 --- a/arch/ia64/sn/io/sn2/klgraph.c +++ b/arch/ia64/sn/io/sn2/klgraph.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,7 @@ extern char arg_maxnodes[]; extern u64 klgraph_addr[]; -void mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid); +void mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid); /* @@ -69,7 +68,7 @@ klhwg_invent_alloc(cnodeid_t cnode, int class, int size) * Add detailed disabled cpu inventory info to the hardware graph. */ void -klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv, +klhwg_disabled_cpu_invent_info(vertex_hdl_t cpuv, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) { @@ -118,7 +117,7 @@ klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv, * Add detailed cpu inventory info to the hardware graph. */ void -klhwg_cpu_invent_info(devfs_handle_t cpuv, +klhwg_cpu_invent_info(vertex_hdl_t cpuv, cnodeid_t cnode, klcpu_t *cpu) { @@ -153,7 +152,7 @@ klhwg_cpu_invent_info(devfs_handle_t cpuv, * as a part of detailed inventory info in the hwgraph. */ void -klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) +klhwg_baseio_inventory_add(vertex_hdl_t baseio_vhdl,cnodeid_t cnode) { invent_miscinfo_t *baseio_inventory; unsigned char version = 0,revision = 0; @@ -177,20 +176,11 @@ klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) sizeof(invent_miscinfo_t)); } -char *hub_rev[] = { - "0.0", - "1.0", - "2.0", - "2.1", - "2.2", - "2.3" -}; - /* * Add detailed cpu inventory info to the hardware graph. */ void -klhwg_hub_invent_info(devfs_handle_t hubv, +klhwg_hub_invent_info(vertex_hdl_t hubv, cnodeid_t cnode, klhub_t *hub) { @@ -215,10 +205,10 @@ klhwg_hub_invent_info(devfs_handle_t hubv, /* ARGSUSED */ void -klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) +klhwg_add_hub(vertex_hdl_t node_vertex, klhub_t *hub, cnodeid_t cnode) { - devfs_handle_t myhubv; - devfs_handle_t hub_mon; + vertex_hdl_t myhubv; + vertex_hdl_t hub_mon; int rc; extern struct file_operations shub_mon_fops; @@ -226,7 +216,7 @@ klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); rc = device_master_set(myhubv, node_vertex); hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, &shub_mon_fops, (void *)(long)cnode); @@ -234,9 +224,9 @@ klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) /* ARGSUSED */ void -klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) +klhwg_add_disabled_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) { - devfs_handle_t my_cpu; + vertex_hdl_t my_cpu; char name[120]; cpuid_t cpu_id; nasid_t nasid; @@ -257,9 +247,9 @@ klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu /* ARGSUSED */ void -klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) +klhwg_add_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) { - devfs_handle_t my_cpu, cpu_dir; + vertex_hdl_t my_cpu, cpu_dir; char name[120]; cpuid_t cpu_id; nasid_t nasid; @@ -295,7 +285,7 @@ klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) nasid_t hub_nasid; cnodeid_t hub_cnode; int widgetnum; - devfs_handle_t xbow_v, hubv; + vertex_hdl_t xbow_v, hubv; /*REFERENCED*/ graph_error_t err; @@ -363,12 +353,12 @@ klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) /* ARGSUSED */ void -klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) +klhwg_add_node(vertex_hdl_t hwgraph_root, cnodeid_t cnode) { nasid_t nasid; lboard_t *brd; klhub_t *hub; - devfs_handle_t node_vertex = NULL; + vertex_hdl_t node_vertex = NULL; char path_buffer[100]; int rv; char *s; @@ -382,7 +372,7 @@ klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) ASSERT(brd); do { - devfs_handle_t cpu_dir; + vertex_hdl_t cpu_dir; /* Generate a hardware graph path for this board. */ board_to_path(brd, path_buffer); @@ -443,7 +433,7 @@ klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) while (cpu) { cpuid_t cpu_id; cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid); - if (cpu_enabled(cpu_id)) + if (cpu_online(cpu_id)) klhwg_add_cpu(node_vertex, cnode, cpu); else klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot); @@ -466,12 +456,12 @@ klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) /* ARGSUSED */ void -klhwg_add_all_routers(devfs_handle_t hwgraph_root) +klhwg_add_all_routers(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; lboard_t *brd; - devfs_handle_t node_vertex; + vertex_hdl_t node_vertex; char path_buffer[100]; int rv; @@ -525,14 +515,14 @@ klhwg_add_all_routers(devfs_handle_t hwgraph_root) /* ARGSUSED */ void -klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, +klhwg_connect_one_router(vertex_hdl_t hwgraph_root, lboard_t *brd, cnodeid_t cnode, nasid_t nasid) { klrou_t *router; char path_buffer[50]; char dest_path[50]; - devfs_handle_t router_hndl; - devfs_handle_t dest_hndl; + vertex_hdl_t router_hndl; + vertex_hdl_t dest_hndl; int rc; int port; lboard_t *dest_brd; @@ -619,7 +609,7 @@ klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, void -klhwg_connect_routers(devfs_handle_t hwgraph_root) +klhwg_connect_routers(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; @@ -652,15 +642,15 @@ klhwg_connect_routers(devfs_handle_t hwgraph_root) void -klhwg_connect_hubs(devfs_handle_t hwgraph_root) +klhwg_connect_hubs(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; lboard_t *brd; klhub_t *hub; lboard_t *dest_brd; - devfs_handle_t hub_hndl; - devfs_handle_t dest_hndl; + vertex_hdl_t hub_hndl; + vertex_hdl_t dest_hndl; char path_buffer[50]; char dest_path[50]; graph_error_t rc; @@ -796,12 +786,12 @@ klhwg_device_disable_hints_add(void) } void -klhwg_add_all_modules(devfs_handle_t hwgraph_root) +klhwg_add_all_modules(vertex_hdl_t hwgraph_root) { cmoduleid_t cm; char name[128]; - devfs_handle_t vhdl; - devfs_handle_t module_vhdl; + vertex_hdl_t vhdl; + vertex_hdl_t module_vhdl; int rc; char buffer[16]; @@ -837,12 +827,12 @@ klhwg_add_all_modules(devfs_handle_t hwgraph_root) } void -klhwg_add_all_nodes(devfs_handle_t hwgraph_root) +klhwg_add_all_nodes(vertex_hdl_t hwgraph_root) { cnodeid_t cnode; for (cnode = 0; cnode < numnodes; cnode++) { - klhwg_add_node(hwgraph_root, cnode, NULL); + klhwg_add_node(hwgraph_root, cnode); } for (cnode = 0; cnode < numnodes; cnode++) { diff --git a/arch/ia64/sn/io/sn2/l1.c b/arch/ia64/sn/io/sn2/l1.c index c83e1c0ade7..ac37d3ce6c9 100644 --- a/arch/ia64/sn/io/sn2/l1.c +++ b/arch/ia64/sn/io/sn2/l1.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -50,6 +51,9 @@ #define UART_BAUD_RATE 57600 +static int L1_connected; /* non-zero when interrupts are enabled */ + + int get_L1_baud(void) { @@ -62,7 +66,23 @@ get_L1_baud(void) int l1_get_intr_value( void ) { - return(0); + cpuid_t intr_cpuid; + nasid_t console_nasid; + int major, minor; + extern nasid_t get_console_nasid(void); + + /* if it is an old prom, run in poll mode */ + + major = sn_sal_rev_major(); + minor = sn_sal_rev_minor(); + if ( (major < 1) || ((major == 1) && (minor < 10)) ) { + /* before version 1.10 doesn't work */ + return (0); + } + + console_nasid = get_console_nasid(); + intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; + return CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); } /* Disconnect the callup functions - throw away interrupts */ @@ -74,19 +94,45 @@ l1_unconnect_intr(void) /* Set up uart interrupt handling for this node's uart */ -void -l1_connect_intr(void *rx_notify, void *tx_notify) +int +l1_connect_intr(void *intr_func, void *arg, struct pt_regs *ep) { -#if 0 - // Will need code here for sn2 - something like this - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); - intr_connect_level(console_nodepda->node_first_cpu, - SGI_UART_VECTOR, INTPEND0_MAXMASK, - dummy_intr_func); - request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), - intr_func, SA_INTERRUPT | SA_SHIRQ, - "l1_protocol_driver", (void *)sc); -#endif + cpuid_t intr_cpuid; + nasid_t console_nasid; + unsigned int console_irq; + int result; + extern int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); + extern nasid_t get_console_nasid(void); + + + /* don't call to connect multiple times - we DON'T support changing the handler */ + + if ( !L1_connected ) { + L1_connected++; + console_nasid = get_console_nasid(); + intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; + console_irq = CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); + result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR, + 0 /*not used*/, 0 /*not used*/); + if (result != SGI_UART_VECTOR) { + if (result < 0) + printk(KERN_WARNING "L1 console driver : intr_connect_level failed %d\n", result); + else + printk(KERN_WARNING "L1 console driver : intr_connect_level returns wrong bit %d\n", result); + return (-1); + } + + result = request_irq(console_irq, intr_func, SA_INTERRUPT, + "SGI L1 console driver", (void *)arg); + if (result < 0) { + printk(KERN_WARNING "L1 console driver : request_irq failed %d\n", result); + return (-1); + } + + /* ask SAL to turn on interrupts in the UART itself */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + } + return (0); } @@ -195,7 +241,7 @@ l1_serial_in_local(void) int l1_serial_out( char *str, int len ) { - int counter = len; + int tmp; /* Ignore empty messages */ if ( len == 0 ) @@ -216,6 +262,8 @@ l1_serial_out( char *str, int len ) if ( IS_RUNNING_ON_SIMULATOR() ) { extern u64 master_node_bedrock_address; void early_sn_setup(void); + int counter = len; + if (!master_node_bedrock_address) early_sn_setup(); if ( master_node_bedrock_address != (u64)0 ) { @@ -237,8 +285,9 @@ l1_serial_out( char *str, int len ) } /* Attempt to write things out thru the sal */ - if ( ia64_sn_console_putb(str, len) ) - return(0); - - return((counter <= 0) ? 0 : (len - counter)); + if ( L1_connected ) + tmp = ia64_sn_console_xmit_chars(str, len); + else + tmp = ia64_sn_console_putb(str, len); + return ((tmp < 0) ? 0 : tmp); } diff --git a/arch/ia64/sn/io/sn2/l1_command.c b/arch/ia64/sn/io/sn2/l1_command.c index 9826308a6ed..280d2bb2ad0 100644 --- a/arch/ia64/sn/io/sn2/l1_command.c +++ b/arch/ia64/sn/io/sn2/l1_command.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -26,37 +25,6 @@ #include #include -#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ -#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ - -#define hub_cpu_get() 0 - -#define LBYTE(caddr) (*(char *) caddr) - -extern char *bcopy(const char * src, char * dest, int count); - -#define LDEBUG 0 - -/* - * ELSC data is in NVRAM page 7 at the following offsets. - */ - -#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ -#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ -#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ -#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ -#define NVRAM_CFG 0x707 /* ELSC Configuration info */ -#define NVRAM_MODULE 0x708 /* system module number */ -#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ -#define NVRAM_PARTITION 0x70a /* module's partition id */ -#define NVRAM_DOMAIN 0x70b /* module's domain id */ -#define NVRAM_CLUSTER 0x70c /* module's cluster id */ -#define NVRAM_CELL 0x70d /* module's cellid */ - -#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ -#define NVRAM_SIZE 16 /* 16 bytes in nvram */ - - /* elsc_display_line writes up to 12 characters to either the top or bottom * line of the L1 display. line points to a buffer containing the message * to be displayed. The zero-based line number is specified by lnum (so @@ -69,6 +37,7 @@ int elsc_display_line(nasid_t nasid, char *line, int lnum) return 0; } + /* * iobrick routines */ @@ -88,9 +57,9 @@ int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) return( ELSC_ERROR_CMD_SEND ); - *rack = (result & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (result & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - *brick_type = (result & L1_ADDR_TYPE_MASK) >> L1_ADDR_TYPE_SHFT; + *rack = (result & MODULE_RACK_MASK) >> MODULE_RACK_SHFT; + *bay = (result & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT; + *brick_type = (result & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT; *brick_type = toupper(*brick_type); return 0; @@ -99,14 +68,12 @@ int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, int iomoduleid_get(nasid_t nasid) { - int result = 0; if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) return( ELSC_ERROR_CMD_SEND ); return result; - } int iobrick_module_get(nasid_t nasid) @@ -142,11 +109,15 @@ int iobrick_module_get(nasid_t nasid) RACK_ADD_NUM(rack, t); switch( brick_type ) { - case 'I': + case L1_BRICKTYPE_IX: + brick_type = MODULE_IXBRICK; break; + case L1_BRICKTYPE_PX: + brick_type = MODULE_PXBRICK; break; + case L1_BRICKTYPE_I: brick_type = MODULE_IBRICK; break; - case 'P': + case L1_BRICKTYPE_P: brick_type = MODULE_PBRICK; break; - case 'X': + case L1_BRICKTYPE_X: brick_type = MODULE_XBRICK; break; } @@ -154,7 +125,7 @@ int iobrick_module_get(nasid_t nasid) return ret; } -#ifdef CONFIG_PCI + /* * iobrick_module_get_nasid() returns a module_id which has the brick * type encoded in bits 15-12, but this is not the true brick type... @@ -179,29 +150,54 @@ iobrick_type_get_nasid(nasid_t nasid) /* convert to a module.h brick type */ for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == type ) + if( brick_types[t] == type ) { return t; + } } return -1; /* unknown brick */ } -#endif + int iobrick_module_get_nasid(nasid_t nasid) { int io_moduleid; -#ifdef PIC_LATER - uint rack, bay; + io_moduleid = iobrick_module_get(nasid); + return io_moduleid; +} + +/* + * given a L1 bricktype, return a bricktype string. This string is the + * string that will be used in the hwpath for I/O bricks + */ +char * +iobrick_L1bricktype_to_name(int type) +{ + switch (type) + { + default: + return("Unknown"); + + case L1_BRICKTYPE_X: + return("Xbrick"); - if (PEBRICK_NODE(nasid)) { - if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) { - printf("Could not read rack and bay location " - "of PEBrick at nasid %d\n", nasid); - } + case L1_BRICKTYPE_I: + return("Ibrick"); - io_moduleid = peer_iobrick_module_get(sc, rack, bay); + case L1_BRICKTYPE_P: + return("Pbrick"); + + case L1_BRICKTYPE_PX: + return("PXbrick"); + + case L1_BRICKTYPE_IX: + return("IXbrick"); + + case L1_BRICKTYPE_C: + return("Cbrick"); + + case L1_BRICKTYPE_R: + return("Rbrick"); } -#endif /* PIC_LATER */ - io_moduleid = iobrick_module_get(nasid); - return io_moduleid; } + diff --git a/arch/ia64/sn/io/sn2/ml_SN_init.c b/arch/ia64/sn/io/sn2/ml_SN_init.c index 51829ce6e02..c5a6701733b 100644 --- a/arch/ia64/sn/io/sn2/ml_SN_init.c +++ b/arch/ia64/sn/io/sn2/ml_SN_init.c @@ -19,25 +19,12 @@ #include #include #include -#include -extern int numcpus; -extern char arg_maxnodes[]; extern cpuid_t master_procid; - -extern int hasmetarouter; - int maxcpus; -cpumask_t boot_cpumask; -hubreg_t region_mask = 0; - extern xwidgetnum_t hub_widget_id(nasid_t); -extern int valid_icache_reasons; /* Reasons to flush the icache */ -extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern u_char miniroot; -extern volatile int need_utlbmiss_patch; extern void iograph_early_init(void); nasid_t master_nasid = INVALID_NASID; /* This is the partition master nasid */ @@ -75,9 +62,6 @@ mlreset(int slave) /* early initialization of iograph */ iograph_early_init(); - - /* Initialize Hub Pseudodriver Management */ - hubdev_init(); } @@ -123,16 +107,6 @@ void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) mutex_init_locked(&npda->xbow_sema); /* init it locked? */ } -/* XXX - Move the interrupt stuff to intr.c ? */ -/* - * Set up the platform-dependent fields in the processor pda. - * Must be done _after_ init_platform_nodepda(). - * If we need a lock here, something else is wrong! - */ -void init_platform_pda(cpuid_t cpu) -{ -} - void update_node_information(cnodeid_t cnodeid) { diff --git a/arch/ia64/sn/io/sn2/ml_SN_intr.c b/arch/ia64/sn/io/sn2/ml_SN_intr.c index e42a347cac0..31da1ccb1bc 100644 --- a/arch/ia64/sn/io/sn2/ml_SN_intr.c +++ b/arch/ia64/sn/io/sn2/ml_SN_intr.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ /* @@ -40,11 +40,14 @@ #include #include -extern irqpda_t *irqpdaindr[]; -extern cnodeid_t master_node_get(devfs_handle_t vhdl); +extern irqpda_t *irqpdaindr; +extern cnodeid_t master_node_get(vertex_hdl_t vhdl); extern nasid_t master_nasid; // Initialize some shub registers for interrupts, both IO and error. +// + + void intr_init_vecblk( nodepda_t *npda, @@ -58,6 +61,8 @@ intr_init_vecblk( nodepda_t *npda, nodepda_t *lnodepda; sh_ii_int0_enable_u_t ii_int_enable; sh_int_node_id_config_u_t node_id_config; + sh_local_int5_config_u_t local5_config; + sh_local_int5_enable_u_t local5_enable; extern void sn_init_cpei_timer(void); static int timer_added = 0; @@ -93,6 +98,19 @@ intr_init_vecblk( nodepda_t *npda, HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); + // Config and enable UART interrupt, all nodes. + + local5_config.sh_local_int5_config_regval = 0; + local5_config.sh_local_int5_config_s.idx = SGI_UART_VECTOR; + local5_config.sh_local_int5_config_s.pid = cpu0; + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_CONFIG), + local5_config.sh_local_int5_config_regval); + + local5_enable.sh_local_int5_enable_regval = 0; + local5_enable.sh_local_int5_enable_s.uart_int = 1; + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), + local5_enable.sh_local_int5_enable_regval); + // The II_INT_CONFIG register for cpu 0. ii_int_config.sh_ii_int0_config_regval = 0; @@ -119,13 +137,6 @@ intr_init_vecblk( nodepda_t *npda, // Enable interrupts for II_INT0 and 1. ii_int_enable.sh_ii_int0_enable_regval = 0; ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; -#ifdef BUS_INT_WAR - /* Dont enable any ints from II. We will poll for interrupts. */ - ii_int_enable.sh_ii_int0_enable_s.ii_enable = 0; - - /* Enable IPIs. We use them ONLY for send INITs to hung cpus */ - *(volatile long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT_ENABLE) = 1; -#endif HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); @@ -147,7 +158,8 @@ do_intr_reserve_level(cpuid_t cpu, int reserve) { int i; - irqpda_t *irqs = irqpdaindr[cpu]; + irqpda_t *irqs = irqpdaindr; + int min_shared; if (reserve) { if (bit < 0) { @@ -158,8 +170,32 @@ do_intr_reserve_level(cpuid_t cpu, } } } - if (bit < 0) { - return -1; + if (bit < 0) { /* ran out of irqs. Have to share. This will be rare. */ + min_shared = 256; + for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { + /* Share with the same device class */ + if (irqpdaindr->current->vendor == irqpdaindr->device_dev[i]->vendor && + irqpdaindr->current->device == irqpdaindr->device_dev[i]->device && + irqpdaindr->share_count[i] < min_shared) { + min_shared = irqpdaindr->share_count[i]; + bit = i; + } + } + min_shared = 256; + if (bit < 0) { /* didn't find a matching device, just pick one. This will be */ + /* exceptionally rare. */ + for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { + if (irqpdaindr->share_count[i] < min_shared) { + min_shared = irqpdaindr->share_count[i]; + bit = i; + } + } + } + irqpdaindr->share_count[bit]++; + } + if (irqs->irq_flags[bit] & SN2_IRQ_SHARED) { + irqs->irq_flags[bit] |= SN2_IRQ_RESERVED; + return bit; } if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) { return -1; @@ -183,7 +219,7 @@ int intr_reserve_level(cpuid_t cpu, int bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name) { return(do_intr_reserve_level(cpu, bit, 1)); @@ -203,9 +239,13 @@ do_intr_connect_level(cpuid_t cpu, int bit, int connect) { - irqpda_t *irqs = irqpdaindr[cpu]; + irqpda_t *irqs = irqpdaindr; if (connect) { + if (irqs->irq_flags[bit] & SN2_IRQ_SHARED) { + irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED; + return bit; + } if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) { return -1; } else { @@ -248,24 +288,29 @@ do_intr_cpu_choose(cnodeid_t cnode) { int slice, min_count = 1000; irqpda_t *irqs; - for (slice = 0; slice < CPUS_PER_NODE; slice++) { + for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) { int intrs; cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) { + if (cpu == num_online_cpus()) { continue; } - if (!cpu_enabled(cpu)) { + if (!cpu_online(cpu)) { continue; } - irqs = irqpdaindr[cpu]; + irqs = irqpdaindr; intrs = irqs->num_irq_used; if (min_count > intrs) { min_count = intrs; best_cpu = cpu; + if ( enable_shub_wars_1_1() ) { + /* Rather than finding the best cpu, always return the first cpu*/ + /* This forces all interrupts to the same cpu */ + break; + } } } return best_cpu; @@ -285,7 +330,7 @@ intr_bit_reserve_test(cpuid_t cpu, cnodeid_t cnode, int req_bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name, int *resp_bit) { @@ -307,18 +352,18 @@ intr_bit_reserve_test(cpuid_t cpu, // Find the node to assign for this interrupt. cpuid_t -intr_heuristic(devfs_handle_t dev, +intr_heuristic(vertex_hdl_t dev, device_desc_t dev_desc, int req_bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name, int *resp_bit) { cpuid_t cpuid; cpuid_t candidate = CPU_NONE; cnodeid_t candidate_node; - devfs_handle_t pconn_vhdl; + vertex_hdl_t pconn_vhdl; pcibr_soft_t pcibr_soft; int bit; @@ -369,8 +414,8 @@ intr_heuristic(devfs_handle_t dev, if (candidate != CPU_NONE) { printk("Cannot target interrupt to target node (%ld).\n",candidate); return CPU_NONE; } else { - printk("Cannot target interrupt to closest node (%d) 0x%p\n", - master_node_get(dev), (void *)owner_dev); + /* printk("Cannot target interrupt to closest node (%d) 0x%p\n", + master_node_get(dev), (void *)owner_dev); */ } // We couldn't put it on the closest node. Try to find another one. diff --git a/arch/ia64/sn/io/sn2/ml_iograph.c b/arch/ia64/sn/io/sn2/ml_iograph.c index 83599fafa98..c36dd00dec8 100644 --- a/arch/ia64/sn/io/sn2/ml_iograph.c +++ b/arch/ia64/sn/io/sn2/ml_iograph.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -43,8 +42,6 @@ /* At most 2 hubs can be connected to an xswitch */ #define NUM_XSWITCH_VOLUNTEER 2 -extern unsigned char Is_pic_on_this_nasid[512]; - /* * Track which hubs have volunteered to manage devices hanging off of * a Crosstalk Switch (e.g. xbow). This structure is allocated, @@ -54,11 +51,11 @@ extern unsigned char Is_pic_on_this_nasid[512]; typedef struct xswitch_vol_s { mutex_t xswitch_volunteer_mutex; int xswitch_volunteer_count; - devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; + vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; } *xswitch_vol_t; void -xswitch_vertex_init(devfs_handle_t xswitch) +xswitch_vertex_init(vertex_hdl_t xswitch) { xswitch_vol_t xvolinfo; int rc; @@ -78,7 +75,7 @@ xswitch_vertex_init(devfs_handle_t xswitch) * xswitch volunteer structure hanging around. Destroy it. */ static void -xswitch_volunteer_delete(devfs_handle_t xswitch) +xswitch_volunteer_delete(vertex_hdl_t xswitch) { xswitch_vol_t xvolinfo; int rc; @@ -94,10 +91,10 @@ xswitch_volunteer_delete(devfs_handle_t xswitch) */ /* ARGSUSED */ static void -volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) +volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master) { xswitch_vol_t xvolinfo = NULL; - devfs_handle_t hubv; + vertex_hdl_t hubv; hubinfo_t hubinfo; (void)hwgraph_info_get_LBL(xswitch, @@ -140,7 +137,7 @@ extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); */ /* ARGSUSED */ static void -assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) +assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv) { xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; @@ -223,18 +220,6 @@ assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) bt = iobrick_type_get_nasid(nasid); if (bt >= 0) { - /* - * PXBRICK has two busses per widget so this - * algorithm wouldn't work (all busses would - * be assigned to one volunteer). Change the - * bricktype to PBRICK whose mapping is setup - * suchthat 2 of the PICs will be assigned to - * one volunteer and the other one will be - * assigned to the other volunteer. - */ - if (bt == MODULE_PXBRICK) - bt = MODULE_PBRICK; - i = io_brick_map_widget(bt, widgetnum) & 1; } } @@ -281,8 +266,6 @@ iograph_early_init(void) DBG("iograph_early_init: Found board 0x%p\n", board); } } - - hubio_init(); } /* @@ -307,7 +290,7 @@ io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) * hwid for our use. */ static void -early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) +early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) { hubreg_t llp_csr_reg; nasid_t nasid; @@ -351,7 +334,7 @@ early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) * added as inventory information. */ static void -xwidget_inventory_add(devfs_handle_t widgetv, +xwidget_inventory_add(vertex_hdl_t widgetv, lboard_t *board, struct xwidget_hwid_s hwid) { @@ -374,14 +357,13 @@ xwidget_inventory_add(devfs_handle_t widgetv, */ void -io_xswitch_widget_init(devfs_handle_t xswitchv, - devfs_handle_t hubv, - xwidgetnum_t widgetnum, - async_attach_t aa) +io_xswitch_widget_init(vertex_hdl_t xswitchv, + vertex_hdl_t hubv, + xwidgetnum_t widgetnum) { xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; - devfs_handle_t widgetv; + vertex_hdl_t widgetv; cnodeid_t cnode; widgetreg_t widget_id; nasid_t nasid, peer_nasid; @@ -427,6 +409,7 @@ io_xswitch_widget_init(devfs_handle_t xswitchv, char name[4]; lboard_t dummy; + /* * If the current hub is not supposed to be the master * for this widgetnum, then skip this widget. @@ -470,12 +453,15 @@ io_xswitch_widget_init(devfs_handle_t xswitchv, memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%cbrick" "/%s/%d", + + sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d", buffer, geo_slab(board->brd_geoid), - (board->brd_type == KLTYPE_IBRICK) ? 'I' : - (board->brd_type == KLTYPE_PBRICK) ? 'P' : - (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', + (board->brd_type == KLTYPE_IBRICK) ? EDGE_LBL_IBRICK : + (board->brd_type == KLTYPE_PBRICK) ? EDGE_LBL_PBRICK : + (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK : + (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK : + (board->brd_type == KLTYPE_XBRICK) ? EDGE_LBL_XBRICK : "?brick", EDGE_LBL_XTALK, widgetnum); DBG("io_xswitch_widget_init: path= %s\n", pathname); @@ -514,36 +500,46 @@ io_xswitch_widget_init(devfs_handle_t xswitchv, xwidget_inventory_add(widgetv,board,hwid); (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid, - aa); + hubv, hub_widgetid); ia64_sn_sysctl_iobrick_module_get(nasid, &io_module); if (io_module >= 0) { char buffer[16]; - devfs_handle_t to, from; + vertex_hdl_t to, from; + char *brick_name; + extern char *iobrick_L1bricktype_to_name(int type); + memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - bt = toupper(MODULE_GET_BTCHAR(io_module)); + if ( islower(MODULE_GET_BTCHAR(io_module)) ) { + bt = toupper(MODULE_GET_BTCHAR(io_module)); + } + else { + bt = MODULE_GET_BTCHAR(io_module); + } + + brick_name = iobrick_L1bricktype_to_name(bt); + /* Add a helper vertex so xbow monitoring * can identify the brick type. It's simply * an edge from the widget 0 vertex to the * brick vertex. */ - sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/" "0", buffer, geo_slab(board->brd_geoid)); from = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(from); - sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" - "%cbrick", - buffer, geo_slab(board->brd_geoid), bt); + "%s", + buffer, geo_slab(board->brd_geoid), brick_name); to = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(to); @@ -566,12 +562,9 @@ link_done: static void -io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) +io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode) { xwidgetnum_t widgetnum; - async_attach_t aa; - - aa = async_attach_new(); DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); @@ -579,13 +572,8 @@ io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) widgetnum++) { io_xswitch_widget_init(xswitchv, cnodeid_to_vertex(cnode), - widgetnum, aa); + widgetnum); } - /* - * Wait for parallel attach threads, if any, to complete. - */ - async_attach_waitall(aa); - async_attach_free(aa); } /* @@ -595,11 +583,11 @@ io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) * graph and risking hangs. */ static void -io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) +io_link_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnodeid) { xwidgetnum_t widgetnum; char pathname[128]; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; nasid_t nasid, peer_nasid; lboard_t *board; @@ -638,21 +626,12 @@ io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) return; } - if ( Is_pic_on_this_nasid[nasid] ) { - /* Check both buses */ - sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else { - sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else - board->brd_graph_link = GRAPH_VERTEX_NONE; - } - } + /* Check both buses */ + sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) + board->brd_graph_link = vhdl; else { - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) board->brd_graph_link = vhdl; else @@ -668,16 +647,14 @@ static void io_init_node(cnodeid_t cnodeid) { /*REFERENCED*/ - devfs_handle_t hubv, switchv, widgetv; + vertex_hdl_t hubv, switchv, widgetv; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; int is_xswitch; nodepda_t *npdap; struct semaphore *peer_sema = 0; uint32_t widget_partnum; - nodepda_router_info_t *npda_rip; cpu_cookie_t c = 0; - extern int hubdev_docallouts(devfs_handle_t); npdap = NODEPDA(cnodeid); @@ -693,23 +670,6 @@ io_init_node(cnodeid_t cnodeid) ASSERT(hubv != GRAPH_VERTEX_NONE); - hubdev_docallouts(hubv); - - /* - * Set up the dependent routers if we have any. - */ - npda_rip = npdap->npda_rip_first; - - while(npda_rip) { - /* If the router info has not been initialized - * then we need to do the router initialization - */ - if (!npda_rip->router_infop) { - router_init(cnodeid,0,npda_rip); - } - npda_rip = npda_rip->router_next; - } - /* * Read mfg info on this hub */ @@ -833,7 +793,7 @@ io_init_node(cnodeid_t cnodeid) */ hubinfo_get(hubv, &hubinfo); - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); + (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid); if (!is_xswitch) { /* io_init_done takes cpu cookie as 2nd argument @@ -915,231 +875,9 @@ io_init_node(cnodeid_t cnodeid) * XXX Irix legacy..controller numbering should be part of devfsd's job */ int num_base_io_scsi_ctlr = 2; /* used by syssgi */ -devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; -static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; - -/* - * Put the logical controller number information in the - * scsi controller vertices for each scsi controller that - * is in a "fixed position". - */ -static void -scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) -{ - { - int i; - - num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; - - /* Initialize base_io_scsi_ctlr_vhdl array */ - for (i=0; i -devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; - -/* Define the system critical vertices and connect them through - * a canonical parent-child relationships for easy traversal - * during io error handling. - */ -static void -sys_critical_graph_init(void) -{ - devfs_handle_t bridge_vhdl,master_node_vhdl; - devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; - extern devfs_handle_t hwgraph_root; - devfs_handle_t pci_slot_conn; - int slot; - devfs_handle_t baseio_console_conn; - - DBG("sys_critical_graph_init: FIXME.\n"); - baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); - - if (baseio_console_conn == NULL) { - return; - } - - /* Get the vertex handle for the baseio bridge */ - bridge_vhdl = device_master_get(baseio_console_conn); - - /* Get the master node of the baseio card */ - master_node_vhdl = cnodeid_to_vertex( - master_node_get(baseio_console_vhdl)); - - /* Add the "root->node" part of the system critical graph */ - - sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); - - /* Check if we have a crossbow */ - if (hwgraph_traverse(master_node_vhdl, - EDGE_LBL_XTALK"/0", - &xbow_vhdl) == GRAPH_SUCCESS) { - /* We have a crossbow.Add "node->xbow" part of the system - * critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); - - /* Add "xbow->baseio bridge" of the system critical graph */ - sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); - - hwgraph_vertex_unref(xbow_vhdl); - } else - /* We donot have a crossbow. Add "node->baseio_bridge" - * part of the system critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); - - /* Add all the populated PCI slot vertices to the system critical - * graph with the bridge vertex as the parent. - */ - for (slot = 0 ; slot < 8; slot++) { - char slot_edge[10]; - - sprintf(slot_edge,"%d",slot); - if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) - != GRAPH_SUCCESS) - continue; - sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); - hwgraph_vertex_unref(pci_slot_conn); - } - - hwgraph_vertex_unref(bridge_vhdl); - - /* Add the "ioc3 pci connection point -> console ioc3" part - * of the system critical graph - */ - - if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_console_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "ethernet pci connection point -> base ethernet" part of - * the system critical graph - */ - if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_enet_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "scsi controller pci connection point -> base scsi - * controller" part of the system critical graph - */ - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[0]); - hwgraph_vertex_unref(pci_slot_conn); - } - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[1]); - hwgraph_vertex_unref(pci_slot_conn); - } - hwgraph_vertex_unref(baseio_console_conn); - -} - -static void -baseio_ctlr_num_set(void) -{ - char name[MAXDEVNAME]; - devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - devfs_handle_t ioc3_console_vhdl_get(void); - - - DBG("baseio_ctlr_num_set; FIXME\n"); - console_vhdl = ioc3_console_vhdl_get(); - if (console_vhdl == GRAPH_VERTEX_NONE) - return; - /* Useful for setting up the system critical graph */ - baseio_console_vhdl = console_vhdl; - - vertex_to_name(console_vhdl,name,MAXDEVNAME); - - strcat(name,__DEVSTR1); - pci_vhdl = hwgraph_path_to_vertex(name); - scsi_ctlr_nums_add(pci_vhdl); - /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(pci_vhdl); - - vertex_to_name(console_vhdl, name, MAXDEVNAME); - strcat(name, __DEVSTR4); - enet_vhdl = hwgraph_path_to_vertex(name); - - /* Useful for setting up the system critical graph */ - baseio_enet_vhdl = enet_vhdl; - - device_controller_num_set(enet_vhdl, 0); - /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(enet_vhdl); -} /* #endif */ /* @@ -1168,13 +906,6 @@ init_all_devices(void) */ update_node_information(cnodeid); - baseio_ctlr_num_set(); - /* Setup the system critical graph (which is a subgraph of the - * main hwgraph). This information is useful during io error - * handling. - */ - sys_critical_graph_init(); - #if HWG_PRINT hwgraph_print(); #endif @@ -1300,6 +1031,20 @@ struct io_brick_map_s io_brick_tab[] = { } }, +/* IXbrick widget number to PCI bus number map */ + { MODULE_IXBRICK, /* IXbrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 0, /* 0x8 */ + 0, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 1, /* 0xc */ + 5, /* 0xd */ + 0, /* 0xe */ + 3 /* 0xf */ + } + }, + /* Xbrick widget to XIO slot map */ { MODULE_XBRICK, /* Xbrick type */ /* XIO Slot # Widget # */ @@ -1335,61 +1080,3 @@ io_brick_map_widget(int brick_type, int widget_num) return 0; } - -/* - * Use the device's vertex to map the device's widget to a meaningful int - */ -int -io_path_map_widget(devfs_handle_t vertex) -{ - char hw_path_name[MAXDEVNAME]; - char *wp, *bp, *sp = NULL; - int widget_num; - long atoi(char *); - int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); - - - /* Get the full path name of the vertex */ - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name, - MAXDEVNAME)) - return 0; - - /* Find the widget number in the path name */ - wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/"); - if (wp == NULL) - return 0; - widget_num = atoi(wp+7); - if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F) - return 0; - - /* Find "brick" in the path name */ - bp = strstr(hw_path_name, "brick"); - if (bp == NULL) - return 0; - - /* Find preceding slash */ - sp = bp; - while (sp > hw_path_name) { - sp--; - if (*sp == '/') - break; - } - - /* Invalid if no preceding slash */ - if (!sp) - return 0; - - /* Bump slash pointer to "brick" prefix */ - sp++; - /* - * Verify "brick" prefix length; valid exaples: - * 'I' from "/Ibrick" - * 'P' from "/Pbrick" - * 'X' from "/Xbrick" - */ - if ((bp - sp) != 1) - return 0; - - return (io_brick_map_widget((int)*sp, widget_num)); - -} diff --git a/arch/ia64/sn/io/sn2/module.c b/arch/ia64/sn/io/sn2/module.c index 9b01b6144f3..4679cf22e69 100644 --- a/arch/ia64/sn/io/sn2/module.c +++ b/arch/ia64/sn/io/sn2/module.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ia64/sn/io/sn2/pcibr/Makefile b/arch/ia64/sn/io/sn2/pcibr/Makefile index 0b384ee57a0..837b873d797 100644 --- a/arch/ia64/sn/io/sn2/pcibr/Makefile +++ b/arch/ia64/sn/io/sn2/pcibr/Makefile @@ -11,11 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -ifdef CONFIG_IA64_SGI_SN2 -EXTRA_CFLAGS += -DSHUB_SWAP_WAR -endif - -obj-$(CONFIG_IA64_SGI_SN2) += pcibr_dvr.o pcibr_ate.o pcibr_config.o \ - pcibr_dvr.o pcibr_hints.o \ - pcibr_intr.o pcibr_rrb.o pcibr_slot.o \ - pcibr_error.o +obj-y += pcibr_ate.o pcibr_config.o pcibr_dvr.o pcibr_hints.o pcibr_intr.o pcibr_rrb.o \ + pcibr_slot.o pcibr_error.o diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c index 5b8460ee01d..ed31eedfab9 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -101,73 +100,26 @@ pcibr_init_ext_ate_ram(bridge_t *bridge) int i, j; bridgereg_t old_enable, new_enable; int s; - int this_is_pic = is_pic(bridge); /* Probe SSRAM to determine its size. */ - if ( this_is_pic ) { - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable)); - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable; - } - else { - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - } - } + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; for (i = 1; i < ATE_NUM_SIZES; i++) { /* Try writing a value */ - if ( this_is_pic ) { - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE); - else - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - } + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; /* Guard against wrap */ for (j = 1; j < i; j++) bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; /* See if value was written */ - if ( this_is_pic ) { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) largest_working_size = i; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE)) - largest_working_size = i; - else { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - } - } - } - if ( this_is_pic ) { - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable; - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */ - } - else { - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } } + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ /* * ensure that we write and read without any interruption. @@ -175,26 +127,10 @@ pcibr_init_ext_ate_ram(bridge_t *bridge) */ s = splhi(); - if ( this_is_pic ) { - bridge->b_wid_control = (bridge->b_wid_control + bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&(bridge->b_wid_control))) = - __swab32((BRIDGE_REG_GET32((&bridge->b_wid_control)) - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size)); - BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */ - } - else { - bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - } - } + bridge->b_wid_control; /* inval addr bug war */ splx(s); num_entries = ATE_NUM_ENTRIES(largest_working_size); @@ -423,16 +359,7 @@ ate_freeze(pcibr_dmamap_t pcibr_dmamap, /* Flush the write buffer associated with this * PCI device which might be using dma map RAM. */ - if ( is_pic(bridge) ) { - bridge->b_wr_req_buf[slot].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge)) ) { - BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg)); - } - else - bridge->b_wr_req_buf[slot].reg; - } + bridge->b_wr_req_buf[slot].reg; } } } diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c index d3f3913b05d..77a9f9a3686 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -28,19 +28,16 @@ #include #include #include -#include #include #include -extern pcibr_info_t pcibr_info_get(devfs_handle_t); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); -uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); -void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); -static void swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); +uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); +uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); +void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); -#ifdef LITTLE_ENDIAN /* * on sn-ia we need to twiddle the the addresses going out * the pci bus because we use the unswizzled synergy space @@ -51,18 +48,13 @@ static void swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#define CBP(b,r) (((volatile uint8_t *) b)[(r)^3]) -#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)^1]) +#define CBP(b,r) (((volatile uint8_t *) b)[(r)]) +#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)]) #define CWP(b,r) (((volatile uint32_t *) b)[(r)/4]) #define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)]) #define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)]) #define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)]) -#else -#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) -#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) -#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) -#endif /* * Return a config space address for given slot / func / offset. Note the @@ -84,8 +76,7 @@ pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot, /* * Type 0 config space */ - if (is_pic(bridge)) - slot++; + slot++; return &bridge->b_type0_cfg_dev[slot].f[func].l[offset]; } @@ -109,7 +100,7 @@ pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset) cfg_p cfg_base; cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); + return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); } /* @@ -122,7 +113,7 @@ pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot, cfg_p cfg_base; cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); - return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); + return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); } /* @@ -135,7 +126,7 @@ pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot, cfg_p cfg_base; cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); + do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); } /* @@ -148,13 +139,13 @@ pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot, cfg_p cfg_base; cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); - do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); + do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); } int pcibr_config_debug = 0; cfg_p -pcibr_config_addr(devfs_handle_t conn, +pcibr_config_addr(vertex_hdl_t conn, unsigned reg) { pcibr_info_t pcibr_info; @@ -183,19 +174,6 @@ pcibr_config_addr(devfs_handle_t conn, pciio_func = PCI_TYPE1_FUNC(reg); ASSERT(pciio_bus != 0); -#if 0 - } else if (conn != pciio_info_hostdev_get(pciio_info)) { - /* - * Conn is on a subordinate bus, so get bus/slot/func directly from - * its pciio_info_t structure. - */ - pciio_bus = pciio_info->c_bus; - pciio_slot = pciio_info->c_slot; - pciio_func = pciio_info->c_func; - if (pciio_func == PCIIO_FUNC_NONE) { - pciio_func = 0; - } -#endif } else { /* * Conn is directly connected to the host bus. PCI bus number is @@ -224,44 +202,23 @@ pcibr_config_addr(devfs_handle_t conn, return cfgbase; } -extern unsigned char Is_pic_on_this_nasid[]; uint64_t -pcibr_config_get(devfs_handle_t conn, +pcibr_config_get(vertex_hdl_t conn, unsigned reg, unsigned size) { - if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) - return do_pcibr_config_get(0, pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); - else - return do_pcibr_config_get(1, pcibr_config_addr(conn, reg), + return do_pcibr_config_get(pcibr_config_addr(conn, reg), PCI_TYPE1_REG(reg), size); } uint64_t -do_pcibr_config_get( - int pic, - cfg_p cfgbase, +do_pcibr_config_get(cfg_p cfgbase, unsigned reg, unsigned size) { unsigned value; - if ( pic ) { - value = CWP(cfgbase, reg); - } - else { - if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) { - /* - * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped! - * Do not swizzle address and byte swap the result. - */ - value = SCW(cfgbase, reg); - value = __swab32(value); - } else { - value = CW(cfgbase, reg); - } - } + value = CWP(cfgbase, reg); if (reg & 3) value >>= 8 * (reg & 3); if (size < 4) @@ -270,108 +227,43 @@ do_pcibr_config_get( } void -pcibr_config_set(devfs_handle_t conn, +pcibr_config_set(vertex_hdl_t conn, unsigned reg, unsigned size, uint64_t value) { - if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) - do_pcibr_config_set(1, pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); - else - swap_do_pcibr_config_set(pcibr_config_addr(conn, reg), + do_pcibr_config_set(pcibr_config_addr(conn, reg), PCI_TYPE1_REG(reg), size, value); } void -do_pcibr_config_set(int pic, - cfg_p cfgbase, +do_pcibr_config_set(cfg_p cfgbase, unsigned reg, unsigned size, uint64_t value) { - if ( pic ) { - switch (size) { - case 1: + switch (size) { + case 1: + CBP(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { CBP(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CBP(cfgbase, reg + 1) = value >> 8; - } else - CSP(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CSP(cfgbase, (reg + 1)) = value >> 8; - } else { - CSP(cfgbase, reg) = value; - CBP(cfgbase, reg + 2) = value >> 16; - } - break; - case 4: - CWP(cfgbase, reg) = value; - break; - } - } - else { - switch (size) { - case 1: - CB(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; - case 4: - CW(cfgbase, reg) = value; - break; - } - } -} - -void -swap_do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - - uint64_t temp_value = 0; - - switch (size) { - case 1: - SCB(cfgbase, reg) = value; - break; - case 2: - temp_value = __swab16(value); - if (reg & 1) { - SCB(cfgbase, reg) = temp_value; - SCB(cfgbase, reg + 1) = temp_value >> 8; - } else - SCS(cfgbase, reg) = temp_value; - break; - case 3: - BUG(); - break; - - case 4: - temp_value = __swab32(value); - SCW(cfgbase, reg) = temp_value; - break; - } + CBP(cfgbase, reg + 1) = value >> 8; + } else + CSP(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CBP(cfgbase, reg) = value; + CSP(cfgbase, (reg + 1)) = value >> 8; + } else { + CSP(cfgbase, reg) = value; + CBP(cfgbase, reg + 2) = value >> 16; + } + break; + case 4: + CWP(cfgbase, reg) = value; + break; + } } diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c index 9b2ce991d5f..2d1d193d07b 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c @@ -4,13 +4,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include +#include #include +#include #include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +31,6 @@ #include #include #include -#include #include #include @@ -74,32 +77,6 @@ int pcibr_debug_slot = -1; /* '-1' for all slots */ #define USS302_BRIDGE_TIMEOUT_HLD 4 #endif -int pcibr_devflag = D_MP; - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - /* kbrick widgetnum-to-bus layout */ int p_busnum[MAX_PORT_NUM] = { /* widget# */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ @@ -116,17 +93,16 @@ int p_busnum[MAX_PORT_NUM] = { /* widget# */ pcibr_list_p pcibr_list = 0; #endif -extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); -extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); +extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen); extern long atoi(register char *p); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); +extern cnodeid_t nodevertex_to_cnodeid(vertex_hdl_t vhdl); +extern char *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen); extern struct map *atemapalloc(uint64_t); extern void atefree(struct map *, size_t, uint64_t); extern void atemapfree(struct map *); -extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); extern void free_pciio_dmamap(pcibr_dmamap_t); -extern void xwidget_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); +extern void xwidget_error_register(vertex_hdl_t, error_handler_f *, error_handler_arg_t); #define ATE_WRITE() ate_write(pcibr_soft, ate_ptr, ate_count, ate) #if PCIBR_FREEZE_TIME @@ -153,9 +129,9 @@ extern void xwidget_error_register(devfs_handle_t, error_handler_f *, error_han extern int do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); -extern int pcibr_wrb_flush(devfs_handle_t); -extern int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -extern void pcibr_rrb_flush(devfs_handle_t); +extern int pcibr_wrb_flush(vertex_hdl_t); +extern int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); +extern void pcibr_rrb_flush(vertex_hdl_t); static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); @@ -166,21 +142,15 @@ extern void pcibr_clearwidint(bridge_t *); extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); -void pcibr_init(void); -int pcibr_attach(devfs_handle_t); -int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, +int pcibr_attach(vertex_hdl_t); +int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, int, pcibr_soft_t *); -int pcibr_detach(devfs_handle_t); -int pcibr_open(devfs_handle_t *, int, int, cred_t *); -int pcibr_close(devfs_handle_t, int, int, cred_t *); -int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int pcibr_unmap(devfs_handle_t, vhandl_t *); -int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); +int pcibr_detach(vertex_hdl_t); int pcibr_pcix_rbars_calc(pcibr_soft_t); extern int pcibr_init_ext_ate_ram(bridge_t *); extern int pcibr_ate_alloc(pcibr_soft_t, int); extern void pcibr_ate_free(pcibr_soft_t, int, int); -extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); +extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, #if PCIBR_FREEZE_TIME @@ -197,45 +167,43 @@ extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index, unsigned *cmd_regs, unsigned s); -pcibr_info_t pcibr_info_get(devfs_handle_t); +pcibr_info_t pcibr_info_get(vertex_hdl_t); -static iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); +static iopaddr_t pcibr_addr_pci_to_xio(vertex_hdl_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); -pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); void pcibr_piomap_free(pcibr_piomap_t); caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); +caddr_t pcibr_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +iopaddr_t pcibr_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t); +void pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); extern bridge_ate_t pcibr_flags_to_ate(unsigned); -pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void pcibr_dmamap_free(pcibr_dmamap_t); extern bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); static iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); -iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t); +iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); +void pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); +void pcibr_dmalist_drain(vertex_hdl_t, alenlist_t); iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); extern unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); -extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +extern pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); extern void pcibr_intr_free(pcibr_intr_t); extern void pcibr_setpciint(xtalk_intr_t); extern int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); extern void pcibr_intr_disconnect(pcibr_intr_t); -extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +extern vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); extern void pcibr_intr_func(intr_arg_t); extern void print_bridge_errcmd(uint32_t, char *); @@ -253,51 +221,48 @@ extern int pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioe extern int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); -void pcibr_provider_startup(devfs_handle_t); -void pcibr_provider_shutdown(devfs_handle_t); +void pcibr_provider_startup(vertex_hdl_t); +void pcibr_provider_shutdown(vertex_hdl_t); -int pcibr_reset(devfs_handle_t); -pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +int pcibr_reset(vertex_hdl_t); +pciio_endian_t pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); -int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); - -extern cfg_p pcibr_config_addr(devfs_handle_t, unsigned); -extern uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -extern void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); - -extern pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -extern void pcibr_hints_fix_rrbs(devfs_handle_t); -extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -extern void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -extern void pcibr_hints_handsoff(devfs_handle_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); - -extern int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); +pciio_priority_t pcibr_priority_set(vertex_hdl_t, pciio_priority_t); +int pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t); + +extern cfg_p pcibr_config_addr(vertex_hdl_t, unsigned); +extern uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); +extern void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); + +extern pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); +extern void pcibr_hints_fix_rrbs(vertex_hdl_t); +extern void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +extern void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); +extern void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); +extern void pcibr_hints_handsoff(vertex_hdl_t); +extern void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); + +extern int pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t); extern int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, pcibr_slot_info_resp_t); extern void pcibr_slot_func_info_return(pcibr_info_h, int, pcibr_slot_func_info_resp_t); -extern int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t); extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); -extern int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); -extern int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_call_device_attach(devfs_handle_t, +extern int pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t); +extern int pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_call_device_attach(vertex_hdl_t, pciio_slot_t, int); -extern int pcibr_slot_call_device_detach(devfs_handle_t, +extern int pcibr_slot_call_device_detach(vertex_hdl_t, pciio_slot_t, int); -extern int pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, +extern int pcibr_slot_attach(vertex_hdl_t, pciio_slot_t, int, char *, int *); -extern int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int, +extern int pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int, char *, int *); -extern int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); - -extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t); -extern int pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t); +extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t, pciio_slot_t); +extern int pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, pciio_slot_t); /* ===================================================================== * Device(x) register management @@ -623,172 +588,47 @@ pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, */ -/* - * pcibr_init: called once during system startup or - * when a loadable driver is loaded. - * - * The driver_register function should normally - * be in _reg, not _init. But the pcibr driver is - * required by devinit before the _reg routines - * are called, so this is an exception. - */ -void -pcibr_init(void) +static int +pcibr_mmap(struct file * file, struct vm_area_struct * vma) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pcibr_init()\n")); - - xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, - XBRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); - xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, - BRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); + vertex_hdl_t pcibr_vhdl = file->f_dentry->d_fsdata; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + unsigned long phys_addr; + int error = 0; + + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED | VM_IO; + error = io_remap_page_range(vma, phys_addr, vma->vm_start, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + return(error); } /* - * open/close mmap/munmap interface would be used by processes - * that plan to map the PCI bridge, and muck around with the - * registers. This is dangerous to do, and will be allowed - * to a select brand of programs. Typically these are - * diagnostics programs, or some user level commands we may - * write to do some weird things. - * To start with expect them to have root priveleges. - * We will ask for more later. + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. */ -/* ARGSUSED */ -int -pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - int error; - devfs_handle_t vhdl = dev_to_vhdl(dev); - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - ASSERT(pcibr_soft); - len = ctob(btoc(len)); /* Make len page aligned */ - error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); - - /* - * If the offset being mapped corresponds to the flash prom - * base, and if the mapping succeeds, and if the user - * has requested the protections to be WRITE, enable the - * flash prom to be written. - * - * XXX- deprecate this in favor of using the - * real flash driver ... - */ - if (IS_BRIDGE_SOFT(pcibr_soft) && !error && - ((off == BRIDGE_EXTERNAL_FLASH) || - (len > BRIDGE_EXTERNAL_FLASH))) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_wid_control)) |= __swab32(BRIDGE_CTRL_FLASH_WR_EN); - BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ - } else { - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - } - splx(s); - } - return error; -} - -/*ARGSUSED */ -int -pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; +static int pcibr_mmap(struct file * file, struct vm_area_struct * vma); +struct file_operations pcibr_fops = { + .owner = THIS_MODULE, + .mmap = pcibr_mmap, +}; - hwgraph_vertex_unref(pcibr_vhdl); - - if ( IS_PIC_SOFT(pcibr_soft) ) { - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (IS_BRIDGE_SOFT(pcibr_soft) && - (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN)) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - if (BRIDGE_REG_GET32((&bridge->b_wid_control)) & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - BRIDGE_REG_SET32((&bridge->b_wid_control)) &= __swab32((unsigned int)~BRIDGE_CTRL_FLASH_WR_EN); - BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ - splx(s); - } else { - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - } - } - } - return 0; -} /* This is special case code used by grio. There are plans to make * this a bit more general in the future, but till then this should * be sufficient. */ pciio_slot_t -pcibr_device_slot_get(devfs_handle_t dev_vhdl) +pcibr_device_slot_get(vertex_hdl_t dev_vhdl) { char devname[MAXDEVNAME]; - devfs_handle_t tdev; + vertex_hdl_t tdev; pciio_info_t pciio_info; pciio_slot_t slot = PCIIO_SLOT_NONE; @@ -812,20 +652,8 @@ pcibr_device_slot_get(devfs_handle_t dev_vhdl) return slot; } -/*ARGSUSED */ -int -pcibr_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - return 0; -} - pcibr_info_t -pcibr_info_get(devfs_handle_t vhdl) +pcibr_info_get(vertex_hdl_t vhdl) { return (pcibr_info_t) pciio_info_get(vhdl); } @@ -902,10 +730,10 @@ pcibr_device_info_new( * This is usually used at the time of shutting down of the PCI card. */ int -pcibr_device_unregister(devfs_handle_t pconn_vhdl) +pcibr_device_unregister(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; bridge_t *bridge; @@ -982,12 +810,12 @@ pcibr_device_unregister(devfs_handle_t pconn_vhdl) * slot's device status to be set. */ void -pcibr_driver_reg_callback(devfs_handle_t pconn_vhdl, +pcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error) { pciio_info_t pciio_info; pcibr_info_t pcibr_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; @@ -1033,12 +861,12 @@ pcibr_driver_reg_callback(devfs_handle_t pconn_vhdl, * slot's device status to be set. */ void -pcibr_driver_unreg_callback(devfs_handle_t pconn_vhdl, +pcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error) { pciio_info_t pciio_info; pcibr_info_t pcibr_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; @@ -1084,14 +912,14 @@ pcibr_driver_unreg_callback(devfs_handle_t pconn_vhdl, * depends on hwgraph separator == '/' */ int -pcibr_bus_cnvlink(devfs_handle_t f_c) +pcibr_bus_cnvlink(vertex_hdl_t f_c) { char dst[MAXDEVNAME]; char *dp = dst; char *cp, *xp; int widgetnum; char pcibus[8]; - devfs_handle_t nvtx, svtx; + vertex_hdl_t nvtx, svtx; int rv; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n")); @@ -1145,11 +973,11 @@ pcibr_bus_cnvlink(devfs_handle_t f_c) */ /*ARGSUSED */ int -pcibr_attach(devfs_handle_t xconn_vhdl) +pcibr_attach(vertex_hdl_t xconn_vhdl) { /* REFERENCED */ graph_error_t rc; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; bridge_t *bridge; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n")); @@ -1180,11 +1008,11 @@ pcibr_attach(devfs_handle_t xconn_vhdl) /*ARGSUSED */ int -pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, - devfs_handle_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) +pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, + vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) { /* REFERENCED */ - devfs_handle_t ctlr_vhdl; + vertex_hdl_t ctlr_vhdl; bridgereg_t id; int rev; pcibr_soft_t pcibr_soft; @@ -1193,7 +1021,7 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, xtalk_intr_t xtalk_intr; int slot; int ibit; - devfs_handle_t noslot_conn; + vertex_hdl_t noslot_conn; char devnm[MAXDEVNAME], *s; pcibr_hints_t pcibr_hints; uint64_t int_enable; @@ -1209,23 +1037,15 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, nasid_t nasid; int iobrick_type_get_nasid(nasid_t nasid); int iobrick_module_get_nasid(nasid_t nasid); - extern unsigned char Is_pic_on_this_nasid[512]; - - - async_attach_t aa = NULL; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum)); - aa = async_attach_get_info(xconn_vhdl); - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, + 0, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + (struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl); ASSERT(ctlr_vhdl != NULL); /* @@ -1261,13 +1081,7 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, pcibr_soft->bs_min_slot = 0; /* lowest possible slot# */ pcibr_soft->bs_max_slot = 7; /* highest possible slot# */ pcibr_soft->bs_busnum = busnum; - if (is_xbridge(bridge)) { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_XBRIDGE; - } else if (is_pic(bridge)) { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; - } else { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_BRIDGE; - } + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; switch(pcibr_soft->bs_bridge_type) { case PCIBR_BRIDGETYPE_BRIDGE: pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; @@ -1367,10 +1181,6 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, nasid = NASID_GET(bridge); - /* set whether it is a PIC or not */ - Is_pic_on_this_nasid[nasid] = (IS_PIC_SOFT(pcibr_soft)) ? 1 : 0; - - if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0) printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl, (unsigned int)pcibr_soft->bs_bricktype); @@ -1380,11 +1190,27 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, if (pcibr_soft->bs_bricktype > 0) { switch (pcibr_soft->bs_bricktype) { case MODULE_PXBRICK: + case MODULE_IXBRICK: pcibr_soft->bs_first_slot = 0; pcibr_soft->bs_last_slot = 1; pcibr_soft->bs_last_reset = 1; + + /* If Bus 1 has IO9 then there are 4 devices in that bus. Note + * we figure this out from klconfig since the kernel has yet to + * probe + */ + if (pcibr_widget_to_bus(pcibr_vhdl) == 1) { + lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); + + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + pcibr_soft->bs_last_slot = 3; + pcibr_soft->bs_last_reset = 3; + } + brd = KLCF_NEXT(brd); + } + } break; - case MODULE_PEBRICK: case MODULE_PBRICK: pcibr_soft->bs_first_slot = 1; pcibr_soft->bs_last_slot = 2; @@ -1527,7 +1353,7 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, /* enable parity checking on PICs internal RAM */ pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; - /* PIC BRINGUP WAR (PV# 862253): don't enable write request + /* PIC BRINGUP WAR (PV# 862253): dont enable write request * parity checking. */ if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { @@ -1559,11 +1385,6 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, int entry; cnodeid_t cnodeid; nasid_t nasid; -#ifdef PIC_LATER - char *node_val; - devfs_handle_t node_vhdl; - char vname[MAXDEVNAME]; -#endif /* Set the Bridge's 32-bit PCI to XTalk * Direct Map register to the most useful @@ -1582,30 +1403,6 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, */ cnodeid = 0; /* default node id */ - /* - * Determine the base address node id to be used for all 32-bit - * Direct Mapping I/O. The default is node 0, but this can be changed - * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE - * attribute in the irix.sm config file. A device driver can obtain - * this node value via a call to pcibr_get_dmatrans_node(). - */ -#ifdef PIC_LATER -// This probably needs to be addressed - pfg - node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE); - if (node_val != NULL) { - node_vhdl = hwgraph_path_to_vertex(node_val); - if (node_vhdl != GRAPH_VERTEX_NONE) { - cnodeid = nodevertex_to_cnodeid(node_vhdl); - } - if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) { - cnodeid = 0; - vertex_to_name(pcibr_vhdl, vname, sizeof(vname)); - printk(KERN_WARNING "Invalid hwgraph node path specified:\n" - " DEVICE_ADMIN: %s %s=%s\n", - vname, ADMIN_LBL_DMATRANS_NODE, node_val); - } - } -#endif /* PIC_LATER */ nasid = COMPACT_TO_NASID_NODEID(cnodeid); paddr = NODE_OFFSET(nasid) + 0; @@ -1763,6 +1560,13 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, */ xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); + { + int irq = ((hub_intr_t)xtalk_intr)->i_bit; + int cpu = ((hub_intr_t)xtalk_intr)->i_cpuid; + + intr_unreserve_level(cpu, irq); + ((hub_intr_t)xtalk_intr)->i_bit = SGI_PCIBR_ERROR; + } ASSERT(xtalk_intr != NULL); pcibr_soft->bsi_err_intr = xtalk_intr; @@ -1778,12 +1582,8 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, (intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); -#ifdef BUS_INT_WAR_NOT_YET - request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, - ((hub_intr_t)xtalk_intr)->i_bit), - (intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error", + request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler, SA_SHIRQ, "PCIBR error", (intr_arg_t) pcibr_soft); -#endif PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, "pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n", @@ -1801,18 +1601,16 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, if (IS_PIC_SOFT(pcibr_soft)) { int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS; int_enable = (uint64_t)int_enable_64; +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff7ffffeff; +#endif } else { int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff); int_enable = ((uint64_t)int_enable_32 & 0xffffffff); - } -#ifdef BUS_INT_WAR_NOT_YET - { - extern void sn_add_polled_interrupt(int irq, int interval); - - sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, - ((hub_intr_t)xtalk_intr)->i_bit), 20000); - } +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff; #endif + } #if BRIDGE_ERROR_INTR_WAR @@ -1849,24 +1647,6 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, } #endif -#ifdef BRIDGE_B_DATACORR_WAR - - /* WAR panic for Rev B silent data corruption. - * PIOERR turned off here because there is a problem - * with not re-arming it in pcibr_error_intr_handler. - * We don't get LLP error interrupts if we don't - * re-arm PIOERR interrupts! Just disable them here - */ - - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) { - int_enable |= BRIDGE_IMR_LLP_REC_CBERR; - int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "Turning on LLP_REC_CBERR for Rev B Bridge.\n")); - } -#endif - /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are * locked out to be freed up sooner (by timing out) so that the * read tnums are never completely used up. @@ -1918,16 +1698,12 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) + (BRIDGE_WIDGET_PART_NUM << 4)) pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - /* WRITE_GATHER: - * Disabled up to but not including the - * rev number in pcibr_wg_enable_rev. There - * is no "WAR range" as with prefetch. - */ + /* WRITE_GATHER: Disabled */ if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) + (BRIDGE_WIDGET_PART_NUM << 4)) pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; /* PIC only supports 64-bit direct mapping in PCI-X mode. Since @@ -2064,7 +1840,23 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, */ if (pcibr_soft->bs_bricktype > 0) { switch (pcibr_soft->bs_bricktype) { + case MODULE_PBRICK: + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); + break; + case MODULE_IBRICK: + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); + } + break; case MODULE_PXBRICK: + case MODULE_IXBRICK: /* * If the IO9 is in the PXBrick (bus1, slot1) allocate * RRBs to all the devices @@ -2080,23 +1872,6 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8); do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); } - - break; - case MODULE_PEBRICK: - case MODULE_PBRICK: - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - break; - case MODULE_IBRICK: - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); - } break; } /* switch */ } @@ -2113,78 +1888,8 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, /* Call the device attach */ (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); -#ifdef PIC_LATER -#if (defined(USS302_TIMEOUT_WAR)) - /* - * If this bridge holds a Lucent USS-302 or USS-312 pci/usb controller, - * increase the Bridge PCI retry backoff interval. This part seems - * to go away for long periods of time if a DAC appears on the bus during - * a read command that is being retried. - */ - -{ - ii_ixtt_u_t ixtt; - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - if (pcibr_soft->bs_slot[slot].bss_vendor_id == - LUCENT_USBHC_VENDOR_ID_NUM && - (pcibr_soft->bs_slot[slot].bss_device_id == - LUCENT_USBHC302_DEVICE_ID_NUM || - pcibr_soft->bs_slot[slot].bss_device_id == - LUCENT_USBHC312_DEVICE_ID_NUM)) { - printk(KERN_NOTICE - "pcibr_attach: %x Bus holds a usb part - setting" - "bridge PCI_RETRY_HLD to %d\n", - pcibr_vhdl, USS302_BRIDGE_TIMEOUT_HLD); - - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_HLD_MASK; - bridge->b_bus_timeout |= - BRIDGE_BUS_PCI_RETRY_HLD(USS302_BRIDGE_TIMEOUT_HLD); - - /* - * Have to consider the read response timer in the hub II as well - */ - - hubii_ixtt_get(xconn_vhdl, &ixtt); - - /* - * bump rrsp_ps to allow at least 1ms for read - * responses from this widget - */ - - ixtt.ii_ixtt_fld_s.i_rrsp_ps = 20000; - hubii_ixtt_set(xconn_vhdl, &ixtt); - - /* - * print the current setting - */ - - hubii_ixtt_get(xconn_vhdl, &ixtt); - printk( "Setting hub ixtt.rrsp_ps field to 0x%x\n", - ixtt.ii_ixtt_fld_s.i_rrsp_ps); - - break; /* only need to do it once */ - } - } -} -#endif /* (defined(USS302_TIMEOUT_WAR)) */ -#else - FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif /* PIC_LATER */ - - if (aa) - async_attach_add_info(noslot_conn, aa); - pciio_device_attach(noslot_conn, (int)0); - /* - * Tear down pointer to async attach info -- async threads for - * bridge's descendants may be running but the bridge's work is done. - */ - if (aa) - async_attach_del_info(xconn_vhdl); - return 0; } @@ -2195,10 +1900,10 @@ pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, */ int -pcibr_detach(devfs_handle_t xconn) +pcibr_detach(vertex_hdl_t xconn) { pciio_slot_t slot; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pcibr_soft_t pcibr_soft; bridge_t *bridge; unsigned s; @@ -2265,9 +1970,9 @@ pcibr_detach(devfs_handle_t xconn) } int -pcibr_asic_rev(devfs_handle_t pconn_vhdl) +pcibr_asic_rev(vertex_hdl_t pconn_vhdl) { - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; int tmp_vhdl; arbitrary_info_t ainfo; @@ -2294,7 +1999,7 @@ pcibr_asic_rev(devfs_handle_t pconn_vhdl) } int -pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) +pcibr_write_gather_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); @@ -2309,7 +2014,7 @@ pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) */ static iopaddr_t -pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, +pcibr_addr_pci_to_xio(vertex_hdl_t pconn_vhdl, pciio_slot_t slot, pciio_space_t space, iopaddr_t pci_addr, @@ -2323,6 +2028,8 @@ pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; + iopaddr_t base; /* base of devio(x) mapped area on PCI */ + iopaddr_t limit; /* base of devio(x) mapped area on PCI */ pciio_space_t wspace; /* which space device is decoding */ iopaddr_t wbase; /* base of device decode on PCI */ @@ -2533,8 +2240,6 @@ pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, "pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg, device_bits)); -#else - printk("pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg); #endif } pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; @@ -2620,18 +2325,46 @@ pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, */ case PCIIO_SPACE_MEM: /* "mem space" */ case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM32_BASE; + limit = PICBRIDGE0_PCI_MEM32_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM32_BASE; + limit = PICBRIDGE1_PCI_MEM32_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM32_BASE; + limit = BRIDGE_PCI_MEM32_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM64_BASE; + limit = PICBRIDGE0_PCI_MEM64_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM64_BASE; + limit = PICBRIDGE1_PCI_MEM64_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM64_BASE; + limit = BRIDGE_PCI_MEM64_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_IO: /* "i/o space" */ + /* + * PIC bridges do not support big-window aliases into PCI I/O space + */ + if (IS_PIC_SOFT(pcibr_soft)) { + xio_addr = XIO_NOWHERE; + break; + } + /* Bridge Hardware Bug WAR #482741: * The 4G area that maps directly from * XIO space to PCI I/O space is busted @@ -2725,7 +2458,7 @@ pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, /*ARGSUSED6 */ pcibr_piomap_t -pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, +pcibr_piomap_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -2737,7 +2470,7 @@ pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, pciio_info_t pciio_info = &pcibr_info->f_c; pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pcibr_piomap_t *mapptr; pcibr_piomap_t maplist; @@ -2867,7 +2600,7 @@ pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) /*ARGSUSED */ caddr_t -pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, +pcibr_piotrans_addr(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -2877,7 +2610,7 @@ pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; iopaddr_t xio_addr; caddr_t addr; @@ -2908,7 +2641,7 @@ pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, /*ARGSUSED */ iopaddr_t -pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, +pcibr_piospace_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, size_t req_size, @@ -3010,7 +2743,7 @@ pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, /*ARGSUSED */ void -pcibr_piospace_free(devfs_handle_t pconn_vhdl, +pcibr_piospace_free(vertex_hdl_t pconn_vhdl, pciio_space_t space, iopaddr_t pciaddr, size_t req_size) @@ -3161,14 +2894,14 @@ pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) /*ARGSUSED */ pcibr_dmamap_t -pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, +pcibr_dmamap_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, size_t req_size_max, unsigned flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pciio_slot_t slot; xwidgetnum_t xio_port; @@ -3454,6 +3187,29 @@ pcibr_addr_xio_to_pci(pcibr_soft_t soft, iopaddr_t pci_addr; pciio_slot_t slot; + if (IS_PIC_BUSNUM_SOFT(soft, 0)) { + if ((xio_addr >= PICBRIDGE0_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE0_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM64_BASE; + return pci_addr; + } + } else if (IS_PIC_BUSNUM_SOFT(soft, 1)) { + if ((xio_addr >= PICBRIDGE1_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE1_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM64_BASE; + return pci_addr; + } + } else { if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; @@ -3464,6 +3220,7 @@ pcibr_addr_xio_to_pci(pcibr_soft_t soft, pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; return pci_addr; } + } for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot) if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) && (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) { @@ -3644,243 +3401,6 @@ pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, } /*ARGSUSED */ -alenlist_t -pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, - alenlist_t palenlist, - unsigned flags) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge=NULL; - - unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - int inplace = flags & PCIIO_INPLACE; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist; - size_t length; - iopaddr_t offset; - unsigned direct64; - int ate_index = 0; - int ate_count = 0; - int ate_total = 0; - bridge_ate_p ate_ptr = (bridge_ate_p)0; - bridge_ate_t ate_proto = (bridge_ate_t)0; - bridge_ate_t ate_prev; - bridge_ate_t ate; - alenaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - alenaddr_t new_addr; - unsigned cmd_regs[8]; - unsigned s = 0; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; -#endif - int ate_freeze_done = 0; /* To pair ATE_THAW - * with an ATE_FREEZE - */ - - pcibr_soft = pcibr_dmamap->bd_soft; - - xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: xtalk_dmamap_list() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_create() failed, " - "pcibr_dmamap=0x%lx\n", (unsigned long)pcibr_dmamap)); - goto fail; - } - } - - direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; - if (!direct64) { - bridge = pcibr_soft->bs_base; - ate_ptr = pcibr_dmamap->bd_ate_ptr; - ate_index = pcibr_dmamap->bd_ate_index; - ate_proto = pcibr_dmamap->bd_ate_proto; - ATE_FREEZE(); - ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ - } - pci_addr = pcibr_dmamap->bd_pci_addr; - - ate_prev = 0; /* matches no valid ATEs */ - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &length, al_flags)) { - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - if (xio_port == pcibr_soft->bs_xid) { - new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: pcibr_addr_xio_to_pci failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - } else if (direct64) { - new_addr = pci_addr | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - new_addr &= ~PCI64_ATTR_PREF; - - } else { - /* calculate the ate value for - * the first address. If it - * matches the previous - * ATE written (ie. we had - * multiple blocks in the - * same IOPG), then back up - * and reuse that ATE. - * - * We are NOT going to - * aggressively try to - * reuse any other ATEs. - */ - offset = IOPGOFF(xio_addr); - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - if (ate == ate_prev) { - PCIBR_DEBUG((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: ATE share\n")); - ate_ptr--; - ate_index--; - pci_addr -= IOPGSIZE; - } - new_addr = pci_addr + offset; - - /* Fill in the hardware ATEs - * that contain this block. - */ - ate_count = IOPG(offset + length - 1) + 1; - ate_total += ate_count; - - /* Ensure that this map contains enough ATE's */ - if (ate_total > pcibr_dmamap->bd_ate_count) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count)); - goto fail; - } - - ATE_WRITE(); - - ate_index += ate_count; - ate_ptr += ate_count; - - ate_count <<= IOPFNSHIFT; - ate += ate_count; - pci_addr += ate_count; - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_replace() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - - goto fail; - } - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_append() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - - /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the - * changes that ATE_FREEZE has done to implement the external SSRAM - * bug workaround. - */ - if (ate_freeze_done) { - ATE_THAW(); - if ( IS_PIC_SOFT(pcibr_soft) ) { - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); - } else { - bridge->b_wid_tflush; - } - } - } - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: pcibr_dmamap=0x%x, pciio_alenlist=0x%x\n", - pcibr_dmamap, pciio_alenlist)); - - return pciio_alenlist; - - fail: - /* There are various points of failure after doing an ATE_FREEZE - * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. - * The decision to do an ATE_THAW needs to be based on whether a - * an ATE_FREEZE was done before. - */ - if (ate_freeze_done) { - ATE_THAW(); - if ( IS_PIC_SOFT(pcibr_soft) ) { - bridge->b_wid_tflush; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); - } else { - bridge->b_wid_tflush; - } - } - } - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -/*ARGSUSED */ void pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) { @@ -3917,7 +3437,7 @@ pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) /*ARGSUSED */ cnodeid_t -pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) +pcibr_get_dmatrans_node(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -3928,7 +3448,7 @@ pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) /*ARGSUSED */ iopaddr_t -pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, +pcibr_dmatrans_addr(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, paddr_t paddr, size_t req_size, @@ -3936,7 +3456,7 @@ pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; @@ -4149,213 +3669,6 @@ pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, return 0; } -/*ARGSUSED */ -alenlist_t -pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - alenlist_t palenlist, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - xwidgetnum_t xio_port; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist = 0; - - int inplace; - unsigned direct64; - unsigned al_flags; - - iopaddr_t xio_base; - alenaddr_t xio_addr; - size_t xio_size; - - size_t map_size; - iopaddr_t pci_base; - alenaddr_t pci_addr; - - unsigned relbits = 0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - inplace = flags & PCIIO_INPLACE; - direct64 = flags & PCIIO_DMA_A64; - al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - - if (direct64) { - map_size = 1ull << 48; - xio_base = 0; - pci_base = slotp->bss_d64_base; - if ((pci_base != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { - /* DMA configuration conflict */ - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: DMA configuration conflict " - "for direct64, flags=0x%x\n", flags)); - goto fail; - } else { - relbits = BRIDGE_DEV_D64_BITS; - pci_base = - pcibr_flags_to_d64(flags, pcibr_soft); - } - } else { - xio_base = pcibr_soft->bs_dir_xbase; - map_size = 1ull << 31; - pci_base = slotp->bss_d32_base; - if ((pci_base != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { - /* DMA configuration conflict */ - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: DMA configuration conflict " - "for direct32, flags=0x%x\n", flags)); - goto fail; - } else { - relbits = BRIDGE_DEV_D32_BITS; - pci_base = PCI32_DIRECT_BASE; - } - } - - xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xtalk_dmatrans_list failed " - "xtalk_alenlist=0x%x\n", xtalk_alenlist)); - goto fail; - } - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_create failed with " - " 0x%x\n", pciio_alenlist)); - goto fail; - } - } - - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &xio_size, al_flags)) { - - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xio_addr == XIO_NOWHERE\n")); - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if (pci_addr == (alenaddr_t)NULL) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: pcibr_addr_xio_to_pci failed " - "xio_addr=0x%x, xio_size=0x%x\n", xio_addr, xio_size)); - goto fail; - } - } else if (direct64) { - ASSERT(xio_port != 0); - pci_addr = pci_base | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - } else { - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = xio_size + offset; - - if ((xio_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xio_size > map_size fail\n" - "xio_addr=0x%x, xio_size=0x%x. map_size=0x%x, " - "xio_port=0x%x, endoff=0x%x\n", - xio_addr, xio_size, map_size, xio_port, endoff)); - goto fail; - } - - pci_addr = pci_base + (xio_addr - xio_base); - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_replace failed\n")); - goto fail; - } - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_append failed\n")); - goto fail; - } - } - } - - if (relbits) { - if (direct64) { - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_base; - } else { - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_base; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: pciio_alenlist=0x%x\n", - pciio_alenlist)); - - return pciio_alenlist; - - fail: - if (relbits) - pcibr_release_device(pcibr_soft, pciio_slot, relbits); - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - void pcibr_dmamap_drain(pcibr_dmamap_t map) { @@ -4363,24 +3676,24 @@ pcibr_dmamap_drain(pcibr_dmamap_t map) } void -pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, +pcibr_dmaaddr_drain(vertex_hdl_t pconn_vhdl, paddr_t paddr, size_t bytes) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); } void -pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, +pcibr_dmalist_drain(vertex_hdl_t pconn_vhdl, alenlist_t list) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; xtalk_dmalist_drain(xconn_vhdl, list); } @@ -4402,18 +3715,18 @@ pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) */ /*ARGSUSED */ void -pcibr_provider_startup(devfs_handle_t pcibr) +pcibr_provider_startup(vertex_hdl_t pcibr) { } /*ARGSUSED */ void -pcibr_provider_shutdown(devfs_handle_t pcibr) +pcibr_provider_shutdown(vertex_hdl_t pcibr) { } int -pcibr_reset(devfs_handle_t conn) +pcibr_reset(vertex_hdl_t conn) { #ifdef PIC_LATER pciio_info_t pciio_info = pciio_info_get(conn); @@ -4484,7 +3797,7 @@ pcibr_reset(devfs_handle_t conn) } pciio_endian_t -pcibr_endian_set(devfs_handle_t pconn_vhdl, +pcibr_endian_set(vertex_hdl_t pconn_vhdl, pciio_endian_t device_end, pciio_endian_t desired_end) { @@ -4629,7 +3942,7 @@ pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, } pciio_priority_t -pcibr_priority_set(devfs_handle_t pconn_vhdl, +pcibr_priority_set(vertex_hdl_t pconn_vhdl, pciio_priority_t device_prio) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -4653,7 +3966,7 @@ pcibr_priority_set(devfs_handle_t pconn_vhdl, * Returns 0 on failure, 1 on success */ int -pcibr_device_flags_set(devfs_handle_t pconn_vhdl, +pcibr_device_flags_set(vertex_hdl_t pconn_vhdl, pcibr_device_flags_t flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -4792,10 +4105,8 @@ pciio_provider_t pcibr_provider = (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, (pciio_dmamap_free_f *) pcibr_dmamap_free, (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, (pciio_dmamap_done_f *) pcibr_dmamap_done, (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, (pciio_dmamap_drain_f *) pcibr_dmamap_drain, (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, (pciio_dmalist_drain_f *) pcibr_dmalist_drain, @@ -4814,23 +4125,16 @@ pciio_provider_t pcibr_provider = (pciio_priority_set_f *) pcibr_priority_set, (pciio_config_get_f *) pcibr_config_get, (pciio_config_set_f *) pcibr_config_set, -#ifdef PIC_LATER - (pciio_error_devenable_f *) pcibr_error_devenable, - (pciio_error_extract_f *) pcibr_error_extract, - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, -#else (pciio_error_devenable_f *) 0, (pciio_error_extract_f *) 0, (pciio_driver_reg_callback_f *) 0, (pciio_driver_unreg_callback_f *) 0, -#endif /* PIC_LATER */ (pciio_device_unregister_f *) pcibr_device_unregister, (pciio_dma_enabled_f *) pcibr_dma_enabled, }; int -pcibr_dma_enabled(devfs_handle_t pconn_vhdl) +pcibr_dma_enabled(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); @@ -4857,7 +4161,7 @@ pcibr_dma_enabled(devfs_handle_t pconn_vhdl) * parameter 'format' is sent to the console. */ void -pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) +pcibr_debug(uint32_t type, vertex_hdl_t vhdl, char *format, ...) { char hwpath[MAXDEVNAME] = "\0"; char copy_of_hwpath[MAXDEVNAME]; @@ -4865,7 +4169,6 @@ pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) short widget = -1; short slot = -1; va_list ap; - char *strtok_r(char *string, const char *sepset, char **lasts); if (pcibr_debug_mask & type) { if (vhdl) { @@ -4873,13 +4176,12 @@ pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) char *cp; if (strcmp(module, pcibr_debug_module)) { - /* strtok_r() wipes out string, use a copy */ + /* use a copy */ (void)strcpy(copy_of_hwpath, hwpath); cp = strstr(copy_of_hwpath, "/module/"); if (cp) { - char *last = NULL; cp += strlen("/module"); - module = strtok_r(cp, "/", &last); + module = strsep(&cp, "/"); } } if (pcibr_debug_widget != -1) { @@ -4918,3 +4220,26 @@ pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) } } } + +int +isIO9(nasid_t nasid) { + lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); + + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + return 1; + } + brd = KLCF_NEXT(brd); + } + /* if it's dual ported, check the peer also */ + nasid = NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer; + if (nasid < 0) return 0; + brd = (lboard_t *)KL_CONFIG_INFO(nasid); + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + return 1; + } + brd = KLCF_NEXT(brd); + } + return 0; +} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c index 4295a33e916..91ee03e14b3 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,26 +27,11 @@ #include #include #include -#include #include #include -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - extern int hubii_check_widget_disabled(nasid_t, int); -#ifdef BRIDGE_B_DATACORR_WAR -extern int ql_bridge_rev_b_war(devfs_handle_t); -extern int bridge_rev_b_data_check_disable; -char *rev_b_datacorr_warning = -"***************************** WARNING! ******************************\n"; -char *rev_b_datacorr_mesg = -"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n"; -#endif + /* ===================================================================== * ERROR HANDLING @@ -76,13 +61,9 @@ uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL | BRIDGE_ISR_PCIBUS_PIOERR; #endif -#if defined (PCIBR_LLP_CONTROL_WAR) -int pcibr_llp_control_war_cnt; -#endif /* PCIBR_LLP_CONTROL_WAR */ +int pcibr_llp_control_war_cnt; /* PCIBR_LLP_CONTROL_WAR */ -/* FIXME: can these arrays be local ? */ - -struct reg_values xio_cmd_pactyp[] = +static struct reg_values xio_cmd_pactyp[] = { {0x0, "RdReq"}, {0x1, "RdResp"}, @@ -103,7 +84,7 @@ struct reg_values xio_cmd_pactyp[] = {0} }; -struct reg_desc xio_cmd_bits[] = +static struct reg_desc xio_cmd_bits[] = { {WIDGET_DIDN, -28, "DIDN", "%x"}, {WIDGET_SIDN, -24, "SIDN", "%x"}, @@ -120,58 +101,7 @@ struct reg_desc xio_cmd_bits[] = #define F(s,n) { 1l<<(s),-(s), n } -struct reg_desc bridge_int_status_desc[] = -{ - F(45, "PCI_X_SPLIT_MES_PE"),/* PIC ONLY */ - F(44, "PCI_X_SPLIT_EMES"), /* PIC ONLY */ - F(43, "PCI_X_SPLIT_TO"), /* PIC ONLY */ - F(42, "PCI_X_UNEX_COMP"), /* PIC ONLY */ - F(41, "INT_RAM_PERR"), /* PIC ONLY */ - F(40, "PCI_X_ARB_ERR"), /* PIC ONLY */ - F(39, "PCI_X_REQ_TOUT"), /* PIC ONLY */ - F(38, "PCI_X_TABORT"), /* PIC ONLY */ - F(37, "PCI_X_PERR"), /* PIC ONLY */ - F(36, "PCI_X_SERR"), /* PIC ONLY */ - F(35, "PCI_X_MRETRY"), /* PIC ONLY */ - F(34, "PCI_X_MTOUT"), /* PIC ONLY */ - F(33, "PCI_X_DA_PARITY"), /* PIC ONLY */ - F(32, "PCI_X_AD_PARITY"), /* PIC ONLY */ - F(31, "MULTI_ERR"), /* BRIDGE ONLY */ - F(30, "PMU_ESIZE_EFAULT"), - F(29, "UNEXPECTED_RESP"), - F(28, "BAD_XRESP_PACKET"), - F(27, "BAD_XREQ_PACKET"), - F(26, "RESP_XTALK_ERROR"), - F(25, "REQ_XTALK_ERROR"), - F(24, "INVALID_ADDRESS"), - F(23, "UNSUPPORTED_XOP"), - F(22, "XREQ_FIFO_OFLOW"), - F(21, "LLP_REC_SNERROR"), - F(20, "LLP_REC_CBERROR"), - F(19, "LLP_RCTY"), - F(18, "LLP_TX_RETRY"), - F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), /* BRIDGE ONLY */ - F(15, "PCI_ABORT"), - F(14, "PCI_PARITY"), - F(13, "PCI_SERR"), - F(12, "PCI_PERR"), - F(11, "PCI_MASTER_TOUT"), - F(10, "PCI_RETRY_CNT"), - F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), /* BRIDGE ONLY */ - F(7, "INT7"), - F(6, "INT6"), - F(5, "INT5"), - F(4, "INT4"), - F(3, "INT3"), - F(2, "INT2"), - F(1, "INT1"), - F(0, "INT0"), - {0} -}; - -struct reg_values space_v[] = +static struct reg_values space_v[] = { {PCIIO_SPACE_NONE, "none"}, {PCIIO_SPACE_ROM, "ROM"}, @@ -189,13 +119,13 @@ struct reg_values space_v[] = {PCIIO_SPACE_BAD, "BAD"}, {0} }; -struct reg_desc space_desc[] = +static struct reg_desc space_desc[] = { {0xFF, 0, "space", 0, space_v}, {0} }; #define device_desc device_bits -struct reg_desc device_bits[] = +static struct reg_desc device_bits[] = { {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, @@ -218,14 +148,14 @@ struct reg_desc device_bits[] = {0} }; -void +static void print_bridge_errcmd(uint32_t cmdword, char *errtype) { printk("\t Bridge %s Error Command Word Register ", errtype); print_register(cmdword, xio_cmd_bits); } -char *pcibr_isr_errs[] = +static char *pcibr_isr_errs[] = { "", "", "", "", "", "", "", "", "08: GIO non-contiguous byte enable in crosstalk packet", /* BRIDGE ONLY */ @@ -279,7 +209,7 @@ char *pcibr_isr_errs[] = /* * display memory directory state */ -void +static void pcibr_show_dir_state(paddr_t paddr, char *prefix) { #ifdef LATER @@ -428,7 +358,6 @@ pcibr_error_dump(pcibr_soft_t pcibr_soft) break; case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ -/* case BRIDGE_ISR_PMU_ESIZE_FAULT: bit30 PMU_ESIZE_FAULT */ if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) reg_desc = "Map Fault Address"; else @@ -592,31 +521,9 @@ pcibr_error_dump(pcibr_soft_t pcibr_soft) printk( "\t%s\n", pcibr_isr_errs[i]); } } - -#if BRIDGE_ERROR_INTR_WAR - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { /* known bridge bug */ - /* - * Should never receive interrupts for these reasons on Rev 1 bridge - * as they are not enabled. Assert for it. - */ - ASSERT((int_status & (BRIDGE_IMR_PCI_MST_TIMEOUT | - BRIDGE_ISR_RESP_XTLK_ERR | - BRIDGE_ISR_LLP_TX_RETRY)) == 0); - } - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { /* known bridge bug */ - /* - * This interrupt is turned off at init time. So, should never - * see this interrupt. - */ - ASSERT((int_status & BRIDGE_ISR_BAD_XRESP_PKT) == 0); - } -#endif } -#define PCIBR_ERRINTR_GROUP(error) \ - (( error & (BRIDGE_IRR_PCI_GRP|BRIDGE_IRR_GIO_GRP) - -uint32_t +static uint32_t pcibr_errintr_group(uint32_t error) { uint32_t group = BRIDGE_IRR_MULTI_CLR; @@ -741,15 +648,7 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) picreg_t int_status_64; int number_bits; int i; - - /* REFERENCED */ uint64_t disable_errintr_mask = 0; -#ifdef EHE_ENABLE - int rv; - int error_code = IOECODE_DMA | IOECODE_READ; - ioerror_mode_t mode = MODE_DEVERROR; - ioerror_t ioe; -#endif /* EHE_ENABLE */ nasid_t nasid; @@ -806,10 +705,6 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) pcibr_soft->bs_errinfo.bserr_toutcnt++; /* Let's go recursive */ return(pcibr_error_intr_handler(irq, arg, ep)); -#ifdef LATER - timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT); -#endif - return; } /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a @@ -847,24 +742,6 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) pcibr_pioerr_check(pcibr_soft); } -#ifdef BRIDGE_B_DATACORR_WAR - if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) && - (err_status & BRIDGE_IMR_LLP_REC_CBERR)) { - if (bridge_rev_b_data_check_disable) - printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning, - pcibr_soft->bs_name, rev_b_datacorr_mesg, - rev_b_datacorr_warning); - else { - ql_bridge_rev_b_war(pcibr_soft->bs_vhdl); - PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning, - pcibr_soft->bs_name, rev_b_datacorr_mesg, - rev_b_datacorr_warning); - } - - err_status &= ~BRIDGE_IMR_LLP_REC_CBERR; - } -#endif /* BRIDGE_B_DATACORR_WAR */ - if (err_status) { struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; @@ -1024,9 +901,8 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) (0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) { err_status &= ~BRIDGE_ISR_INVLD_ADDR; } -#if defined (PCIBR_LLP_CONTROL_WAR) /* - * The bridge bug, where the llp_config or control registers + * The bridge bug (PCIBR_LLP_CONTROL_WAR), where the llp_config or control registers * need to be read back after being written, affects an MP * system since there could be small windows between writing * the register and reading it back on one cpu while another @@ -1039,40 +915,9 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) if ((err_status & BRIDGE_ISR_INVLD_ADDR) && ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) == (BRIDGE_INT_RST_STAT & 0xff0))) { -#if 0 - if (kdebug) - printk(KERN_NOTICE "%s bridge: ignoring llp/control address interrupt", - pcibr_soft->bs_name); -#endif pcibr_llp_control_war_cnt++; err_status &= ~BRIDGE_ISR_INVLD_ADDR; } -#endif /* PCIBR_LLP_CONTROL_WAR */ - -#ifdef EHE_ENABLE - /* Check if this is the RESP_XTALK_ERROR interrupt. - * This can happen due to a failed DMA READ operation. - */ - if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) { - /* Phase 1 : Look at the error state in the bridge and further - * down in the device layers. - */ - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP); - IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid); - (void)pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - /* Phase 2 : Perform the action agreed upon in phase 1. - */ - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION); - rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - } - if (rv != IOERROR_HANDLED) { -#endif /* EHE_ENABLE */ bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; @@ -1089,25 +934,16 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) */ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) && (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { - printk("BRIDGE ERR_STATUS 0x%x\n", err_status); + printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); pcibr_error_dump(pcibr_soft); -#ifdef LATER - machine_error_dump(""); -#endif PRINT_PANIC("PCI Bridge Error interrupt killed the system"); } if (err_status & BRIDGE_ISR_ERROR_FATAL) { -#ifdef LATER - machine_error_dump(""); -#endif PRINT_PANIC("PCI Bridge Error interrupt killed the system"); /*NOTREACHED */ } -#ifdef EHE_ENABLE - } -#endif /* * We can't return without re-enabling the interrupt, since @@ -1137,136 +973,6 @@ pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) pcibr_soft->bs_errinfo.bserr_intstat = 0; } -/* - * pcibr_addr_toslot - * Given the 'pciaddr' find out which slot this address is - * allocated to, and return the slot number. - * While we have the info handy, construct the - * function number, space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - */ -int -pcibr_addr_toslot(pcibr_soft_t pcibr_soft, - iopaddr_t pciaddr, - pciio_space_t *spacep, - iopaddr_t *offsetp, - pciio_function_t *funcp) -{ - int s, f = 0, w; - iopaddr_t base; - size_t size; - pciio_piospace_t piosp; - - /* - * Check if the address is in config space - */ - - if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { - - if (pciaddr >= BRIDGE_CONFIG1_BASE) - pciaddr -= BRIDGE_CONFIG1_BASE; - else - pciaddr -= BRIDGE_CONFIG_BASE; - - s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; - pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; - - if (funcp) { - f = pciaddr / 0x100; - pciaddr %= 0x100; - } - if (spacep) - *spacep = PCIIO_SPACE_CFG; - if (offsetp) - *offsetp = pciaddr; - if (funcp) - *funcp = f; - - return s; - } - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - for (w = 0; w < 6; w++) { - if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) { - continue; - } - base = pcibr_info->f_window[w].w_base; - size = pcibr_info->f_window[w].w_size; - - if ((pciaddr >= base) && (pciaddr < (base + size))) { - if (spacep) - *spacep = PCIIO_SPACE_WIN(w); - if (offsetp) - *offsetp = pciaddr - base; - if (funcp) - *funcp = f; - return s; - } /* endif match */ - } /* next window */ - } /* next func */ - } /* next slot */ - - /* - * Check if the address was allocated as part of the - * pcibr_piospace_alloc calls. - */ - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - piosp = pcibr_info->f_piospace; - while (piosp) { - if ((piosp->start <= pciaddr) && - ((piosp->count + piosp->start) > pciaddr)) { - if (spacep) - *spacep = piosp->space; - if (offsetp) - *offsetp = pciaddr - piosp->start; - return s; - } /* endif match */ - piosp = piosp->next; - } /* next piosp */ - } /* next func */ - } /* next slot */ - - /* - * Some other random address on the PCI bus ... - * we have no way of knowing whether this was - * a MEM or I/O access; so, for now, we just - * assume that the low 1G is MEM, the next - * 3G is I/O, and anything above the 4G limit - * is obviously MEM. - */ - - if (spacep) - *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : - (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : - PCIIO_SPACE_MEM); - if (offsetp) - *offsetp = pciaddr; - - return PCIIO_SLOT_NONE; - -} - void pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) { @@ -1286,59 +992,6 @@ pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) (void) bridge->b_wid_tflush; /* flushbus */ } -/* - * pcibr_error_extract - * Given the 'pcibr vertex handle' find out which slot - * the bridge status error address (from pcibr_soft info - * hanging off the vertex) - * allocated to, and return the slot number. - * While we have the info handy, construct the - * space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - * - * XXX- this interface has no way to return the function - * number on a multifunction card, even though that data - * is available. - */ - -pciio_slot_t -pcibr_error_extract(devfs_handle_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *offsetp) -{ - pcibr_soft_t pcibr_soft = 0; - iopaddr_t bserr_addr; - bridge_t *bridge; - pciio_slot_t slot = PCIIO_SLOT_NONE; - arbitrary_info_t rev; - - /* Do a sanity check as to whether we really got a - * bridge vertex handle. - */ - if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != - GRAPH_SUCCESS) - return(slot); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) { - bridge = pcibr_soft->bs_base; - bserr_addr = - bridge->b_pci_err_lower | - ((uint64_t) (bridge->b_pci_err_upper & - BRIDGE_ERRUPPR_ADDRMASK) << 32); - - slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, - spacep, offsetp, NULL); - } - return slot; -} - /*ARGSUSED */ void pcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum) @@ -1426,7 +1079,7 @@ pcibr_pioerror( { int retval = IOERROR_HANDLED; - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; bridge_t *bridge = pcibr_soft->bs_base; iopaddr_t bad_xaddr; @@ -1837,7 +1490,7 @@ pcibr_dmard_error( ioerror_mode_t mode, ioerror_t *ioe) { - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t bus_lowaddr, bus_uppraddr; int retval = 0; @@ -1946,7 +1599,7 @@ pcibr_dmawr_error( ioerror_mode_t mode, ioerror_t *ioe) { - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; int retval; retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); @@ -1982,34 +1635,12 @@ pcibr_error_handler( pcibr_soft_t pcibr_soft; int retval = IOERROR_BADERRORCODE; -#ifdef EHE_ENABLE - devfs_handle_t xconn_vhdl,pcibr_vhdl; - error_state_t e_state; -#endif /* EHE_ENABLE */ - pcibr_soft = (pcibr_soft_t) einfo; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, "pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n", pcibr_soft, error_code)); -#ifdef EHE_ENABLE - xconn_vhdl = pcibr_soft->bs_conn; - pcibr_vhdl = pcibr_soft->bs_vhdl; - - e_state = error_state_get(xconn_vhdl); - - if (error_state_set(pcibr_vhdl, e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); - - /* If we are in the action handling phase clean out the error state - * on the xswitch. - */ - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(xconn_vhdl, ERROR_STATE_NONE); -#endif /* EHE_ENABLE */ - #if DEBUG && ERROR_DEBUG printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name); #endif @@ -2086,11 +1717,6 @@ pcibr_error_handler_wrapper( * the error from the PIO address. */ -#if 0 - if (mode == MODE_DEVPROBE) - pio_retval = IOERROR_HANDLED; - else { -#endif if (error_code & IOECODE_PIO) { iopaddr_t bad_xaddr; /* @@ -2123,9 +1749,6 @@ pcibr_error_handler_wrapper( pio_retval = IOERROR_UNHANDLED; } } -#if 0 - } /* MODE_DEVPROBE */ -#endif /* * If the error was a result of a DMA Write, we tell what bus on the PIC @@ -2201,37 +1824,3 @@ pcibr_error_handler_wrapper( return IOERROR_HANDLED; } } - - -/* - * Reenable a device after handling the error. - * This is called by the lower layers when they wish to be reenabled - * after an error. - * Note that each layer would be calling the previous layer to reenable - * first, before going ahead with their own re-enabling. - */ - -int -pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - ASSERT(error_code & IOECODE_PIO); - - /* If the error is not known to be a write, - * we have to call devenable. - * write errors are isolated to the bridge. - */ - if (!(error_code & IOECODE_WRITE)) { - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - int rc; - - rc = xtalk_error_devenable(xconn_vhdl, pciio_slot, error_code); - if (rc != IOERROR_HANDLED) - return rc; - } - pcibr_error_cleanup(pcibr_soft, error_code); - return IOERROR_HANDLED; -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c index 657e2f855d3..3b9344a36f5 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,20 +27,19 @@ #include #include #include -#include #include #include -pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -void pcibr_hints_fix_rrbs(devfs_handle_t); -void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); +void pcibr_hints_fix_rrbs(vertex_hdl_t); +void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); +void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); +void pcibr_hints_handsoff(vertex_hdl_t); +void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); pcibr_hints_t -pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) +pcibr_hints_get(vertex_hdl_t xconn_vhdl, int alloc) { arbitrary_info_t ainfo = 0; graph_error_t rv; @@ -79,7 +78,7 @@ abnormal_exit: } void -pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) +pcibr_hints_fix_some_rrbs(vertex_hdl_t xconn_vhdl, unsigned mask) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -91,13 +90,13 @@ pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) } void -pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) +pcibr_hints_fix_rrbs(vertex_hdl_t xconn_vhdl) { pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); } void -pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, +pcibr_hints_dualslot(vertex_hdl_t xconn_vhdl, pciio_slot_t host, pciio_slot_t guest) { @@ -111,7 +110,7 @@ pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, } void -pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, +pcibr_hints_intr_bits(vertex_hdl_t xconn_vhdl, pcibr_intr_bits_f *xxx_intr_bits) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -124,7 +123,7 @@ pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, } void -pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) +pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -133,7 +132,7 @@ pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_fu } void -pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) +pcibr_hints_handsoff(vertex_hdl_t xconn_vhdl) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -145,13 +144,13 @@ pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) } void -pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, +pcibr_hints_subdevs(vertex_hdl_t xconn_vhdl, pciio_slot_t slot, uint64_t subdevs) { arbitrary_info_t ainfo = 0; char sdname[16]; - devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; + vertex_hdl_t pconn_vhdl = GRAPH_VERTEX_NONE; sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot); (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c deleted file mode 100644 index 93c52e35a7c..00000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef LATER - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); - sprintf(name, "%v", pcibr_info->f_vertex); - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); - sprintf(name, "%v", pcibr_info->f_master); - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} -#endif /* LATER */ diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c index 22b679e9d8a..211aec200f4 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -36,20 +35,32 @@ #define rmfreemap atemapfree #define rmfree atefree #define rmalloc atealloc + +inline int +compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) +{ + FIXME("compare_and_swap_ptr : NOT ATOMIC"); + if (*location == old_ptr) { + *location = new_ptr; + return(1); + } + else + return(0); +} #endif unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); -pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); void pcibr_intr_free(pcibr_intr_t); void pcibr_setpciint(xtalk_intr_t); int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); void pcibr_intr_disconnect(pcibr_intr_t); -devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); void pcibr_intr_func(intr_arg_t); -extern pcibr_info_t pcibr_info_get(devfs_handle_t); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); /* ===================================================================== * INTERRUPT MANAGEMENT @@ -132,6 +143,102 @@ pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) } /* + * On SN systems there is a race condition between a PIO read response + * and DMA's. In rare cases, the read response may beat the DMA, causing + * the driver to think that data in memory is complete and meaningful. + * This code eliminates that race. + * This routine is called by the PIO read routines after doing the read. + * This routine then forces a fake interrupt on another line, which + * is logically associated with the slot that the PIO is addressed to. + * (see sn_dma_flush_init() ) + * It then spins while watching the memory location that the interrupt + * is targetted to. When the interrupt response arrives, we are sure + * that the DMA has landed in memory and it is safe for the driver + * to proceed. + */ + +extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; + +void +sn_dma_flush(unsigned long addr) { + nasid_t nasid; + int wid_num; + volatile struct sn_flush_device_list *p; + int i,j; + int bwin; + unsigned long flags; + + nasid = NASID_GET(addr); + wid_num = SWIN_WIDGETNUM(addr); + bwin = BWIN_WINDOWNUM(addr); + + if (flush_nasid_list[nasid].widget_p == NULL) return; + if (bwin > 0) { + bwin--; + switch (bwin) { + case 0: + wid_num = ((flush_nasid_list[nasid].iio_itte1) >> 8) & 0xf; + break; + case 1: + wid_num = ((flush_nasid_list[nasid].iio_itte2) >> 8) & 0xf; + break; + case 2: + wid_num = ((flush_nasid_list[nasid].iio_itte3) >> 8) & 0xf; + break; + case 3: + wid_num = ((flush_nasid_list[nasid].iio_itte4) >> 8) & 0xf; + break; + case 4: + wid_num = ((flush_nasid_list[nasid].iio_itte5) >> 8) & 0xf; + break; + case 5: + wid_num = ((flush_nasid_list[nasid].iio_itte6) >> 8) & 0xf; + break; + case 6: + wid_num = ((flush_nasid_list[nasid].iio_itte7) >> 8) & 0xf; + break; + } + } + if (flush_nasid_list[nasid].widget_p == NULL) return; + if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) return; + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + + // find a matching BAR + + for (i=0; ibar_list[j].start == 0) break; + if (addr >= p->bar_list[j].start && addr <= p->bar_list[j].end) break; + } + if (j < PCI_ROM_RESOURCE && p->bar_list[j].start != 0) break; + p++; + } + + // if no matching BAR, return without doing anything. + + if (i == DEV_PER_WIDGET) return; + + spin_lock_irqsave(&p->flush_lock, flags); + + p->flush_addr = 0; + + // force an interrupt. + + *(bridgereg_t *)(p->force_int_addr) = 1; + + // wait for the interrupt to come back. + + while (p->flush_addr != 0x10f); + + // okay, everything is synched up. + spin_unlock_irqrestore(&p->flush_lock, flags); + + return; +} + +EXPORT_SYMBOL(sn_dma_flush); + +/* * There are end cases where a deadlock can occur if interrupt * processing completes and the Bridge b_int_status bit is still set. * @@ -164,51 +271,42 @@ pcibr_wrap_put(pcibr_intr_wrap_t wrap, pcibr_intr_cbuf_t cbuf) * to check if a specific Bridge b_int_status bit is set, and if so, * cause the setting of the corresponding interrupt bit. * - * On a XBridge (SN1), we do this by writing the appropriate Bridge Force - * Interrupt register. On SN0, or SN1 with an older Bridge, the Bridge - * Force Interrupt register does not exist, so we write the Hub - * INT_PEND_MOD register directly. Likewise for Octane, where we write the - * Heart Set Interrupt Status register directly. + * On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force + * Interrupt register. */ void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +pcibr_force_interrupt(pcibr_intr_t intr) { -#ifdef PIC_LATER unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; + unsigned bits; + pcibr_soft_t pcibr_soft = intr->bi_soft; bridge_t *bridge = pcibr_soft->bs_base; - bit = wrap->iw_ibit; + bits = intr->bi_ibits; + for (bit = 0; bit < 8; bit++) { + if (bits & (1 << bit)) { - PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, - "pcibr_force_interrupt: bit=0x%x\n", bit)); + PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, + "pcibr_force_interrupt: bit=0x%x\n", bit)); - if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = xtalk_intr_cpuid_get(xtalk_intr); - REMOTE_CPU_SEND_INTR(cpu, intr_bit); + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { + bridge->b_force_pin[bit].intr = 1; + } + } } -#endif /* PIC_LATER */ } /*ARGSUSED */ pcibr_intr_t -pcibr_intr_alloc(devfs_handle_t pconn_vhdl, +pcibr_intr_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_intr_line_t lines, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; bridge_t *bridge = pcibr_soft->bs_base; int is_threaded = 0; @@ -498,25 +596,18 @@ pcibr_setpciint(xtalk_intr_t xtalk_intr) { iopaddr_t addr; xtalk_intr_vector_t vect; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; bridge_t *bridge; + picreg_t *int_addr; addr = xtalk_intr_addr_get(xtalk_intr); vect = xtalk_intr_vector_get(xtalk_intr); vhdl = xtalk_intr_dev_get(xtalk_intr); bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0); - if (is_pic(bridge)) { - picreg_t *int_addr; - int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); - *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | + int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); + *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | (PIC_INT_ADDR_HOST & addr)); - } else { - bridgereg_t *int_addr; - int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr); - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - } } /*ARGSUSED */ @@ -582,8 +673,7 @@ pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t in PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, " "pcibr_int_bit=0x%x\n", int_addr, - (is_pic(bridge) ? - *(picreg_t *)int_addr : *(bridgereg_t *)int_addr), + *(picreg_t *)int_addr, pcibr_int_bit)); } @@ -699,7 +789,7 @@ pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *)pcibr_int_bit); + (void *)(long)pcibr_int_bit); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", pcibr_int_bit)); @@ -707,7 +797,7 @@ pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) } /*ARGSUSED */ -devfs_handle_t +vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) { pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; @@ -780,9 +870,6 @@ pcibr_setwidint(xtalk_intr_t intr) bridge->b_wid_int_lower = NEW_b_wid_int_lower; bridge->b_int_host_err = vect; -printk("pcibr_setwidint: b_wid_int_upper 0x%x b_wid_int_lower 0x%x b_int_host_err 0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, vect); - } /* @@ -957,7 +1044,7 @@ pcibr_intr_func(intr_arg_t arg) * interrupt to avoid a potential deadlock situation. */ if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); + pcibr_force_interrupt((pcibr_intr_t) wrap); } } diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c index 3febeecaa10..bafa7d7d303 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -41,11 +40,11 @@ void do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); -int pcibr_wrb_flush(devfs_handle_t); -int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -void pcibr_rrb_flush(devfs_handle_t); -int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +int pcibr_wrb_flush(vertex_hdl_t); +int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); +int pcibr_rrb_check(vertex_hdl_t, int *, int *, int *, int *); +void pcibr_rrb_flush(vertex_hdl_t); +int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); void pcibr_rrb_debug(char *, pcibr_soft_t); @@ -70,17 +69,15 @@ void pcibr_rrb_debug(char *, pcibr_soft_t); #define RRB_SIZE (4) /* sizeof rrb within reg (bits) */ #define RRB_ENABLE_BIT(bridge) (0x8) /* [BRIDGE | PIC]_RRB_EN */ -#define NUM_PDEV_BITS(bridge) (is_pic((bridge)) ? 1 : 2) -#define NUM_VDEV_BITS(bridge) (is_pic((bridge)) ? 2 : 1) -#define NUMBER_VCHANNELS(bridge) (is_pic((bridge)) ? 4 : 2) +#define NUM_PDEV_BITS(bridge) (1) +#define NUM_VDEV_BITS(bridge) (2) +#define NUMBER_VCHANNELS(bridge) (4) #define SLOT_2_PDEV(bridge, slot) ((slot) >> 1) #define SLOT_2_RRB_REG(bridge, slot) ((slot) & 0x1) /* validate that the slot and virtual channel are valid for a given bridge */ #define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \ - (is_pic((bridge)) ? \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0)) + (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) /* * Count how many RRBs are marked valid for the specified PCI slot @@ -105,16 +102,7 @@ do_pcibr_rrb_count_valid(bridge_t *bridge, pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) @@ -144,16 +132,7 @@ do_pcibr_rrb_count_avail(bridge_t *bridge, enable_bit = RRB_ENABLE_BIT(bridge); - if ( is_pic(bridge) ) { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & enable_bit) != enable_bit) @@ -192,17 +171,8 @@ do_pcibr_rrb_alloc(bridge_t *bridge, pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } - + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) { if ((tmp & enable_bit) != enable_bit) { /* clear the rrb and OR in the new rrb into 'reg' */ @@ -213,16 +183,7 @@ do_pcibr_rrb_alloc(bridge_t *bridge, tmp = (tmp >> RRB_SIZE); } - if ( is_pic(bridge) ) { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; - } else { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - } + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; return (more ? -1 : 0); } @@ -255,17 +216,8 @@ do_pcibr_rrb_free(bridge_t *bridge, pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } - + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) { /* @@ -281,16 +233,7 @@ do_pcibr_rrb_free(bridge_t *bridge, tmp = (tmp >> RRB_SIZE); } - if ( is_pic(bridge) ) { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; - } else { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - } + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; /* call do_pcibr_rrb_clear() for all the rrbs we've freed */ for (rrb_index = 0; rrb_index < 8; rrb_index++) { @@ -337,50 +280,18 @@ do_pcibr_rrb_clear(bridge_t *bridge, int rrb) * this RRB must be disabled. */ - if ( is_pic(bridge) ) { - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } + /* wait until RRB has no outstanduing XIO packets. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ + } - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb)); - - /* wait until RRB is no longer valid. */ - while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } - } else { /* io_get_sh_swapper(NASID_GET(bridge)) */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ } } } @@ -399,43 +310,16 @@ do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) int shft = (RRB_SIZE * (rrbn >> 1)); unsigned long ebit = RRB_ENABLE_BIT(bridge) << shft; - if ( is_pic(bridge) ) { - rrbv = *rrbp; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - rrbv = BRIDGE_REG_GET32((&rrbp)); - } else { - rrbv = *rrbp; - } - } + rrbv = *rrbp; if (rrbv & ebit) { - if ( is_pic(bridge) ) { - *rrbp = rrbv & ~ebit; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit)); - } else { - *rrbp = rrbv & ~ebit; - } - } + *rrbp = rrbv & ~ebit; } do_pcibr_rrb_clear(bridge, rrbn); if (rrbv & ebit) { - if ( is_pic(bridge) ) { - *rrbp = rrbv; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv); - } else { - *rrbp = rrbv; - } - } + *rrbp = rrbv; } } @@ -475,7 +359,7 @@ do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, * Flush all the rrb's assigned to the specified connection point. */ void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) +pcibr_rrb_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); @@ -510,7 +394,7 @@ pcibr_rrb_flush(devfs_handle_t pconn_vhdl) * device hanging off the bridge. */ int -pcibr_wrb_flush(devfs_handle_t pconn_vhdl) +pcibr_wrb_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); @@ -546,7 +430,7 @@ pcibr_wrb_flush(devfs_handle_t pconn_vhdl) * as best we can and return 0. */ int -pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, +pcibr_rrb_alloc(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1) { @@ -753,7 +637,7 @@ pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, */ int -pcibr_rrb_check(devfs_handle_t pconn_vhdl, +pcibr_rrb_check(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1, int *count_reserved, @@ -802,7 +686,7 @@ pcibr_rrb_check(devfs_handle_t pconn_vhdl, */ int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, +pcibr_slot_initial_rrb_alloc(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -889,7 +773,7 @@ rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot) */ int -pcibr_initial_rrb(devfs_handle_t pcibr_vhdl, +pcibr_initial_rrb(vertex_hdl_t pcibr_vhdl, pciio_slot_t first, pciio_slot_t last) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c index 1cf9b77c9ee..c469c78454a 100644 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -41,42 +40,41 @@ #endif -extern pcibr_info_t pcibr_info_get(devfs_handle_t); -extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); +extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); extern int pcibr_pcix_rbars_calc(pcibr_soft_t); -int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, pciio_slot_t slot); -int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, +int pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); -int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, +int pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); -int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, +int pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); -int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); -void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); +void pcibr_device_info_free(vertex_hdl_t, pciio_slot_t); iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t); cfg_p pcibr_find_capability(cfg_p, unsigned); -extern uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); -void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); +extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); -int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, +int pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot, pcibr_slot_info_resp_t respp); -extern devfs_handle_t baseio_pci_vhdl; -int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t); +extern vertex_hdl_t baseio_pci_vhdl; +int scsi_ctlr_nums_add(vertex_hdl_t, vertex_hdl_t); /* For now .... */ @@ -111,7 +109,7 @@ int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 }; #ifdef PIC_LATER int -pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_startup(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pciio_slot_t slot; @@ -127,11 +125,6 @@ pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) /* req_slot is the 'external' slot number, convert for internal use */ slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); - /* Do not allow start-up of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - /* Check for the valid slot */ if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); @@ -170,7 +163,7 @@ pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) * Software shut-down the PCI slot */ int -pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_shutdown(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge; @@ -194,11 +187,6 @@ pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); - /* Do not allow shut-down of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - #ifdef PIC_LATER /* Acquire update access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); @@ -284,7 +272,6 @@ pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, { pcibr_info_t pcibr_info = pcibr_infoh[func]; int win; - boolean_t is_sys_critical_vertex(devfs_handle_t); funcp->resp_f_status = 0; @@ -296,9 +283,6 @@ pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, #if defined(SUPPORT_PRINTING_V_FORMAT) sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); #endif - if(is_sys_critical_vertex(pcibr_info->f_vertex)) { - funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; - } funcp->resp_f_bus = pcibr_info->f_bus; funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info); @@ -345,7 +329,6 @@ pcibr_slot_info_return(pcibr_soft_t pcibr_soft, reg_p b_respp; pcibr_slot_info_resp_t slotp; pcibr_slot_func_info_resp_t funcp; - boolean_t is_sys_critical_vertex(devfs_handle_t); extern void snia_kmem_free(void *, int); slotp = snia_kmem_zalloc(sizeof(*slotp), 0); @@ -368,11 +351,6 @@ pcibr_slot_info_return(pcibr_soft_t pcibr_soft, slotp->resp_slot_status = pss->slot_status; slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); - - if (is_sys_critical_vertex(pss->slot_conn)) { - slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; - } - slotp->resp_bss_ninfo = pss->bss_ninfo; for (func = 0; func < pss->bss_ninfo; func++) { @@ -455,7 +433,7 @@ pcibr_slot_info_return(pcibr_soft_t pcibr_soft, * External SSRAM workaround info */ int -pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_query(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pciio_slot_t slot; @@ -481,11 +459,6 @@ pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) return(PCI_NOT_A_SLOT); } - /* Do not allow a query of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - /* Return information for the requested PCI slot */ if (slot != PCIIO_SLOT_NONE) { if (size < sizeof(*respp)) { @@ -534,88 +507,6 @@ pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) return(error); } -#if 0 -/* - * pcibr_slot_reset - * Reset the PCI device in the particular slot. - * - * The Xbridge does not comply with the PCI Specification - * when resetting an indiviaudl slot. An individual slot is - * is reset by toggling the slot's bit in the Xbridge Control - * Register. The Xbridge will assert the target slot's - * (non-bussed) RST signal, but does not assert the (bussed) - * REQ64 signal as required by the specification. As - * designed, the Xbridge cannot assert the REQ64 signal - * becuase it may interfere with a bus transaction in progress. - * The practical effects of this Xbridge implementation is - * device dependent; it probably will not adversely effect - * 32-bit cards, but may disable 64-bit data transfers by those - * cards that normally support 64-bit data transfers. - * - * The Xbridge will assert REQ64 when all four slots are reset - * by simultaneously toggling all four slot reset bits in the - * Xbridge Control Register. This is basically a PCI bus reset - * and asserting the (bussed) REQ64 signal will not interfere - * with any bus transactions in progress. - * - * The Xbridge (and the SN0 Bridge) support resetting only - * four PCI bus slots via the (X)bridge Control Register. - * - * To reset an individual slot for the PCI Hot-Plug feature - * use the L1 console commands to power-down and then - * power-up the slot, or use the kernel infrastructure - * functions to power-down/up the slot when they are - * implemented for SN1. - */ -int -pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge; - bridgereg_t ctrlreg,tmp; - volatile bridgereg_t *wrb_flush; - - if (!pcibr_soft) - return(EINVAL); - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - /* Enable the DMA operations from this device of the xtalk widget - * (PCI host bridge in this case). - */ - xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); - - /* Set the reset slot bit in the bridge's wid control register - * to reset the PCI slot - */ - bridge = pcibr_soft->bs_base; - - /* Read the bridge widget control and clear out the reset pin - * bit for the corresponding slot. - */ - tmp = ctrlreg = bridge->b_wid_control; - - tmp &= ~BRIDGE_CTRL_RST_PIN(slot); - - bridge->b_wid_control = tmp; - tmp = bridge->b_wid_control; - - /* Restore the old control register back. - * NOTE : PCI card gets reset when the reset pin bit - * changes from 0 (set above) to 1 (going to be set now). - */ - - bridge->b_wid_control = ctrlreg; - - /* Flush the write buffers if any !! */ - wrb_flush = &(bridge->b_wr_req_buf[slot].reg); - while (*wrb_flush); - - return(0); -} -#endif - #define PROBE_LOCK 0 /* FIXME: we're attempting to lock around accesses * to b_int_enable. This hangs pcibr_probe_slot() */ @@ -627,7 +518,7 @@ pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) * information associated with this particular PCI device. */ int -pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -650,7 +541,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, int nfunc; pciio_function_t rfunc; int func; - devfs_handle_t conn_vhdl; + vertex_hdl_t conn_vhdl; pcibr_soft_slot_t slotp; /* Get the basic software information required to proceed */ @@ -669,10 +560,6 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, return(0); } - /* Check for a slot with any system critical functions */ - if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - /* Try to read the device-id/vendor-id from the config space */ cfgw = pcibr_slot_config_addr(bridge, slot, 0); @@ -701,7 +588,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, if (vendor == 0xFFFF) return(ENODEV); - htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); nfunc = 1; rfunc = PCIIO_FUNC_NONE; pfail = 0; @@ -750,7 +637,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); rfunc = func; } htype &= 0x7f; @@ -810,16 +697,10 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, * Timer for these devices */ - lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1); + lt_time = do_pcibr_config_get(cfgw, PCI_CFG_LATENCY_TIMER, 1); if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) && - !((vendor == IOC3_VENDOR_ID_NUM) && - ( -#ifdef PIC_LATER - (device == IOC3_DEVICE_ID_NUM) || - (device == LINC_DEVICE_ID_NUM) || -#endif - (device == 0x5 /* RAD_DEV */)))) { + (device == 0x5 /* RAD_DEV */)) { unsigned min_gnt; unsigned min_gnt_mult; @@ -827,7 +708,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, * needs in increments of 250ns. But latency timer is in * PCI clock cycles, so a conversion is needed. */ - min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1); + min_gnt = do_pcibr_config_get(cfgw, PCI_MIN_GNT, 1); if (IS_133MHZ(pcibr_soft)) min_gnt_mult = 32; /* 250ns @ 133MHz in clocks */ @@ -843,7 +724,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, else lt_time = 4 * min_gnt_mult; /* 1 micro second */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); + do_pcibr_config_set(cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, "pcibr_slot_info_init: set Latency Timer for slot=%d, " @@ -851,12 +732,27 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time)); } - /* Get the PCI-X capability if running in PCI-X mode. If the func - * doesn't have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE - * pcibr_info struct so the device driver for that function is not - * called. + + /* In our architecture the setting of the cacheline size isn't + * beneficial for cards in PCI mode, but in PCI-X mode devices + * can optionally use the cacheline size value for internal + * device optimizations (See 7.1.5 of the PCI-X v1.0 spec). + * NOTE: cachline size is in doubleword increments */ if (IS_PCIX(pcibr_soft)) { + if (!do_pcibr_config_get(cfgw, PCI_CFG_CACHE_LINE, 1)) { + do_pcibr_config_set(cfgw, PCI_CFG_CACHE_LINE, 1, 0x20); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: set CacheLine for slot=%d, " + "func=%d, to 0x20\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); + } + + /* Get the PCI-X capability if running in PCI-X mode. If the func + * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE + * pcibr_info struct so the device driver for that function is not + * called. + */ if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) { printk(KERN_WARNING #if defined(SUPPORT_PRINTING_V_FORMAT) @@ -898,7 +794,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, if (func == 0) slotp->slot_conn = conn_vhdl; - cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; @@ -949,7 +845,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, * this could be pushed up into pciio, when we * start supporting more PCI providers. */ - base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); + base = do_pcibr_config_get(wptr, (win * 4), 4); if (base & PCI_BA_IO_SPACE) { /* BASE is in I/O space. */ @@ -975,7 +871,7 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, } else if (base & 0xC0000000) { base = 0; /* outside permissable range */ } else if ((code == PCI_BA_MEM_64BIT) && - (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) { + (do_pcibr_config_get(wptr, ((win + 1)*4), 4) != 0)) { base = 0; /* outside permissable range */ } } @@ -983,8 +879,8 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, if (base != 0) { /* estimate size */ size = base & -base; } else { /* calculate size */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0); /* write 1's */ - size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */ + do_pcibr_config_set(wptr, (win * 4), 4, ~0); /* write 1's */ + size = do_pcibr_config_get(wptr, (win * 4), 4); /* read back */ size &= mask; /* keep addr */ size &= -size; /* keep lsbit */ if (size == 0) @@ -995,45 +891,9 @@ pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pcibr_info->f_window[win].w_base = base; pcibr_info->f_window[win].w_size = size; -#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) - /* - * IOC3 BASE_ADDR* BUG WORKAROUND - * - - * If we write to BASE1 on the IOC3, the - * data in BASE0 is replaced. The - * original workaround was to remember - * the value of BASE0 and restore it - * when we ran off the end of the BASE - * registers; however, a later - * workaround was added (I think it was - * rev 1.44) to avoid setting up - * anything but BASE0, with the comment - * that writing all ones to BASE1 set - * the enable-parity-error test feature - * in IOC3's SCR bit 14. - * - * So, unless we defer doing any PCI - * space allocation until drivers - * attach, and set up a way for drivers - * (the IOC3 in paricular) to tell us - * generically to keep our hands off - * BASE registers, we gotta "know" about - * the IOC3 here. - * - * Too bad the PCI folks didn't reserve the - * all-zero value for 'no BASE here' (it is a - * valid code for an uninitialized BASE in - * 32-bit PCI memory space). - */ - - if ((vendor == IOC3_VENDOR_ID_NUM) && - (device == IOC3_DEVICE_ID_NUM)) - break; -#endif if (code == PCI_BA_MEM_64BIT) { win++; /* skip upper half */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0); /* must be zero */ + do_pcibr_config_set(wptr, (win * 4), 4, 0); /* must be zero */ } } /* next win */ } /* next func */ @@ -1056,7 +916,7 @@ pcibr_find_capability(cfg_p cfgw, int defend_against_circular_linkedlist = 0; /* Check to see if there is a capabilities pointer in the cfg header */ - if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { + if (!(do_pcibr_config_get(cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { return (NULL); } @@ -1067,14 +927,14 @@ pcibr_find_capability(cfg_p cfgw, * significant bits of the next pointer must be ignored, so we mask * with 0xfc). */ - cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); + cap_nxt = (do_pcibr_config_get(cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); while (cap_nxt && (defend_against_circular_linkedlist <= 48)) { - cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1); + cap_id = do_pcibr_config_get(cfgw, cap_nxt, 1); if (cap_id == capability) { return ((cfg_p)((char *)cfgw + cap_nxt)); } - cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc); + cap_nxt = (do_pcibr_config_get(cfgw, cap_nxt+1, 1) & 0xfc); defend_against_circular_linkedlist++; } @@ -1087,7 +947,7 @@ pcibr_find_capability(cfg_p cfgw, * with a particular PCI device. */ int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, +pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1223,20 +1083,21 @@ int as_debug = 0; * the base registers in the card. */ int -pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; bridge_t *bridge; - size_t align_slot; iopaddr_t mask; int nbars; int nfunc; int func; int win; int rc = 0; + int align; + int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); @@ -1275,7 +1136,8 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, * the entire "lo" area is only a * megabyte, total ... */ - align_slot = (slot < 2) ? 0x200000 : 0x100000; + align_slot = 0x100000; + align = align_slot; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; @@ -1300,7 +1162,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) + if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) nbars = 2; else nbars = PCI_CFG_BASE_ADDRS; @@ -1333,23 +1195,24 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, continue; /* already allocated */ } + align = (win) ? size : align_slot; + + if (align < _PAGESZ) + align = _PAGESZ; /* ie. 0x00004000 */ + switch (space) { case PCIIO_SPACE_IO: base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_IO, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; break; case PCIIO_SPACE_MEM: - if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) & + if ((do_pcibr_config_get(wptr, (win * 4), 4) & PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) { - int align = size; /* ie. 0x00001000 */ - - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ /* allocate from 20-bit PCI space */ base = pcibr_bus_addr_alloc(pcibr_soft, @@ -1363,7 +1226,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_MEM32, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; } @@ -1377,7 +1240,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space)); } pcibr_info->f_window[win].w_base = base; - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base); + do_pcibr_config_set(wptr, (win * 4), 4, base); #if defined(SUPPORT_PRINTING_R_FORMAT) if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { @@ -1405,26 +1268,22 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, /* * Allocate space for the EXPANSION ROM - * NOTE: DO NOT DO THIS ON AN IOC3, - * as it blows the system away. */ base = size = 0; - if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || - (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { - + { wptr = cfgw + PCI_EXPANSION_ROM / 4; - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000); - mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4); + do_pcibr_config_set(wptr, 0, 4, 0xFFFFF000); + mask = do_pcibr_config_get(wptr, 0, 4); if (mask & 0xFFFFF000) { size = mask & -mask; base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_rwindow, PCIIO_SPACE_MEM32, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; else { - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base); + do_pcibr_config_set(wptr, 0, 4, base); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, func=%d, " "ROM in [0x%X..0x%X], allocated by pcibr\n", @@ -1435,7 +1294,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, } pcibr_info->f_rbase = base; pcibr_info->f_rsize = size; - + /* * if necessary, update the board's * command register to enable decoding @@ -1463,7 +1322,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + pci_cfg_cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); #if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) @@ -1471,7 +1330,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, #endif pci_cfg_cmd_reg &= 0xFFFF; if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, + do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); } /* next func */ return(rc); @@ -1483,7 +1342,7 @@ pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, */ int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1525,8 +1384,6 @@ pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, "pcibr_slot_device_init: Device(%d): %R\n", slot, devreg, device_bits)); -#else - printk("pcibr_slot_device_init: Device(%d) 0x%x\n", slot, devreg); #endif return(0); } @@ -1536,7 +1393,7 @@ pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, * Setup the host/guest relations for a PCI slot. */ int -pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1605,18 +1462,17 @@ pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, * card in this slot. */ int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, +pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; - async_attach_t aa = NULL; int func; - devfs_handle_t xconn_vhdl, conn_vhdl; + vertex_hdl_t xconn_vhdl, conn_vhdl; #ifdef PIC_LATER - devfs_handle_t scsi_vhdl; + vertex_hdl_t scsi_vhdl; #endif int nfunc; int error_func; @@ -1639,7 +1495,6 @@ pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, } xconn_vhdl = pcibr_soft->bs_conn; - aa = async_attach_get_info(xconn_vhdl); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -1656,13 +1511,6 @@ pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, conn_vhdl = pcibr_info->f_vertex; -#ifdef LATER - /* - * Activate if and when we support cdl. - */ - if (aa) - async_attach_add_info(conn_vhdl, aa); -#endif /* LATER */ error_func = pciio_device_attach(conn_vhdl, drv_flags); @@ -1728,7 +1576,7 @@ pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, * card in this slot. */ int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, +pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags) { @@ -1736,7 +1584,7 @@ pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; int func; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + vertex_hdl_t conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; int error_func; int error_slot = 0; @@ -1811,7 +1659,7 @@ pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, * PCI card on the bus. */ int -pcibr_slot_attach(devfs_handle_t pcibr_vhdl, +pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, @@ -1850,7 +1698,7 @@ pcibr_slot_attach(devfs_handle_t pcibr_vhdl, * slot-specific freeing that needs to be done. */ int -pcibr_slot_detach(devfs_handle_t pcibr_vhdl, +pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, @@ -1859,10 +1707,6 @@ pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); int error; - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(PCI_IS_SYS_CRITICAL); - /* Call the device detach function */ error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); if (error) { @@ -1892,61 +1736,6 @@ pcibr_slot_detach(devfs_handle_t pcibr_vhdl, } /* - * pcibr_is_slot_sys_critical - * Check slot for any functions that are system critical. - * Return 1 if any are system critical or 0 otherwise. - * - * This function will always return 0 when called by - * pcibr_attach() because the system critical vertices - * have not yet been set in the hwgraph. - */ -int -pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int func; - boolean_t is_sys_critical_vertex(devfs_handle_t); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return(EINVAL); - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - if (is_sys_critical_vertex(conn_vhdl)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); -#else - printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); -#endif - return(1); - } - - } - - return(0); -} - -/* * pcibr_probe_slot_pic: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. @@ -1984,57 +1773,6 @@ pcibr_probe_slot_pic(bridge_t *bridge, } /* - * pcibr_probe_slot_non_pic: read a config space word - * while trapping any errors; return zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -static int -pcibr_probe_slot_non_pic(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) -{ - int rv; - bridgereg_t b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0; - extern int badaddr_val(volatile void *, int, volatile void *); - - b_old_enable = bridge->b_int_enable; - b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = b_new_enable; - - /* - * The xbridge doesn't clear b_err_int_view unless - * multi-err is cleared... - */ - if (is_xbridge(bridge)) { - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp); - /* - * The xbridge doesn't set master timeout in b_int_status - * here. Fortunately it's in error_interrupt_view. - */ - if (is_xbridge(bridge)) { - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ - } - } - bridge->b_int_enable = b_old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - return(rv); -} - - -/* * pcibr_probe_slot: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. @@ -2046,15 +1784,12 @@ pcibr_probe_slot(bridge_t *bridge, cfg_p cfg, unsigned *valp) { - if ( is_pic(bridge) ) - return(pcibr_probe_slot_pic(bridge, cfg, valp)); - else - return(pcibr_probe_slot_non_pic(bridge, cfg, valp)); + return(pcibr_probe_slot_pic(bridge, cfg, valp)); } void -pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +pcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pcibr_info_t pcibr_info; @@ -2079,9 +1814,9 @@ pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) /* Disable memory and I/O BARs */ cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); - cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg); + do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg); for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) @@ -2181,7 +1916,7 @@ pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p) * io_brick_tab[] array defined in ml/SN/iograph.c */ int -pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) +pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); xwidgetnum_t widget = pcibr_soft->bs_xid; diff --git a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c index 5af418be346..e0a147a57dc 100644 --- a/arch/ia64/sn/io/sn2/pciio.c +++ b/arch/ia64/sn/io/sn2/pciio.c @@ -7,8 +7,6 @@ * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ -#define USRPCI 0 - #include #include #include @@ -44,13 +42,8 @@ #undef DEBUG_PCIIO /* turn this on for yet more console output */ -#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DO_DEL(ptr) (kfree(ptr)) - char pciio_info_fingerprint[] = "pciio_info"; -cdl_p pciio_registry = NULL; - int badaddr_val(volatile void *addr, int len, volatile void *ptr) { @@ -97,8 +90,6 @@ get_master_baseio_nasid(void) extern char master_baseio_wid; if (master_baseio_nasid < 0) { - nasid_t tmp; - master_baseio_nasid = ia64_sn_get_master_baseio_nasid(); if ( master_baseio_nasid >= 0 ) { @@ -109,13 +100,13 @@ get_master_baseio_nasid(void) } int -hub_dma_enabled(devfs_handle_t xconn_vhdl) +hub_dma_enabled(vertex_hdl_t xconn_vhdl) { return(0); } int -hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +hub_error_devenable(vertex_hdl_t xconn_vhdl, int devnum, int error_code) { return(0); } @@ -153,66 +144,64 @@ ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) */ #if !defined(DEV_FUNC) -static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); +static pciio_provider_t *pciio_to_provider_fns(vertex_hdl_t dev); #endif -pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +pciio_piomap_t pciio_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); void pciio_piomap_free(pciio_piomap_t); caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); void pciio_piomap_done(pciio_piomap_t); -caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); +caddr_t pciio_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +caddr_t pciio_pio_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); -iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); +iopaddr_t pciio_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t); +void pciio_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); -pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +pciio_dmamap_t pciio_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void pciio_dmamap_free(pciio_dmamap_t); iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); void pciio_dmamap_done(pciio_dmamap_t); -iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +iopaddr_t pciio_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); void pciio_dmamap_drain(pciio_dmamap_t); -void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pciio_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); +void pciio_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); +void pciio_dmalist_drain(vertex_hdl_t, alenlist_t); +iopaddr_t pciio_dma_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +pciio_intr_t pciio_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); void pciio_intr_free(pciio_intr_t); int pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t); void pciio_intr_disconnect(pciio_intr_t); -devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); +vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t); void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); -void pciio_provider_startup(devfs_handle_t); -void pciio_provider_shutdown(devfs_handle_t); +void pciio_provider_startup(vertex_hdl_t); +void pciio_provider_shutdown(vertex_hdl_t); -pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); -devfs_handle_t pciio_intr_dev_get(pciio_intr_t); +pciio_endian_t pciio_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); +pciio_priority_t pciio_priority_set(vertex_hdl_t, pciio_priority_t); +vertex_hdl_t pciio_intr_dev_get(pciio_intr_t); -devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); +vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t); pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); pciio_space_t pciio_pio_space_get(pciio_piomap_t); iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); ulong pciio_pio_mapsz_get(pciio_piomap_t); caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); -devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); +vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t); pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); -pciio_info_t pciio_info_chk(devfs_handle_t); -pciio_info_t pciio_info_get(devfs_handle_t); -void pciio_info_set(devfs_handle_t, pciio_info_t); -devfs_handle_t pciio_info_dev_get(pciio_info_t); +pciio_info_t pciio_info_chk(vertex_hdl_t); +pciio_info_t pciio_info_get(vertex_hdl_t); +void pciio_info_set(vertex_hdl_t, pciio_info_t); +vertex_hdl_t pciio_info_dev_get(pciio_info_t); pciio_slot_t pciio_info_slot_get(pciio_info_t); pciio_function_t pciio_info_function_get(pciio_info_t); pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); pciio_device_id_t pciio_info_device_id_get(pciio_info_t); -devfs_handle_t pciio_info_master_get(pciio_info_t); +vertex_hdl_t pciio_info_master_get(pciio_info_t); arbitrary_info_t pciio_info_mfast_get(pciio_info_t); pciio_provider_t *pciio_info_pops_get(pciio_info_t); error_handler_f *pciio_info_efunc_get(pciio_info_t); @@ -223,30 +212,28 @@ size_t pciio_info_bar_size_get(pciio_info_t, int); iopaddr_t pciio_info_rom_base_get(pciio_info_t); size_t pciio_info_rom_size_get(pciio_info_t); -void pciio_init(void); -int pciio_attach(devfs_handle_t); +int pciio_attach(vertex_hdl_t); -void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); -void pciio_provider_unregister(devfs_handle_t); -pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); +void pciio_provider_register(vertex_hdl_t, pciio_provider_t *pciio_fns); +void pciio_provider_unregister(vertex_hdl_t); +pciio_provider_t *pciio_provider_fns_get(vertex_hdl_t); int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); -void pciio_driver_unregister(char *driver_prefix); -devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +vertex_hdl_t pciio_device_register(vertex_hdl_t, vertex_hdl_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -void pciio_device_unregister(devfs_handle_t); -pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +void pciio_device_unregister(vertex_hdl_t); +pciio_info_t pciio_device_info_new(pciio_info_t, vertex_hdl_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); void pciio_device_info_free(pciio_info_t); -devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); -void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t, int); -int pciio_device_detach(devfs_handle_t, int); -void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); +vertex_hdl_t pciio_device_info_register(vertex_hdl_t, pciio_info_t); +void pciio_device_info_unregister(vertex_hdl_t, pciio_info_t); +int pciio_device_attach(vertex_hdl_t, int); +int pciio_device_detach(vertex_hdl_t, int); +void pciio_error_register(vertex_hdl_t, error_handler_f *, error_handler_arg_t); -int pciio_reset(devfs_handle_t); -int pciio_write_gather_flush(devfs_handle_t); -int pciio_slot_inuse(devfs_handle_t); +int pciio_reset(vertex_hdl_t); +int pciio_write_gather_flush(vertex_hdl_t); +int pciio_slot_inuse(vertex_hdl_t); /* ===================================================================== * Provider Function Location @@ -261,7 +248,7 @@ int pciio_slot_inuse(devfs_handle_t); #if !defined(DEV_FUNC) static pciio_provider_t * -pciio_to_provider_fns(devfs_handle_t dev) +pciio_to_provider_fns(vertex_hdl_t dev) { pciio_info_t card_info; pciio_provider_t *provider_fns; @@ -316,7 +303,7 @@ pciio_to_provider_fns(devfs_handle_t dev) */ pciio_piomap_t -pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +pciio_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* lowest address (or offset in window) */ @@ -354,7 +341,7 @@ pciio_piomap_done(pciio_piomap_t pciio_piomap) } caddr_t -pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ +pciio_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* starting address (or offset in window) */ @@ -366,7 +353,7 @@ pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ } caddr_t -pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ +pciio_pio_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* starting address (or offset in window) */ @@ -410,7 +397,7 @@ pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ } iopaddr_t -pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ +pciio_piospace_alloc(vertex_hdl_t dev, /* Device requiring space */ device_desc_t dev_desc, /* Device descriptor */ pciio_space_t space, /* MEM32/MEM64/IO */ size_t byte_count, /* Size of mapping */ @@ -423,7 +410,7 @@ pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ } void -pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ +pciio_piospace_free(vertex_hdl_t dev, /* Device freeing space */ pciio_space_t space, /* Type of space */ iopaddr_t pciaddr, /* starting address */ size_t byte_count) @@ -440,7 +427,7 @@ pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ */ pciio_dmamap_t -pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ +pciio_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) @@ -465,15 +452,6 @@ pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); } -alenlist_t -pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(pciio_dmamap, dmamap_list) - (CAST_DMAMAP(pciio_dmamap), alenlist, flags); -} - void pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) { @@ -482,7 +460,7 @@ pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) } iopaddr_t -pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ +pciio_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -492,18 +470,8 @@ pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ (dev, dev_desc, paddr, byte_count, flags); } -alenlist_t -pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - iopaddr_t -pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ +pciio_dma_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -553,14 +521,14 @@ pciio_dmamap_drain(pciio_dmamap_t map) } void -pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +pciio_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) { DEV_FUNC(dev, dmaaddr_drain) (dev, addr, size); } void -pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) +pciio_dmalist_drain(vertex_hdl_t dev, alenlist_t list) { DEV_FUNC(dev, dmalist_drain) (dev, list); @@ -577,10 +545,10 @@ pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) * Return resource handle in intr_hdl. */ pciio_intr_t -pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ +pciio_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ pciio_intr_line_t lines, /* INTR line(s) to attach */ - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { /* owner of this interrupt */ return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) (dev, dev_desc, lines, owner_dev); @@ -624,7 +592,7 @@ pciio_intr_disconnect(pciio_intr_t intr_hdl) * Return a hwgraph vertex that represents the CPU currently * targeted by an interrupt. */ -devfs_handle_t +vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t intr_hdl) { return INTR_FUNC(intr_hdl, intr_cpu_get) @@ -663,12 +631,12 @@ pciio_slot_func_to_name(char *name, */ static pciio_info_t pciio_cardinfo_get( - devfs_handle_t pciio_vhdl, + vertex_hdl_t pciio_vhdl, pciio_slot_t pci_slot) { char namebuf[16]; pciio_info_t info = 0; - devfs_handle_t conn; + vertex_hdl_t conn; pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE); if (GRAPH_SUCCESS == @@ -699,22 +667,16 @@ pciio_cardinfo_get( /*ARGSUSED */ int pciio_error_handler( - devfs_handle_t pciio_vhdl, + vertex_hdl_t pciio_vhdl, int error_code, ioerror_mode_t mode, ioerror_t *ioerror) { pciio_info_t pciio_info; - devfs_handle_t pconn_vhdl; -#if USRPCI - devfs_handle_t usrpci_v; -#endif + vertex_hdl_t pconn_vhdl; pciio_slot_t slot; int retval; -#ifdef EHE_ENABLE - error_state_t e_state; -#endif /* EHE_ENABLE */ #if DEBUG && ERROR_DEBUG printk("%v: pciio_error_handler\n", pciio_vhdl); @@ -733,16 +695,6 @@ pciio_error_handler( if (pciio_info && pciio_info->c_efunc) { pconn_vhdl = pciio_info_dev_get(pciio_info); -#ifdef EHE_ENABLE - e_state = error_state_get(pciio_vhdl); - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif - retval = pciio_info->c_efunc (pciio_info->c_einfo, error_code, mode, ioerror); if (retval != IOERROR_UNHANDLED) @@ -770,49 +722,11 @@ pciio_error_handler( pconn_vhdl = pciio_info_dev_get(pciio_info); -#ifdef EHE_ENABLE - e_state = error_state_get(pciio_vhdl); - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - if (error_state_set(pconn_vhdl,e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif /* EHE_ENABLE */ - retval = pciio_info->c_efunc (pciio_info->c_einfo, error_code, mode, ioerror); if (retval != IOERROR_UNHANDLED) return retval; } - -#if USRPCI - /* If the USRPCI driver is available and - * knows about this connection point, - * deliver the error to it. - * - * OK to use pconn_vhdl here, even though we - * have already UNREF'd it, since we know that - * it is not going away. - */ - pconn_vhdl = pciio_info_dev_get(pciio_info); - if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) { - iopaddr_t busaddr; - IOERROR_GETVALUE(busaddr, ioerror, busaddr); - retval = usrpci_error_handler (usrpci_v, error_code, busaddr); - hwgraph_vertex_unref(usrpci_v); - if (retval != IOERROR_UNHANDLED) { - /* - * This unref is not needed. If this code is called often enough, - * the system will crash, due to vertex reference count reaching 0, - * causing vertex to be unallocated. -jeremy - * hwgraph_vertex_unref(pconn_vhdl); - */ - return retval; - } - } -#endif } } @@ -829,7 +743,7 @@ pciio_error_handler( * Startup a crosstalk provider */ void -pciio_provider_startup(devfs_handle_t pciio_provider) +pciio_provider_startup(vertex_hdl_t pciio_provider) { DEV_FUNC(pciio_provider, provider_startup) (pciio_provider); @@ -839,7 +753,7 @@ pciio_provider_startup(devfs_handle_t pciio_provider) * Shutdown a crosstalk provider */ void -pciio_provider_shutdown(devfs_handle_t pciio_provider) +pciio_provider_shutdown(vertex_hdl_t pciio_provider) { DEV_FUNC(pciio_provider, provider_shutdown) (pciio_provider); @@ -851,7 +765,7 @@ pciio_provider_shutdown(devfs_handle_t pciio_provider) * how things will actually appear in memory. */ pciio_endian_t -pciio_endian_set(devfs_handle_t dev, +pciio_endian_set(vertex_hdl_t dev, pciio_endian_t device_end, pciio_endian_t desired_end) { @@ -880,7 +794,7 @@ pciio_endian_set(devfs_handle_t dev, * Specify PCI arbitration priority. */ pciio_priority_t -pciio_priority_set(devfs_handle_t dev, +pciio_priority_set(vertex_hdl_t dev, pciio_priority_t device_prio) { ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); @@ -893,7 +807,7 @@ pciio_priority_set(devfs_handle_t dev, * Read value of configuration register */ uint64_t -pciio_config_get(devfs_handle_t dev, +pciio_config_get(vertex_hdl_t dev, unsigned reg, unsigned size) { @@ -923,7 +837,7 @@ pciio_config_get(devfs_handle_t dev, * Change value of configuration register */ void -pciio_config_set(devfs_handle_t dev, +pciio_config_set(vertex_hdl_t dev, unsigned reg, unsigned size, uint64_t value) @@ -953,7 +867,7 @@ pciio_config_set(devfs_handle_t dev, * Issue a hardware reset to a card. */ int -pciio_reset(devfs_handle_t dev) +pciio_reset(vertex_hdl_t dev) { return DEV_FUNC(dev, reset) (dev); } @@ -962,19 +876,19 @@ pciio_reset(devfs_handle_t dev) * flush write gather buffers */ int -pciio_write_gather_flush(devfs_handle_t dev) +pciio_write_gather_flush(vertex_hdl_t dev) { return DEV_FUNC(dev, write_gather_flush) (dev); } -devfs_handle_t +vertex_hdl_t pciio_intr_dev_get(pciio_intr_t pciio_intr) { return (pciio_intr->pi_dev); } /****** Generic crosstalk pio interfaces ******/ -devfs_handle_t +vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap) { return (pciio_piomap->pp_dev); @@ -1011,7 +925,7 @@ pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) } /****** Generic crosstalk dma interfaces ******/ -devfs_handle_t +vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) { return (pciio_dmamap->pd_dev); @@ -1026,7 +940,7 @@ pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) /****** Generic pci slot information interfaces ******/ pciio_info_t -pciio_info_chk(devfs_handle_t pciio) +pciio_info_chk(vertex_hdl_t pciio) { arbitrary_info_t ainfo = 0; @@ -1035,7 +949,7 @@ pciio_info_chk(devfs_handle_t pciio) } pciio_info_t -pciio_info_get(devfs_handle_t pciio) +pciio_info_get(vertex_hdl_t pciio) { pciio_info_t pciio_info; @@ -1051,18 +965,17 @@ pciio_info_get(devfs_handle_t pciio) #endif /* DEBUG_PCIIO */ if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { + (pciio_info->c_fingerprint != pciio_info_fingerprint) + && (pciio_info->c_fingerprint != NULL)) { - return((pciio_info_t)-1); /* Should panic .. */ + return((pciio_info_t)-1); /* Should panic .. */ } - return pciio_info; } void -pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) +pciio_info_set(vertex_hdl_t pciio, pciio_info_t pciio_info) { if (pciio_info != NULL) pciio_info->c_fingerprint = pciio_info_fingerprint; @@ -1076,7 +989,7 @@ pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) (arbitrary_info_t) pciio_info); } -devfs_handle_t +vertex_hdl_t pciio_info_dev_get(pciio_info_t pciio_info) { return (pciio_info->c_vertex); @@ -1106,7 +1019,7 @@ pciio_info_device_id_get(pciio_info_t pciio_info) return (pciio_info->c_device); } -devfs_handle_t +vertex_hdl_t pciio_info_master_get(pciio_info_t pciio_info) { return (pciio_info->c_master); @@ -1172,47 +1085,12 @@ pciio_info_rom_size_get(pciio_info_t info) */ /* - * pciioinit: called once during device driver - * initializtion if this driver is configured into - * the system. - */ -void -pciio_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("pciio_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (pciio_registry == NULL) { - cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); - if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(pciio_registry != NULL); -} - -/* * pciioattach: called for each vertex in the graph * that is a PCI provider. */ /*ARGSUSED */ int -pciio_attach(devfs_handle_t pciio) +pciio_attach(vertex_hdl_t pciio) { #if DEBUG && ATTACH_DEBUG #if defined(SUPPORT_PRINTING_V_FORMAT) @@ -1228,7 +1106,7 @@ pciio_attach(devfs_handle_t pciio) * Associate a set of pciio_provider functions with a vertex. */ void -pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) +pciio_provider_register(vertex_hdl_t provider, pciio_provider_t *pciio_fns) { hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); } @@ -1237,7 +1115,7 @@ pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) * Disassociate a set of pciio_provider functions with a vertex. */ void -pciio_provider_unregister(devfs_handle_t provider) +pciio_provider_unregister(vertex_hdl_t provider) { arbitrary_info_t ainfo; @@ -1249,7 +1127,7 @@ pciio_provider_unregister(devfs_handle_t provider) * provider. */ pciio_provider_t * -pciio_provider_fns_get(devfs_handle_t provider) +pciio_provider_fns_get(vertex_hdl_t provider) { arbitrary_info_t ainfo = 0; @@ -1265,86 +1143,13 @@ pciio_driver_register( char *driver_prefix, unsigned flags) { - /* a driver's init routine might call - * pciio_driver_register before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - return cdl_add_driver(pciio_registry, - vendor_id, device_id, - driver_prefix, flags, NULL); -} - -/* - * Remove an initialization function. - */ -void -pciio_driver_unregister( - char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called register; so - * we can assume we have a registry here. - */ - ASSERT(pciio_registry != NULL); - - cdl_del_driver(pciio_registry, driver_prefix, NULL); -} - -/* - * Set the slot status for a device supported by the - * driver being registered. - */ -void -pciio_driver_reg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Set the slot status for a device supported by the - * driver being unregistered. - */ -void -pciio_driver_unreg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -pciio_iterate(char *driver_prefix, - pciio_iter_f * func) -{ - /* a driver's init routine might call - * pciio_iterate before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - ASSERT(pciio_registry != NULL); - - cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); + return(0); } -devfs_handle_t +vertex_hdl_t pciio_device_register( - devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ - devfs_handle_t master, /* card's master ASIC (PCI provider) */ + vertex_hdl_t connectpt, /* vertex for /hw/.../pciio/%d */ + vertex_hdl_t master, /* card's master ASIC (PCI provider) */ pciio_slot_t slot, /* card's slot */ pciio_function_t func, /* card's func */ pciio_vendor_id_t vendor_id, @@ -1356,7 +1161,7 @@ pciio_device_register( } void -pciio_device_unregister(devfs_handle_t pconn) +pciio_device_unregister(vertex_hdl_t pconn) { DEV_FUNC(pconn,device_unregister)(pconn); } @@ -1364,14 +1169,14 @@ pciio_device_unregister(devfs_handle_t pconn) pciio_info_t pciio_device_info_new( pciio_info_t pciio_info, - devfs_handle_t master, + vertex_hdl_t master, pciio_slot_t slot, pciio_function_t func, pciio_vendor_id_t vendor_id, pciio_device_id_t device_id) { if (!pciio_info) - GET_NEW(pciio_info); + NEW(pciio_info); ASSERT(pciio_info != NULL); pciio_info->c_slot = slot; @@ -1396,14 +1201,14 @@ pciio_device_info_free(pciio_info_t pciio_info) BZERO((char *)pciio_info,sizeof(pciio_info)); } -devfs_handle_t +vertex_hdl_t pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info) /* details about the connectpt */ { char name[32]; - devfs_handle_t pconn; - int device_master_set(devfs_handle_t, devfs_handle_t); + vertex_hdl_t pconn; + int device_master_set(vertex_hdl_t, vertex_hdl_t); pciio_slot_func_to_name(name, pciio_info->c_slot, @@ -1429,25 +1234,15 @@ pciio_device_info_register( */ device_master_set(pconn, pciio_info->c_master); - -#if USRPCI - /* - * Call into usrpci provider to let it initialize for - * the given slot. - */ - if (pciio_info->c_slot != PCIIO_SLOT_NONE) - usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); -#endif - return pconn; } void -pciio_device_info_unregister(devfs_handle_t connectpt, +pciio_device_info_unregister(vertex_hdl_t connectpt, pciio_info_t pciio_info) { char name[32]; - devfs_handle_t pconn; + vertex_hdl_t pconn; if (!pciio_info) return; @@ -1470,7 +1265,7 @@ pciio_device_info_unregister(devfs_handle_t connectpt, /* Add the pci card inventory information to the hwgraph */ static void -pciio_device_inventory_add(devfs_handle_t pconn_vhdl) +pciio_device_inventory_add(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -1488,7 +1283,7 @@ pciio_device_inventory_add(devfs_handle_t pconn_vhdl) /*ARGSUSED */ int -pciio_device_attach(devfs_handle_t pconn, +pciio_device_attach(vertex_hdl_t pconn, int drv_flags) { pciio_info_t pciio_info; @@ -1507,34 +1302,15 @@ pciio_device_attach(devfs_handle_t pconn, * pciio_init) have been called; so we * can assume here that we have a registry. */ - ASSERT(pciio_registry != NULL); - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); + return(cdl_add_connpt(vendor_id, device_id, pconn, drv_flags)); } int -pciio_device_detach(devfs_handle_t pconn, +pciio_device_detach(vertex_hdl_t pconn, int drv_flags) { - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_del_connpt(pciio_registry, vendor_id, device_id, - pconn, drv_flags)); - + return(0); } /* SN2 */ @@ -1728,7 +1504,7 @@ pciio_device_win_free(pciio_win_alloc_t win_alloc) * cooperating drivers, well, cooperate ... */ void -pciio_error_register(devfs_handle_t pconn, +pciio_error_register(vertex_hdl_t pconn, error_handler_f *efunc, error_handler_arg_t einfo) { @@ -1746,7 +1522,7 @@ pciio_error_register(devfs_handle_t pconn, * vhdl is the vertex for the slot */ int -pciio_slot_inuse(devfs_handle_t pconn_vhdl) +pciio_slot_inuse(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -1763,7 +1539,7 @@ pciio_slot_inuse(devfs_handle_t pconn_vhdl) } int -pciio_dma_enabled(devfs_handle_t pconn_vhdl) +pciio_dma_enabled(vertex_hdl_t pconn_vhdl) { return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); } @@ -1777,7 +1553,7 @@ pciio_info_type1_get(pciio_info_t pci_info) /* * These are complementary Linux interfaces that takes in a pci_dev * as the - * first arguement instead of devfs_handle_t. + * first arguement instead of vertex_hdl_t. */ iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); @@ -1800,7 +1576,7 @@ snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, int *count_vchan0, int *count_vchan1) { - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1); } @@ -1811,7 +1587,7 @@ snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, pciio_endian_t desired_end) { - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end); @@ -1825,7 +1601,7 @@ snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device * unsigned flags) { /* defined in dma.h */ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be @@ -1842,7 +1618,7 @@ snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this de unsigned flags) { /* defined in dma.h */ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be diff --git a/arch/ia64/sn/io/sn2/pic.c b/arch/ia64/sn/io/sn2/pic.c index 4dba132ca4c..ee95e9b4848 100644 --- a/arch/ia64/sn/io/sn2/pic.c +++ b/arch/ia64/sn/io/sn2/pic.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -36,29 +35,16 @@ extern char *bcopy(const char * src, char * dest, int count); #define PCI_BUS_NO_1 1 -int pic_devflag = D_MP; +extern int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, int, pcibr_soft_t *); +extern void pcibr_driver_reg_callback(vertex_hdl_t, int, int, int); +extern void pcibr_driver_unreg_callback(vertex_hdl_t, int, int, int); -extern int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, int, pcibr_soft_t *); -extern void pcibr_driver_reg_callback(devfs_handle_t, int, int, int); -extern void pcibr_driver_unreg_callback(devfs_handle_t, int, int, int); - - -void -pic_init(void) -{ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pic_init()\n")); - - xwidget_driver_register(PIC_WIDGET_PART_NUM_BUS0, - PIC_WIDGET_MFGR_NUM, - "pic_", - 0); -} /* * copy inventory_t from conn_v to peer_conn_v */ int -pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) +pic_bus1_inventory_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v) { inventory_t *pinv, *peer_pinv; @@ -66,7 +52,7 @@ pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) (arbitrary_info_t *)&pinv) == GRAPH_SUCCESS) { NEW(peer_pinv); - bcopy(pinv, peer_pinv, sizeof(inventory_t)); + bcopy((const char *)pinv, (char *)peer_pinv, sizeof(inventory_t)); if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_INVENT, (arbitrary_info_t)peer_pinv) != GRAPH_SUCCESS) { DEL(peer_pinv); @@ -75,8 +61,7 @@ pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) return 1; } - printk("pic_bus1_inventory_dup: cannot get INFO_LBL_INVENT from 0x%lx\n ", - conn_v); + printk("pic_bus1_inventory_dup: cannot get INFO_LBL_INVENT from 0x%lx\n ", (uint64_t)conn_v); return 0; } @@ -84,13 +69,12 @@ pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) * copy xwidget_info_t from conn_v to peer_conn_v */ int -pic_bus1_widget_info_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v, +pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, cnodeid_t xbow_peer) { xwidget_info_t widget_info, peer_widget_info; char peer_path[256]; - char *p; - devfs_handle_t peer_hubv; + vertex_hdl_t peer_hubv; hubinfo_t peer_hub_info; /* get the peer hub's widgetid */ @@ -126,7 +110,7 @@ pic_bus1_widget_info_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v, } printk("pic_bus1_widget_info_dup: " - "cannot get INFO_LBL_XWIDGET from 0x%lx\n", conn_v); + "cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v); return 0; } @@ -138,15 +122,15 @@ pic_bus1_widget_info_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v, * If not successful, return zero and both buses will attach to the * vertex passed into pic_attach(). */ -devfs_handle_t -pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) +vertex_hdl_t +pic_bus1_redist(nasid_t nasid, vertex_hdl_t conn_v) { cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); cnodeid_t xbow_peer = -1; char pathname[256], peer_path[256], tmpbuf[256]; char *p; int rc; - devfs_handle_t peer_conn_v; + vertex_hdl_t peer_conn_v; int pos; slabid_t slab; @@ -155,7 +139,7 @@ pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) /* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */ /* sprintf(pathname, "%v", conn_v); */ xbow_peer = NASID_TO_COMPACT_NODEID(NODEPDA(cnode)->xbow_peer); - pos = devfs_generate_path(conn_v, tmpbuf, 256); + pos = hwgfs_generate_path(conn_v, tmpbuf, 256); strcpy(pathname, &tmpbuf[pos]); p = pathname + strlen("hw/module/001c01/slab/0/"); @@ -170,7 +154,7 @@ pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v); if (GRAPH_SUCCESS == rc) printk("pic_attach: found unexpected vertex: 0x%lx\n", - peer_conn_v); + (uint64_t)peer_conn_v); else if (GRAPH_NOT_FOUND != rc) { printk("pic_attach: hwgraph_traverse unexpectedly" " returned 0x%x\n", rc); @@ -208,13 +192,13 @@ pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) int -pic_attach(devfs_handle_t conn_v) +pic_attach(vertex_hdl_t conn_v) { int rc; bridge_t *bridge0, *bridge1 = (bridge_t *)0; - devfs_handle_t pcibr_vhdl0, pcibr_vhdl1 = (devfs_handle_t)0; + vertex_hdl_t pcibr_vhdl0, pcibr_vhdl1 = (vertex_hdl_t)0; pcibr_soft_t bus0_soft, bus1_soft = (pcibr_soft_t)0; - devfs_handle_t conn_v0, conn_v1, peer_conn_v; + vertex_hdl_t conn_v0, conn_v1, peer_conn_v; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n")); @@ -229,11 +213,11 @@ pic_attach(devfs_handle_t conn_v) conn_v0 = conn_v1 = conn_v; /* If dual-ported then split the two PIC buses across both Cbricks */ - if (peer_conn_v = pic_bus1_redist(NASID_GET(bridge0), conn_v)) + if ((peer_conn_v = (pic_bus1_redist(NASID_GET(bridge0), conn_v)))) conn_v1 = peer_conn_v; /* - * Create the vertex for the PCI buses, which week + * Create the vertex for the PCI buses, which we * will also use to hold the pcibr_soft and * which will be the "master" vertex for all the * pciio connection points we will hang off it. @@ -266,7 +250,6 @@ pic_attach(devfs_handle_t conn_v) /* save a pointer to the PIC's other bus's soft struct */ bus0_soft->bs_peers_soft = bus1_soft; bus1_soft->bs_peers_soft = bus0_soft; - bus0_soft->bs_peers_soft = (pcibr_soft_t)0; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach: bus0_soft=0x%x, bus1_soft=0x%x\n", @@ -294,10 +277,8 @@ pciio_provider_t pci_pic_provider = (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, (pciio_dmamap_free_f *) pcibr_dmamap_free, (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, (pciio_dmamap_done_f *) pcibr_dmamap_done, (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, (pciio_dmamap_drain_f *) pcibr_dmamap_drain, (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, (pciio_dmalist_drain_f *) pcibr_dmalist_drain, diff --git a/arch/ia64/sn/io/sn2/sgi_io_init.c b/arch/ia64/sn/io/sn2/sgi_io_init.c deleted file mode 100644 index ed1417ed456..00000000000 --- a/arch/ia64/sn/io/sn2/sgi_io_init.c +++ /dev/null @@ -1,226 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void mlreset(void); -extern int init_hcl(void); -extern void klgraph_hack_init(void); -extern void hubspc_init(void); -extern void pciio_init(void); -extern void pcibr_init(void); -extern void xtalk_init(void); -extern void xbow_init(void); -extern void xbmon_init(void); -extern void pciiox_init(void); -extern void pic_init(void); -extern void usrpci_init(void); -extern void ioc3_init(void); -extern void initialize_io(void); -extern void klhwg_add_all_modules(devfs_handle_t); -extern void klhwg_add_all_nodes(devfs_handle_t); - -void sn_mp_setup(void); -extern devfs_handle_t hwgraph_root; -extern void io_module_init(void); -extern void pci_bus_cvlink_init(void); -extern void temp_hack(void); - -extern int pci_bus_to_hcl_cvlink(void); - -/* #define DEBUG_IO_INIT 1 */ -#ifdef DEBUG_IO_INIT -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_IO_INIT */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - npdap = NODEPDA(cnode); - - REMOTE_HUB_S(nasid, IIO_IWEIM, 0x8000); - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ -#ifdef BRINGUP2 - REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - //REMOTE_HUB_S(nasid, IIO_IWI, 0x00FF00FF00FFFFFF); -#endif - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void -sgi_master_io_infr_init(void) -{ - int cnode; - extern void kdba_io_init(); - - /* - * Do any early init stuff .. einit_tbl[] etc. - */ - init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ - - /* - * initialize the Linux PCI to xwidget vertexes .. - */ - pci_bus_cvlink_init(); - - kdba_io_init(); - -#ifdef BRINGUP - /* - * Hack to provide statically initialzed klgraph entries. - */ - DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); - klgraph_hack_init(); -#endif /* BRINGUP */ - - /* - * This is the Master CPU. Emulate mlsetup and main.c in Irix. - */ - mlreset(); - - /* - * allowboot() is called by kern/os/main.c in main() - * Emulate allowboot() ... - * per_cpu_init() - only need per_hub_init() - * cpu_io_setup() - Nothing to do. - * - */ - sn_mp_setup(); - - for (cnode = 0; cnode < numnodes; cnode++) { - per_hub_init(cnode); - } - - /* We can do headless hub cnodes here .. */ - - /* - * io_init[] stuff. - * - * Get SGI IO Infrastructure drivers to init and register with - * each other etc. - */ - - hubspc_init(); - pciio_init(); - pcibr_init(); - pic_init(); - xtalk_init(); - xbow_init(); - xbmon_init(); - pciiox_init(); - usrpci_init(); - ioc3_init(); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - initialize_io(); - pci_bus_to_hcl_cvlink(); - -#ifdef CONFIG_PCIBA - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); -#ifndef BRINGUP2 - pciba_init(); -#endif -#endif -} - -/* - * One-time setup for MP SN. - * Allocate per-node data, slurp prom klconfig information and - * convert it to hwgraph information. - */ -void -sn_mp_setup(void) -{ - cpuid_t cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - io_module_init(); /* Use to be called module_init() .. */ - klhwg_add_all_modules(hwgraph_root); - klhwg_add_all_nodes(hwgraph_root); -} diff --git a/arch/ia64/sn/io/sn2/shub.c b/arch/ia64/sn/io/sn2/shub.c index ee48cd1eb34..9709c01cc27 100644 --- a/arch/ia64/sn/io/sn2/shub.c +++ b/arch/ia64/sn/io/sn2/shub.c @@ -97,6 +97,14 @@ shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val) } static inline void +shub_mmr_write_iospace(cnodeid_t cnode, shubreg_t reg, uint64_t val) +{ + int nasid = cnodeid_to_nasid(cnode); + + REMOTE_HUB_S(nasid, reg, val); +} + +static inline void shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val) { int nasid = cnodeid_to_nasid(cnode); @@ -118,6 +126,14 @@ shub_mmr_read(cnodeid_t cnode, shubreg_t reg) return val; } +static inline uint64_t +shub_mmr_read_iospace(cnodeid_t cnode, shubreg_t reg) +{ + int nasid = cnodeid_to_nasid(cnode); + + return REMOTE_HUB_L(nasid, reg); +} + static inline uint32_t shub_mmr_read32(cnodeid_t cnode, shubreg_t reg) { @@ -182,11 +198,9 @@ shubstats_ioctl(struct inode *inode, struct file *file, { cnodeid_t cnode; uint64_t longarg; - devfs_handle_t d; + vertex_hdl_t d; int nasid; - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; cnode = (cnodeid_t)hwgraph_fastinfo_get(d); switch (cmd) { @@ -231,3 +245,252 @@ shubstats_ioctl(struct inode *inode, struct file *file, struct file_operations shub_mon_fops = { ioctl: shubstats_ioctl, }; + +/* + * "linkstatd" kernel thread to export SGI Numalink + * stats via /proc/sgi_sn/linkstats + */ +static struct s_linkstats { + uint64_t hs_ni_sn_errors[2]; + uint64_t hs_ni_cb_errors[2]; + uint64_t hs_ni_retry_errors[2]; + int hs_ii_up; + uint64_t hs_ii_sn_errors; + uint64_t hs_ii_cb_errors; + uint64_t hs_ii_retry_errors; +} *sn_linkstats; + +static spinlock_t sn_linkstats_lock; +static unsigned long sn_linkstats_starttime; +static unsigned long sn_linkstats_samples; +static unsigned long sn_linkstats_overflows; +static unsigned long sn_linkstats_update_msecs; + +void +sn_linkstats_reset(unsigned long msecs) +{ + int cnode; + uint64_t iio_wstat; + uint64_t llp_csr_reg; + + spin_lock(&sn_linkstats_lock); + memset(sn_linkstats, 0, numnodes * sizeof(struct s_linkstats)); + for (cnode=0; cnode < numnodes; cnode++) { + shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L); + shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L); + shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L); + + /* zero the II retry counter */ + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */ + shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat); + + /* Check if the II xtalk link is working */ + llp_csr_reg = shub_mmr_read_iospace(cnode, IIO_LLP_CSR); + if (llp_csr_reg & IIO_LLP_CSR_IS_UP) + sn_linkstats[cnode].hs_ii_up = 1; + } + + sn_linkstats_update_msecs = msecs; + sn_linkstats_samples = 0; + sn_linkstats_overflows = 0; + sn_linkstats_starttime = jiffies; + spin_unlock(&sn_linkstats_lock); +} + +int +linkstatd_thread(void *unused) +{ + int cnode; + int overflows; + uint64_t reg[2]; + uint64_t iio_wstat = 0L; + ii_illr_u_t illr; + struct s_linkstats *lsp; + struct task_struct *tsk = current; + + daemonize("linkstatd"); + set_user_nice(tsk, 19); + sigfillset(&tsk->blocked); + strcpy(tsk->comm, "linkstatd"); + + while(1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(sn_linkstats_update_msecs * HZ / 1000); + + spin_lock(&sn_linkstats_lock); + + overflows = 0; + for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) { + reg[0] = shub_mmr_read(cnode, SH_NI0_LLP_ERR); + reg[1] = shub_mmr_read(cnode, SH_NI1_LLP_ERR); + if (lsp->hs_ii_up) { + illr = (ii_illr_u_t)shub_mmr_read_iospace(cnode, IIO_LLP_LOG); + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + } + + if (!overflows && ( + (reg[0] & SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK) == + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK || + (reg[0] & SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK) == + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK || + (reg[1] & SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK) == + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK || + (reg[1] & SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK) == + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK || + (lsp->hs_ii_up && illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) || + (lsp->hs_ii_up && illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX))) { + overflows = 1; + } + +#define LINKSTAT_UPDATE(reg, cnt, mask, shift) cnt += (reg & mask) >> shift + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_sn_errors[0], + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK, + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_sn_errors[1], + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK, + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_cb_errors[0], + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK, + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_cb_errors[1], + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK, + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_retry_errors[0], + SH_NI0_LLP_ERR_RETRY_COUNT_MASK, + SH_NI0_LLP_ERR_RETRY_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_retry_errors[1], + SH_NI1_LLP_ERR_RETRY_COUNT_MASK, + SH_NI1_LLP_ERR_RETRY_COUNT_SHFT); + + if (lsp->hs_ii_up) { + /* II sn and cb errors */ + lsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt; + lsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt; + lsp->hs_ii_retry_errors += (iio_wstat & 0x0000000000ff0000) >> 16; + + shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L); + shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L); + shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L); + + /* zero the II retry counter */ + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */ + shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat); + } + } + + sn_linkstats_samples++; + if (overflows) + sn_linkstats_overflows++; + + spin_unlock(&sn_linkstats_lock); + } +} + +static char * +rate_per_minute(uint64_t val, uint64_t secs) +{ + static char buf[16]; + uint64_t a=0, b=0, c=0, d=0; + + if (secs) { + a = 60 * val / secs; + b = 60 * 10 * val / secs - (10 * a); + c = 60 * 100 * val / secs - (100 * a) - (10 * b); + d = 60 * 1000 * val / secs - (1000 * a) - (100 * b) - (10 * c); + } + sprintf(buf, "%4lu.%lu%lu%lu", a, b, c, d); + + return buf; +} + +int +sn_linkstats_get(char *page) +{ + int n = 0; + int cnode; + int nlport; + struct s_linkstats *lsp; + nodepda_t *npda; + uint64_t snsum = 0; + uint64_t cbsum = 0; + uint64_t retrysum = 0; + uint64_t snsum_ii = 0; + uint64_t cbsum_ii = 0; + uint64_t retrysum_ii = 0; + uint64_t secs; + + spin_lock(&sn_linkstats_lock); + secs = (jiffies - sn_linkstats_starttime) / HZ; + + n += sprintf(page, "# SGI Numalink stats v1 : %lu samples, %lu o/flows, update %lu msecs\n", + sn_linkstats_samples, sn_linkstats_overflows, sn_linkstats_update_msecs); + + n += sprintf(page+n, "%-37s %8s %8s %8s %8s\n", + "# Numalink", "sn errs", "cb errs", "cb/min", "retries"); + + for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) { + npda = NODEPDA(cnode); + + /* two NL links on each SHub */ + for (nlport=0; nlport < 2; nlport++) { + cbsum += lsp->hs_ni_cb_errors[nlport]; + snsum += lsp->hs_ni_sn_errors[nlport]; + retrysum += lsp->hs_ni_retry_errors[nlport]; + + /* avoid buffer overrun (should be using seq_read API) */ + if (numnodes > 64) + continue; + + n += sprintf(page + n, "/%s/link/%d %8lu %8lu %8s %8lu\n", + npda->hwg_node_name, nlport+1, lsp->hs_ni_sn_errors[nlport], + lsp->hs_ni_cb_errors[nlport], + rate_per_minute(lsp->hs_ni_cb_errors[nlport], secs), + lsp->hs_ni_retry_errors[nlport]); + } + + /* one II port on each SHub (may not be connected) */ + if (lsp->hs_ii_up) { + n += sprintf(page + n, "/%s/xtalk %8lu %8lu %8s %8lu\n", + npda->hwg_node_name, lsp->hs_ii_sn_errors, + lsp->hs_ii_cb_errors, rate_per_minute(lsp->hs_ii_cb_errors, secs), + lsp->hs_ii_retry_errors); + + snsum_ii += lsp->hs_ii_sn_errors; + cbsum_ii += lsp->hs_ii_cb_errors; + retrysum_ii += lsp->hs_ii_retry_errors; + } + } + + n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n", + "System wide NL totals", snsum, cbsum, + rate_per_minute(cbsum, secs), retrysum); + + n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n", + "System wide II totals", snsum_ii, cbsum_ii, + rate_per_minute(cbsum_ii, secs), retrysum_ii); + + spin_unlock(&sn_linkstats_lock); + + return n; +} + +static int __init +linkstatd_init(void) +{ + spin_lock_init(&sn_linkstats_lock); + sn_linkstats = kmalloc(numnodes * sizeof(struct s_linkstats), GFP_KERNEL); + sn_linkstats_reset(60000UL); /* default 60 second update interval */ + kernel_thread(linkstatd_thread, NULL, CLONE_FS | CLONE_FILES); + + return 0; +} + +__initcall(linkstatd_init); diff --git a/arch/ia64/sn/io/sn2/shub_intr.c b/arch/ia64/sn/io/sn2/shub_intr.c index d64022e1cc1..f081c260f39 100644 --- a/arch/ia64/sn/io/sn2/shub_intr.c +++ b/arch/ia64/sn/io/sn2/shub_intr.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -30,7 +30,7 @@ /* ARGSUSED */ void -hub_intr_init(devfs_handle_t hubv) +hub_intr_init(vertex_hdl_t hubv) { } @@ -45,9 +45,9 @@ hub_widget_id(nasid_t nasid) } static hub_intr_t -do_hub_intr_alloc(devfs_handle_t dev, +do_hub_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, int uncond_nothread) { cpuid_t cpu = 0; @@ -71,7 +71,7 @@ do_hub_intr_alloc(devfs_handle_t dev, cpuphys = cpu_physical_id(cpu); slice = cpu_physical_id_to_slice(cpuphys); nasid = cpu_physical_id_to_nasid(cpuphys); - cnode = cpu_to_node_map[cpu]; + cnode = cpuid_to_cnodeid(cpu); if (slice) { xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47); @@ -101,17 +101,17 @@ do_hub_intr_alloc(devfs_handle_t dev, } hub_intr_t -hub_intr_alloc(devfs_handle_t dev, +hub_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); } hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, +hub_intr_alloc_nothd(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); } @@ -188,18 +188,3 @@ hub_intr_disconnect(hub_intr_t intr_hdl) ASSERT(rv == 0); intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; } - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl) -{ - cpuid_t cpuid = intr_hdl->i_cpuid; - - ASSERT(cpuid != CPU_NONE); - - return(cpuid_to_vertex(cpuid)); -} diff --git a/arch/ia64/sn/io/sn2/shuberror.c b/arch/ia64/sn/io/sn2/shuberror.c index 0861a3b0831..2469c553261 100644 --- a/arch/ia64/sn/io/sn2/shuberror.c +++ b/arch/ia64/sn/io/sn2/shuberror.c @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include #include #include @@ -27,28 +28,26 @@ #include #include #include +#include #include #include #include extern void hubni_eint_init(cnodeid_t cnode); extern void hubii_eint_init(cnodeid_t cnode); -extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); -int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); -extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); +extern irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +int hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); +int hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); +extern void bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); +void print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe); extern int maxcpus; +extern error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); #define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ -#ifdef BUS_INT_WAR -void sn_add_polled_interrupt(int irq, int interval); -void sn_delete_polled_interrupt(int irq); -extern int bus_int_war_ide_irq; -#endif - - void hub_error_clear(nasid_t nasid) { @@ -74,9 +73,7 @@ hub_error_clear(nasid_t nasid) REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); } - REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); - idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); - REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); + REMOTE_HUB_S(nasid, IIO_IECLR, -1); } @@ -117,7 +114,6 @@ hub_error_init(cnodeid_t cnode) * Returns : None. */ - void hubii_eint_init(cnodeid_t cnode) { @@ -125,33 +121,41 @@ hubii_eint_init(cnodeid_t cnode) ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; - devfs_handle_t hub_v; + vertex_hdl_t hub_v; int bit_pos_to_irq(int bit); + ii_ilcsr_u_t ilcsr; - hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); + hub_v = (vertex_hdl_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. Disable LLP. Clear old errors. + * Enable interrupts to handle BTE errors. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + } + /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ - intr_cpu = intr_heuristic(hub_v,0,-1,0,hub_v, + intr_cpu = intr_heuristic(hub_v,0,SGI_II_ERROR,0,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } - rv = intr_connect_level(intr_cpu, bit, 0, NULL); - request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN_hub_error", (void *)hub_v); - irq_desc(bit + (intr_cpu << 8))->status |= SN2_IRQ_PER_HUB; -#ifdef BUS_INT_WAR - sn_add_polled_interrupt(bit + (intr_cpu << 8), (0.01 * HZ)); -#endif + rv = intr_connect_level(intr_cpu, SGI_II_ERROR, 0, NULL); + request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); + irq_desc(bit)->status |= SN2_IRQ_PER_HUB; ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; @@ -164,21 +168,32 @@ hubii_eint_init(cnodeid_t cnode) /*ARGSUSED*/ -void +irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { - devfs_handle_t hub_v; + vertex_hdl_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; + ii_ilcsr_u_t ilcsr; /* two levels of casting avoids compiler warning.!! */ - hub_v = (devfs_handle_t)(long)(arg); + hub_v = (vertex_hdl_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); +#if 0 + if (idsr & 0x1) { + /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ + printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); + printk("***** Please file PV with the above messages *****\n"); + /* panic("We have to panic to prevent further unknown states ..\n"); */ + } +#endif + /* * Identify the reason for error. */ @@ -218,10 +233,26 @@ hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ - printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", - hinfo->h_cnodeid, reason); + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + if (ilcsr.ii_ilcsr_fld_s.i_llp_en == 1) { /* Link is enabled */ + printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_nasid, hinfo->h_cnodeid, reason); + } } + + /* + * Before processing any interrupt related information, clear all + * error indication and reenable interrupts. This will prevent + * lost interrupts due to the interrupt handler scanning past a PRB/CRB + * which has not errorred yet and then the PRB/CRB goes into error. + * Note, PRB errors are cleared individually. + */ + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xff0000); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); + + /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. @@ -232,14 +263,8 @@ hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); - /* - * If we reach here, it indicates crb/prb handlers successfully - * handled the error. So, re-enable II to send more interrupt - * and return. - */ - REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); - idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); + + return IRQ_HANDLED; } /* @@ -295,6 +320,105 @@ char *hubiio_crb_errors[] = { "Xtalk Error Packet" }; +void +print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe) +{ + printk("CRB %d regA\n\t" + "a_iow 0x%x\n\t" + "valid0x%x\n\t" + "Address0x%lx\n\t" + "a_tnum 0x%x\n\t" + "a_sidn 0x%x\n", + crb_num, + icrba.a_iow, + icrba.a_valid, + icrba.a_addr, + icrba.a_tnum, + icrba.a_sidn); + printk("CRB %d regB\n\t" + "b_imsgtype 0x%x\n\t" + "b_imsg 0x%x\n" + "\tb_use_old 0x%x\n\t" + "b_initiator 0x%x\n\t" + "b_exc 0x%x\n" + "\tb_ackcnt 0x%x\n\t" + "b_resp 0x%x\n\t" + "b_ack 0x%x\n" + "\tb_hold 0x%x\n\t" + "b_wb 0x%x\n\t" + "b_intvn 0x%x\n" + "\tb_stall_ib 0x%x\n\t" + "b_stall_int 0x%x\n" + "\tb_stall_bte_0 0x%x\n\t" + "b_stall_bte_1 0x%x\n" + "\tb_error 0x%x\n\t" + "b_lnetuce 0x%x\n\t" + "b_mark 0x%x\n\t" + "b_xerr 0x%x\n", + crb_num, + icrbb.b_imsgtype, + icrbb.b_imsg, + icrbb.b_use_old, + icrbb.b_initiator, + icrbb.b_exc, + icrbb.b_ackcnt, + icrbb.b_resp, + icrbb.b_ack, + icrbb.b_hold, + icrbb.b_wb, + icrbb.b_intvn, + icrbb.b_stall_ib, + icrbb.b_stall_int, + icrbb.b_stall_bte_0, + icrbb.b_stall_bte_1, + icrbb.b_error, + icrbb.b_lnetuce, + icrbb.b_mark, + icrbb.b_xerr); + printk("CRB %d regC\n\t" + "c_source 0x%x\n\t" + "c_xtsize 0x%x\n\t" + "c_cohtrans 0x%x\n\t" + "c_btenum 0x%x\n\t" + "c_gbr 0x%x\n\t" + "c_doresp 0x%x\n\t" + "c_barrop 0x%x\n\t" + "c_suppl 0x%x\n", + crb_num, + icrbc.c_source, + icrbc.c_xtsize, + icrbc.c_cohtrans, + icrbc.c_btenum, + icrbc.c_gbr, + icrbc.c_doresp, + icrbc.c_barrop, + icrbc.c_suppl); + printk("CRB %d regD\n\t" + "d_bteaddr 0x%lx\n\t" + "d_bteop 0x%x\n\t" + "d_pripsc 0x%x\n\t" + "d_pricnt 0x%x\n\t" + "d_sleep 0x%x\n\t", + crb_num, + icrbd.d_bteaddr, + icrbd.d_bteop, + icrbd.d_pripsc, + icrbd.d_pricnt, + icrbd.d_sleep); + printk("CRB %d regE\n\t" + "icrbe_timeout 0x%x\n\t" + "icrbe_context 0x%x\n\t" + "icrbe_toutvld 0x%x\n\t" + "icrbe_ctxtvld 0x%x\n\t", + crb_num, + icrbe.icrbe_timeout, + icrbe.icrbe_context, + icrbe.icrbe_toutvld, + icrbe.icrbe_ctxtvld); +} + /* * hubiio_crb_error_handler * @@ -317,7 +441,7 @@ char *hubiio_crb_errors[] = { */ int -hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { cnodeid_t cnode; nasid_t nasid; @@ -335,6 +459,9 @@ hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) cnode = NASID_TO_COMPACT_NODEID(nasid); /* + * XXX - Add locking for any recovery actions + */ + /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ @@ -373,16 +500,11 @@ hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; - /* >>> bte_crb_error_handler needs to be - * broken into two parts. The first should - * cleanup the CRB. The second should wait - * until all bte related CRB's are complete - * and then do the error reset. - */ + hubiio_crb_free(hinfo, i); + bte_crb_error_handler(hub_v, bte_num, i, &ioerror, icrbd.d_bteop); - hubiio_crb_free(hinfo, i); num_errors++; continue; } @@ -430,6 +552,86 @@ hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); } + if (icrbb.b_error) { + /* + * CRB 'i' has some error. Identify the type of error, + * and try to handle it. + * + */ + switch(icrbb.b_ecode) { + case IIO_ICRB_ECODE_PERR: + case IIO_ICRB_ECODE_WERR: + case IIO_ICRB_ECODE_AERR: + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_TOUT: + case IIO_ICRB_ECODE_XTERR: + printk("Shub II CRB %d: error %s on hub cnodeid: %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* + * Any sort of write error is mostly due + * bad programming (Note it's not a timeout.) + * So, invoke hub_iio_error_handler with + * appropriate information. + */ + IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + + /* Go through the error bit lookup phase */ + if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVERROR, + &ioerror); + if (rc == IOERROR_HANDLED) { + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVREENABLE, + &ioerror); + }else { + printk("Unable to handle %s on hub %d", + hubiio_crb_errors[icrbb.b_ecode], + cnode); + /* panic; */ + } + /* Go to Next error */ + print_crb_fields(i, icrba, icrbb, icrbc, + icrbd, icrbe); + hubiio_crb_free(hinfo, i); + continue; + case IIO_ICRB_ECODE_PRERR: + case IIO_ICRB_ECODE_DERR: + printk("Shub II CRB %d: error %s on hub : %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* panic */ + default: + printk("Shub II CRB error (code : %d) on hub : %d", + icrbb.b_ecode, cnode); + /* panic */ + } + } + /* + * Error is not indicated via the errcode field + * Check other error indications in this register. + */ + if (icrbb.b_xerr) { + printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", + i, cnode); + /* panic */ + } + if (icrbb.b_lnetuce) { + printk("Shub II CRB %d: Uncorrectable data error detected on data " + " from NUMAlink to node %d", + i, cnode); + /* panic */ + } + print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); + + + + if (icrbb.b_error) { /* @@ -488,7 +690,7 @@ hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) default: panic("Fatal error (code : %d) on hub : %d", - cnode); + icrbb.b_ecode, cnode); /*NOTREACHED*/ } @@ -568,7 +770,7 @@ hubii_check_widget_disabled(nasid_t nasid, int wnum) * Cleanup involes freeing the PRB register */ static void -hubii_prb_handler(devfs_handle_t hub_v, hubinfo_t hinfo, int wnum) +hubii_prb_handler(vertex_hdl_t hub_v, hubinfo_t hinfo, int wnum) { nasid_t nasid; @@ -576,13 +778,13 @@ hubii_prb_handler(devfs_handle_t hub_v, hubinfo_t hinfo, int wnum) /* * Clear error bit by writing to IECLR register. */ - REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, (1 << wnum)); + REMOTE_HUB_S(nasid, IIO_IECLR, (1 << wnum)); /* * PIO Write to Widget 'i' got into an error. * Invoke hubiio_error_handler with this information. */ - printk( "Hub nasid %d got a PIO Write error from widget %d, cleaning up and continuing", - nasid, wnum); + printk( "Hub nasid %d got a PIO Write error from widget %d, " + "cleaning up and continuing", nasid, wnum); /* * XXX * It may be necessary to adjust IO PRB counter @@ -591,7 +793,7 @@ hubii_prb_handler(devfs_handle_t hub_v, hubinfo_t hinfo, int wnum) } int -hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { int wnum; nasid_t nasid; diff --git a/arch/ia64/sn/io/sn2/shubio.c b/arch/ia64/sn/io/sn2/shubio.c index 90294319bf0..676498ec0a0 100644 --- a/arch/ia64/sn/io/sn2/shubio.c +++ b/arch/ia64/sn/io/sn2/shubio.c @@ -30,8 +30,8 @@ #include -error_state_t error_state_get(devfs_handle_t v); -error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state); +error_state_t error_state_get(vertex_hdl_t v); +error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); /* @@ -42,7 +42,7 @@ error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state); /*ARGSUSED*/ int hub_xp_error_handler( - devfs_handle_t hub_v, + vertex_hdl_t hub_v, nasid_t nasid, int error_code, ioerror_mode_t mode, @@ -50,7 +50,7 @@ hub_xp_error_handler( { /*REFERENCED*/ hubreg_t iio_imem; - devfs_handle_t xswitch; + vertex_hdl_t xswitch; error_state_t e_state; cnodeid_t cnode; @@ -148,7 +148,7 @@ is_widget_pio_enabled(ioerror_t *ioerror) */ int hub_ioerror_handler( - devfs_handle_t hub_v, + vertex_hdl_t hub_v, int error_code, int mode, struct io_error_s *ioerror) @@ -158,6 +158,7 @@ hub_ioerror_handler( int retval = 0; /*REFERENCED*/ iopaddr_t p; + caddr_t cp; IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror); @@ -193,14 +194,14 @@ hub_ioerror_handler( * This is typically true for user mode bus errors while * accessing I/O space. */ - IOERROR_GETVALUE(p,ioerror,vaddr); - if (p){ + IOERROR_GETVALUE(cp,ioerror,vaddr); + if (cp){ /* * If neither in small window nor in large window range, * outright reject it. */ - IOERROR_GETVALUE(p,ioerror,vaddr); - if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){ + IOERROR_GETVALUE(cp,ioerror,vaddr); + if (NODE_SWIN_ADDR(nasid, (paddr_t)cp)){ iopaddr_t hubaddr; xwidgetnum_t widgetnum; iopaddr_t xtalkaddr; @@ -216,7 +217,7 @@ hub_ioerror_handler( IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); - } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){ + } else if (NODE_BWIN_ADDR(nasid, (paddr_t)cp)){ /* * Address corresponds to large window space. * Convert it to xtalk address. @@ -428,11 +429,6 @@ end: return retval; } -#define L_BITSMINOR 18 -#define L_MAXMAJ 0x1ff -#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ) -#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0) - #define INFO_LBL_ERROR_STATE "error_state" #define v_error_state_get(v,s) \ @@ -454,12 +450,12 @@ hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s)) * current state otherwise */ error_state_t -error_state_get(devfs_handle_t v) +error_state_get(vertex_hdl_t v) { error_state_t s; /* Check if we have a valid hwgraph vertex */ - if (!dev_is_vertex(v)) + if ( v == (vertex_hdl_t)0 ) return(ERROR_STATE_NONE); /* Get the labelled info hanging off the vertex which corresponds @@ -479,13 +475,13 @@ error_state_get(devfs_handle_t v) * ERROR_RETURN_CODE_SUCCESS otherwise */ error_return_code_t -error_state_set(devfs_handle_t v,error_state_t new_state) +error_state_set(vertex_hdl_t v,error_state_t new_state) { error_state_t old_state; boolean_t replace = B_TRUE; /* Check if we have a valid hwgraph vertex */ - if (!dev_is_vertex(v)) + if ( v == (vertex_hdl_t)0 ) return(ERROR_RETURN_CODE_GENERAL_FAILURE); diff --git a/arch/ia64/sn/io/sn2/xbow.c b/arch/ia64/sn/io/sn2/xbow.c index dd28e1158d1..2afe2ce0c2a 100644 --- a/arch/ia64/sn/io/sn2/xbow.c +++ b/arch/ia64/sn/io/sn2/xbow.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -45,8 +45,6 @@ #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) #define DEL(ptr) (kfree(ptr)) -int xbow_devflag = D_MP; - /* * This file supports the Xbow chip. Main functions: initializtion, * error handling, and GBR. @@ -60,9 +58,9 @@ int xbow_devflag = D_MP; typedef struct xbow_soft_s *xbow_soft_t; struct xbow_soft_s { - devfs_handle_t conn; /* our connection point */ - devfs_handle_t vhdl; /* xbow's private vertex */ - devfs_handle_t busv; /* the xswitch vertex */ + vertex_hdl_t conn; /* our connection point */ + vertex_hdl_t vhdl; /* xbow's private vertex */ + vertex_hdl_t busv; /* the xswitch vertex */ xbow_t *base; /* PIO pointer to crossbow chip */ char *name; /* hwgraph name */ @@ -90,36 +88,27 @@ struct xbow_soft_s { */ void xbow_mlreset(xbow_t *); -void xbow_init(void); -int xbow_attach(devfs_handle_t); - -int xbow_open(devfs_handle_t *, int, int, cred_t *); -int xbow_close(devfs_handle_t, int, int, cred_t *); - -int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int xbow_unmap(devfs_handle_t, vhandl_t *); -int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); +int xbow_attach(vertex_hdl_t); int xbow_widget_present(xbow_t *, int); static int xbow_link_alive(xbow_t *, int); -devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); +vertex_hdl_t xbow_widget_lookup(vertex_hdl_t, int); void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void xbow_update_perf_counters(devfs_handle_t); -xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -int xbow_enable_perf_counter(devfs_handle_t, int, int, int); -xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); -void xbow_update_llp_status(devfs_handle_t); +void xbow_update_perf_counters(vertex_hdl_t); +xbow_perf_link_t *xbow_get_perf_counters(vertex_hdl_t); +int xbow_enable_perf_counter(vertex_hdl_t, int, int, int); +xbow_link_status_t *xbow_get_llp_status(vertex_hdl_t); +void xbow_update_llp_status(vertex_hdl_t); -int xbow_disable_llp_monitor(devfs_handle_t); -int xbow_enable_llp_monitor(devfs_handle_t); -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, +int xbow_disable_llp_monitor(vertex_hdl_t); +int xbow_enable_llp_monitor(vertex_hdl_t); +int xbow_prio_bw_alloc(vertex_hdl_t, xwidgetnum_t, xwidgetnum_t, unsigned long long, unsigned long long); static void xbow_setwidint(xtalk_intr_t); -void idbg_xbowregs(int64_t); xswitch_reset_link_f xbow_reset_link; @@ -128,32 +117,6 @@ xswitch_provider_t xbow_provider = xbow_reset_link, }; -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -static int xbow_mmap(struct file * file, struct vm_area_struct * vma); -struct file_operations xbow_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: xbow_mmap, - open: xbow_open, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL, - sendpage: NULL, - get_unmapped_area: NULL -}; static int xbow_mmap(struct file * file, struct vm_area_struct * vma) @@ -164,12 +127,21 @@ xbow_mmap(struct file * file, struct vm_area_struct * vma) phys_addr = (unsigned long)file->private_data & ~0xc000000000000000; /* Mask out the Uncache bits */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED | VM_IO; - error = io_remap_page_range(vma, vma->vm_start, phys_addr, - vma->vm_end - vma->vm_start, + error = io_remap_page_range(vma, phys_addr, vma->vm_start, + vma->vm_end-vma->vm_start, vma->vm_page_prot); return(error); } +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations xbow_fops = { + .owner = THIS_MODULE, + .mmap = xbow_mmap, +}; /* * xbow_mlreset: called at mlreset time if the @@ -188,39 +160,6 @@ xbow_mlreset(xbow_t * xbow) { } -/* - * xbow_init: called with the rest of the device - * driver XXX_init routines. This platform *might* - * have a Crossbow chip, or even several, but it - * might have none. Register with the crosstalk - * generic provider so when we encounter the chip - * the right magic happens. - */ -void -xbow_init(void) -{ - -#if DEBUG && ATTACH_DEBUG - printk("xbow_init\n"); -#endif - - xwidget_driver_register(PXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - - xwidget_driver_register(XXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - xwidget_driver_register(XBOW_WIDGET_PART_NUM, - XBOW_WIDGET_MFGR_NUM, - "xbow_", - CDL_PRI_HI); /* attach before friends */ -} - #ifdef XBRIDGE_REGS_SIM /* xbow_set_simulated_regs: sets xbow regs as needed * for powering through the boot @@ -257,11 +196,11 @@ xbow_set_simulated_regs(xbow_t *xbow, int port) /*ARGSUSED */ int -xbow_attach(devfs_handle_t conn) +xbow_attach(vertex_hdl_t conn) { /*REFERENCED */ - devfs_handle_t vhdl; - devfs_handle_t busv; + vertex_hdl_t vhdl; + vertex_hdl_t busv; xbow_t *xbow; xbow_soft_t soft; int port; @@ -322,10 +261,10 @@ xbow_attach(devfs_handle_t conn) * file ops. */ vhdl = NULL; - vhdl = devfs_register(conn, EDGE_LBL_XBOW, - DEVFS_FL_AUTO_DEVNUM, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &xbow_fops, (void *)xbow); + vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, 0, + 0, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + (struct file_operations *)&xbow_fops, (void *)xbow); if (!vhdl) { printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", (void *)conn); @@ -393,6 +332,14 @@ xbow_attach(devfs_handle_t conn) */ intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl); ASSERT(intr_hdl != NULL); + + { + int irq = ((hub_intr_t)intr_hdl)->i_bit; + int cpu = ((hub_intr_t)intr_hdl)->i_cpuid; + + intr_unreserve_level(cpu, irq); + ((hub_intr_t)intr_hdl)->i_bit = SGI_XBOW_ERROR; + } xtalk_intr_connect(intr_hdl, (intr_func_t) xbow_errintr_handler, @@ -400,19 +347,9 @@ xbow_attach(devfs_handle_t conn) (xtalk_intr_setfunc_t) xbow_setwidint, (void *) xbow); - request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, - ((hub_intr_t)intr_hdl)->i_bit), - (intr_func_t)xbow_errintr_handler, 0, "XBOW error", + request_irq(SGI_XBOW_ERROR, (void *)xbow_errintr_handler, SA_SHIRQ, "XBOW error", (intr_arg_t) soft); -#ifdef BUS_INT_WAR_NOT_YET - { - void sn_add_polled_interrupt(int, int); - sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, - ((hub_intr_t)intr_hdl)->i_bit), 5000); - } -#endif - /* * Enable xbow error interrupts @@ -482,50 +419,14 @@ xbow_attach(devfs_handle_t conn) return 0; /* attach successful */ } -/*ARGSUSED */ -int -xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - xbow_soft_t soft = xbow_soft_get(vhdl); - int error; - - ASSERT(soft); - len = ctob(btoc(len)); - /* XXX- this ignores the offset!!! */ - error = v_mapphys(vt, (void *) soft->base, len); - return error; -} - -/*ARGSUSED */ -int -xbow_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - /* This contains special-case code for grio. There are plans to make * this general sometime in the future, but till then this should * be good enough. */ xwidgetnum_t -xbow_widget_num_get(devfs_handle_t dev) +xbow_widget_num_get(vertex_hdl_t dev) { - devfs_handle_t tdev; + vertex_hdl_t tdev; char devname[MAXDEVNAME]; xwidget_info_t xwidget_info; int i; @@ -555,58 +456,6 @@ xbow_widget_num_get(devfs_handle_t dev) return XWIDGET_NONE; } -int -xbow_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t vhdl; - int error = 0; - -#if defined (DEBUG) - int rc; - devfs_handle_t conn; - struct xwidget_info_s *xwidget_info; - xbow_soft_t xbow_soft; -#endif - *rvalp = 0; - - vhdl = dev_to_vhdl(dev); -#if defined (DEBUG) - xbow_soft = xbow_soft_get(vhdl); - conn = xbow_soft->conn; - - xwidget_info = xwidget_info_get(conn); - ASSERT_ALWAYS(xwidget_info != NULL); - - rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); - ASSERT_ALWAYS(rc != 0); -#endif - switch (cmd) { - - case XBOWIOC_LLP_ERROR_ENABLE: - if ((error = xbow_enable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - case XBOWIOC_LLP_ERROR_DISABLE: - - if ((error = xbow_disable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - default: - break; - - } - return error; -} - /* * xbow_widget_present: See if a device is present * on the specified port of this crossbow. @@ -648,12 +497,12 @@ xbow_link_alive(xbow_t * xbow, int port) * specified. * If not found, return 0. */ -devfs_handle_t -xbow_widget_lookup(devfs_handle_t vhdl, +vertex_hdl_t +xbow_widget_lookup(vertex_hdl_t vhdl, int widgetnum) { xswitch_info_t xswitch_info; - devfs_handle_t conn; + vertex_hdl_t conn; xswitch_info = xswitch_info_get(vhdl); conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); @@ -713,48 +562,14 @@ xbow_intr_preset(void *which_widget, XEM_ADD_NVAR("ioe." #n, p); \ } -#ifdef LATER -static void -xem_add_ioe(ioerror_t *ioe) -{ - union tmp { - ushort stmp; - unsigned long long lltmp; - cpuid_t cputmp; - cnodeid_t cntmp; - iopaddr_t iotmp; - caddr_t catmp; - paddr_t patmp; - } tmp; - - XEM_ADD_IOEF(tmp.stmp, errortype); - XEM_ADD_IOEF(tmp.stmp, widgetnum); - XEM_ADD_IOEF(tmp.stmp, widgetdev); - XEM_ADD_IOEF(tmp.cputmp, srccpu); - XEM_ADD_IOEF(tmp.cntmp, srcnode); - XEM_ADD_IOEF(tmp.cntmp, errnode); - XEM_ADD_IOEF(tmp.iotmp, sysioaddr); - XEM_ADD_IOEF(tmp.iotmp, xtalkaddr); - XEM_ADD_IOEF(tmp.iotmp, busspace); - XEM_ADD_IOEF(tmp.iotmp, busaddr); - XEM_ADD_IOEF(tmp.catmp, vaddr); - XEM_ADD_IOEF(tmp.patmp, memaddr); - XEM_ADD_IOEF(tmp.catmp, epc); - XEM_ADD_IOEF(tmp.catmp, ef); - XEM_ADD_IOEF(tmp.stmp, tnum); -} - -#define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* LATER */ - -int xbow_xmit_retry_errors = 0; +int xbow_xmit_retry_errors; int xbow_xmit_retry_error(xbow_soft_t soft, int port) { xswitch_info_t info; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; widget_cfg_t *wid; widgetreg_t id; int part; @@ -904,7 +719,7 @@ xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep) link_pend &= ~XB_STAT_XMT_RTRY_ERR; } if (link_pend) { - devfs_handle_t xwidget_vhdl; + vertex_hdl_t xwidget_vhdl; char *xwidget_name; /* Get the widget name corresponding to the current @@ -956,12 +771,6 @@ xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep) XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status); -#ifdef LATER - if (dump_ioe) { - XEM_ADD_IOE(); - dump_ioe = 0; - } -#endif #if !DEBUG } #endif @@ -1026,8 +835,8 @@ xbow_error_handler( xbow_soft_t soft = (xbow_soft_t) einfo; int port; - devfs_handle_t conn; - devfs_handle_t busv; + vertex_hdl_t conn; + vertex_hdl_t busv; xbow_t *xbow = soft->base; xbowreg_t wid_stat; @@ -1279,7 +1088,7 @@ xbow_error_handler( } void -xbow_update_perf_counters(devfs_handle_t vhdl) +xbow_update_perf_counters(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; @@ -1307,7 +1116,7 @@ xbow_update_perf_counters(devfs_handle_t vhdl) } xbow_perf_link_t * -xbow_get_perf_counters(devfs_handle_t vhdl) +xbow_get_perf_counters(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; @@ -1316,7 +1125,7 @@ xbow_get_perf_counters(devfs_handle_t vhdl) } int -xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) +xbow_enable_perf_counter(vertex_hdl_t vhdl, int link, int mode, int counter) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; @@ -1370,7 +1179,7 @@ xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) } xbow_link_status_t * -xbow_get_llp_status(devfs_handle_t vhdl) +xbow_get_llp_status(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; @@ -1379,7 +1188,7 @@ xbow_get_llp_status(devfs_handle_t vhdl) } void -xbow_update_llp_status(devfs_handle_t vhdl) +xbow_update_llp_status(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; @@ -1387,7 +1196,7 @@ xbow_update_llp_status(devfs_handle_t vhdl) xbwX_stat_t lnk_sts; xbow_aux_link_status_t aux_sts; int link; - devfs_handle_t xwidget_vhdl; + vertex_hdl_t xwidget_vhdl; char *xwidget_name; xbow = (xbow_t *) xbow_soft->base; @@ -1421,7 +1230,7 @@ xbow_update_llp_status(devfs_handle_t vhdl) } int -xbow_disable_llp_monitor(devfs_handle_t vhdl) +xbow_disable_llp_monitor(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); int port; @@ -1436,7 +1245,7 @@ xbow_disable_llp_monitor(devfs_handle_t vhdl) } int -xbow_enable_llp_monitor(devfs_handle_t vhdl) +xbow_enable_llp_monitor(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); @@ -1446,7 +1255,7 @@ xbow_enable_llp_monitor(devfs_handle_t vhdl) int -xbow_reset_link(devfs_handle_t xconn_vhdl) +xbow_reset_link(vertex_hdl_t xconn_vhdl) { xwidget_info_t widget_info; xwidgetnum_t port; @@ -1469,7 +1278,7 @@ xbow_reset_link(devfs_handle_t xconn_vhdl) xbow = XBOW_K1PTR; #else { - devfs_handle_t xbow_vhdl; + vertex_hdl_t xbow_vhdl; xbow_soft_t xbow_soft; hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); @@ -1502,46 +1311,6 @@ xbow_reset_link(devfs_handle_t xconn_vhdl) return 0; } -/* - * Dump xbow registers. - * input parameter is either a pointer to - * the xbow chip or the vertex handle for - * an xbow vertex. - */ -void -idbg_xbowregs(int64_t regs) -{ - xbow_t *xbow; - int i; - xb_linkregs_t *link; - - xbow = (xbow_t *) regs; - -#ifdef LATER - qprintf("Printing xbow registers starting at 0x%x\n", xbow); - qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", - xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, - xbow->xb_wid_err_lower, xbow->xb_wid_control, - xbow->xb_wid_req_timeout); - qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", - xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, - xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, - xbow->xb_wid_arb_reload); -#endif - - for (i = 8; i <= 0xf; i++) { - link = &xbow->xb_link(i); -#ifdef LATER - qprintf("Link %d registers\n", i); - qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", - link->link_control, link->link_status, - link->link_arb_upper, link->link_arb_lower, - link->link_aux_status); -#endif - } -} - - #define XBOW_ARB_RELOAD_TICKS 25 /* granularity: 4 MB/s, max: 124 MB/s */ #define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) @@ -1601,7 +1370,7 @@ xbow_gbr_to_bytes(int gbr) * If bandwidth allocation is successful, return success else return failure. */ int -xbow_prio_bw_alloc(devfs_handle_t vhdl, +xbow_prio_bw_alloc(vertex_hdl_t vhdl, xwidgetnum_t src_wid, xwidgetnum_t dest_wid, unsigned long long old_alloc_bw, diff --git a/arch/ia64/sn/io/sn2/xtalk.c b/arch/ia64/sn/io/sn2/xtalk.c index ac9988596bf..fbcec3e395e 100644 --- a/arch/ia64/sn/io/sn2/xtalk.c +++ b/arch/ia64/sn/io/sn2/xtalk.c @@ -37,8 +37,6 @@ char widget_info_fingerprint[] = "widget_info"; -cdl_p xtalk_registry = NULL; - #define DEV_FUNC(dev,func) hub_##func #define CAST_PIOMAP(x) ((hub_piomap_t)(x)) #define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) @@ -47,71 +45,70 @@ cdl_p xtalk_registry = NULL; /* ===================================================================== * Function Table of Contents */ -xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); +xtalk_piomap_t xtalk_piomap_alloc(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); void xtalk_piomap_free(xtalk_piomap_t); caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); +caddr_t xtalk_piotrans_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, unsigned); +caddr_t xtalk_pio_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +xtalk_dmamap_t xtalk_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void xtalk_dmamap_free(xtalk_dmamap_t); iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +iopaddr_t xtalk_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t xtalk_dmatrans_list(vertex_hdl_t, device_desc_t, alenlist_t, unsigned); void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); -xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); -xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); +void xtalk_dmaaddr_drain(vertex_hdl_t, iopaddr_t, size_t); +void xtalk_dmalist_drain(vertex_hdl_t, alenlist_t); +xtalk_intr_t xtalk_intr_alloc(vertex_hdl_t, device_desc_t, vertex_hdl_t); +xtalk_intr_t xtalk_intr_alloc_nothd(vertex_hdl_t, device_desc_t, vertex_hdl_t); void xtalk_intr_free(xtalk_intr_t); int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *); void xtalk_intr_disconnect(xtalk_intr_t); -devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int xtalk_error_devenable(devfs_handle_t, int, int); -void xtalk_provider_startup(devfs_handle_t); -void xtalk_provider_shutdown(devfs_handle_t); -devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); +vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t); +int xtalk_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); +int xtalk_error_devenable(vertex_hdl_t, int, int); +void xtalk_provider_startup(vertex_hdl_t); +void xtalk_provider_shutdown(vertex_hdl_t); +vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t); xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); void *xtalk_intr_sfarg_get(xtalk_intr_t); -devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); +vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t); xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); ulong xtalk_pio_mapsz_get(xtalk_piomap_t); caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); +vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t); xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(devfs_handle_t); -xwidget_info_t xwidget_info_get(devfs_handle_t); -void xwidget_info_set(devfs_handle_t, xwidget_info_t); -devfs_handle_t xwidget_info_dev_get(xwidget_info_t); +xwidget_info_t xwidget_info_chk(vertex_hdl_t); +xwidget_info_t xwidget_info_get(vertex_hdl_t); +void xwidget_info_set(vertex_hdl_t, xwidget_info_t); +vertex_hdl_t xwidget_info_dev_get(xwidget_info_t); xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -devfs_handle_t xwidget_info_master_get(xwidget_info_t); +vertex_hdl_t xwidget_info_master_get(xwidget_info_t); xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); char *xwidget_info_name_get(xwidget_info_t); -void xtalk_init(void); -void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); -void xtalk_provider_unregister(devfs_handle_t); -xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); +void xtalk_provider_register(vertex_hdl_t, xtalk_provider_t *); +void xtalk_provider_unregister(vertex_hdl_t); +xtalk_provider_t *xtalk_provider_fns_get(vertex_hdl_t); int xwidget_driver_register(xwidget_part_num_t, xwidget_mfg_num_t, char *, unsigned); void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, devfs_handle_t, - xwidgetnum_t, devfs_handle_t, - xwidgetnum_t, async_attach_t); -int xwidget_unregister(devfs_handle_t); -void xwidget_reset(devfs_handle_t); -char *xwidget_name_get(devfs_handle_t); +int xwidget_register(xwidget_hwid_t, vertex_hdl_t, + xwidgetnum_t, vertex_hdl_t, + xwidgetnum_t); +int xwidget_unregister(vertex_hdl_t); +void xwidget_reset(vertex_hdl_t); +char *xwidget_name_get(vertex_hdl_t); #if !defined(DEV_FUNC) /* * There is more than one possible provider @@ -126,7 +123,7 @@ char *xwidget_name_get(devfs_handle_t); #define CAST_INTR(x) ((xtalk_intr_t)(x)) static xtalk_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) +xwidget_to_provider_fns(vertex_hdl_t xconn) { xwidget_info_t widget_info; xtalk_provider_t *provider_fns; @@ -159,7 +156,7 @@ xwidget_to_provider_fns(devfs_handle_t xconn) */ xtalk_piomap_t -xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +xtalk_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -198,7 +195,7 @@ xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) caddr_t -xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -209,7 +206,7 @@ xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ } caddr_t -xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_pio_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t addr, /* starting address (or offset in window) */ size_t byte_count, /* map this many bytes */ @@ -326,7 +323,7 @@ null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, */ xtalk_dmamap_t -xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ +xtalk_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) @@ -373,7 +370,7 @@ xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) iopaddr_t -xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -385,7 +382,7 @@ xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ alenlist_t -xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_list(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags) @@ -402,14 +399,14 @@ xtalk_dmamap_drain(xtalk_dmamap_t map) } void -xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +xtalk_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) { DEV_FUNC(dev, dmaaddr_drain) (dev, addr, size); } void -xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) +xtalk_dmalist_drain(vertex_hdl_t dev, alenlist_t list) { DEV_FUNC(dev, dmalist_drain) (dev, list); @@ -426,9 +423,9 @@ xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) * Return resource handle in intr_hdl. */ xtalk_intr_t -xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ +xtalk_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { /* owner of this interrupt */ return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) (dev, dev_desc, owner_dev); @@ -440,9 +437,9 @@ xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ * Return resource handle in intr_hdl. */ xtalk_intr_t -xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ +xtalk_intr_alloc_nothd(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt */ + vertex_hdl_t owner_dev) /* owner of this interrupt */ { return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) (dev, dev_desc, owner_dev); @@ -492,11 +489,10 @@ xtalk_intr_disconnect(xtalk_intr_t intr_hdl) * Return a hwgraph vertex that represents the CPU currently * targeted by an interrupt. */ -devfs_handle_t +vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) { - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); + return (vertex_hdl_t)0; } @@ -526,7 +522,7 @@ xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) */ int xtalk_error_handler( - devfs_handle_t xconn, + vertex_hdl_t xconn, int error_code, ioerror_mode_t mode, ioerror_t *ioerror) @@ -555,7 +551,7 @@ xtalk_error_handler( #if defined(SUPPORT_PRINTING_V_FORMAT) printk(KERN_WARNING "Xbow at %v encountered Fatal error", xconn); #else - printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", xconn); + printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", (void *)xconn); #endif ioerror_dump("xtalk", error_code, mode, ioerror); @@ -563,7 +559,7 @@ xtalk_error_handler( } int -xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +xtalk_error_devenable(vertex_hdl_t xconn_vhdl, int devnum, int error_code) { return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code); } @@ -577,7 +573,7 @@ xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) * Startup a crosstalk provider */ void -xtalk_provider_startup(devfs_handle_t xtalk_provider) +xtalk_provider_startup(vertex_hdl_t xtalk_provider) { DEV_FUNC(xtalk_provider, provider_startup) (xtalk_provider); @@ -588,7 +584,7 @@ xtalk_provider_startup(devfs_handle_t xtalk_provider) * Shutdown a crosstalk provider */ void -xtalk_provider_shutdown(devfs_handle_t xtalk_provider) +xtalk_provider_shutdown(vertex_hdl_t xtalk_provider) { DEV_FUNC(xtalk_provider, provider_shutdown) (xtalk_provider); @@ -598,22 +594,22 @@ xtalk_provider_shutdown(devfs_handle_t xtalk_provider) * Enable a device on a xtalk widget */ void -xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) +xtalk_widgetdev_enable(vertex_hdl_t xconn_vhdl, int devnum) { - DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); + return; } /* * Shutdown a device on a xtalk widget */ void -xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) +xtalk_widgetdev_shutdown(vertex_hdl_t xconn_vhdl, int devnum) { - DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); + return; } int -xtalk_dma_enabled(devfs_handle_t xconn_vhdl) +xtalk_dma_enabled(vertex_hdl_t xconn_vhdl) { return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); } @@ -623,7 +619,7 @@ xtalk_dma_enabled(devfs_handle_t xconn_vhdl) */ /****** Generic crosstalk interrupt interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) { return (xtalk_intr->xi_dev); @@ -654,7 +650,7 @@ xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) } /****** Generic crosstalk pio interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) { return (xtalk_piomap->xp_dev); @@ -686,7 +682,7 @@ xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) /****** Generic crosstalk dma interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) { return (xtalk_dmamap->xd_dev); @@ -707,7 +703,7 @@ xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) * if not, return NULL. */ xwidget_info_t -xwidget_info_chk(devfs_handle_t xwidget) +xwidget_info_chk(vertex_hdl_t xwidget) { arbitrary_info_t ainfo = 0; @@ -717,28 +713,18 @@ xwidget_info_chk(devfs_handle_t xwidget) xwidget_info_t -xwidget_info_get(devfs_handle_t xwidget) +xwidget_info_get(vertex_hdl_t xwidget) { xwidget_info_t widget_info; widget_info = (xwidget_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef LATER - if ((widget_info != NULL) && - (widget_info->w_fingerprint != widget_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v bad xwidget_info", xwidget); -#else - PRINT_PANIC("%x bad xwidget_info", xwidget); -#endif -#endif /* LATER */ - return (widget_info); } void -xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) +xwidget_info_set(vertex_hdl_t xwidget, xwidget_info_t widget_info) { if (widget_info != NULL) widget_info->w_fingerprint = widget_info_fingerprint; @@ -753,11 +739,11 @@ xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) (arbitrary_info_t) widget_info); } -devfs_handle_t +vertex_hdl_t xwidget_info_dev_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_dev_get: null xwidget_info"); return (xwidget_info->w_vertex); } @@ -765,16 +751,16 @@ xwidgetnum_t xwidget_info_id_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_id_get: null xwidget_info"); return (xwidget_info->w_id); } -devfs_handle_t +vertex_hdl_t xwidget_info_master_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_master_get: null xwidget_info"); return (xwidget_info->w_master); } @@ -782,7 +768,7 @@ xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_masterid_get: null xwidget_info"); return (xwidget_info->w_masterid); } @@ -790,7 +776,7 @@ xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_part_num_get: null xwidget_info"); return (xwidget_info->w_hwid.part_num); } @@ -798,7 +784,7 @@ xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_mfg_num_get: null xwidget_info"); return (xwidget_info->w_hwid.mfg_num); } /* Extract the widget name from the widget information @@ -808,49 +794,16 @@ char * xwidget_info_name_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget info"); + panic("xwidget_info_name_get: null xwidget_info"); return(xwidget_info->w_name); } /****** Generic crosstalk initialization interfaces ******/ /* - * One-time initialization needed for systems that support crosstalk. - */ -void -xtalk_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("xtalk_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (xtalk_registry == NULL) { - cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); - if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(xtalk_registry != NULL); -} - -/* * Associate a set of xtalk_provider functions with a vertex. */ void -xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) +xtalk_provider_register(vertex_hdl_t provider, xtalk_provider_t *xtalk_fns) { hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); } @@ -859,7 +812,7 @@ xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) * Disassociate a set of xtalk_provider functions with a vertex. */ void -xtalk_provider_unregister(devfs_handle_t provider) +xtalk_provider_unregister(vertex_hdl_t provider) { hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); } @@ -869,50 +822,19 @@ xtalk_provider_unregister(devfs_handle_t provider) * provider. */ xtalk_provider_t * -xtalk_provider_fns_get(devfs_handle_t provider) +xtalk_provider_fns_get(vertex_hdl_t provider) { return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); } /* - * Announce a driver for a particular crosstalk part. - * Returns 0 on success or -1 on failure. Failure occurs if the - * specified hardware already has a driver. - */ -/*ARGSUSED4 */ -int -xwidget_driver_register(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine could call - * xwidget_driver_register before the - * system calls xtalk_init; so, we - * make the call here. - */ - if (xtalk_registry == NULL) - xtalk_init(); - - return cdl_add_driver(xtalk_registry, - part_num, mfg_num, - driver_prefix, flags, NULL); -} - -/* * Inform xtalk infrastructure that a driver is no longer available for * handling any widgets. */ void xwidget_driver_unregister(char *driver_prefix) { - /* before a driver calls unregister, - * it must have called registger; so we - * can assume we have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - cdl_del_driver(xtalk_registry, driver_prefix, NULL); + return; } /* @@ -923,9 +845,6 @@ void xtalk_iterate(char *driver_prefix, xtalk_iter_f *func) { - ASSERT(xtalk_registry != NULL); - - cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); } /* @@ -939,11 +858,10 @@ xtalk_iterate(char *driver_prefix, */ int xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - devfs_handle_t widget, /* widget to initialize */ + vertex_hdl_t widget, /* widget to initialize */ xwidgetnum_t id, /* widget's target id (0..f) */ - devfs_handle_t master, /* widget's master vertex */ - xwidgetnum_t targetid, /* master's target id (9/a) */ - async_attach_t aa) + vertex_hdl_t master, /* widget's master vertex */ + xwidgetnum_t targetid) /* master's target id (9/a) */ { xwidget_info_t widget_info; char *s,devnm[MAXDEVNAME]; @@ -972,21 +890,11 @@ xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ device_master_set(widget, master); - /* All the driver init routines (including - * xtalk_init) are called before we get into - * attaching devices, so we can assume we - * have a registry here. - */ - ASSERT(xtalk_registry != NULL); - /* * Add pointer to async attach info -- tear down will be done when * the particular descendant is done with the info. */ - if (aa) - async_attach_add_info(widget, aa); - - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + return cdl_add_connpt(hwid->part_num, hwid->mfg_num, widget, 0); } @@ -995,7 +903,7 @@ xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ * Unregister the xtalk device and detach all its hwgraph namespace. */ int -xwidget_unregister(devfs_handle_t widget) +xwidget_unregister(vertex_hdl_t widget) { xwidget_info_t widget_info; xwidget_hwid_t hwid; @@ -1011,9 +919,6 @@ xwidget_unregister(devfs_handle_t widget) hwid = &(widget_info->w_hwid); - cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); - /* Clean out the xwidget information */ (void)kfree(widget_info->w_name); BZERO((void *)widget_info, sizeof(widget_info)); @@ -1023,7 +928,7 @@ xwidget_unregister(devfs_handle_t widget) } void -xwidget_error_register(devfs_handle_t xwidget, +xwidget_error_register(vertex_hdl_t xwidget, error_handler_f *efunc, error_handler_arg_t einfo) { @@ -1039,37 +944,23 @@ xwidget_error_register(devfs_handle_t xwidget, * Issue a link reset to a widget. */ void -xwidget_reset(devfs_handle_t xwidget) +xwidget_reset(vertex_hdl_t xwidget) { xswitch_reset_link(xwidget); - } void -xwidget_gfx_reset(devfs_handle_t xwidget) +xwidget_gfx_reset(vertex_hdl_t xwidget) { - xwidget_info_t info; - - xswitch_reset_link(xwidget); - info = xwidget_info_get(xwidget); -#ifdef LATER - ASSERT_ALWAYS(info != NULL); -#endif - - /* - * Enable this for other architectures once we add widget_reset to the - * xtalk provider interface. - */ - DEV_FUNC(xtalk_provider, widget_reset) - (xwidget_info_master_get(info), xwidget_info_id_get(info)); + return; } #define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ /* Get the canonical hwgraph name of xtalk widget */ char * -xwidget_name_get(devfs_handle_t xwidget_vhdl) +xwidget_name_get(vertex_hdl_t xwidget_vhdl) { xwidget_info_t info; diff --git a/arch/ia64/sn/io/stubs.c b/arch/ia64/sn/io/stubs.c deleted file mode 100644 index 0acbdb83df1..00000000000 --- a/arch/ia64/sn/io/stubs.c +++ /dev/null @@ -1,140 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/****** - ****** hack defines ...... - ******/ - -int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; -int default_intr_pri; -int force_fire_and_forget = 1; -int ignore_conveyor_override = 0; - -devfs_handle_t dummy_vrtx; /* Needed for cpuid_to_vertex() in hack.h */ - - -/* ARGSUSED */ -void hub_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) - {FIXME("hub_widgetdev_enable");} - -/* ARGSUSED */ -void hub_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) - {FIXME("hub_widgetdev_shutdown");} - -/* ARGSUSED */ -void hub_widget_reset(devfs_handle_t hubv, xwidgetnum_t widget) - {FIXME("hub_widget_reset");} - -boolean_t -is_sys_critical_vertex(devfs_handle_t x) -{ - FIXME("is_sys_critical_vertex : returns 0"); - return(0); -} - -void * -snia_kmem_zone_alloc(register struct zone *zone, int flags) -{ - FIXME("snia_kmem_zone_alloc : return null"); - return((void *)0); -} - -void -snia_kmem_zone_free(register struct zone *zone, void *ptr) -{ - FIXME("snia_kmem_zone_free : no-op"); -} - -struct zone * -snia_kmem_zone_init(register int size, char *zone_name) -{ - FIXME("snia_kmem_zone_free : returns NULL"); - return((struct zone *)0); -} - -int -compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) -{ - FIXME("compare_and_swap_ptr : NOT ATOMIC"); - if (*location == old_ptr) { - *location = new_ptr; - return(1); - } - else - return(0); -} - -/* For ml/SN/SN1/slots.c */ -/* ARGSUSED */ -slotid_t get_widget_slotnum(int xbow, int widget) - {FIXME("get_widget_slotnum"); return (unsigned char)NULL;} - -/* For router */ -int -router_init(cnodeid_t cnode,int writeid, void *npda_rip) - {FIXME("router_init"); return(0);} - -/* From io/ioerror_handling.c */ -error_return_code_t -sys_critical_graph_vertex_add(devfs_handle_t parent, devfs_handle_t child) - {FIXME("sys_critical_graph_vertex_add"); return(0);} - -/* From io/ioc3.c */ -devfs_handle_t -ioc3_console_vhdl_get(void) - {FIXME("ioc3_console_vhdl_get"); return( (devfs_handle_t)-1);} - -void -nic_vmc_check(devfs_handle_t vhdl, char *nicinfo) -{ - - FIXME("nic_vmc_check\n"); - -} - -char * -nic_vertex_info_get(devfs_handle_t v) -{ - FIXME("nic_vertex_info_get\n"); - return(NULL); -} - -int -vector_read_node(net_vec_t dest, nasid_t nasid, - int write_id, int address, - uint64_t *value) -{ - FIXME("vector_read_node\n"); - return(0); -} - -int -vector_write_node(net_vec_t dest, nasid_t nasid, - int write_id, int address, - uint64_t value) -{ - FIXME("vector_write_node\n"); - return(0); -} diff --git a/arch/ia64/sn/io/xbow.c b/arch/ia64/sn/io/xbow.c deleted file mode 100644 index 00983e0def8..00000000000 --- a/arch/ia64/sn/io/xbow.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG 1 */ -/* #define XBOW_DEBUG 1 */ - - -/* - * Files needed to get the device driver entry points - */ - -#include -#include -#include -#include - -#include -#include - - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -int xbow_devflag = D_MP; - -/* - * This file supports the Xbow chip. Main functions: initializtion, - * error handling, and GBR. - */ - -/* - * each vertex corresponding to an xbow chip - * has a "fastinfo" pointer pointing at one - * of these things. - */ -typedef struct xbow_soft_s *xbow_soft_t; - -struct xbow_soft_s { - devfs_handle_t conn; /* our connection point */ - devfs_handle_t vhdl; /* xbow's private vertex */ - devfs_handle_t busv; /* the xswitch vertex */ - xbow_t *base; /* PIO pointer to crossbow chip */ - char *name; /* hwgraph name */ - - xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; - xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; - xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - spinlock_t xbow_perf_lock; - int link_monitor; - widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ - - /* Bandwidth allocation state. Bandwidth values are for the - * destination port since contention happens there. - * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. - */ - spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ - unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ - unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ -}; - -#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) -#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v))) - -/* - * Function Table of Contents - */ - -void xbow_mlreset(xbow_t *); -void xbow_init(void); -int xbow_attach(devfs_handle_t); - -int xbow_open(devfs_handle_t *, int, int, cred_t *); -int xbow_close(devfs_handle_t, int, int, cred_t *); - -int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int xbow_unmap(devfs_handle_t, vhandl_t *); -int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -int xbow_widget_present(xbow_t *, int); -static int xbow_link_alive(xbow_t *, int); -devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); - -#ifdef LATER -static void xbow_setwidint(xtalk_intr_t); -static void xbow_errintr_handler(intr_arg_t); -#endif -void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); - - - -void xbow_update_perf_counters(devfs_handle_t); -xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -int xbow_enable_perf_counter(devfs_handle_t, int, int, int); -xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); -void xbow_update_llp_status(devfs_handle_t); - -int xbow_disable_llp_monitor(devfs_handle_t); -int xbow_enable_llp_monitor(devfs_handle_t); -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, - unsigned long long, unsigned long long); - -xswitch_reset_link_f xbow_reset_link; - -void idbg_xbowregs(int64_t); - -xswitch_provider_t xbow_provider = -{ - xbow_reset_link, -}; - -/* - * xbow_mlreset: called at mlreset time if the - * platform specific code determines that there is - * a crossbow in a critical path that must be - * functional before the driver would normally get - * the device properly set up. - * - * what do we need to do, that the boot prom can - * not be counted on to have already done, that is - * generic across all platforms using crossbows? - */ -/*ARGSUSED */ -void -xbow_mlreset(xbow_t * xbow) -{ -} - -/* - * xbow_init: called with the rest of the device - * driver XXX_init routines. This platform *might* - * have a Crossbow chip, or even several, but it - * might have none. Register with the crosstalk - * generic provider so when we encounter the chip - * the right magic happens. - */ -void -xbow_init(void) -{ - -#if DEBUG && ATTACH_DEBUG - printf("xbow_init\n"); -#endif - - xwidget_driver_register(XXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - xwidget_driver_register(XBOW_WIDGET_PART_NUM, - XBOW_WIDGET_MFGR_NUM, - "xbow_", - CDL_PRI_HI); /* attach before friends */ -} - -#ifdef XBRIDGE_REGS_SIM -/* xbow_set_simulated_regs: sets xbow regs as needed - * for powering through the boot - */ -void -xbow_set_simulated_regs(xbow_t *xbow, int port) -{ - /* - * turn on link - */ - xbow->xb_link(port).link_status = (1<<31); - /* - * and give it a live widget too - */ - xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; - /* - * zero the link control reg - */ - xbow->xb_link(port).link_control = 0x0; -} -#endif /* XBRIDGE_REGS_SIM */ - -/* - * xbow_attach: the crosstalk provider has - * determined that there is a crossbow widget - * present, and has handed us the connection - * point for that vertex. - * - * We not only add our own vertex, but add - * some "xtalk switch" data to the switch - * vertex (at the connect point's parent) if - * it does not have any. - */ - -/*ARGSUSED */ -int -xbow_attach(devfs_handle_t conn) -{ - /*REFERENCED */ - devfs_handle_t vhdl; - devfs_handle_t busv; - xbow_t *xbow; - xbow_soft_t soft; - int port; - xswitch_info_t info; -#ifdef LATER - xtalk_intr_t intr_hdl; - device_desc_t dev_desc; -#endif - char devnm[MAXDEVNAME], *s; - xbowreg_t id; - int rev; - int i; - int xbow_num; - -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT - printk("%v: xbow_attach\n", conn); -#else - printk("0x%x: xbow_attach\n", conn); -#endif -#endif - - /* - * Get a PIO pointer to the base of the crossbow - * chip. - */ -#ifdef XBRIDGE_REGS_SIM - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); - xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); - /* - * turn on ports e and f like in a real live ibrick - */ - xbow_set_simulated_regs(xbow, 0xe); - xbow_set_simulated_regs(xbow, 0xf); -#else - xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); -#endif /* XBRIDGE_REGS_SIM */ - - /* - * Locate the "switch" vertex: it is the parent - * of our connection point. - */ - busv = hwgraph_connectpt_get(conn); -#if DEBUG && ATTACH_DEBUG - printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); -#endif - - ASSERT(busv != GRAPH_VERTEX_NONE); - - /* - * Create our private vertex, and connect our - * driver information to it. This makes it possible - * for diagnostic drivers to open the crossbow - * vertex for access to registers. - */ - - /* - * We need to teach xbow drivers to provide the right set of - * file ops. - */ - vhdl = NULL; - vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - /* &hcl_fops */ (void *)&vhdl, NULL); - if (!vhdl) { - printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", - (void *)conn); - } - - /* - * Allocate the soft state structure and attach - * it to the xbow's vertex - */ - NEW(soft); - soft->conn = conn; - soft->vhdl = vhdl; - soft->busv = busv; - soft->base = xbow; - /* does the universe really need another macro? */ - /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); - -#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" - - /* Add xbow number as a suffix to the hwgraph name of the xbow. - * This is helpful while looking at the error/warning messages. - */ - xbow_num = 0; - - /* - * get the name of this xbow vertex and keep the info. - * This is needed during errors and interrupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(vhdl, devnm, MAXDEVNAME); - soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, - GFP_KERNEL); - sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); - -#ifdef XBRIDGE_REGS_SIM - /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined - * as 0xd000, so I'm using that for the partnum bitfield. - */ - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); - id = 0x2d000049; -#else - id = xbow->xb_wid_id; -#endif /* XBRIDGE_REGS_SIM */ - rev = XWIDGET_PART_REV_NUM(id); - - /* - * Print the revision if DEBUG, or SHOW_REVS and kdebug, - * or the xbow is downrev. - * - * If xbow is downrev, make it a WARNING that the - * Crossbow is DOWNREV: these chips are not good - * to have around, and the operator should be told. - */ -#ifdef LATER -#if !DEBUG - if ( -#if SHOW_REVS - (kdebug) || -#endif /* SHOW_REVS */ - (rev < XBOW_REV_1_1)) -#endif /* !DEBUG */ - printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", - (rev < XBOW_REV_1_1) ? "DOWNREV " : "", - (rev == XBOW_REV_1_0) ? "1.0" : - (rev == XBOW_REV_1_1) ? "1.1" : - (rev == XBOW_REV_1_2) ? "1.2" : - (rev == XBOW_REV_1_3) ? "1.3" : - (rev == XBOW_REV_2_0) ? "2.0" : - (rev == XXBOW_PART_REV_1_0) ? "Xbridge 1.0" : - (rev == XXBOW_PART_REV_2_0) ? "Xbridge 2.0" : - "unknown", - rev, soft->name, - (rev < XBOW_REV_1_1) ? "" : "\n"); -#endif /* LATER */ - mutex_spinlock_init(&soft->xbow_perf_lock); - soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; - soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; - - /* Initialization for GBR bw allocation */ - mutex_spinlock_init(&soft->xbow_bw_alloc_lock); - -#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ -#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ - - /* Set bandwidth hiwatermark and current values */ - for (i = 0; i < MAX_XBOW_PORTS; i++) { - soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ - soft->bw_cur_used[i] = 0; - } - - /* - * Enable xbow error interrupts - */ - xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); - - /* - * take a census of the widgets present, - * leaving notes at the switch vertex. - */ - info = xswitch_info_new(busv); - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; ++port) { - if (!xbow_link_alive(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is not alive\n", - busv, port); -#endif - continue; - } - if (!xbow_widget_present(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port); -#endif - continue; - } -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d has a widget\n", - busv, port); -#endif - - xswitch_info_link_is_ok(info, port); - /* - * Turn some error interrupts on - * and turn others off. The PROM has - * some things turned on we don't - * want to see (bandwidth allocation - * errors for instance); so if it - * is not listed here, it is not on. - */ - xbow->xb_link(port).link_control = - ( (xbow->xb_link(port).link_control - /* - * Turn off these bits; they are non-fatal, - * but we might want to save some statistics - * on the frequency of these errors. - * XXX FIXME XXX - */ - & ~XB_CTRL_RCV_CNT_OFLOW_IE - & ~XB_CTRL_XMT_CNT_OFLOW_IE - & ~XB_CTRL_BNDWDTH_ALLOC_IE - & ~XB_CTRL_RCV_IE) - /* - * These are the ones we want to turn on. - */ - | (XB_CTRL_ILLEGAL_DST_IE - | XB_CTRL_OALLOC_IBUF_IE - | XB_CTRL_XMT_MAX_RTRY_IE - | XB_CTRL_MAXREQ_TOUT_IE - | XB_CTRL_XMT_RTRY_IE - | XB_CTRL_SRC_TOUT_IE) ); - } - - xswitch_provider_register(busv, &xbow_provider); - - return 0; /* attach successful */ -} - -/*ARGSUSED */ -int -xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; - -} - -/*ARGSUSED */ -int -xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - xbow_soft_t soft = xbow_soft_get(vhdl); - int error; - - ASSERT(soft); - len = ctob(btoc(len)); - /* XXX- this ignores the offset!!! */ - error = v_mapphys(vt, (void *) soft->base, len); - return error; -} - -/*ARGSUSED */ -int -xbow_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* This contains special-case code for grio. There are plans to make - * this general sometime in the future, but till then this should - * be good enough. - */ -xwidgetnum_t -xbow_widget_num_get(devfs_handle_t dev) -{ - devfs_handle_t tdev; - char devname[MAXDEVNAME]; - xwidget_info_t xwidget_info; - int i; - - vertex_to_name(dev, devname, MAXDEVNAME); - - /* If this is a pci controller vertex, traverse up using - * the ".." links to get to the widget. - */ - if (strstr(devname, EDGE_LBL_PCI) && - strstr(devname, EDGE_LBL_CONTROLLER)) { - tdev = dev; - for (i=0; i< 2; i++) { - if (hwgraph_edge_get(tdev, - HWGRAPH_EDGELBL_DOTDOT, &tdev) != - GRAPH_SUCCESS) - return XWIDGET_NONE; - } - - if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) { - return (xwidget_info_id_get(xwidget_info)); - } else { - return XWIDGET_NONE; - } - } - - return XWIDGET_NONE; -} - -int -xbow_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t vhdl; - int error = 0; - -#if defined (DEBUG) - int rc; - devfs_handle_t conn; - struct xwidget_info_s *xwidget_info; - xbow_soft_t xbow_soft; -#endif - *rvalp = 0; - - vhdl = dev_to_vhdl(dev); -#if defined (DEBUG) - xbow_soft = xbow_soft_get(vhdl); - conn = xbow_soft->conn; - - xwidget_info = xwidget_info_get(conn); - ASSERT_ALWAYS(xwidget_info != NULL); - - rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); - ASSERT_ALWAYS(rc != 0); -#endif - switch (cmd) { -#ifdef LATER - case XBOWIOC_PERF_ENABLE: - case XBOWIOC_PERF_DISABLE: - { - struct xbow_perfarg_t xbow_perf_en; - - if (!_CAP_CRABLE(cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if ((flag & FWRITE) == 0) { - error = EBADF; - break; - } - if (COPYIN(arg, &xbow_perf_en, sizeof(xbow_perf_en))) { - error = EFAULT; - break; - } - if (error = xbow_enable_perf_counter(vhdl, - xbow_perf_en.link, - (cmd == XBOWIOC_PERF_DISABLE) ? 0 : xbow_perf_en.mode, - xbow_perf_en.counter)) { - error = EINVAL; - break; - } - break; - } -#endif - -#ifdef LATER - case XBOWIOC_PERF_GET: - { - xbow_perf_link_t *xbow_perf_cnt; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_perf_cnt = xbow_get_perf_counters(vhdl); - ASSERT_ALWAYS(xbow_perf_cnt != NULL); - - if (COPYOUT((void *) xbow_perf_cnt, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_perf_link_t))) { - error = EFAULT; - break; - } - break; - } -#endif - - case XBOWIOC_LLP_ERROR_ENABLE: - if ((error = xbow_enable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - case XBOWIOC_LLP_ERROR_DISABLE: - - if ((error = xbow_disable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - -#ifdef LATER - case XBOWIOC_LLP_ERROR_GET: - { - xbow_link_status_t *xbow_llp_status; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_llp_status = xbow_get_llp_status(vhdl); - ASSERT_ALWAYS(xbow_llp_status != NULL); - - if (COPYOUT((void *) xbow_llp_status, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_link_status_t))) { - error = EFAULT; - break; - } - break; - } -#endif - -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth allocation is bi-directional. Since bandwidth - * reservations have already been done at an earlier stage, - * we cannot fail here for lack of bandwidth. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - 0, info.reqbw); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - 0, info.reqbw); - - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth reservation is bi-directional. Hence, remove - * bandwidth reservations for both directions. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - info.reqbw, (-1 * info.reqbw)); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - info.reqbw, (-1 * info.reqbw)); - - break; - } -#endif - - default: - break; - - } - return error; -} - -/* - * xbow_widget_present: See if a device is present - * on the specified port of this crossbow. - */ -int -xbow_widget_present(xbow_t * xbow, int port) -{ - if ( IS_RUNNING_ON_SIMULATOR() ) { - if ( (port == 14) || (port == 15) ) { - return 1; - } - else { - return 0; - } - } - else { - return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; - } -} - -static int -xbow_link_alive(xbow_t * xbow, int port) -{ - xbwX_stat_t xbow_linkstat; - - xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; - return (xbow_linkstat.link_alive); -} - -/* - * xbow_widget_lookup - * Lookup the edges connected to the xbow specified, and - * retrieve the handle corresponding to the widgetnum - * specified. - * If not found, return 0. - */ -devfs_handle_t -xbow_widget_lookup(devfs_handle_t vhdl, - int widgetnum) -{ - xswitch_info_t xswitch_info; - devfs_handle_t conn; - - xswitch_info = xswitch_info_get(vhdl); - conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); - return conn; -} - -/* - * xbow_setwidint: called when xtalk - * is establishing or migrating our - * interrupt service. - */ -#ifdef LATER -static void -xbow_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); - - xbow_intr_preset((void *) xbow, 0, targ, addr, vect); -} -#endif /* LATER */ - -/* - * xbow_intr_preset: called during mlreset time - * if the platform specific code needs to route - * an xbow interrupt before the xtalk infrastructure - * is available for use. - * - * Also called from xbow_setwidint, so we don't - * replicate the guts of the routine. - * - * XXX- probably should be renamed xbow_wid_intr_set or - * something to reduce confusion. - */ -/*ARGSUSED3 */ -void -xbow_intr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - xbow_t *xbow = (xbow_t *) which_widget; - - xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | - (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); -} - -#define XEM_ADD_STR(s) printk("%s", (s)) -#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%x\n", (n), (v)) -#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) -#define XEM_ADD_IOEF(n) if (IOERROR_FIELDVALID(ioe,n)) \ - XEM_ADD_NVAR("ioe." #n, \ - IOERROR_GETVALUE(ioe,n)) - -#ifdef LATER -static void -xem_add_ioe(ioerror_t *ioe) -{ - XEM_ADD_IOEF(errortype); - XEM_ADD_IOEF(widgetnum); - XEM_ADD_IOEF(widgetdev); - XEM_ADD_IOEF(srccpu); - XEM_ADD_IOEF(srcnode); - XEM_ADD_IOEF(errnode); - XEM_ADD_IOEF(sysioaddr); - XEM_ADD_IOEF(xtalkaddr); - XEM_ADD_IOEF(busspace); - XEM_ADD_IOEF(busaddr); - XEM_ADD_IOEF(vaddr); - XEM_ADD_IOEF(memaddr); - XEM_ADD_IOEF(epc); - XEM_ADD_IOEF(ef); -} - -#define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* LATER */ - -int xbow_xmit_retry_errors = 0; - -int -xbow_xmit_retry_error(xbow_soft_t soft, - int port) -{ - xswitch_info_t info; - devfs_handle_t vhdl; - widget_cfg_t *wid; - widgetreg_t id; - int part; - int mfgr; - - wid = soft->wpio[port - BASE_XBOW_PORT]; - if (wid == NULL) { - /* If we can't track down a PIO - * pointer to our widget yet, - * leave our caller knowing that - * we are interested in this - * interrupt if it occurs in - * the future. - */ - info = xswitch_info_get(soft->busv); - if (!info) - return 1; - vhdl = xswitch_info_vhdl_get(info, port); - if (vhdl == GRAPH_VERTEX_NONE) - return 1; - wid = (widget_cfg_t *) xtalk_piotrans_addr - (vhdl, 0, 0, sizeof *wid, 0); - if (!wid) - return 1; - soft->wpio[port - BASE_XBOW_PORT] = wid; - } - id = wid->w_id; - part = XWIDGET_PART_NUM(id); - mfgr = XWIDGET_MFG_NUM(id); - - /* If this thing is not a Bridge, - * do not activate the WAR, and - * tell our caller we do not need - * to be called again. - */ - if ((part != BRIDGE_WIDGET_PART_NUM) || - (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { - /* FIXME: add Xbridge to the WAR. - * Shouldn't hurt anything. Later need to - * check if we can remove this. - */ - if ((part != XBRIDGE_WIDGET_PART_NUM) || - (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) - return 0; - } - - /* count how many times we - * have picked up after - * LLP Transmit problems. - */ - xbow_xmit_retry_errors++; - - /* rewrite the control register - * to fix things up. - */ - wid->w_control = wid->w_control; - wid->w_control; - - return 1; -} - -void -xbow_update_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; - xbow_perfcount_t perf_reg; - unsigned long s; - int link, i; - - for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { - if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) - continue; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - - link = perf_reg.xb_perf.link_select; - - (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += - ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); - xbow_perf->xp_current = perf_reg.xb_perf.count; - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - } - /* Do port /mode multiplexing here */ - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - -} - -xbow_perf_link_t * -xbow_get_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; - - return xbow_perf_link; -} - -int -xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_linkctrl_t xbow_link_ctrl; - xbow_t *xbow = xbow_soft->base; - xbow_perfcount_t perf_reg; - unsigned long s; - int i; - - link -= BASE_XBOW_PORT; - if ((link < 0) || (link >= MAX_XBOW_PORTS)) - return -1; - - if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) - return -1; - - if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) - return -1; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - if ((xbow_perf + counter)->xp_mode && mode) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - for (i = 0; i < XBOW_PERF_COUNTERS; i++) { - if (i == counter) - continue; - if (((xbow_perf + i)->xp_link == link) && - ((xbow_perf + i)->xp_mode)) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - } - xbow_perf += counter; - - xbow_perf->xp_curlink = xbow_perf->xp_link = link; - xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; - - xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; - xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; - xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - perf_reg.xb_perf.link_select = link; - *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; - xbow_perf->xp_current = perf_reg.xb_perf.count; - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - - return 0; -} - -xbow_link_status_t * -xbow_get_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - - return xbow_llp_status; -} - -void -xbow_update_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - xbow_t *xbow; - xbwX_stat_t lnk_sts; - xbow_aux_link_status_t aux_sts; - int link; - devfs_handle_t xwidget_vhdl; - char *xwidget_name; - - xbow = (xbow_t *) xbow_soft->base; - for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { - /* Get the widget name corresponding the current link. - * Note : 0 <= link < MAX_XBOW_PORTS(8). - * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) - */ - xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); - xwidget_name = xwidget_name_get(xwidget_vhdl); - aux_sts.aux_linkstatus - = xbow->xb_link_raw[link].link_aux_status; - lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; - - if (lnk_sts.link_alive == 0) - continue; - - xbow_llp_status->rx_err_count += - aux_sts.xb_aux_linkstatus.rx_err_cnt; - - xbow_llp_status->tx_retry_count += - aux_sts.xb_aux_linkstatus.tx_retry_cnt; - - if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { -#ifdef LATER - printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", - link, xwidget_name, lnk_sts.linkstatus); -#endif - } - } -#ifdef LATER - if (xbow_soft->link_monitor) - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif -} - -int -xbow_disable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - int port; - - for (port = 0; port < MAX_XBOW_PORTS; port++) { - xbow_soft->xbow_link_status[port].rx_err_count = 0; - xbow_soft->xbow_link_status[port].tx_retry_count = 0; - } - - xbow_soft->link_monitor = 0; - return 0; -} - -int -xbow_enable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - -#ifdef LATER - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif - xbow_soft->link_monitor = 1; - return 0; -} - - -int -xbow_reset_link(devfs_handle_t xconn_vhdl) -{ - xwidget_info_t widget_info; - xwidgetnum_t port; - xbow_t *xbow; - xbowreg_t ctrl; - xbwX_stat_t stat; - unsigned itick; - unsigned dtick; - static int ticks_per_ms = 0; - - if (!ticks_per_ms) { - itick = get_timestamp(); - us_delay(1000); - ticks_per_ms = get_timestamp() - itick; - } - widget_info = xwidget_info_get(xconn_vhdl); - port = xwidget_info_id_get(widget_info); - -#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ - xbow = XBOW_K1PTR; -#else - { - devfs_handle_t xbow_vhdl; - xbow_soft_t xbow_soft; - - hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); - xbow_soft = xbow_soft_get(xbow_vhdl); - xbow = xbow_soft->base; - } -#endif - - /* - * This requires three PIOs (reset the link, check for the - * reset, restore the control register for the link) plus - * 10us to wait for the reset. We allow up to 1ms for the - * widget to come out of reset before giving up and - * returning a failure. - */ - ctrl = xbow->xb_link(port).link_control; - xbow->xb_link(port).link_reset = 0; - itick = get_timestamp(); - while (1) { - stat.linkstatus = xbow->xb_link(port).link_status; - if (stat.link_alive) - break; - dtick = get_timestamp() - itick; - if (dtick > ticks_per_ms) { - return -1; /* never came out of reset */ - } - DELAY(2); /* don't beat on link_status */ - } - xbow->xb_link(port).link_control = ctrl; - return 0; -} - -/* - * Dump xbow registers. - * input parameter is either a pointer to - * the xbow chip or the vertex handle for - * an xbow vertex. - */ -void -idbg_xbowregs(int64_t regs) -{ - xbow_t *xbow; - int i; - xb_linkregs_t *link; - -#ifdef LATER - if (dev_is_vertex((devfs_handle_t) regs)) { - devfs_handle_t vhdl = (devfs_handle_t) regs; - xbow_soft_t soft = xbow_soft_get(vhdl); - - xbow = soft->base; - } else -#endif - { - xbow = (xbow_t *) regs; - } - -#ifdef LATER - qprintf("Printing xbow registers starting at 0x%x\n", xbow); - qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", - xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, - xbow->xb_wid_err_lower, xbow->xb_wid_control, - xbow->xb_wid_req_timeout); - qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", - xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, - xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, - xbow->xb_wid_arb_reload); -#endif - - for (i = 8; i <= 0xf; i++) { - link = &xbow->xb_link(i); -#ifdef LATER - qprintf("Link %d registers\n", i); - qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", - link->link_control, link->link_status, - link->link_arb_upper, link->link_arb_lower, - link->link_aux_status); -#endif - } -} - - -#define XBOW_ARB_RELOAD_TICKS 25 - /* granularity: 4 MB/s, max: 124 MB/s */ -#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) - -#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY) - -#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY) - -#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ - ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr) - -#define XBOW_ARB_GBR_MAX 31 - -#define ABS(x) ((x > 0) ? (x) : (-1 * x)) - /* absolute value */ - -int -xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec) -{ - int gbr_granted; - int new_total_gbr; - int change_gbr; - bandwidth_t new_total_bw; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", - old_bytes_per_sec, bytes_per_sec); -#endif /* GRIO_DEBUG */ - - gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), - old_bytes_per_sec); - new_total_bw = old_bytes_per_sec + bytes_per_sec; - new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), - new_total_bw); - - change_gbr = new_total_gbr - gbr_granted; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", - gbr_granted, new_total_gbr, change_gbr); -#endif /* GRIO_DEBUG */ - - return (change_gbr); -} - -/* Conversion from GBR to bytes */ -bandwidth_t -xbow_gbr_to_bytes(int gbr) -{ - return (XBOW_GBR_TO_BYTES(gbr)); -} - -/* Given the vhdl for the desired xbow, the src and dest. widget ids - * and the req_bw value, this xbow driver entry point accesses the - * xbow registers and allocates the desired bandwidth if available. - * - * If bandwidth allocation is successful, return success else return failure. - */ -int -xbow_prio_bw_alloc(devfs_handle_t vhdl, - xwidgetnum_t src_wid, - xwidgetnum_t dest_wid, - unsigned long long old_alloc_bw, - unsigned long long req_bw) -{ - xbow_soft_t soft = xbow_soft_get(vhdl); - volatile xbowreg_t *xreg; - xbowreg_t mask; - unsigned long s; - int error = 0; - bandwidth_t old_bw_BYTES, req_bw_BYTES; - xbowreg_t old_xreg; - int old_bw_GBR, req_bw_GBR, new_bw_GBR; - -#ifdef GRIO_DEBUG - printf("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", - (int) vhdl, (int) src_wid, (int) dest_wid, req_bw); -#endif - - ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); - ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); - - s = mutex_spinlock(&soft->xbow_bw_alloc_lock); - - /* Get pointer to the correct register */ - xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); - - /* Get mask for GBR count value */ - mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); - - req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); - req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) - : xbow_gbr_to_bytes(req_bw_GBR); - -#ifdef GRIO_DEBUG - printf("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", - req_bw, req_bw_BYTES, req_bw_GBR); -#endif /* GRIO_DEBUG */ - - old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; - old_xreg = *xreg; - old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid)); - -#ifdef GRIO_DEBUG - ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); - - printf("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); - - printf("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", - req_bw_BYTES, old_bw_BYTES, - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); - -#endif /* GRIO_DEBUG */ - - /* Accept the request only if we don't exceed the destination - * port HIWATER_MARK *AND* the max. link GBR arbitration count - */ - if (((old_bw_BYTES + req_bw_BYTES) <= - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && - (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { - - new_bw_GBR = (old_bw_GBR + req_bw_GBR); - - /* Set this in the xbow link register */ - *xreg = (old_xreg & ~mask) | \ - (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); - - soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = - xbow_gbr_to_bytes(new_bw_GBR); - } else { - error = 1; - } - - mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); - - return (error); -} diff --git a/arch/ia64/sn/io/xswitch.c b/arch/ia64/sn/io/xswitch.c index 9d0ffa896da..286d0afa7c6 100644 --- a/arch/ia64/sn/io/xswitch.c +++ b/arch/ia64/sn/io/xswitch.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -23,8 +23,6 @@ #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) #define DEL(ptr) (kfree(ptr)) -int xswitch_devflag = D_MP; - /* * This file provides generic support for Crosstalk * Switches, in a way that insulates crosstalk providers @@ -45,9 +43,9 @@ int xswitch_devflag = D_MP; #define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func static xswitch_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) +xwidget_to_provider_fns(vertex_hdl_t xconn) { - devfs_handle_t busv; + vertex_hdl_t busv; xswitch_info_t xswitch_info; xswitch_provider_t provider_fns; @@ -75,27 +73,18 @@ static char xswitch_info_fingerprint[] = "xswitch_info"; struct xswitch_info_s { char *fingerprint; unsigned census; - devfs_handle_t vhdl[XSWITCH_CENSUS_PORTS]; - devfs_handle_t master_vhdl[XSWITCH_CENSUS_PORTS]; + vertex_hdl_t vhdl[XSWITCH_CENSUS_PORTS]; + vertex_hdl_t master_vhdl[XSWITCH_CENSUS_PORTS]; xswitch_provider_t *xswitch_fns; }; xswitch_info_t -xswitch_info_get(devfs_handle_t xwidget) +xswitch_info_get(vertex_hdl_t xwidget) { xswitch_info_t xswitch_info; xswitch_info = (xswitch_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef LATER - if ((xswitch_info != NULL) && - (xswitch_info->fingerprint != xswitch_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget); -#else - PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget); -#endif -#endif /* LATER */ return (xswitch_info); } @@ -103,7 +92,7 @@ xswitch_info_get(devfs_handle_t xwidget) void xswitch_info_vhdl_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t xwidget) + vertex_hdl_t xwidget) { #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) @@ -115,15 +104,10 @@ xswitch_info_vhdl_set(xswitch_info_t xswitch_info, xswitch_info->vhdl[port - XSWITCH_CENSUS_PORT_MIN] = xwidget; } -devfs_handle_t +vertex_hdl_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { -#ifdef LATER - if (xswitch_info == NULL) - PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info"); -#endif - #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) return GRAPH_VERTEX_NONE; @@ -142,7 +126,7 @@ xswitch_info_vhdl_get(xswitch_info_t xswitch_info, void xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t master_vhdl) + vertex_hdl_t master_vhdl) { #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) @@ -154,7 +138,7 @@ xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, xswitch_info->master_vhdl[port - XSWITCH_CENSUS_PORT_MIN] = master_vhdl; } -devfs_handle_t +vertex_hdl_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { @@ -169,14 +153,14 @@ xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, } void -xswitch_info_set(devfs_handle_t xwidget, xswitch_info_t xswitch_info) +xswitch_info_set(vertex_hdl_t xwidget, xswitch_info_t xswitch_info) { xswitch_info->fingerprint = xswitch_info_fingerprint; hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) xswitch_info); } xswitch_info_t -xswitch_info_new(devfs_handle_t xwidget) +xswitch_info_new(vertex_hdl_t xwidget) { xswitch_info_t xswitch_info; @@ -202,7 +186,7 @@ xswitch_info_new(devfs_handle_t xwidget) } void -xswitch_provider_register(devfs_handle_t busv, +xswitch_provider_register(vertex_hdl_t busv, xswitch_provider_t * xswitch_fns) { xswitch_info_t xswitch_info = xswitch_info_get(busv); @@ -232,35 +216,8 @@ xswitch_info_link_ok(xswitch_info_t xswitch_info, xwidgetnum_t port) } int -xswitch_reset_link(devfs_handle_t xconn_vhdl) +xswitch_reset_link(vertex_hdl_t xconn_vhdl) { return DEV_FUNC(xconn_vhdl, reset_link) (xconn_vhdl); } - -/* Given a vertex handle to the xswitch get its logical - * id. - */ -int -xswitch_id_get(devfs_handle_t xconn_vhdl) -{ - arbitrary_info_t xbow_num; - graph_error_t rv; - - rv = hwgraph_info_get_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID,&xbow_num); - ASSERT(rv == GRAPH_SUCCESS); - return(xbow_num); -} - -/* Given a vertex handle to the xswitch set its logical - * id. - */ -void -xswitch_id_set(devfs_handle_t xconn_vhdl,int xbow_num) -{ - graph_error_t rv; - - rv = hwgraph_info_add_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID, - (arbitrary_info_t)xbow_num); - ASSERT(rv == GRAPH_SUCCESS); -} diff --git a/arch/ia64/sn/io/xtalk.c b/arch/ia64/sn/io/xtalk.c deleted file mode 100644 index fdb0671500b..00000000000 --- a/arch/ia64/sn/io/xtalk.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Implement crosstalk provider operations. The xtalk* layer provides a - * platform-independent interface for crosstalk devices. This layer - * switches among the possible implementations of a crosstalk adapter. - * - * On platforms with only one possible xtalk provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -char widget_info_fingerprint[] = "widget_info"; - -cdl_p xtalk_registry = NULL; - -#define DEV_FUNC(dev,func) hub_##func -#define CAST_PIOMAP(x) ((hub_piomap_t)(x)) -#define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) -#define CAST_INTR(x) ((hub_intr_t)(x)) - -/* ===================================================================== - * Function Table of Contents - */ -xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); -void xtalk_piomap_free(xtalk_piomap_t); -caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); -void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); -void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void xtalk_dmamap_free(xtalk_dmamap_t); -iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); -alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); -void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); -xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); -xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); -void xtalk_intr_free(xtalk_intr_t); -int xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *); -void xtalk_intr_disconnect(xtalk_intr_t); -devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int xtalk_error_devenable(devfs_handle_t, int, int); -void xtalk_provider_startup(devfs_handle_t); -void xtalk_provider_shutdown(devfs_handle_t); -devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); -xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); -xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); -iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); -void *xtalk_intr_sfarg_get(xtalk_intr_t); -devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); -xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); -iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); -ulong xtalk_pio_mapsz_get(xtalk_piomap_t); -caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); -xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(devfs_handle_t); -xwidget_info_t xwidget_info_get(devfs_handle_t); -void xwidget_info_set(devfs_handle_t, xwidget_info_t); -devfs_handle_t xwidget_info_dev_get(xwidget_info_t); -xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -devfs_handle_t xwidget_info_master_get(xwidget_info_t); -xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); -xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); -xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); -char *xwidget_info_name_get(xwidget_info_t); -void xtalk_init(void); -void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); -void xtalk_provider_unregister(devfs_handle_t); -xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); -int xwidget_driver_register(xwidget_part_num_t, - xwidget_mfg_num_t, - char *, unsigned); -void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, devfs_handle_t, - xwidgetnum_t, devfs_handle_t, - xwidgetnum_t, async_attach_t); -int xwidget_unregister(devfs_handle_t); -void xwidget_reset(devfs_handle_t); -char *xwidget_name_get(devfs_handle_t); -#if !defined(DEV_FUNC) -/* - * There is more than one possible provider - * for this platform. We need to examine the - * master vertex of the current vertex for - * a provider function structure, and indirect - * through the appropriately named member. - */ -#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) -#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) -#define CAST_INTR(x) ((xtalk_intr_t)(x)) - -static xtalk_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) -{ - xwidget_info_t widget_info; - xtalk_provider_t *provider_fns; - - widget_info = xwidget_info_get(xconn); - ASSERT(widget_info != NULL); - - provider_fns = xwidget_info_pops_get(widget_info); - ASSERT(provider_fns != NULL); - - return (provider_fns); -} -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) -#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * xtalk space on a specified widget - */ - -xtalk_piomap_t -xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); -} - - -void -xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_free) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk address */ - size_t byte_count) -{ /* map this many bytes */ - return PIOMAP_FUNC(xtalk_piomap, piomap_addr) - (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); -} - - -void -xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_done) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, xtalk_addr, byte_count, flags); -} - -caddr_t -xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - xtalk_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - xtalk_piomap_t map = 0; - caddr_t res; - - if (mapp) - *mapp = 0; /* record "no map used" */ - - res = xtalk_piotrans_addr - (dev, dev_desc, addr, byte_count, flags); - if (res) - return res; /* xtalk_piotrans worked */ - - map = xtalk_piomap_alloc - (dev, dev_desc, addr, byte_count, byte_count, flags); - if (!map) - return res; /* xtalk_piomap_alloc failed */ - - res = xtalk_piomap_addr - (map, addr, byte_count); - if (!res) { - xtalk_piomap_free(map); - return res; /* xtalk_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* xtalk_piomap_addr succeeded */ -} - -/* ===================================================================== - * EARLY PIOTRANS SUPPORT - * - * There are places where drivers (mgras, for instance) - * need to get PIO translations before the infrastructure - * is extended to them (setting up textports, for - * instance). These drivers should call - * xtalk_early_piotrans_addr with their xtalk ID - * information, a sequence number (so we can use the second - * mgras for instance), and the usual piotrans parameters. - * - * Machine specific code should provide an implementation - * of early_piotrans_addr, and present a pointer to this - * function to xtalk_set_early_piotrans_addr so it can be - * used by clients without the clients having to know what - * platform or what xtalk provider is in use. - */ - -static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; - -xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; - -/* xtalk_set_early_piotrans_addr: - * specify the early_piotrans_addr implementation function. - */ -void -xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) -{ - impl_early_piotrans_addr = impl; -} - -/* xtalk_early_piotrans_addr: - * figure out a PIO address for the "nth" crosstalk widget that - * matches the specified part and mfgr number. Returns NULL if - * there is no such widget, or if the requested mapping can not - * be constructed. - * Limitations on which crosstalk slots (and busses) are - * checked, and definitions of the ordering of the search across - * the crosstalk slots, are defined by the platform. - */ -caddr_t -xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ - return impl_early_piotrans_addr - (part_num, mfg_num, which, xtalk_addr, byte_count, flags); -} - -/* null_xtalk_early_piotrans_addr: - * used as the early_piotrans_addr implementation until and - * unless a real implementation is provided. In DEBUG kernels, - * we want to know who is calling before the implementation is - * registered; in non-DEBUG kernels, return NULL representing - * lack of mapping support. - */ -/*ARGSUSED */ -static caddr_t -null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ -#if DEBUG - PRINT_PANIC("null_xtalk_early_piotrans_addr"); -#endif - return NULL; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from crosstalk space to system - * physical space. - */ - -xtalk_dmamap_t -xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - - -void -xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_free) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) - (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); -} - - -alenlist_t -xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) - (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); -} - - -void -xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_done) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - - -alenlist_t -xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -void -xtalk_dmamap_drain(xtalk_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, owner_dev); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Unconditionally setup resources to be non-threaded. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt */ -{ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) - (dev, dev_desc, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -xtalk_intr_free(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - - -/* - * Associate resources allocated with a previous xtalk_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), setfunc, setfunc_arg); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -xtalk_intr_disconnect(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -xtalk_provider_startup(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_startup) - (xtalk_provider); -} - - -/* - * Shutdown a crosstalk provider - */ -void -xtalk_provider_shutdown(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_shutdown) - (xtalk_provider); -} - -/* - * Enable a device on a xtalk widget - */ -void -xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); -} - -/* - * Shutdown a device on a xtalk widget - */ -void -xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); -} - -int -xtalk_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); -} -/* - * Generic crosstalk functions, for use with all crosstalk providers - * and all crosstalk devices. - */ - -/****** Generic crosstalk interrupt interfaces ******/ -devfs_handle_t -xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_dev); -} - -xwidgetnum_t -xtalk_intr_target_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_target); -} - -xtalk_intr_vector_t -xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_vector); -} - -iopaddr_t -xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) -{ - return (xtalk_intr->xi_addr); -} - -void * -xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_sfarg); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_dev); -} - -xwidgetnum_t -xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_target); -} - -iopaddr_t -xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_xtalk_addr); -} - -ulong -xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_mapsz); -} - -caddr_t -xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_kvaddr); -} - - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_dev); -} - -xwidgetnum_t -xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_target); -} - - -/****** Generic crosstalk widget information interfaces ******/ - -/* xwidget_info_chk: - * check to see if this vertex is a widget; - * if so, return its widget_info (if any). - * if not, return NULL. - */ -xwidget_info_t -xwidget_info_chk(devfs_handle_t xwidget) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); - return (xwidget_info_t) ainfo; -} - - -xwidget_info_t -xwidget_info_get(devfs_handle_t xwidget) -{ - xwidget_info_t widget_info; - - widget_info = (xwidget_info_t) - hwgraph_fastinfo_get(xwidget); - -#ifdef LATER - if ((widget_info != NULL) && - (widget_info->w_fingerprint != widget_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v bad xwidget_info", xwidget); -#else - PRINT_PANIC("%x bad xwidget_info", xwidget); -#endif -#endif /* LATER */ - - return (widget_info); -} - -void -xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) -{ - if (widget_info != NULL) - widget_info->w_fingerprint = widget_info_fingerprint; - - hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); - - /* Also, mark this vertex as an xwidget, - * and use the widget_info, so xwidget_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, - (arbitrary_info_t) widget_info); -} - -devfs_handle_t -xwidget_info_dev_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_vertex); -} - -xwidgetnum_t -xwidget_info_id_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_id); -} - - -devfs_handle_t -xwidget_info_master_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_master); -} - -xwidgetnum_t -xwidget_info_masterid_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_masterid); -} - -xwidget_part_num_t -xwidget_info_part_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.part_num); -} - -xwidget_mfg_num_t -xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.mfg_num); -} -/* Extract the widget name from the widget information - * for the xtalk widget. - */ -char * -xwidget_info_name_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget info"); - return(xwidget_info->w_name); -} -/****** Generic crosstalk initialization interfaces ******/ - -/* - * One-time initialization needed for systems that support crosstalk. - */ -void -xtalk_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("xtalk_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (xtalk_registry == NULL) { - cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); - if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(xtalk_registry != NULL); -} - -/* - * Associate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); -} - -/* - * Disassociate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_unregister(devfs_handle_t provider) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); -} - -/* - * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk - * provider. - */ -xtalk_provider_t * -xtalk_provider_fns_get(devfs_handle_t provider) -{ - return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); -} - -/* - * Announce a driver for a particular crosstalk part. - * Returns 0 on success or -1 on failure. Failure occurs if the - * specified hardware already has a driver. - */ -/*ARGSUSED4 */ -int -xwidget_driver_register(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine could call - * xwidget_driver_register before the - * system calls xtalk_init; so, we - * make the call here. - */ - if (xtalk_registry == NULL) - xtalk_init(); - - return cdl_add_driver(xtalk_registry, - part_num, mfg_num, - driver_prefix, flags, NULL); -} - -/* - * Inform xtalk infrastructure that a driver is no longer available for - * handling any widgets. - */ -void -xwidget_driver_unregister(char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called registger; so we - * can assume we have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - cdl_del_driver(xtalk_registry, driver_prefix, NULL); -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -xtalk_iterate(char *driver_prefix, - xtalk_iter_f *func) -{ - ASSERT(xtalk_registry != NULL); - - cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); -} - -/* - * xwidget_register: - * Register a xtalk device (xwidget) by doing the following. - * -allocate and initialize xwidget_info data - * -allocate a hwgraph vertex with name based on widget number (id) - * -look up the widget's initialization function and call it, - * or remember the vertex for later initialization. - * - */ -int -xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - devfs_handle_t widget, /* widget to initialize */ - xwidgetnum_t id, /* widget's target id (0..f) */ - devfs_handle_t master, /* widget's master vertex */ - xwidgetnum_t targetid, /* master's target id (9/a) */ - async_attach_t aa) -{ - xwidget_info_t widget_info; - char *s,devnm[MAXDEVNAME]; - - /* Allocate widget_info and associate it with widget vertex */ - NEW(widget_info); - - /* Initialize widget_info */ - widget_info->w_vertex = widget; - widget_info->w_id = id; - widget_info->w_master = master; - widget_info->w_masterid = targetid; - widget_info->w_hwid = *hwid; /* structure copy */ - widget_info->w_efunc = 0; - widget_info->w_einfo = 0; - /* - * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interrupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(widget,devnm,MAXDEVNAME); - widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(widget_info->w_name,s); - - xwidget_info_set(widget, widget_info); - - device_master_set(widget, master); - - /* All the driver init routines (including - * xtalk_init) are called before we get into - * attaching devices, so we can assume we - * have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - /* - * Add pointer to async attach info -- tear down will be done when - * the particular descendant is done with the info. - */ - if (aa) - async_attach_add_info(widget, aa); - - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); -} - -/* - * xwidget_unregister : - * Unregister the xtalk device and detach all its hwgraph namespace. - */ -int -xwidget_unregister(devfs_handle_t widget) -{ - xwidget_info_t widget_info; - xwidget_hwid_t hwid; - - /* Make sure that we have valid widget information initialized */ - if (!(widget_info = xwidget_info_get(widget))) - return(1); - - /* Remove the inventory information associated - * with the widget. - */ - hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1); - - hwid = &(widget_info->w_hwid); - - cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); - - /* Clean out the xwidget information */ - (void)kfree(widget_info->w_name); - BZERO((void *)widget_info, sizeof(widget_info)); - DEL(widget_info); - - return(0); -} - -/* - * Issue a link reset to a widget. - */ -void -xwidget_reset(devfs_handle_t xwidget) -{ - xswitch_reset_link(xwidget); - -} - - -void -xwidget_gfx_reset(devfs_handle_t xwidget) -{ - xwidget_info_t info; - - xswitch_reset_link(xwidget); - info = xwidget_info_get(xwidget); -#ifdef LATER - ASSERT_ALWAYS(info != NULL); -#endif - - /* - * Enable this for other architectures once we add widget_reset to the - * xtalk provider interface. - */ - DEV_FUNC(xtalk_provider, widget_reset) - (xwidget_info_master_get(info), xwidget_info_id_get(info)); -} - -#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ - -/* Get the canonical hwgraph name of xtalk widget */ -char * -xwidget_name_get(devfs_handle_t xwidget_vhdl) -{ - xwidget_info_t info; - - /* If we have a bogus widget handle then return - * a default anonymous widget name. - */ - if (xwidget_vhdl == GRAPH_VERTEX_NONE) - return(ANON_XWIDGET_NAME); - /* Read the widget name stored in the widget info - * for the widget setup during widget initialization. - */ - info = xwidget_info_get(xwidget_vhdl); - ASSERT(info != NULL); - return(xwidget_info_name_get(info)); -} - -/* - * xtalk_device_shutdown - * Disable the specified xtalk widget and clean out all the software - * state associated with it. - */ -int -xtalk_device_shutdown(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - devfs_handle_t widget_vhdl; - char edge_name[8]; - - sprintf(edge_name, "%d", widget); - if (hwgraph_traverse(xbus_vhdl, edge_name, &widget_vhdl) - != GRAPH_SUCCESS) - return(1); - - xwidget_unregister(widget_vhdl); - - return(0); -} diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index 35191abfd28..f1fe35e6696 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile @@ -9,11 +9,7 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y := probe.o setup.o sn_asm.o sv.o bte.o iomv.o \ - irq.o mca.o +obj-y := probe.o setup.o sv.o bte.o irq.o mca.o sn2/ -obj-$(CONFIG_IA64_SGI_SN2) += sn2/ -obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o obj-$(CONFIG_IA64_GENERIC) += machvec.o obj-$(CONFIG_MODULES) += sn_ksyms.o -obj-$(CONFIG_IA64_SGI_SN_BRT) += bte_regr_test.o diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c index 0e592be762e..88409fcc4b8 100644 --- a/arch/ia64/sn/kernel/bte.c +++ b/arch/ia64/sn/kernel/bte.c @@ -1,7 +1,7 @@ /* * * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -38,124 +38,160 @@ #include #include #include -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif #include #include #include #include -#include +#include -int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; +#ifndef L1_CACHE_MASK +#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) +#endif /* - * bte_init_node(nodepda, cnode) + * The base address of for each set of bte registers. + */ +static int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; + + +/************************************************************************ + * Block Transfer Engine copy related functions. * - * Initialize the nodepda structure with BTE base addresses and - * spinlocks. + ***********************************************************************/ + + +/* + * bte_copy(src, dest, len, mode, notification) + * + * Use the block transfer engine to move kernel memory from src to dest + * using the assigned mode. + * + * Paramaters: + * src - physical address of the transfer source. + * dest - physical address of the transfer destination. + * len - number of bytes to transfer from source to dest. + * mode - hardware defined. See reference information + * for IBCT0/1 in the SHUB Programmers Reference + * notification - kernel virtual address of the notification cache + * line. If NULL, the default is used and + * the bte_copy is synchronous. * - * NOTE: The kernel parameter btetest will cause the initialization - * code to reserve blocks of physically contiguous memory to be - * used by the bte test module. + * NOTE: This function requires src, dest, and len to + * be cacheline aligned. */ -void -bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +bte_result_t +bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) { - int i; + int bte_to_use; + u64 transfer_size; + struct bteinfo_s *bte; + bte_result_t bte_status; + unsigned long irq_flags; - /* - * Indicate that all the block transfer engines on this node - * are available. - */ - for (i = 0; i < BTES_PER_NODE; i++) { -#ifdef CONFIG_IA64_SGI_SN2 - /* >>> Don't know why the 0x1800000L is here. Robin */ - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", + src, dest, len, mode, notification)); -#elif CONFIG_IA64_SGI_SN1 - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_HUB_ADDR(bte_offsets[i]); -#else -#error BTE Not defined for this hardware platform. -#endif + if (len == 0) { + return BTE_SUCCESS; + } + + ASSERT(!((len & L1_CACHE_MASK) || + (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); + ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); + + do { + local_irq_save(irq_flags); + + bte_to_use = 0; + /* Attempt to lock one of the BTE interfaces. */ + while ((bte_to_use < BTES_PER_NODE) && + BTE_LOCK_IF_AVAIL(bte_to_use)) { + bte_to_use++; + } + + if (bte_to_use < BTES_PER_NODE) { + break; + } + + local_irq_restore(irq_flags); + + if (!(mode & BTE_WACQUIRE)) { + return BTEFAIL_NOTAVAIL; + } + + /* Wait until a bte is available. */ + udelay(10); + } while (1); + + bte = pda->cpu_bte_if[bte_to_use]; + BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); - /* - * Initialize the notification and spinlock - * so the first transfer can occur. - */ - mynodepda->bte_if[i].most_rcnt_na = - &(mynodepda->bte_if[i].notify); - mynodepda->bte_if[i].notify = 0L; -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_lock_init(&mynodepda->bte_if[i].spinlock); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - mynodepda->bte_if[i].bte_test_buf = - alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + if (notification == NULL) { + /* User does not want to be notified. */ + bte->most_rcnt_na = &bte->notify; + } else { + bte->most_rcnt_na = notification; } -} + /* Calculate the number of cache lines to transfer. */ + transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); + /* Initialize the notification to a known value. */ + *bte->most_rcnt_na = -1L; -/* - * bte_reset_nasid(nasid_t) - * - * Does a soft reset of the BTEs on the specified nasid. - * This is followed by a one-line transfer from each of the - * virtual interfaces. - */ -void -bte_reset_nasid(nasid_t n) -{ - ii_ibcr_u_t ibcr; - - ibcr.ii_ibcr_regval = REMOTE_HUB_L(n, IIO_IBCR); - ibcr.ii_ibcr_fld_s.i_soft_reset = 1; - REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval); - - /* One line transfer on virtual interface 0 */ - REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS0)) { - /* >>> Need some way out in case of hang... */ + /* Set the status reg busy bit and transfer length */ + BTE_PRINTKV(("IBLS - HUB_S(0x%p, 0x%lx)\n", + BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); + HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); + + /* Set the source and destination registers */ + BTE_PRINTKV(("IBSA - HUB_S(0x%p, 0x%lx)\n", BTEREG_SRC_ADDR, + (TO_PHYS(src)))); + HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); + BTE_PRINTKV(("IBDA - HUB_S(0x%p, 0x%lx)\n", BTEREG_DEST_ADDR, + (TO_PHYS(dest)))); + HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); + + /* Set the notification register */ + BTE_PRINTKV(("IBNA - HUB_S(0x%p, 0x%lx)\n", BTEREG_NOTIF_ADDR, + (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))))); + HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))); + + + /* Initiate the transfer */ + BTE_PRINTK(("IBCT - HUB_S(0x%p, 0x%lx)\n", BTEREG_CTRL_ADDR, + BTE_VALID_MODE(mode))); + HUB_S(BTEREG_CTRL_ADDR, BTE_VALID_MODE(mode)); + + spin_unlock_irqrestore(&bte->spinlock, irq_flags); + + + if (notification != NULL) { + return BTE_SUCCESS; } - /* One line transfer on virtual interface 1 */ - REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS1)) { - /* >>> Need some way out in case of hang... */ + while (*bte->most_rcnt_na == -1UL) { } -} -/* - * bte_init_cpu() - * - * Initialize the cpupda structure with pointers to the - * nodepda bte blocks. - * - */ -void -bte_init_cpu(void) -{ - pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); - pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, most_rcnt_na = 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + if (*bte->most_rcnt_na & IBLS_ERROR) { + bte_status = *bte->most_rcnt_na & ~IBLS_ERROR; + *bte->most_rcnt_na = 0L; + } else { + bte_status = BTE_SUCCESS; + } + BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + return bte_status; } @@ -192,15 +228,11 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) char *bteBlock; if (len == 0) { - return (BTE_SUCCESS); + return BTE_SUCCESS; } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING -#error bte_unaligned_copy() assumes single BTE selection in bte_copy(). -#else /* temporary buffer used during unaligned transfers */ - bteBlock = pda->cpu_bte_if[0]->bte_test_buf; -#endif + bteBlock = pda->cpu_bte_if[0]->scratch_buf; headBcopySrcOffset = src & L1_CACHE_MASK; destFirstCacheOffset = dest & L1_CACHE_MASK; @@ -265,15 +297,15 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) headBteLen += footBteLen; } else if (footBcopyLen > 0) { rv = bte_copy(footBteSource, - __pa(bteBlock), + ia64_tpa((unsigned long)bteBlock), footBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } memcpy(__va(footBcopyDest), - (char *)bteBlock, footBcopyLen); + (char *) bteBlock, footBcopyLen); } } else { footBcopyLen = 0; @@ -288,7 +320,7 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) (len - headBcopyLen - footBcopyLen), mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } } @@ -315,14 +347,93 @@ bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode) if (headBcopyLen > 0) { rv = bte_copy(headBteSource, - __pa(bteBlock), headBteLen, mode, NULL); + ia64_tpa((unsigned long)bteBlock), headBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } - memcpy(__va(headBcopyDest), ((char *)bteBlock + + memcpy(__va(headBcopyDest), ((char *) bteBlock + headBcopySrcOffset), headBcopyLen); } - return (BTE_SUCCESS); + return BTE_SUCCESS; +} + + +/************************************************************************ + * Block Transfer Engine initialization functions. + * + ***********************************************************************/ + + +/* + * bte_init_node(nodepda, cnode) + * + * Initialize the nodepda structure with BTE base addresses and + * spinlocks. + */ +void +bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +{ + int i; + + + /* + * Indicate that all the block transfer engines on this node + * are available. + */ + + /* + * Allocate one bte_recover_t structure per node. It holds + * the recovery lock for node. All the bte interface structures + * will point at this one bte_recover structure to get the lock. + */ + spin_lock_init(&mynodepda->bte_recovery_lock); + init_timer(&mynodepda->bte_recovery_timer); + mynodepda->bte_recovery_timer.function = bte_error_handler; + mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; + + for (i = 0; i < BTES_PER_NODE; i++) { + /* >>> Don't know why the 0x1800000L is here. Robin */ + mynodepda->bte_if[i].bte_base_addr = + (char *) LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + + /* + * Initialize the notification and spinlock + * so the first transfer can occur. + */ + mynodepda->bte_if[i].most_rcnt_na = + &(mynodepda->bte_if[i].notify); + mynodepda->bte_if[i].notify = 0L; + spin_lock_init(&mynodepda->bte_if[i].spinlock); + + mynodepda->bte_if[i].scratch_buf = + alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + mynodepda->bte_if[i].bte_cnode = cnode; + mynodepda->bte_if[i].bte_error_count = 0; + mynodepda->bte_if[i].bte_num = i; + mynodepda->bte_if[i].cleanup_active = 0; + mynodepda->bte_if[i].bh_error = 0; + } + +} + +/* + * bte_init_cpu() + * + * Initialize the cpupda structure with pointers to the + * nodepda bte blocks. + * + */ +void +bte_init_cpu(void) +{ + /* Called by setup.c as each cpu is being added to the nodepda */ + if (local_node_data->active_cpu_count & 0x1) { + pda->cpu_bte_if[0] = &(nodepda->bte_if[0]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[1]); + } else { + pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + } } diff --git a/arch/ia64/sn/kernel/idle.c b/arch/ia64/sn/kernel/idle.c new file mode 100644 index 00000000000..fe86352a7c9 --- /dev/null +++ b/arch/ia64/sn/kernel/idle.c @@ -0,0 +1,36 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include + +void snidle(int state) { + if (state) { + if (pda.idle_flag == 0) { + /* + * Turn the activity LED off. + */ + set_led_bits(0, LED_CPU_ACTIVITY); + } + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) + SIMULATOR_SLEEP(); +#endif + + pda.idle_flag = 1; + } else { + /* + * Turn the activity LED on. + */ + set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); + + pda.idle_flag = 0; + } +} diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c deleted file mode 100644 index 6d439ee7521..00000000000 --- a/arch/ia64/sn/kernel/iomv.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include - -extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */ - -/** - * sn_inb - read a byte from a port - * @port: port to read from - * - * Reads a byte from @port and returns it to the caller. - */ -unsigned int -sn_inb (unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - unsigned char ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inw - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inw (unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - unsigned short ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inl - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inl (unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - unsigned int ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_outb - write a byte to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outb (unsigned char val, unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outw - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outw (unsigned short val, unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outl - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outl (unsigned int val, unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - - *addr = val; -} - -EXPORT_SYMBOL(sn_inb); -EXPORT_SYMBOL(sn_inw); -EXPORT_SYMBOL(sn_inl); -EXPORT_SYMBOL(sn_outb); -EXPORT_SYMBOL(sn_outw); -EXPORT_SYMBOL(sn_outl); diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 4bf411ccae9..8d58bfbc7bf 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -1,7 +1,7 @@ /* - * Platform dependent support for SGI SN1 + * Platform dependent support for SGI SN * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -32,12 +32,12 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include #include #include #include #include #include +#include #include #include #include @@ -49,19 +49,25 @@ #include #include #include -#ifdef ajmtestintr #include #include -#endif /* ajmtestintr */ #include #include #include #include #include #include -#include +#include +#include +#include +#include int irq_to_bit_pos(int irq); +static void force_interrupt(int irq); +extern void pcibr_force_interrupt(pcibr_intr_t intr); +extern int sn_force_interrupt_flag; + + static unsigned int sn_startup_irq(unsigned int irq) @@ -87,49 +93,11 @@ sn_enable_irq(unsigned int irq) static void sn_ack_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - int bit = -1; - unsigned long long intpend_val; - int subnode; -#endif -#ifdef CONFIG_IA64_SGI_SN2 unsigned long event_occurred, mask = 0; -#endif int nasid; irq = irq & 0xff; nasid = smp_physical_node_id(); -#ifdef CONFIG_IA64_SGI_SN1 - subnode = cpuid_to_subnode(smp_processor_id()); - if (irq == SGI_UART_IRQ) { - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & (1L<sn_in_service_ivecs); } static void sn_end_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - unsigned long long intpend_val, mask = 0x70L; - int subnode; -#endif int nasid; -#ifdef CONFIG_IA64_SGI_SN2 + int ivec; unsigned long event_occurred; -#endif - irq = irq & 0xff; -#ifdef CONFIG_IA64_SGI_SN1 - if (irq == SGI_UART_IRQ) { - nasid = smp_physical_node_id(); - subnode = cpuid_to_subnode(smp_processor_id()); - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & mask) { - platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0); - } - } -#endif -#ifdef CONFIG_IA64_SGI_SN2 - if (irq == SGI_UART_VECTOR) { + ivec = irq & 0xff; + if (ivec == SGI_UART_VECTOR) { nasid = smp_physical_node_id(); event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); // If the UART bit is set here, we may have received an interrupt from the @@ -181,8 +133,9 @@ sn_end_irq(unsigned int irq) platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0); } } -#endif - + __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs); + if (sn_force_interrupt_flag) + force_interrupt(irq); } static void @@ -191,7 +144,7 @@ sn_set_affinity_irq(unsigned int irq, unsigned long mask) } -struct hw_interrupt_type irq_type_iosapic_level = { +struct hw_interrupt_type irq_type_sn = { "SN hub", sn_startup_irq, sn_shutdown_irq, @@ -203,29 +156,17 @@ struct hw_interrupt_type irq_type_iosapic_level = { }; -#define irq_type_sn irq_type_iosapic_level -struct irq_desc *_sn_irq_desc[NR_CPUS]; - struct irq_desc * sn_irq_desc(unsigned int irq) { - int cpu = irq >> 8; - irq = irq & 0xff; + irq = SN_IVEC_FROM_IRQ(irq); - return(_sn_irq_desc[cpu] + irq); + return(_irq_desc + irq); } u8 sn_irq_to_vector(u8 irq) { - return(irq & 0xff); -} - -int gsi_to_vector(u32 irq) { - return irq & 0xff; -} - -int gsi_to_irq(u32 irq) { - return irq & 0xff; + return(irq); } unsigned int @@ -233,47 +174,24 @@ sn_local_vector_to_irq(u8 vector) { return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); } -void *kmalloc(size_t, int); - void sn_irq_init (void) { int i; irq_desc_t *base_desc = _irq_desc; - for (i=IA64_FIRST_DEVICE_VECTOR; i 118) bit = 118; -#ifdef CONFIG_IA64_SGI_SN1 - if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { - return SGI_UART_IRQ; - } -#endif - return bit + BIT_TO_IRQ; } @@ -285,53 +203,181 @@ irq_to_bit_pos(int irq) { return bit; } -#ifdef ajmtestintr - -#include -struct timer_list intr_test_timer = TIMER_INITIALIZER(NULL, 0, 0); -int intr_test_icount[NR_IRQS]; -struct intr_test_reg_struct { - pcibr_soft_t pcibr_soft; - int slot; +struct pcibr_intr_list_t { + struct pcibr_intr_list_t *next; + pcibr_intr_t intr; }; -struct intr_test_reg_struct intr_test_registered[NR_IRQS]; + +static struct pcibr_intr_list_t **pcibr_intr_list; void -intr_test_handle_timer(unsigned long data) { +register_pcibr_intr(int irq, pcibr_intr_t intr) { + struct pcibr_intr_list_t *p = kmalloc(sizeof(struct pcibr_intr_list_t), GFP_KERNEL); + struct pcibr_intr_list_t *list; + int cpu = SN_CPU_FROM_IRQ(irq); + + if (pcibr_intr_list == NULL) { + pcibr_intr_list = kmalloc(sizeof(struct pcibr_intr_list_t *) * NR_IRQS, GFP_KERNEL); + if (pcibr_intr_list == NULL) panic("Could not allocate memory for pcibr_intr_list\n"); + memset( (void *)pcibr_intr_list, 0, sizeof(struct pcibr_intr_list_t *) * NR_IRQS); + } + if (pdacpu(cpu)->sn_last_irq < irq) { + pdacpu(cpu)->sn_last_irq = irq; + } + if (pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq; + if (!p) panic("Could not allocate memory for pcibr_intr_list_t\n"); + if ((list = pcibr_intr_list[irq])) { + while (list->next) list = list->next; + list->next = p; + p->next = NULL; + p->intr = intr; + } else { + pcibr_intr_list[irq] = p; + p->next = NULL; + p->intr = intr; + } +} + +void +force_polled_int(void) { int i; - bridge_t *bridge; - - for (i=0;ibs_intr[intr_test_registered[i].slot].bsi_xtalk_intr; - /* send interrupt */ - bridge = pcibr_soft->bs_base; - bridge->b_force_always[intr_test_registered[i].slot].intr = 1; + struct pcibr_intr_list_t *p; + + for (i=0; iintr){ + pcibr_force_interrupt(p->intr); + } + p = p->next; } } - del_timer(&intr_test_timer); - intr_test_timer.expires = jiffies + HZ/100; - add_timer(&intr_test_timer); } -void -intr_test_set_timer(void) { - intr_test_timer.expires = jiffies + HZ/100; - intr_test_timer.function = intr_test_handle_timer; - add_timer(&intr_test_timer); +static void +force_interrupt(int irq) { + struct pcibr_intr_list_t *p = pcibr_intr_list[irq]; + + while (p) { + if (p->intr) { + pcibr_force_interrupt(p->intr); + } + p = p->next; + } +} + +/* +Check for lost interrupts. If the PIC int_status reg. says that +an interrupt has been sent, but not handled, and the interrupt +is not pending in either the cpu irr regs or in the soft irr regs, +and the interrupt is not in service, then the interrupt may have +been lost. Force an interrupt on that pin. It is possible that +the interrupt is in flight, so we may generate a spurious interrupt, +but we should never miss a real lost interrupt. +*/ + +static void +sn_check_intr(int irq, pcibr_intr_t intr) { + unsigned long regval; + int irr_reg_num; + int irr_bit; + unsigned long irr_reg; + + + regval = intr->bi_soft->bs_base->p_int_status_64; + irr_reg_num = irq_to_vector(irq) / 64; + irr_bit = irq_to_vector(irq) % 64; + switch (irr_reg_num) { + case 0: + irr_reg = ia64_get_irr0(); + break; + case 1: + irr_reg = ia64_get_irr1(); + break; + case 2: + irr_reg = ia64_get_irr2(); + break; + case 3: + irr_reg = ia64_get_irr3(); + break; + } + if (!test_bit(irr_bit, &irr_reg) ) { + if (!test_bit(irq, pda->sn_soft_irr) ) { + if (!test_bit(irq, pda->sn_in_service_ivecs) ) { + regval &= 0xff; + if (intr->bi_ibits & regval & intr->bi_last_intr) { + regval &= ~(intr->bi_ibits & regval); + pcibr_force_interrupt(intr); + } + } + } + } + intr->bi_last_intr = regval; } void -intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) { - irq = irq & 0xff; - intr_test_registered[irq].pcibr_soft = pcibr_soft; - intr_test_registered[irq].slot = slot; +sn_lb_int_war_check(void) { + int i; + + if (pda->sn_first_irq == 0) return; + for (i=pda->sn_first_irq; + i <= pda->sn_last_irq; i++) { + struct pcibr_intr_list_t *p = pcibr_intr_list[i]; + if (p == NULL) { + continue; + } + while (p) { + sn_check_intr(i, p->intr); + p = p->next; + } + } +} + +static inline int +sn_get_next_bit(void) { + int i; + int bit; + + for (i = 3; i >= 0; i--) { + if (pda->sn_soft_irr[i] != 0) { + bit = (i * 64) + __ffs(pda->sn_soft_irr[i]); + __change_bit(bit, (volatile void *)pda->sn_soft_irr); + return(bit); + } + } + return IA64_SPURIOUS_INT_VECTOR; } void -intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) { - intr_test_icount[irq]++; - printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq); +sn_set_tpr(int vector) { + if (vector > IA64_LAST_DEVICE_VECTOR || vector < IA64_FIRST_DEVICE_VECTOR) { + ia64_set_tpr(vector); + } else { + ia64_set_tpr(IA64_LAST_DEVICE_VECTOR); + } +} + +static inline void +sn_get_all_ivr(void) { + int vector; + + vector = ia64_get_ivr(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + __set_bit(vector, (volatile void *)pda->sn_soft_irr); + ia64_eoi(); + if (vector > IA64_LAST_DEVICE_VECTOR) return; + vector = ia64_get_ivr(); + } +} + +int +sn_get_ivr(void) { + int vector; + + vector = sn_get_next_bit(); + if (vector == IA64_SPURIOUS_INT_VECTOR) { + sn_get_all_ivr(); + vector = sn_get_next_bit(); + } + return vector; } -#endif /* ajmtestintr */ diff --git a/arch/ia64/sn/kernel/llsc4.c b/arch/ia64/sn/kernel/llsc4.c deleted file mode 100644 index 38373739789..00000000000 --- a/arch/ia64/sn/kernel/llsc4.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "llsc4.h" - - -#ifdef STANDALONE -#include "lock.h" -#endif - -#ifdef INTTEST -static int inttest=0; -#endif - -#ifdef IA64_SEMFIX_INSN -#undef IA64_SEMFIX_INSN -#endif -#ifdef IA64_SEMFIX -#undef IA64_SEMFIX -#endif -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" - -#define NOLOCK 0xdead -#define BGUARD(linei) (0xbbbb0000 | (linei)); -#define EGUARD(linei) (0xeeee0000 | (linei)); -#define GUARDLINE(v) ((v)&0xffff) - -/* - * Test parameter table for AUTOTEST - */ -typedef struct { - int passes; - int linecount; - int linepad; -} autotest_table_t; - -autotest_table_t autotest_table[] = { - {50000000, 2, 0x2b4 }, - {50000000, 16, 0, }, - {50000000, 16, 4, }, - {50000000, 128, 0x44 }, - {50000000, 128, 0x84 }, - {50000000, 128, 0x200 }, - {50000000, 128, 0x204 }, - {50000000, 128, 0x2b4 }, - {50000000, 2, 8*MB+0x2b4 }, - {50000000, 16, 8*MB+0 }, - {50000000, 16, 8*MB+4 }, - {50000000, 128, 8*MB+0x44 }, - {50000000, 128, 8*MB+0x84 }, - {50000000, 128, 8*MB+0x200 }, - {50000000, 128, 8*MB+0x204 }, - {50000000, 128, 8*MB+0x2b4 }, - {0}}; - -/* - * Array of virtual addresses available for test purposes. - */ - -typedef struct { - long vstart; - long vend; - long nextaddr; - long nextinit; - int wrapcount; -} memmap_t; - -#define MAPCHUNKS 128 -memmap_t memmap[MAPCHUNKS]; -int memmapx=0; - -typedef struct { - void *addr; - long data[16]; - long data_fc[16]; -} capture_line_t; - -typedef struct { - int size; - void *blockaddr; - void *shadaddr; - long blockdata[48]; - long shaddata[48]; - long blockdata_fc[48]; - long shaddata_fc[48]; - long synerr; -} capture_t; - -/* - * PORTING NOTE: revisit this statement. On hardware we put mbase at 0 and - * the rest of the tables have to start at 1MB to skip PROM tables. - */ -#define THREADPRIVATESZ() ((sizeof(threadprivate_t)+511)/512*512) -#define THREADPRIVATE(t) ((threadprivate_t*)(((long)mbase)+4096+t*THREADPRIVATESZ())) - -#define k_capture mbase->sk_capture -#define k_go mbase->sk_go -#define k_linecount mbase->sk_linecount -#define k_passes mbase->sk_passes -#define k_napticks mbase->sk_napticks -#define k_stop_on_error mbase->sk_stop_on_error -#define k_verbose mbase->sk_verbose -#define k_threadprivate mbase->sk_threadprivate -#define k_blocks mbase->sk_blocks -#define k_iter_msg mbase->sk_iter_msg -#define k_vv mbase->sk_vv -#define k_linepad mbase->sk_linepad -#define k_options mbase->sk_options -#define k_testnumber mbase->sk_testnumber -#define k_currentpass mbase->sk_currentpass - -static long blocks[MAX_LINECOUNT]; /* addresses of data blocks */ -static control_t *mbase; -static vint initialized=0; - -static unsigned int ran_conf_llsc(int); -static int rerr(capture_t *, char *, void *, void *, int, int, int, int, int, int); -static void dumpline(void *, char *, char *, void *, void *, int); -static int checkstop(int, int, uint); -static void spin(int); -static void capturedata(capture_t *, uint, void *, void *, int); -static int randn(uint max, uint *seed); -static uint zrandom (uint *zranseed); -static int set_lock(uint *, uint); -static int clr_lock(uint *, uint); -static void Speedo(void); - -int autotest_enabled=0; -static int llsctest_number=-1; -static int errstop_enabled=0; -static int fail_enabled=0; -static int l4_opt=0; -static int selective_trigger=0; -static int dump_block_addrs_opt=0; -static lock_t errlock=NOLOCK; -static private_t init_private[LLSC_MAXCPUS]; - -static int __init autotest_enable(char *str) -{ - autotest_enabled = 1; - return 1; -} -static int __init set_llscblkadr(char *str) -{ - dump_block_addrs_opt = 1; - return 1; -} -static int __init set_llscselt(char *str) -{ - selective_trigger = 1; - return 1; -} -static int __init set_llsctest(char *str) -{ - llsctest_number = simple_strtol(str, &str, 10); - if (llsctest_number < 0 || llsctest_number > 15) - llsctest_number = -1; - return 1; -} -static int __init set_llscerrstop(char *str) -{ - errstop_enabled = 1; - return 1; -} -static int __init set_llscfail(char *str) -{ - fail_enabled = 8; - return 1; -} -static int __init set_llscl4(char *str) -{ - l4_opt = 1; - return 1; -} - -static void print_params(void) -{ - printk ("********* Enter AUTOTEST facility on master cpu *************\n"); - printk (" Test options:\n"); - printk (" llsctest=\t%d\tTest number to run (all = -1)\n", llsctest_number); - printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); - printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); - printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk (" llscl4 \t%s\tRun only tests that evict from L4\n", l4_opt ? "on" : "off"); - printk (" SEMFIX: %s\n", IA64_SEMFIX); - printk ("\n"); -} -__setup("autotest", autotest_enable); -__setup("llsctest=", set_llsctest); -__setup("llscerrstop", set_llscerrstop); -__setup("llscfail", set_llscfail); -__setup("llscselt", set_llscselt); -__setup("llscblkadr", set_llscblkadr); -__setup("llscl4", set_llscl4); - - - -static inline int -set_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_acq(lock, NOLOCK, id); - return (old == NOLOCK); -} - -static inline int -clr_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_rel(lock, id, NOLOCK); - return (old == id); -} - -static inline void -init_lock(uint *lock) -{ - *lock = NOLOCK; -} - -/*------------------------------------------------------------------------+ -| Routine : ran_conf_llsc - ll/sc shared data test | -| Description: This test checks the coherency of shared data | -+------------------------------------------------------------------------*/ -static unsigned int -ran_conf_llsc(int thread) -{ - private_t pval; - share_t sval, sval2; - uint vv, linei, slinei, sharei, pass; - long t; - lock_t lockpat; - share_t *sharecopy; - long verbose, napticks, passes, linecount, lcount; - dataline_t *linep, *slinep; - int s, seed; - threadprivate_t *tp; - uint iter_msg, iter_msg_i=0; - int vv_mask; - int correct_errors; - int errs=0; - int stillbad; - capture_t capdata; - private_t *privp; - share_t *sharep; - - - linecount = k_linecount; - napticks = k_napticks; - verbose = k_verbose; - passes = k_passes; - iter_msg = k_iter_msg; - seed = (thread + 1) * 647; - tp = THREADPRIVATE(thread); - vv_mask = (k_vv>>((thread%16)*4)) & 0xf; - correct_errors = k_options&0xff; - - memset (&capdata, 0, sizeof(capdata)); - for (linei=0; lineiprivate[linei] = thread; - - for (pass = 1; passes == 0 || pass < passes; pass++) { - lockpat = (pass & 0x0fffffff) + (thread <<28); - if (lockpat == NOLOCK) - continue; - tp->threadpasses = pass; - if (checkstop(thread, pass, lockpat)) - return 0; - iter_msg_i++; - if (iter_msg && iter_msg_i > iter_msg) { - printk("Thread %d, Pass %d\n", thread, pass); - iter_msg_i = 0; - } - lcount = 0; - - /* - * Select line to perform operations on. - */ - linei = randn(linecount, &seed); - sharei = randn(2, &seed); - slinei = (linei + (linecount/2))%linecount; /* I don't like this - fix later */ - - linep = (dataline_t *)blocks[linei]; - slinep = (dataline_t *)blocks[slinei]; - if (sharei == 0) - sharecopy = &slinep->share0; - else - sharecopy = &slinep->share1; - - - vv = randn(4, &seed); - if ((vv_mask & (1<private[thread]; - sharep = &linep->share[sharei]; - - switch(vv) { - case 0: - /* Read and verify private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - if (correct_errors) { - tp->private[linei] = *privp; - } - errs++; - } - break; - - case 1: - /* Read, verify, and increment private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count & inc", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - errs++; - } - pval = (pval==255) ? 0 : pval+1; - *privp = pval; - tp->private[linei] = pval; - break; - - case 2: - /* Lock line, read and verify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - - sval = *sharep; - sval2 = *sharecopy; - if (pass > 12 && thread == 0 && fail_enabled == 1) - sval++; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - if (correct_errors) - *sharep = *sharecopy; - errs++; - } - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data unlock", linep, slinep, thread, pass, linei, lockpat, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - - case 3: - /* Lock line, read and verify shared data, modify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock & inc", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - sval = *sharep; - sval2 = *sharecopy; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data & inc", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - errs++; - } - - *sharep = lockpat; - *sharecopy = lockpat; - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data & inc unlock", linep, slinep, thread, pass, linei, thread, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - } - } - - return (errs > 0); -} - -static void -trigger_la(long val) -{ - long *p; - - p = (long*)0xc0000a0001000020L; /* PI_CPU_NUM */ - *p = val; -} - -static long -getsynerr(void) -{ - long err, *errp; - - errp = (long*)0xc0000e0000000340L; /* SYN_ERR */ - err = *errp; - if (err) - *errp = -1L; - return (err & ~0x60); -} - -static int -rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int badlinei, int exp, int found, int stillbad) -{ - int cpu, i, linei; - long synerr; - int selt; - - - selt = selective_trigger && stillbad > 1 && - memcmp(cap->blockdata, cap->blockdata_fc, 128) != 0 && - memcmp(cap->shaddata, cap->shaddata_fc, 128) == 0; - if (selt) { - trigger_la(pass); - } else if (selective_trigger) { - k_go = ST_STOP; - return k_stop_on_error;; - } - - spin(1); - i = 100; - while (i && set_lock(&errlock, 1) != 1) { - spin(1); - i--; - } - printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", - msg, k_testnumber, thread, badlinei, pass, pass, jiffies, exp, found); - - dumpline (lp, "Corrupted data", "D ", cap->blockaddr, cap->blockdata, cap->size); -#ifdef ZZZ - if (memcmp(cap->blockdata, cap->blockdata_fc, 128)) - dumpline (lp, "Corrupted data", "DF", cap->blockaddr, cap->blockdata_fc, cap->size); -#endif - - if (cap->shadaddr) { - dumpline (slp, "Shadow data", "S ", cap->shadaddr, cap->shaddata, cap->size); -#ifdef ZZZ - if (memcmp(cap->shaddata, cap->shaddata_fc, 128)) - dumpline (slp, "Shadow data", "SF", cap->shadaddr, cap->shaddata_fc, cap->size); -#endif - } - - printk("Threadpasses: "); - for (cpu=0,i=0; cputhreadpasses) { - if (i && (i%8) == 0) - printk("\n : "); - printk(" %d:0x%x", cpu, k_threadprivate[cpu]->threadpasses); - i++; - } - printk("\n"); - - for (linei=0; lineiguard1); - g2linei = GUARDLINE(linep->guard2); - g1err = (g1linei != linei); - g2err = (g2linei != linei); - sh0err = (linep->share[0] != slinep->share0); - sh1err = (linep->share[1] != slinep->share1); - - if (g1err || g2err || sh0err || sh1err) { - printk("Line 0x%lx (%03d), %sG1 0x%lx (%03d), %sG2 0x%lx (%03d), %sSH0 %08x (%08x), %sSH1 %08x (%08x)\n", - blocks[linei], linei, - g1err ? "*" : " ", blocks[g1linei], g1linei, - g2err ? "*" : " ", blocks[g2linei], g2linei, - sh0err ? "*" : " ", linep->share[0], slinep->share0, - sh1err ? "*" : " ", linep->share[1], slinep->share1); - - - } - } - - printk("\nData was %sfixed by flushcache\n", (stillbad == 1 ? "**** NOT **** " : " ")); - synerr = getsynerr(); - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - spin(2); - printk("\n\n"); - clr_lock(&errlock, 1); - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - return k_stop_on_error; -} - - -static void -dumpline(void *lp, char *str1, char *str2, void *addr, void *data, int size) -{ - long *p; - int i, off; - - printk("%s at 0x%lx, size %d, block starts at 0x%lx\n", str1, (long)addr, size, (long)lp); - p = (long*) data; - for (i=0; i<48; i++, p++) { - if (i%8 == 0) printk("%2s", i==16 ? str2 : " "); - printk(" %016lx", *p); - if ((i&7)==7) printk("\n"); - } - printk(" "); - off = (((long)addr) ^ size) & 63L; - for (i=0; i=off) ? "--" : " "); - if ((i%8) == 7) - printk(" "); - } - - off = ((long)addr) & 127; - printk(" (line %d)\n", 2+off/64+1); -} - - -static int -randn(uint max, uint *seedp) -{ - if (max == 1) - return(0); - else - return((int)(zrandom(seedp)>>10) % max); -} - - -static int -checkstop(int thread, int pass, uint lockpat) -{ - long synerr; - - if (k_go == ST_RUN) - return 0; - if (k_go == ST_STOP) - return 1; - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - synerr = getsynerr(); - spin(2); - if (k_go == ST_STOP) - return 1; - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - return 1; -} - - -static void -spin(int j) -{ - udelay(j * 500000); -} - -static void -capturedata(capture_t *cap, uint pass, void *blockaddr, void *shadaddr, int size) -{ - - if (!selective_trigger) - trigger_la (pass); - - memcpy (cap->blockdata, CACHEALIGN(blockaddr)-128, 3*128); - if (shadaddr) - memcpy (cap->shaddata, CACHEALIGN(shadaddr)-128, 3*128); - - if (k_stop_on_error) { - k_go = ST_ERRSTOP; - } - - cap->size = size; - cap->blockaddr = blockaddr; - cap->shadaddr = shadaddr; - - asm volatile ("fc %0" :: "r"(blockaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->blockdata_fc, CACHEALIGN(blockaddr)-128, 3*128); - - if (shadaddr) { - asm volatile ("fc %0" :: "r"(shadaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->shaddata_fc, CACHEALIGN(shadaddr)-128, 3*128); - } -} - -int zranmult = 0x48c27395; - -static uint -zrandom (uint *seedp) -{ - *seedp = (*seedp * zranmult) & 0x7fffffff; - return (*seedp); -} - - -void -set_autotest_params(void) -{ - static int testnumber=-1; - - if (llsctest_number >= 0) { - testnumber = llsctest_number; - } else { - testnumber++; - if (autotest_table[testnumber].passes == 0) { - testnumber = 0; - dump_block_addrs_opt = 0; - } - } - if (testnumber == 0 && l4_opt) testnumber = 9; - - k_passes = autotest_table[testnumber].passes; - k_linepad = autotest_table[testnumber].linepad; - k_linecount = autotest_table[testnumber].linecount; - k_testnumber = testnumber; - - if (IS_RUNNING_ON_SIMULATOR()) { - printk ("llsc start test %ld\n", k_testnumber); - k_passes = 1000; - } -} - - -static void -set_leds(int errs) -{ - unsigned char leds=0; - - /* - * Leds are: - * ppppeee- - * where - * pppp = test number - * eee = error count but top bit is stick - */ - - leds = ((errs&7)<<1) | ((k_testnumber&15)<<4) | (errs ? 0x08 : 0); - set_led_bits(leds, LED_MASK_AUTOTEST); -} - -static void -setup_block_addresses(void) -{ - int i, stride, memmapi; - dataline_t *dp; - long *ip, *ipe; - - - stride = k_linepad + sizeof(dataline_t); - memmapi = 0; - for (i=0; i= memmap[memmapi].vend) { - memmap[memmapi].wrapcount++; - memmap[memmapi].nextaddr = memmap[memmapi].vstart + - memmap[memmapi].wrapcount * sizeof(dataline_t); - } - - ip = (long*)((memmap[memmapi].nextinit+7)&~7); - ipe = (long*)(memmap[memmapi].nextaddr+2*sizeof(dataline_t)+8); - while(ip <= ipe && ip < ((long*)memmap[memmapi].vend-8)) - *ip++ = (long)ip; - memmap[memmapi].nextinit = (long) ipe; - dp->guard1 = BGUARD(i); - dp->guard2 = EGUARD(i); - dp->lock[0] = dp->lock[1] = NOLOCK; - dp->share[0] = dp->share0 = 0x1111; - dp->share[1] = dp->share1 = 0x2222; - memcpy(dp->private, init_private, LLSC_MAXCPUS*sizeof(private_t)); - - - if (stride > 16384) { - memmapi++; - if (memmapi == memmapx) - memmapi = 0; - } - } - -} - -static void -dump_block_addrs(void) -{ - int i; - - printk("LLSC TestNumber %ld\n", k_testnumber); - - for (i=0; ithreadstate == TS_KILLED) { - set_led_bits(LED_MASK_AUTOTEST, LED_MASK_AUTOTEST); - while(1); - } - k_threadprivate[cpuid]->threadstate = state; -} - -#define MINBLK (16*1024*1024) -static int -build_mem_map(unsigned long start, unsigned long end, void *arg) -{ - long lstart, lend; - long align = 8*MB; - - printk ("LLSC memmap: start 0x%lx, end 0x%lx, (0x%lx - 0x%lx)\n", - start, end, (long) virt_to_page(start), (long) virt_to_page(end-PAGE_SIZE)); - - if (memmapx >= MAPCHUNKS || (end-start) < MINBLK) - return 0; - - /* - * Start in the middle of the range & find the first non-free page in both directions - * from the midpoint. This is likely to be the bigest free block. - */ - lend = lstart = start + (end-start)/2; - while (lend < end && !PageReserved(virt_to_page(lend)) && virt_to_page(lend)->count.counter == 0) - lend += PAGE_SIZE; - lend -= PAGE_SIZE; - - while (lstart >= start && !PageReserved(virt_to_page(lstart)) && virt_to_page(lstart)->count.counter == 0) - lstart -= PAGE_SIZE; - lstart += PAGE_SIZE; - - lstart = (lstart + align -1) /align * align; - end = end / align * align; - if (lstart >= end) - return 0; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); - - memmap[memmapx].vstart = lstart; - memmap[memmapx].vend = end; - memmapx++; - return 0; -} - -void int_test(void); - -int -llsc_main (int cpuid) -{ - int i, cpu, is_master, repeatcnt=0; - unsigned int preverr=0, errs=0, pass=0; - int automode=0; - -#ifdef INTTEST - if (inttest) - int_test(); -#endif - - if (!autotest_enabled) - return 0; - -#ifdef CONFIG_SMP - is_master = !smp_processor_id(); -#else - is_master = 1; -#endif - - - if (is_master) { - mbase = (control_t*) __get_free_pages(GFP_KERNEL, get_order(4096+THREADPRIVATESZ()*LLSC_MAXCPUS)); - printk("LLSC: mbase 0x%lx\n", (long)mbase); - print_params(); - if(!IS_RUNNING_ON_SIMULATOR()) - spin(10); - k_currentpass = 0; - k_go = ST_IDLE; - k_passes = DEF_PASSES; - k_napticks = DEF_NAPTICKS; - k_stop_on_error = DEF_STOP_ON_ERROR; - k_verbose = DEF_VERBOSE; - k_linecount = DEF_LINECOUNT; - k_iter_msg = DEF_ITER_MSG; - k_vv = DEF_VV; - k_linepad = DEF_LINEPAD; - k_blocks = (void*)blocks; - efi_memmap_walk(build_mem_map, 0); - -#ifdef CONFIG_IA64_SGI_AUTOTEST - automode = 1; -#endif - - for (i=0; i 5) { - set_autotest_params(); - repeatcnt = 0; - } - } else { - while (k_go == ST_IDLE); - } - - k_go = ST_INIT; - if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; - k_linecount = k_linecount & ~1; - setup_block_addresses(); - if (!preverr && dump_block_addrs_opt) - dump_block_addrs(); - - k_currentpass = pass++; - k_go = ST_RUN; - if (fail_enabled) - fail_enabled--; - - } else { - while (k_go != ST_RUN || k_currentpass != pass); - pass++; - } - - - set_leds(errs); - set_thread_state(cpuid, TS_RUNNING); - - errs += ran_conf_llsc(cpuid); - preverr = (k_go == ST_ERRSTOP); - - set_leds(errs); - set_thread_state(cpuid, TS_STOPPED); - - if (is_master) { - Speedo(); - for (i=0, cpu=0; cputhreadstate == TS_RUNNING) { - i++; - if (i == 10000) { - k_go = ST_STOP; - printk (" llsc master stopping test number %ld\n", k_testnumber); - } - if (i > 100000) { - k_threadprivate[cpu]->threadstate = TS_KILLED; - printk (" llsc: master killing cpuid %d, running test number %ld\n", - cpu, k_testnumber); - } - udelay(1000); - } - } - } - - goto loop; -} - - -static void -Speedo(void) -{ - static int i = 0; - - switch (++i%4) { - case 0: - printk("|\b"); - break; - case 1: - printk("\\\b"); - break; - case 2: - printk("-\b"); - break; - case 3: - printk("/\b"); - break; - } -} - -#ifdef INTTEST - -/* ======================================================================================================== - * - * Some test code to verify that interrupts work - * - * Add the following to the arch/ia64/kernel/smp.c after the comment "Reschedule callback" - * if (zzzprint_resched) printk(" cpu %d got interrupt\n", smp_processor_id()); - * - * Enable the code in arch/ia64/sn/sn1/smp.c to print sending IPIs. - * - */ - -static int __init set_inttest(char *str) -{ - inttest = 1; - autotest_enabled = 1; - - return 1; -} - -__setup("inttest=", set_inttest); - -int zzzprint_resched=0; - -void -int_test() { - int mycpu, cpu; - static volatile int control_cpu=0; - - mycpu = smp_processor_id(); - zzzprint_resched = 2; - - printk("Testing cross interrupts\n"); - - while (control_cpu != smp_num_cpus) { - if (mycpu == cpu_logical_map(control_cpu)) { - for (cpu=0; cpulock[(i)] -#define LOCK(i) set_lock(LOCKADDR(i), lockpat) -#define UNLOCK(i) clr_lock(LOCKADDR(i), lockpat) -#define GETLOCK(i) *LOCKADDR(i) -#define ZEROLOCK(i) init_lock(LOCKADDR(i)) - -#define CACHEALIGN(a) ((char*)((long)(a) & ~127L)) - -typedef uint guard_t; -typedef uint lock_t; -typedef uint share_t; -typedef uchar private_t; - -typedef struct { - guard_t guard1; - lock_t lock[2]; - share_t share[2]; - private_t private[LLSC_MAXCPUS]; - share_t share0; - share_t share1; - guard_t guard2; -} dataline_t ; - - -#define LINEPAD k_linepad -#define LINESTRIDE (((sizeof(dataline_t)+CACHELINE-1)/CACHELINE)*CACHELINE + LINEPAD) - - -typedef struct { - vint threadstate; - uint threadpasses; - private_t private[MAX_LINECOUNT]; -} threadprivate_t; - -typedef struct { - vlong sk_go; /* 0=idle, 1=init, 2=run */ - long sk_linecount; - long sk_passes; - long sk_napticks; - long sk_stop_on_error; - long sk_verbose; - long sk_iter_msg; - long sk_vv; - long sk_linepad; - long sk_options; - long sk_testnumber; - vlong sk_currentpass; - void *sk_blocks; - threadprivate_t *sk_threadprivate[LLSC_MAXCPUS]; -} control_t; - -/* Run state (k_go) constants */ -#define ST_IDLE 0 -#define ST_INIT 1 -#define ST_RUN 2 -#define ST_STOP 3 -#define ST_ERRSTOP 4 - - -/* Threadstate constants */ -#define TS_STOPPED 0 -#define TS_RUNNING 1 -#define TS_KILLED 2 - - - -int llsc_main (int cpuid); - diff --git a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c index 72a81f6f21d..010b0623b1f 100644 --- a/arch/ia64/sn/kernel/machvec.c +++ b/arch/ia64/sn/kernel/machvec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -30,32 +30,5 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include - -#ifdef CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn1 -#define MACHVEC_PLATFORM_HEADER -#else CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn2 -#define MACHVEC_PLATFORM_HEADER -#else -#error "unknown platform" -#endif - +#define MACHVEC_PLATFORM_NAME sn2 #include -#include -#include -void* -sn_mk_io_addr_MACRO - -dma_addr_t -sn_pci_map_single_MACRO - -int -sn_pci_map_sg_MACRO - -unsigned long -sn_virt_to_phys_MACRO - -void * -sn_phys_to_virt_MACRO diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c dissimilarity index 75% index cfbfa1c24aa..02a25836ebb 100644 --- a/arch/ia64/sn/kernel/mca.c +++ b/arch/ia64/sn/kernel/mca.c @@ -1,280 +1,134 @@ -/* - * File: mca.c - * Purpose: SN specific MCA code. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KDB -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static char *shub_mmr_names[] = { - "sh_event_occurred", - "sh_first_error", - "sh_event_overflow", - -/* PI */ - "sh_pi_first_error", - "sh_pi_error_summary", - "sh_pi_error_overflow", - -/* PI HW */ - "sh_pi_error_detail_1", - "sh_pi_error_detail_2", - "sh_pi_hw_time_stamp", - -/* PI UCE */ - "sh_pi_uncorrected_detail_1", - "sh_pi_uncorrected_detail_2", - "sh_pi_uncorrected_detail_3", - "sh_pi_uncorrected_detail_4", - "sh_pi_uncor_time_stamp", - -/* PI CE */ - "sh_pi_corrected_detail_1", - "sh_pi_corrected_detail_2", - "sh_pi_corrected_detail_3", - "sh_pi_corrected_detail_4", - "sh_pi_cor_time_stamp", - -/* MD */ - "sh_mem_error_summary", - "sh_mem_error_overflow", -/* MD HW */ - "sh_misc_err_hdr_upper", - "sh_misc_err_hdr_lower", - "sh_md_dqlp_mmr_xperr_val", - "sh_md_dqlp_mmr_yperr_val", - "sh_md_dqrp_mmr_xperr_val", - "sh_md_dqrp_mmr_yperr_val", - "sh_md_hw_time_stamp", - -/* MD UCE */ - "sh_dir_uc_err_hdr_lower", - "sh_dir_uc_err_hdr_upper", - "sh_md_dqlp_mmr_xuerr1", - "sh_md_dqlp_mmr_xuerr2", - "sh_md_dqlp_mmr_yuerr1", - "sh_md_dqlp_mmr_yuerr2", - "sh_md_dqrp_mmr_xuerr1", - "sh_md_dqrp_mmr_xuerr2", - "sh_md_dqrp_mmr_yuerr1", - "sh_md_dqrp_mmr_yuerr2", - "sh_md_uncor_time_stamp", - -/* MD CE */ - "sh_dir_cor_err_hdr_lower", - "sh_dir_cor_err_hdr_upper", - "sh_md_dqlp_mmr_xcerr1", - "sh_md_dqlp_mmr_xcerr2", - "sh_md_dqlp_mmr_ycerr1", - "sh_md_dqlp_mmr_ycerr2", - "sh_md_dqrp_mmr_xcerr1", - "sh_md_dqrp_mmr_xcerr2", - "sh_md_dqrp_mmr_ycerr1", - "sh_md_dqrp_mmr_ycerr2", - "sh_md_cor_time_stamp", - -/* MD CE, UCE */ - "sh_md_dqls_mmr_xamopw_err", - "sh_md_dqrs_mmr_yamopw_err", - -/* XN */ - "sh_xn_error_summary", - "sh_xn_first_error", - "sh_xn_error_overflow", - -/* XN HW */ - "sh_xniilb_error_summary", - "sh_xniilb_first_error", - "sh_xniilb_error_overflow", - "sh_xniilb_error_detail_1", - "sh_xniilb_error_detail_2", - "sh_xniilb_error_detail_3", - - "sh_ni0_error_summary_1", - "sh_ni0_first_error_1", - "sh_ni0_error_overflow_1", - - "sh_ni0_error_summary_2", - "sh_ni0_first_error_2", - "sh_ni0_error_overflow_2", - "sh_ni0_error_detail_1", - "sh_ni0_error_detail_2", - "sh_ni0_error_detail_3", - - "sh_ni1_error_summary_1", - "sh_ni1_first_error_1", - "sh_ni1_error_overflow_1", - - "sh_ni1_error_summary_2", - "sh_ni1_first_error_2", - "sh_ni1_error_overflow_2", - - "sh_ni1_error_detail_1", - "sh_ni1_error_detail_2", - "sh_ni1_error_detail_3", - - "sh_xn_hw_time_stamp", - -/* XN HW & UCE & SBE */ - "sh_xnpi_error_summary", - "sh_xnpi_first_error", - "sh_xnpi_error_overflow", - "sh_xnpi_error_detail_1", - - "sh_xnmd_error_summary", - "sh_xnmd_first_error", - "sh_xnmd_error_overflow", - "sh_xnmd_ecc_err_report", - "sh_xnmd_error_detail_1", - -/* XN UCE */ - "sh_xn_uncorrected_detail_1", - "sh_xn_uncorrected_detail_2", - "sh_xn_uncorrected_detail_3", - "sh_xn_uncorrected_detail_4", - "sh_xn_uncor_time_stamp", - -/* XN CE */ - "sh_xn_corrected_detail_1", - "sh_xn_corrected_detail_2", - "sh_xn_corrected_detail_3", - "sh_xn_corrected_detail_4", - "sh_xn_cor_time_stamp", - -/* LB HW */ - "sh_lb_error_summary", - "sh_lb_first_error", - "sh_lb_error_overflow", - "sh_lb_error_detail_1", - "sh_lb_error_detail_2", - "sh_lb_error_detail_3", - "sh_lb_error_detail_4", - "sh_lb_error_detail_5", - "sh_junk_error_status", -}; - -void -sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) -{ - sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data; - u64 *mmr_val = (u64 *)&(sh_info->shub_state); - char **mmr_name = shub_mmr_names; - int mmr_count = sizeof(sal_log_shub_state_t)>>3; - - while(mmr_count) { - if(*mmr_val) { - prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val); - } - mmr_name++; - mmr_val++; - mmr_count--; - } - -} - -void -sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) { - - struct ia64_sal_retval isrv; -// this function's sole purpose is to call SAL when we receive -// a CE interrupt from SHUB or when the timer routine decides -// we need to call SAL to check for CEs. - - // CALL SAL_LOG_CE - SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0); -} - -#include - -#define CPEI_INTERVAL (HZ/100) -struct timer_list sn_cpei_timer = TIMER_INITIALIZER(NULL, 0, 0); -void sn_init_cpei_timer(void); - -void -sn_cpei_timer_handler(unsigned long dummy) { - sn_cpei_handler(-1, NULL, NULL); - del_timer(&sn_cpei_timer); - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_cpei_timer); -} - -void -sn_init_cpei_timer() { - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - sn_cpei_timer.function = sn_cpei_timer_handler; - add_timer(&sn_cpei_timer); -} - -#ifdef ajmtestceintr - -struct timer_list sn_ce_timer; - -void -sn_ce_timer_handler(long dummy) { - unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; - - *pi_ce_error_inject_reg = 0x0000000000000100; - del_timer(&sn_ce_timer); - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_ce_timer); -} - -sn_init_ce_timer() { - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - sn_ce_timer.function = sn_ce_timer_handler; - add_timer(&sn_ce_timer); -} -#endif /* ajmtestceintr */ +/* + * File: mca.c + * Purpose: SN specific MCA code. + * + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include + + + +/* + * Interval for calling SAL to poll for errors that do NOT cause error + * interrupts. SAL will raise a CPEI if any errors are present that + * need to be logged. + */ +#define CPEI_INTERVAL (5*HZ) + + +struct timer_list sn_cpei_timer; +void sn_init_cpei_timer(void); + + +/* + * print_hook + * + * This function is the callback routine that SAL calls to log error + * info for platform errors. + */ +static int +print_hook(const char *fmt, ...) +{ + static int newline=1; + char buf[400], *p; + va_list args; + int len=0; + + + va_start(args, fmt); + if (newline) { + strcpy(buf, "+ "); + len += 2; + } + len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args); + + /* Prefix each line with "+ " to be consistent with mca.c. */ + p = buf; + while ((p=strchr(p, '\n')) && *++p != '\0') { + memmove(p+2, p, 1+strlen(p)); + strncpy(p, "+ ", 2); + len += 2; + } + newline = (p != 0); + + va_end(args); + printk("%s", buf); + return len; +} + + + +/* + * ia64_sn2_platform_plat_specific_err_print + * + * Called by the MCA handler to log platform-specific errors. + */ +void +ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) +{ + ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); +} + + + +static void +sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) +{ + /* + * this function's sole purpose is to call SAL when we receive + * a CE interrupt from SHUB or when the timer routine decides + * we need to call SAL to check for CEs. + */ + + /* CALL SAL_LOG_CE */ + + ia64_sn_plat_cpei_handler(); +} + + +static void +sn_cpei_timer_handler(unsigned long dummy) { + sn_cpei_handler(-1, NULL, NULL); + mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL); +} + +void +sn_init_cpei_timer() { + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_timer.function = sn_cpei_timer_handler; + add_timer(&sn_cpei_timer); +} diff --git a/arch/ia64/sn/kernel/misctest.c b/arch/ia64/sn/kernel/misctest.c deleted file mode 100644 index 974c95e6be1..00000000000 --- a/arch/ia64/sn/kernel/misctest.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int autotest_enabled; -long mcatest=0, debug0, debug1, debug2, debug3; - -#define HDELAY(t) (IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t)) - -/* - * mcatest - * mactest contains a decimal number (RPTT) where - * R - flag, if non zero, run forever - * - * P - identifies when to run the test - * 0 execute test at cpu 0 early init - * 1 execute test at cpu 0 idle - * 2 execute test at last (highest numbered) cpu idle - * 3 execute test on all cpus at idle - * - * TT- identifies test to run - * 01 = MCA via dup TLB dropin - * 02 = MCA via garbage address - * 03 = lfetch via garbage address - * 05 = INIT self - * 06 = INIT other cpu - * 07 = INIT non-existent cpu - * 10 = IPI stress test. Target cpu 0 - * 11 = IPI stress test. Target all cpus - * 12 = TLB stress test - * 13 = Park cpu (spinloop) - * 14 = One shot TLB test with tlb spinlock - * 15 = One shot TLB test - * 16 = One shot TLB test sync'ed with RTC - * 20 = set led to the cpuid & spin. - * 21 = Try mixed cache/uncached refs & see what happens - * 22 = Call SAL reboot - * 23 = Call PAL halt - */ -static int __init set_mcatest(char *str) -{ - int val; - get_option(&str, &val); - mcatest = val; - return 1; -} -__setup("mcatest=", set_mcatest); - -static int __init set_debug0(char *str) -{ - int val; - get_option(&str, &val); - debug0 = val; - return 1; -} -__setup("debug0=", set_debug0); - -static int __init set_debug1(char *str) -{ - int val; - get_option(&str, &val); - debug1 = val; - return 1; -} -__setup("debug1=", set_debug1); - -static int __init set_debug2(char *str) -{ - int val; - get_option(&str, &val); - debug2 = val; - return 1; -} -__setup("debug2=", set_debug2); - -static int __init set_debug3(char *str) -{ - int val; - get_option(&str, &val); - debug3 = val; - return 1; -} -__setup("debug3=", set_debug3); - -static volatile int go; - -static void -do_sync(int pos) { - if (pos != 3) - return; - else if (smp_processor_id() == 0) - go = 1; - else - while (!go); -} - -static void -sgi_mcatest_bkpt(void) -{ -} - - -/* - * Optional test - * pos - 0 called from early init - * pos - called when cpu about to go idle (fully initialized - */ -void -sgi_mcatest(int pos) -{ - long spos, test, repeat; - int cpu, curcpu, i, n; - - //if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323; - repeat = mcatest/1000; - spos = (mcatest/100)%10; - test = mcatest % 100; - curcpu = smp_processor_id(); - - if ( mcatest == 0 || !((pos == 0 && spos == 0) || - (pos == 1 && spos == 3) || - (pos == 1 && spos == 1 && curcpu == 0) || - (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1))) - return; - -again: - if (test == 1 || test == 2 || test == 3) { - void zzzmca(int); - printk("CPU %d: About to cause unexpected MCA\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - zzzmca(test-1); - - HDELAY(100000); - } - - if (test == 4) { - long result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL, 0xc00000180e022004UL, 0xc00000180e023004UL }; - long size[] = {1,2,4,8}; - int r, i, j, k; - - for (k=0; k<2; k++) { - for (i=0; i<6; i++) { - for (j=0; j<4; j++) { - printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); - result = -1; - r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); - printk(" status %d, val 0x%lx\n", r, result); - udelay(100000); - } - } - } - - } - - if (test == 5) { - cpu = curcpu; - printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Returned from INIT\n", curcpu); - } - - if (test == 6) { - cpu = curcpu ^ 1; - printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 7) { - printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 10) { - n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000; - cpu = 0; - printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i 2 && cpu != curcpu) - platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 12) { - long adr = 0xe002200000000000UL; - n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000; - printk("CPU %d: TLB flush stress test\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i= smp_num_cpus-2) { - printk("Parking cpu %d\n", curcpu); - local_irq_disable(); - while(1); - } else { - printk("Waiting cpu %d\n", curcpu); - HDELAY(1000000); - } - HDELAY(1000000); - inited = 1; - } - if (test == 16 || test == 17) { - unsigned long t, shift, mask; - mask = (smp_num_cpus > 16) ? 0x1f : 0xf; - shift = 25-debug1; - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t == curcpu); - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t != curcpu); - } - if(debug3) printk("CPU %d: One TLB start\n", curcpu); - if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14); - if(debug3) printk("CPU %d: One TLB flush done\n", curcpu); - } - if (test == 20) { - local_irq_disable(); - set_led_bits(smp_processor_id(), 0xff); - while(1); - } - if (test == 21) { - extern long ia64_mca_stack[]; - int i, n; - volatile long *p, *up; - p = (volatile long*)__imva(ia64_mca_stack); - up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET); - - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n"); - for (n=0, i=0; i<100; i++) - n += *(p+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n"); - for (n=0, i=0; i<100; i++) - *(p+i) = i; - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n"); - for (n=0, i=0; i<100; i++) - ia64_fc((void*)(p+i)); - printk("ZZZ done\n"); - } - if (test == 21) { - int i; - volatile long tb, t[10]; - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - sgi_mcatest_bkpt(); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ NULL 0x%lx\n", t[i]); - } - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ DRAIN 0x%lx\n", t[i]); - } - } - if (test == 22) { - extern void machine_restart(char*); - printk("ZZZ machine_restart\n"); - machine_restart(0); - } - if (test == 23) { - printk("ZZZ ia64_pal_halt_light\n"); - ia64_pal_halt_light(); - } - if (repeat) - goto again; - -} diff --git a/arch/ia64/sn/kernel/probe.c b/arch/ia64/sn/kernel/probe.c index 4b2cf42c284..e00518746db 100644 --- a/arch/ia64/sn/kernel/probe.c +++ b/arch/ia64/sn/kernel/probe.c @@ -1,7 +1,7 @@ /* * Platform dependent support for IO probing. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index b923da1375c..8831bd886e3 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -69,23 +69,26 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif DEFINE_PER_CPU(struct pda_s, pda_percpu); +#define pxm_to_nasid(pxm) ((pxm)<<1) + extern void bte_init_node (nodepda_t *, cnodeid_t); extern void bte_init_cpu (void); +extern void sn_timer_init (void); +extern void (*ia64_mark_idle)(int); +void snidle(int); unsigned long sn_rtc_cycles_per_second; -unsigned long sn_rtc_usec_per_cyc; partid_t sn_partid = -1; char sn_system_serial_number_string[128]; u64 sn_partition_serial_number; +short physical_node_map[MAX_PHYSNODE_ID]; + /* * This is the address of the RRegs in the HSpace of the global * master. It is used by a hack in serial.c (serial_[in|out], @@ -94,21 +97,14 @@ u64 sn_partition_serial_number; * early_printk won't try to access the UART before * master_node_bedrock_address is properly calculated. */ -u64 master_node_bedrock_address = 0UL; +u64 master_node_bedrock_address; static void sn_init_pdas(char **); -extern struct irq_desc *_sn_irq_desc[]; - -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; -#ifdef CONFIG_IA64_SGI_SN2 -irqpda_t *irqpdaindr[NR_CPUS]; -#endif /* CONFIG_IA64_SGI_SN2 */ +irqpda_t *irqpdaindr; /* @@ -135,29 +131,19 @@ struct screen_info sn_screen_info = { * running in the simulator. Note that passing zeroes in DRIVE_INFO * is sufficient (the IDE driver will autodetect the drive geometry). */ +#ifdef CONFIG_IA64_GENERIC +extern char drive_info[4*16]; +#else char drive_info[4*16]; - -/** - * sn_map_nr - return the mem_map entry for a given kernel address - * @addr: kernel address to query - * - * Finds the mem_map entry for the kernel address given. Used by - * virt_to_page() (asm-ia64/page.h), among other things. - */ -unsigned long -sn_map_nr (unsigned long addr) -{ - return BANK_MAP_NR(addr); -} +#endif /** * early_sn_setup - early setup routine for SN platforms * * Sets up an initial console to aid debugging. Intended primarily - * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK - * are turned on. See start_kernel() in init/main.c. + * for bringup. See start_kernel() in init/main.c. */ -#if defined(CONFIG_IA64_EARLY_PRINTK) +#if defined(CONFIG_IA64_EARLY_PRINTK) || defined(CONFIG_IA64_SGI_SN_SIM) void __init early_sn_setup(void) @@ -195,21 +181,48 @@ early_sn_setup(void) } if ( IS_RUNNING_ON_SIMULATOR() ) { -#if defined(CONFIG_IA64_SGI_SN1) - master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); -#else master_node_bedrock_address = (u64)REMOTE_HUB(get_nasid(), SH_JUNK_BUS_UART0); -#endif printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } } -#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_IA64_MCA extern int platform_intr_list[]; #endif extern nasid_t master_nasid; +static int shub_1_1_found __initdata; + + +/* + * sn_check_for_wars + * + * Set flag for enabling shub specific wars + */ + +static inline int __init +is_shub_1_1(int nasid) +{ + unsigned long id; + int rev; + + id = REMOTE_HUB_L(nasid, SH_SHUB_ID); + rev = (id & SH_SHUB_ID_REVISION_MASK) >> SH_SHUB_ID_REVISION_SHFT; + return rev <= 2; +} + +static void __init +sn_check_for_wars(void) +{ + int cnode; + + for (cnode=0; cnode< numnodes; cnode++) + if (is_shub_1_1(cnodeid_to_nasid(cnode))) + shub_1_1_found = 1; +} + + /** * sn_setup - SN platform setup routine @@ -223,8 +236,18 @@ void __init sn_setup(char **cmdline_p) { long status, ticks_per_sec, drift; - int i; + int pxm; int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); + extern void io_sh_swapper(int, int); + extern nasid_t get_master_baseio_nasid(void); + extern void sn_cpu_init(void); + + MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; + + memset(physical_node_map, -1, sizeof(physical_node_map)); + for (pxm=0; pxmthread.flags |= IA64_THREAD_FPEMU_NOPRINT; + sn_timer_init(); + + ia64_mark_idle = &snidle; } /** @@ -325,22 +327,19 @@ sn_init_pdas(char **cmdline_p) * Make sure that the PDA fits entirely in the same page as the * cpu_data area. */ - if ( (((unsigned long)pda & ~PAGE_MASK) + sizeof(pda_t)) > PAGE_SIZE) + if ((((unsigned long)pda & (~PAGE_MASK)) + sizeof(pda_t)) > PAGE_SIZE) panic("overflow of cpu_data page"); + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (cnode=0; cnodecnodeid_to_nasid_table[cnode] = pxm_to_nasid(nid_to_pxm_map[cnode]); + /* * Allocate & initalize the nodepda for each node. */ for (cnode=0; cnode < numnodes; cnode++) { nodepdaindr[cnode] = alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t)); memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); - -#if defined(CONFIG_IA64_SGI_SN1) - Synergy_da_indr[cnode * 2] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - Synergy_da_indr[cnode * 2 + 1] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2], 0, sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2 + 1], 0, sizeof(synergy_da_t)); -#endif } /* @@ -349,7 +348,7 @@ sn_init_pdas(char **cmdline_p) for (cnode=0; cnode < numnodes; cnode++) memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); -#ifdef CONFIG_PCI + /* * Set up IO related platform-dependent nodepda fields. * The following routine actually sets up the hubinfo struct @@ -359,7 +358,6 @@ sn_init_pdas(char **cmdline_p) init_platform_nodepda(nodepdaindr[cnode], cnode); bte_init_node (nodepdaindr[cnode], cnode); } -#endif } /** @@ -374,7 +372,11 @@ sn_init_pdas(char **cmdline_p) void __init sn_cpu_init(void) { - int cpuid, cpuphyid, nasid, nodeid, slice; + int cpuid; + int cpuphyid; + int nasid; + int slice; + int cnode, i; /* * The boot cpu makes this call again after platform initialization is @@ -386,14 +388,43 @@ sn_cpu_init(void) cpuid = smp_processor_id(); cpuphyid = ((ia64_get_lid() >> 16) & 0xffff); nasid = cpu_physical_id_to_nasid(cpuphyid); - nodeid = cpu_to_node_map[cpuphyid]; + cnode = nasid_to_cnodeid(nasid); slice = cpu_physical_id_to_slice(cpuphyid); - memset(pda, 0, sizeof(pda_t)); - pda->p_nodepda = nodepdaindr[nodeid]; + printk("CPU %d: nasid %d, slice %d, cnode %d\n", + smp_processor_id(), nasid, slice, cnode); + + memset(pda, 0, sizeof(pda)); + pda->p_nodepda = nodepdaindr[cnode]; + pda->led_address = (typeof(pda->led_address)) (LED0 + (slice<led_state = LED_ALWAYS_SET; pda->hb_count = HZ/2; pda->hb_state = 0; pda->idle_flag = 0; + pda->shub_1_1_found = shub_1_1_found; + + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (i=0; icnodeid_to_nasid_table[i] = pxm_to_nasid(nid_to_pxm_map[i]); + + if (local_node_data->active_cpu_count == 1) + nodepda->node_first_cpu = cpuid; + + + + /* + * We must use different memory allocators for first cpu (bootmem + * allocator) than for the other cpus (regular allocator). + */ + if (cpuid == 0) + irqpdaindr = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t)); + + memset(irqpdaindr, 0, sizeof(irqpda_t)); + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] |= SN2_IRQ_RESERVED; + irqpdaindr->irq_flags[SGI_II_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_II_ERROR] |= SN2_IRQ_RESERVED; + pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); pda->mem_write_status_addr = (volatile u64 *) @@ -401,89 +432,25 @@ sn_cpu_init(void) if (nodepda->node_first_cpu == cpuid) { int buddy_nasid; - buddy_nasid = cnodeid_to_nasid(local_nodeid == numnodes - 1 ? 0 : local_nodeid + 1); + buddy_nasid = cnodeid_to_nasid(numa_node_id() == numnodes-1 ? 0 : numa_node_id()+ 1); pda->pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL); } bte_init_cpu(); } -#ifdef II_PRTE_TLB_WAR -long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */ -#endif - -#ifdef BUS_INT_WAR - -#include -#include - -void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs); - -static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; - -#define IRQCPU(irq) ((irq)>>8) - -void -sn_add_polled_interrupt(int irq, int interval) -{ - unsigned long flags, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - irq_list[irq_cnt].irq = irq; - irq_list[irq_cnt].interval = interval; - irq_list[irq_cnt].tick = interval; - pdacpu(IRQCPU(irq)).pda_poll_entry_count++; - spin_unlock_irqrestore(&irq_lock, flags); - - -} - -void -sn_delete_polled_interrupt(int irq) +void snidle(int idleness) { - unsigned long flags, i, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - for (i=0; iidle_flag == 0) { + set_led_bits(0, LED_CPU_ACTIVITY); } - } - spin_unlock_irqrestore(&irq_lock, flags); -} -void -sn_irq_poll(int cpu, int reason) -{ - unsigned long flags, i; - sn_poll_entry_t *irq_list; - - - ia64_handle_irq(IA64_IPI_VECTOR, 0); - - if (reason == 0) - return; - - irq_list = pda->pda_poll_entries; - - for (i=0; ipda_poll_entry_count; i++, irq_list++) { - if (--irq_list->tick <= 0) { - irq_list->tick = irq_list->interval; - local_irq_save(flags); - ia64_handle_irq(irq_to_vector(irq_list->irq), 0); - local_irq_restore(flags); - } + pda->idle_flag = 1; } -} + else { + set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); -#endif + pda->idle_flag = 0; + } +} diff --git a/arch/ia64/sn/kernel/sn1/Makefile b/arch/ia64/sn/kernel/sn1/Makefile deleted file mode 100644 index 65261dc37f5..00000000000 --- a/arch/ia64/sn/kernel/sn1/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# arch/ia64/sn/kernel/sn1/Makefile -# -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# Further, this software is distributed without any warranty that it is -# free of the rightful claim of any third person regarding infringement -# or the like. Any license provided herein, whether implied or -# otherwise, applies only to this software file. Patent licenses, if -# any, provided herein do not apply to combinations of this program with -# other software, or any other product whatsoever. -# -# You should have received a copy of the GNU General Public -# License along with this program; if not, write the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, -# Mountain View, CA 94043, or: -# -# http://www.sgi.com -# -# For further information regarding this notice, see: -# -# http://oss.sgi.com/projects/GenInfo/NoticeExplan -# - - -EXTRA_CFLAGS := -DLITTLE_ENDIAN - -.S.s: - $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< - -O_TARGET = sn1.o - -obj-y = cache.o error.o iomv.o synergy.o sn1_smp.o diff --git a/arch/ia64/sn/kernel/sn1/cache.c b/arch/ia64/sn/kernel/sn1/cache.c deleted file mode 100644 index c0894b03fca..00000000000 --- a/arch/ia64/sn/kernel/sn1/cache.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - */ - -#include -#include -#include -#include -#include -#include - -#ifndef MB -#define MB (1024*1024) -#endif - -/* - * Lock for protecting SYN_TAG_DISABLE_WAY. - * Consider making this a per-FSB lock. - */ -static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED; - -/** - * sn_flush_all_caches - flush a range of addresses from all caches (incl. L4) - * @flush_addr: identity mapped region 7 address to start flushing - * @bytes: number of bytes to flush - * - * Flush a range of addresses from all caches including L4. All addresses - * fully or partially contained within @flush_addr to @flush_addr + @bytes - * are flushed from the all caches. - */ -void -sn_flush_all_caches(long flush_addr, long bytes) -{ - ulong addr, baddr, eaddr, bitbucket; - int way, alias; - - /* - * Because of the way synergy implements "fc", this flushes the - * data from all caches on all cpus & L4's on OTHER FSBs. It also - * flushes both cpus on the local FSB. It does NOT flush it from - * the local FSB. - */ - flush_icache_range(flush_addr, flush_addr+bytes); - - /* - * Memory DIMMs are a minimum of 256MB and start on 256MB - * boundaries. Convert the start address to an address - * that is between +0MB & +128 of the same DIMM. - * Then add 8MB to skip the uncached MinState areas if the address - * is on the master node. - */ - if (bytes > SYNERGY_L4_BYTES_PER_WAY) - bytes = SYNERGY_L4_BYTES_PER_WAY; - baddr = TO_NODE(smp_physical_node_id(), PAGE_OFFSET + (flush_addr & (128*MB-1)) + 8*MB); - eaddr = (baddr+bytes+SYNERGY_BLOCK_SIZE-1) & ~(SYNERGY_BLOCK_SIZE-1); - baddr = baddr & ~(SYNERGY_BLOCK_SIZE-1); - - /* - * Now flush the local synergy. - */ - spin_lock(&flush_lock); - for(way=0; way -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/** - * snia_error_intr_handler - handle SN specific error interrupts - * @irq: error interrupt received - * @devid: device causing the interrupt - * @pt_regs: saved register state - * - * This routine is called when certain interrupts occur on SN systems. - * It will either recover from the situations that caused the interrupt - * or panic. - */ -void -snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) -{ - unsigned long long intpend_val; - unsigned long long bit; - - switch (irq) { - case SGI_UART_IRQ: - /* - * This isn't really an error interrupt. We're just - * here because we have to do something with them. - * This is probably wrong, and this code will be - * removed. - */ - intpend_val = LOCAL_HUB_L(PI_INT_PEND0); - if ( (bit = ~(1L< -#include -#include -#include -#include - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -/** - * sn1_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN1, we wait for the PIO_WRITE_STATUS Bedrock register to clear. - */ -void -sn1_mmiob (void) -{ - (volatile unsigned long) (*pda.bedrock_rev_id); - while (!(volatile unsigned long) (*pda.pio_write_status_addr)) - udelay(5); -} diff --git a/arch/ia64/sn/kernel/sn1/sn1_smp.c b/arch/ia64/sn/kernel/sn1/sn1_smp.c deleted file mode 100644 index e24f97eba65..00000000000 --- a/arch/ia64/sn/kernel/sn1/sn1_smp.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * SN1 Platform specific SMP Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - union { - struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - } ptc; - char pad[SMP_CACHE_BYTES]; - }; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - -/* - * The following table/struct is for remembering PTC coherency domains. It - * is also used to translate sapicid into cpuids. We don't want to start - * cpus unless we know their cache domain. - */ -#ifdef PTC_NOTYET -sn_sapicid_info_t sn_sapicid_info[NR_CPUS]; -#endif - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->ptc.start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->ptc.end; - nbits = ptcParams->ptc.nbits; - rid = ptcParams->ptc.rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->ptc.unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu= &ptcParamArray[0]) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->ptc.unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->ptc.unfinished_count) == 0) { - if (atomic_read(&next->ptc.unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->ptc.unfinished_count) > 0) { - barrier(); - } - } - - params->ptc.start = start; - params->ptc.end = end; - params->ptc.nbits = nbits; - params->ptc.rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->ptc.unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* Currently we don't think global TLB purges need to be atomic. - * All CPUs get sent IPIs, so if they haven't done the purge, - * they're busy with interrupts that are at the IPI level, which is - * priority 15. We're asserting that any code at that level - * shouldn't be using user TLB entries. To change this to wait - * for all the flushes to complete, enable the following code. - */ -#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR) - /* this code is not tested */ - /* wait for the flush to complete */ - while (atomic_read(¶ms->ptc.unfinished_count) > 0) - barrier(); -#endif -} - -/** - * sn_send_IPI_phys - send an IPI to a Nasid and slice - * @physid: physical cpuid to receive the interrupt. - * @vector: command to send - * @delivery_mode: delivery mechanism - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @physid - * - * @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn_send_IPI_phys(long physid, int vector, int delivery_mode) -{ - long *p; - long nasid, slice; - - static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; - -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector) { - return; - } -#endif - - nasid = cpu_physical_id_to_nasid(physid); - slice = cpu_physical_id_to_slice(physid); - - p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); - - mb(); - *p = (delivery_mode << 8) | (vector & 0xff); -} - - -/** - * sn1_send_IPI - send an IPI to a processor - * @cpuid: target of the IPI - * @vector: command to send - * @delivery_mode: delivery mechanism - * @redirect: redirect the IPI? - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @cpuid. @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn1_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) -{ - long physid; - - physid = cpu_physical_id(cpuid); - - sn_send_IPI_phys(physid, vector, delivery_mode); -} -#ifdef CONFIG_SMP - -#ifdef PTC_NOTYET -static void __init -process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) -{ - ia64_sal_ptc_domain_proc_entry_t *pe; - int i, sapicid, cpuid; - - pe = __va(di->proc_list); - for (i=0; iproc_count; i++, pe++) { - sapicid = id_eid_to_sapicid(pe->id, pe->eid); - cpuid = cpu_logical_id(sapicid); - sn_sapicid_info[cpuid].domain = domain; - sn_sapicid_info[cpuid].sapicid = sapicid; - } -} - - -static void __init -process_sal_desc_ptc(ia64_sal_desc_ptc_t *ptc) -{ - ia64_sal_ptc_domain_info_t *di; - int i; - - di = __va(ptc->domain_info); - for (i=0; inum_domains; i++, di++) { - process_sal_ptc_domain_info(di, i); - } -} -#endif /* PTC_NOTYET */ - -/** - * init_sn1_smp_config - setup PTC domains per processor - */ -void __init -init_sn1_smp_config(void) -{ - if (!ia64_ptc_domain_info) { - printk("SMP: Can't find PTC domain info. Forcing UP mode\n"); - smp_num_cpus = 1; - return; - } - -#ifdef PTC_NOTYET - memset (sn_sapicid_info, -1, sizeof(sn_sapicid_info)); - process_sal_desc_ptc(ia64_ptc_domain_info); -#endif -} - -#else /* CONFIG_SMP */ - -void __init -init_sn1_smp_config(void) -{ - -#ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_smp_processor_id(); -#endif -} - -#endif /* CONFIG_SMP */ diff --git a/arch/ia64/sn/kernel/sn1/synergy.c b/arch/ia64/sn/kernel/sn1/synergy.c deleted file mode 100644 index df31731bc73..00000000000 --- a/arch/ia64/sn/kernel/sn1/synergy.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * SN1 Platform specific synergy Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int bit_pos_to_irq(int bit); -void setclear_mask_b(int irq, int cpuid, int set); -void setclear_mask_a(int irq, int cpuid, int set); -void * kmalloc(size_t size, int flags); - -static int synergy_perf_initialized = 0; - -void -synergy_intr_alloc(int bit, int cpuid) { - return; -} - -int -synergy_intr_connect(int bit, - int cpuid) -{ - int irq; - unsigned is_b; - - irq = bit_pos_to_irq(bit); - - is_b = (cpuid_to_slice(cpuid)) & 1; - if (is_b) { - setclear_mask_b(irq,cpuid,1); - setclear_mask_a(irq,cpuid, 0); - } else { - setclear_mask_a(irq, cpuid, 1); - setclear_mask_b(irq, cpuid, 0); - } - return 0; -} -void -setclear_mask_a(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0A; - addr = VEC_MASK0A_ADDR; - break; - case 1: - reg = VEC_MASK1A; - addr = VEC_MASK1A_ADDR; - break; - case 2: - reg = VEC_MASK2A; - addr = VEC_MASK2A_ADDR; - break; - case 3: - reg = VEC_MASK3A; - addr = VEC_MASK3A_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -void -setclear_mask_b(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0B; - addr = VEC_MASK0B_ADDR; - break; - case 1: - reg = VEC_MASK1B; - addr = VEC_MASK1B_ADDR; - break; - case 2: - reg = VEC_MASK2B; - addr = VEC_MASK2B_ADDR; - break; - case 3: - reg = VEC_MASK3B; - addr = VEC_MASK3B_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -/* - * Synergy perf stats. Multiplexed via timer_interrupt. - */ - -static int -synergy_perf_append(uint64_t modesel) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int checked = 0; - int err = 0; - unsigned long flags; - - /* bit 45 is enable */ - modesel |= (1UL << 45); - - for (cnode=0; cnode < numnodes; cnode++) { - /* for each node, insert a new synergy_perf entry */ - if ((npdap = NODEPDA(cnode)) == NULL) { - printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, (void *)nodepda); - continue; - } - - if (npdap->synergy_perf_enabled) { - /* user must disable counting to append new events */ - err = -EBUSY; - break; - } - - if (!checked && npdap->synergy_perf_data != NULL) { - checked = 1; - for (p = npdap->synergy_perf_first; ;) { - if (p->modesel == modesel) - return 0; /* event already registered */ - if ((p = p->next) == npdap->synergy_perf_first) - break; - } - } - - /* XX use kmem_alloc_node() when it is implemented */ - p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); - if ((((uint64_t)p) & 7UL) != 0) - BUG(); /* bad alignment */ - if (p == NULL) { - err = -ENOMEM; - break; - } - else { - memset(p, 0, sizeof(synergy_perf_t)); - p->modesel = modesel; - - spin_lock_irqsave(&npdap->synergy_perf_lock, flags); - if (npdap->synergy_perf_data == NULL) { - /* circular list */ - p->next = p; - npdap->synergy_perf_first = p; - npdap->synergy_perf_data = p; - } - else { - p->next = npdap->synergy_perf_data->next; - npdap->synergy_perf_data->next = p; - } - spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags); - } - } - - return err; -} - -static void -synergy_perf_set_freq(int freq) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_freq = freq; - } -} - -static void -synergy_perf_set_enable(int enable) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_enabled = enable; - } - printk("NOTICE: synergy perf counting %sabled on all nodes\n", enable ? "en" : "dis"); -} - -static int -synergy_perf_size(nodepda_t *npdap) -{ - synergy_perf_t *p; - int n; - - if (npdap->synergy_perf_enabled == 0) { - /* no stats to return */ - return 0; - } - - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - n++; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* bytes == n pairs of {event,counter} */ - return n * 2 * sizeof(uint64_t); -} - -static int -synergy_perf_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int intarg; - int fsb; - uint64_t longarg; - uint64_t *stats; - int n; - devfs_handle_t d; - arbitrary_info_t info; - - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; - info = hwgraph_fastinfo_get(d); - - cnode = SYNERGY_PERF_INFO_CNODE(info); - fsb = SYNERGY_PERF_INFO_FSB(info); - npdap = NODEPDA(cnode); - - switch (cmd) { - case SNDRV_GET_SYNERGY_VERSION: - /* return int, version of data structure for SNDRV_GET_SYNERGYINFO */ - intarg = 1; /* version 1 */ - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_INFOSIZE: - /* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */ - intarg = synergy_perf_size(npdap); - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_SYNERGYINFO: - /* return array of event/value pairs, this node only */ - if ((intarg = synergy_perf_size(npdap)) <= 0) - return -ENODATA; - if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL) - return -ENOMEM; - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - stats[n++] = p->modesel; - if (p->intervals > 0) - stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals; - else - stats[n++] = 0; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - if (copy_to_user((void *)arg, stats, intarg)) { - kfree(stats); - return -EFAULT; - } - - kfree(stats); - break; - - case SNDRV_SYNERGY_APPEND: - /* reads 64bit event, append synergy perf event to all nodes */ - if (copy_from_user(&longarg, (void *)arg, sizeof(longarg))) - return -EFAULT; - return synergy_perf_append(longarg); - break; - - case SNDRV_GET_SYNERGY_STATUS: - /* return int, 1 if enabled else 0 */ - intarg = npdap->synergy_perf_enabled; - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_SYNERGY_ENABLE: - /* read int, if true enable counting else disable */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - synergy_perf_set_enable(intarg); - break; - - case SNDRV_SYNERGY_FREQ: - /* read int, set jiffies per update */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - if (intarg < 0 || intarg >= HZ) - return -EINVAL; - synergy_perf_set_freq(intarg); - break; - - default: - printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%d\n", cmd, cnode, fsb); - return -EINVAL; - } - return(0); -} - -struct file_operations synergy_mon_fops = { - .ioctl = synergy_perf_ioctl, -}; - -void -synergy_perf_update(int cpu) -{ - nasid_t nasid; - cnodeid_t cnode; - struct nodepda_s *npdap; - - /* - * synergy_perf_initialized is set by synergy_perf_init() - * which is called last thing by sn_mp_setup(), i.e. well - * after nodepda has been initialized. - */ - if (!synergy_perf_initialized) - return; - - cnode = cpuid_to_cnodeid(cpu); - npdap = NODEPDA(cnode); - - if (npdap == NULL || cnode < 0 || cnode >= numnodes) - /* this should not happen: still in early io init */ - return; - -#if 0 - /* use this to check nodepda initialization */ - if (((uint64_t)npdap) & 0x7) { - printk("\nERROR on cpu %d : cnode=%d, npdap == %p, not aligned\n", cpu, cnode, npdap); - BUG(); - } -#endif - - if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) { - /* Not enabled, or no events to monitor */ - return; - } - - if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { - /* don't multiplex on every timer interrupt */ - return; - } - - /* - * Read registers for last interval and increment counters. - * Hold the per-node synergy_perf_lock so concurrent readers get - * consistent values. - */ - spin_lock_irq(&npdap->synergy_perf_lock); - - nasid = cpuid_to_nasid(cpu); - npdap->synergy_active_intervals++; - npdap->synergy_perf_data->intervals++; - npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals; - - npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); - - npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); - - /* skip to next in circular list */ - npdap->synergy_perf_data = npdap->synergy_perf_data->next; - - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* set the counter 0 selection modes for both A and B */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); - - /* and reset the counter registers to zero */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); -} - -void -synergy_perf_init(void) -{ - printk("synergy_perf_init(), counting is initially disabled\n"); - synergy_perf_initialized++; -} diff --git a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile index ed6461de224..a56bcb1e6cf 100644 --- a/arch/ia64/sn/kernel/sn2/Makefile +++ b/arch/ia64/sn/kernel/sn2/Makefile @@ -11,4 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o +obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ + prominfo_proc.o timer.o diff --git a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c index af59e0fe3dd..f0cce9edc53 100644 --- a/arch/ia64/sn/kernel/sn2/cache.c +++ b/arch/ia64/sn/kernel/sn2/cache.c @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ @@ -24,6 +24,5 @@ void sn_flush_all_caches(long flush_addr, long bytes) { flush_icache_range(flush_addr, flush_addr+bytes); + mb(); } - - diff --git a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c index 9de12763a35..59423708d30 100644 --- a/arch/ia64/sn/kernel/sn2/io.c +++ b/arch/ia64/sn/kernel/sn2/io.c @@ -9,13 +9,8 @@ * we wrap the inlines from asm/ia64/sn/sn2/io.h here. */ -#include -#include - #include -#ifdef CONFIG_IA64_GENERIC - unsigned int sn_inb (unsigned long port) { @@ -73,7 +68,7 @@ sn_readl (void *addr) unsigned long sn_readq (void *addr) { - return __sn_readq (addr) + return __sn_readq (addr); } @@ -94,5 +89,3 @@ asm ("__sn_readb = sn_readb"); asm ("__sn_readw = sn_readw"); asm ("__sn_readl = sn_readl"); asm ("__sn_readq = sn_readq"); - -#endif /* CONFIG_IA64_GENERIC */ diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c new file mode 100644 index 00000000000..f860679d5b1 --- /dev/null +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -0,0 +1,361 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Module to export the system's Firmware Interface Tables, including + * PROM revision numbers, in /proc + */ +#include +#include +#include +#include +#include +#include + +/* to lookup nasids */ +#include + +MODULE_DESCRIPTION("PROM version reporting for /proc"); +MODULE_AUTHOR("Chad Talbott"); +MODULE_LICENSE("GPL"); + +#undef DEBUG_PROMINFO + +#define TRACE_PROMINFO + +#if defined(DEBUG_PROMINFO) +# define DPRINTK(x...) printk(KERN_DEBUG x) +#else +# define DPRINTK(x...) +#endif + +#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO) +# if defined(__GNUC__) +# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ + __FILE__, __LINE__, __FUNCTION__) +# else +# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) +# endif +#else +# define TRACE() +#endif + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +#define FIT_SIGNATURE 0x2020205f5449465ful +/* Standard Intel FIT entry types */ +#define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ +#define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ +/* Entries 0x02 through 0x0D reserved by Intel */ +#define FIT_ENTRY_PAL_A_PROC 0x0E /* Processor-specific PAL_A entry */ +#define FIT_ENTRY_PAL_A 0x0F /* PAL_A entry, same as... */ +#define FIT_ENTRY_PAL_A_GEN 0x0F /* ...Generic PAL_A entry */ +#define FIT_ENTRY_UNUSED 0x7F /* Unused (reserved by Intel?) */ +/* OEM-defined entries range from 0x10 to 0x7E. */ +#define FIT_ENTRY_SAL_A 0x10 /* SAL_A entry */ +#define FIT_ENTRY_SAL_B 0x11 /* SAL_B entry */ +#define FIT_ENTRY_SALRUNTIME 0x12 /* SAL runtime entry */ +#define FIT_ENTRY_EFI 0x1F /* EFI entry */ +#define FIT_ENTRY_FPSWA 0x20 /* embedded fpswa entry */ +#define FIT_ENTRY_VMLINUX 0x21 /* embedded vmlinux entry */ + +#define FIT_MAJOR_SHIFT (32 + 8) +#define FIT_MAJOR_MASK ((1 << 8) - 1) +#define FIT_MINOR_SHIFT 32 +#define FIT_MINOR_MASK ((1 << 8) - 1) + +#define FIT_MAJOR(q) \ + ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK) +#define FIT_MINOR(q) \ + ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK) + +#define FIT_TYPE_SHIFT (32 + 16) +#define FIT_TYPE_MASK ((1 << 7) - 1) + +#define FIT_TYPE(q) \ + ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) + +#define FIT_ENTRY(type, maj, min, size) \ + ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \ + (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \ + (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \ + (size)) + +struct fit_type_map_t { + unsigned char type; + const char *name; +}; + +static const struct fit_type_map_t fit_entry_types[] = { + { FIT_ENTRY_FIT_HEADER, "FIT Header" }, + { FIT_ENTRY_PAL_A_GEN, "Generic PAL_A" }, + { FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A" }, + { FIT_ENTRY_PAL_A, "PAL_A" }, + { FIT_ENTRY_PAL_B, "PAL_B" }, + { FIT_ENTRY_SAL_A, "SAL_A" }, + { FIT_ENTRY_SAL_B, "SAL_B" }, + { FIT_ENTRY_SALRUNTIME, "SAL runtime" }, + { FIT_ENTRY_EFI, "EFI" }, + { FIT_ENTRY_VMLINUX, "Embedded Linux" }, + { FIT_ENTRY_FPSWA, "Embedded FPSWA" }, + { FIT_ENTRY_UNUSED, "Unused" }, + { 0xff, "Error" }, +}; + +static const char * +fit_type_name(unsigned char type) +{ + struct fit_type_map_t const*mapp; + + for (mapp = fit_entry_types; mapp->type != 0xff; mapp++) + if (type == mapp->type) + return mapp->name; + + if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED)) + return "OEM type"; + if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A)) + return "Reserved"; + + return "Unknown type"; +} + +/* These two routines read the FIT table directly from the FLASH PROM + * on a specific node. The PROM can only be accessed using aligned 64 + * bit reads, so we do that and then shift and mask the result to get + * at each field. + */ +static int +dump_fit_entry(char *page, unsigned long *fentry) +{ + unsigned long q1, q2; + unsigned type; + + TRACE(); + + q1 = readq(fentry); + q2 = readq(fentry + 1); + type = FIT_TYPE(q2); + return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n", + type, + fit_type_name(type), + FIT_MAJOR(q2), FIT_MINOR(q2), + q1, + /* mult by sixteen to get size in bytes */ + (unsigned)q2 * 16); +} + +/* We assume that the fit table will be small enough that we can print + * the whole thing into one page. (This is true for our default 16kB + * pages -- each entry is about 60 chars wide when printed.) I read + * somewhere that the maximum size of the FIT is 128 entries, so we're + * OK except for 4kB pages (and no one is going to do that on SN + * anyway). + */ +static int +dump_fit(char *page, unsigned long *fit) +{ + unsigned long qw; + int nentries; + int fentry; + char *p; + + TRACE(); + + DPRINTK("dumping fit from %p\n", (void *)fit); + + qw = readq(fit); + DPRINTK("FIT signature: %016lx (%.8s)\n", qw, (char *)&qw); + if (qw != FIT_SIGNATURE) + printk(KERN_WARNING "Unrecognized FIT signature"); + + qw = readq(fit + 1); + nentries = (unsigned)qw; + DPRINTK("number of fit entries: %u\n", nentries); + /* check that we won't overflow the page -- see comment above */ + BUG_ON(nentries * 60 > PAGE_SIZE); + + p = page; + for (fentry = 0; fentry < nentries; fentry++) + /* each FIT entry is two 64 bit words */ + p += dump_fit_entry(p, fit + 2 * fentry); + + return p - page; +} + +static int +dump_version(char *page, unsigned long *fit) +{ + int nentries; + int fentry; + unsigned long qw; + + TRACE(); + + nentries = (unsigned)readq(fit + 1); + BUG_ON(nentries * 60 > PAGE_SIZE); + + for (fentry = 0; fentry < nentries; fentry++) { + qw = readq(fit + 2 * fentry + 1); + if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A) + return sprintf(page, "%x.%02x\n", + FIT_MAJOR(qw), FIT_MINOR(qw)); + } + return 0; +} + +/* same as in proc_misc.c */ +static int +proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof, + int len) +{ + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int +read_version_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_version(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + return len; +} + +static int +read_fit_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_fit(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + + return len; +} + +/* this is a fake FIT that's used on the medusa simulator which + * doesn't usually run a complete PROM. + */ +#ifdef CONFIG_IA64_SGI_SN_SIM +static unsigned long fakefit[] = { + /* this is all we need to satisfy the code below */ + FIT_SIGNATURE, + FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2), + /* dump something arbitrary for + * /proc/sgi_prominfo/nodeX/version */ + 0xbadbeef00fa3ef17ul, + FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100) +}; +#endif + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) + return fakefit; +#endif + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + DPRINTK("pointer to fit at %p\n", (void *)fitp); + fit_paddr = readq(fitp); + DPRINTK("fit pointer contains %lx\n", fit_paddr); + /* snag just the node-relative offset */ + fit_paddr &= ~0ul >> (63-35); + /* the pointer to the FIT is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + fit_paddr += 0x700000000; + fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr); + DPRINTK("fit at %p\n", (void *)fit_vaddr); + return fit_vaddr; +} + +/* module entry points */ +int __init prominfo_init(void); +void __exit prominfo_exit(void); + +module_init(prominfo_init); +module_exit(prominfo_exit); + +static struct proc_dir_entry **proc_entries; +static struct proc_dir_entry *sgi_prominfo_entry; + +#define NODE_NAME_LEN 11 + +int __init +prominfo_init(void) +{ + struct proc_dir_entry **entp; + cnodeid_t cnodeid; + nasid_t nasid; + char name[NODE_NAME_LEN]; + + TRACE(); + + DPRINTK("running on cpu %d\n", smp_processor_id()); + DPRINTK("numnodes %d\n", numnodes); + + proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *), + GFP_KERNEL); + + sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + sprintf(name, "node%d", cnodeid); + *entp = proc_mkdir(name, sgi_prominfo_entry); + nasid = cnodeid_to_nasid(cnodeid); + create_proc_read_entry( + "fit", 0, *entp, read_fit_entry, + lookup_fit(nasid)); + create_proc_read_entry( + "version", 0, *entp, read_version_entry, + lookup_fit(nasid)); + } + + return 0; +} + +void __exit +prominfo_exit(void) +{ + struct proc_dir_entry **entp; + unsigned cnodeid; + char name[NODE_NAME_LEN]; + + TRACE(); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + remove_proc_entry("fit", *entp); + remove_proc_entry("version", *entp); + sprintf(name, "node%d", cnodeid); + remove_proc_entry(name, sgi_prominfo_entry); + } + remove_proc_entry("sgi_prominfo", NULL); + kfree(proc_entries); +} diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c index 1850229970c..c7116a35e5b 100644 --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c @@ -1,7 +1,7 @@ /* * SN2 Platform specific SMP Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -79,284 +79,6 @@ wait_piowc(void) return ws; } -#ifdef PTCG_WAR -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - char fill[96]; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->end; - nbits = ptcParams->nbits; - rid = ptcParams->rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu= &ptcParamArray[0]) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->unfinished_count) == 0) { - if (atomic_read(&next->unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->unfinished_count) > 0) { - barrier(); - } - } - - params->start = start; - params->end = end; - params->nbits = nbits; - params->rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* - * Since IPIs are polled event (for now), we need to wait til the - * TLB flush has started. - * wait for the flush to complete - */ - while (atomic_read(¶ms->unfinished_count) > 0) - barrier(); -} - -#endif /* PTCG_WAR */ /** @@ -372,18 +94,10 @@ sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbit void sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) { - int cnode, mycnode, nasid; + int cnode, mycnode, nasid, flushed=0; volatile unsigned long *ptc0, *ptc1; unsigned long flags=0, data0, data1; - /* - * Special case 1 cpu & 1 node. Use local purges. - */ -#ifdef PTCG_WAR - sn1_global_tlb_purge(start, end, nbits); - return; -#endif /* PTCG_WAR */ - data0 = (1UL<>8)<pio_write_status_addr; - mycnode = local_nodeid; + mycnode = numa_node_id(); for (cnode = 0; cnode < numnodes; cnode++) { if (is_headless_node(cnode) || cnode == mycnode) @@ -482,16 +189,10 @@ sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1) void sn_send_IPI_phys(long physid, int vector, int delivery_mode) { - long nasid, slice; - long val; + long nasid, slice, val; + unsigned long flags=0; volatile long *p; -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector && delivery_mode == IA64_IPI_DM_INT) { - return; - } -#endif - nasid = cpu_physical_id_to_nasid(physid); slice = cpu_physical_id_to_slice(physid); @@ -503,12 +204,15 @@ sn_send_IPI_phys(long physid, int vector, int delivery_mode) (0x000feeUL< +#include #ifdef CONFIG_PROC_FS #include @@ -43,7 +44,7 @@ static int partition_id_read_proc(char *page, char **start, off_t off, return sprintf(page, "%d\n", sn_local_partid()); } -struct proc_dir_entry * sgi_proc_dir = NULL; +static struct proc_dir_entry * sgi_proc_dir; void register_sn_partition_id(void) { @@ -135,11 +136,60 @@ register_sn_force_interrupt(void) { entry->write_proc = sn_force_interrupt_write_proc; } } + +extern int sn_linkstats_get(char *); +extern int sn_linkstats_reset(unsigned long); + +static int +sn_linkstats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + + return sn_linkstats_get(page); +} + +static int +sn_linkstats_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char s[64]; + unsigned long msecs; + int e = count; + + if (copy_from_user(s, buffer, count < sizeof(s) ? count : sizeof(s))) + e = -EFAULT; + else { + if (sscanf(s, "%lu", &msecs) != 1 || msecs < 5) + /* at least 5 milliseconds between updates */ + e = -EINVAL; + else + sn_linkstats_reset(msecs); + } + + return e; +} + +void +register_sn_linkstats(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("linkstats", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = sn_linkstats_read_proc; + entry->write_proc = sn_linkstats_write_proc; + } +} + void register_sn_procfs(void) { register_sn_partition_id(); register_sn_serial_numbers(); register_sn_force_interrupt(); + register_sn_linkstats(); } #endif /* CONFIG_PROC_FS */ diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c new file mode 100644 index 00000000000..57844feea36 --- /dev/null +++ b/arch/ia64/sn/kernel/sn2/timer.c @@ -0,0 +1,76 @@ +/* + * linux/arch/ia64/sn/kernel/sn2/timer.c + * + * Copyright (C) 2003 Silicon Graphics, Inc. + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger : updated for new timer-interpolation infrastructure + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +extern unsigned long sn_rtc_cycles_per_second; +static volatile unsigned long last_wall_rtc; + +static unsigned long rtc_offset; /* updated only when xtime write-lock is held! */ +static long rtc_nsecs_per_cycle; +static long rtc_per_timer_tick; + +static unsigned long +getoffset(void) +{ + return rtc_offset + (GET_RTC_COUNTER() - last_wall_rtc)*rtc_nsecs_per_cycle; +} + + +static void +update(long delta_nsec) +{ + unsigned long rtc_counter = GET_RTC_COUNTER(); + unsigned long offset = rtc_offset + (rtc_counter - last_wall_rtc)*rtc_nsecs_per_cycle; + + /* Be careful about signed/unsigned comparisons here: */ + if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) + rtc_offset = offset - delta_nsec; + else + rtc_offset = 0; + last_wall_rtc = rtc_counter; +} + + +static void +reset(void) +{ + rtc_offset = 0; + last_wall_rtc = GET_RTC_COUNTER(); +} + + +static struct time_interpolator sn2_interpolator = { + .get_offset = getoffset, + .update = update, + .reset = reset +}; + +void __init +sn_timer_init(void) +{ + sn2_interpolator.frequency = sn_rtc_cycles_per_second; + sn2_interpolator.drift = -1; /* unknown */ + register_time_interpolator(&sn2_interpolator); + + rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ; + rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second; + + last_wall_rtc = GET_RTC_COUNTER(); +} diff --git a/arch/ia64/sn/kernel/sn_asm.S b/arch/ia64/sn/kernel/sn_asm.S deleted file mode 100644 index 833a399afe9..00000000000 --- a/arch/ia64/sn/kernel/sn_asm.S +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#ifdef CONFIG_IA64_SGI_AUTOTEST - -// Testing only. -// Routine will cause MCAs -// zzzmca(n) -// n=0 MCA via duplicate TLB dropin -// n=1 MCA via read of garbage address -// n=2 MCA via lfetch read of garbage address -// - -#define ITIR(key, ps) ((key<<8) | (ps<<2)) -#define TLB_PAGESIZE 28 // Use 256MB pages for now. - - .global zzzmca - .proc zzzmca -zzzmca: - alloc loc4 = ar.pfs,2,8,1,0;; - cmp.ne p6,p0=r32,r0;; - movl r2=0x2dead - movl r3=0x3dead - movl r15=0x15dead - movl r16=0x16dead - movl r31=0x31dead - movl loc0=0x34beef - movl loc1=0x35beef - movl loc2=0x36beef - movl loc3=0x37beef - movl out0=0x42beef - - movl r20=0x32feed;; - mov ar32=r20 - movl r20=0x36feed;; - mov ar36=r20 - movl r20=0x65feed;; - mov ar65=r20 - movl r20=0x66feed;; - mov ar66=r20 - -(p6) br.cond.sptk 1f - - rsm 0x2000;; - srlz.d; - mov r11 = 5 - mov r3 = ITIR(0,TLB_PAGESIZE);; - mov cr.itir = r3 - mov r10 = 0;; - itr.d dtr[r11] = r10;; - mov r11 = 6 - - itr.d dtr[r11] = r10;; - br 9f - -1: - cmp.eq p6,p7=1,r32 -#ifdef CONFIG_IA64_SGI_SN1 - movl r8=0xe00000fe00000048;; -#else - movl r8=0xe0007fb000000048;; -#endif - (p6) ld8 r9=[r8] - (p7) lfetch.fault.nt2 [r8] - ;; - mf - ;; - mf.a - ;; - srlz.d - -9: mov ar.pfs=loc4 - br.ret.sptk rp - - .endp zzzmca - -#endif diff --git a/arch/ia64/sn/kernel/sn_ksyms.c b/arch/ia64/sn/kernel/sn_ksyms.c index ec882453610..f9d3bcd16a3 100644 --- a/arch/ia64/sn/kernel/sn_ksyms.c +++ b/arch/ia64/sn/kernel/sn_ksyms.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -16,36 +16,16 @@ #include #include -#include #include -#include -extern devfs_handle_t base_io_scsi_ctlr_vhdl[]; +#include +extern vertex_hdl_t base_io_scsi_ctlr_vhdl[]; #include extern cnodeid_t master_node_get(devfs_handle_t vhdl); #include EXPORT_SYMBOL(base_io_scsi_ctlr_vhdl); EXPORT_SYMBOL(master_node_get); - -/* - * symbols referenced by the PCIBA module - */ -#include -#include -#include -#include - -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn); -EXPORT_SYMBOL(devfn_to_vertex); -EXPORT_SYMBOL(hwgraph_vertex_unref); -EXPORT_SYMBOL(pciio_config_get); -EXPORT_SYMBOL(pciio_info_slot_get); -EXPORT_SYMBOL(hwgraph_edge_add); -EXPORT_SYMBOL(pciio_info_master_get); -EXPORT_SYMBOL(pciio_info_get); - #ifdef CONFIG_IA64_SGI_SN_DEBUG EXPORT_SYMBOL(__pa_debug); EXPORT_SYMBOL(__va_debug); @@ -55,29 +35,26 @@ EXPORT_SYMBOL(__va_debug); EXPORT_SYMBOL(sn_send_IPI_phys); /* symbols referenced by partitioning modules */ -#include +#include +EXPORT_SYMBOL(bte_copy); EXPORT_SYMBOL(bte_unaligned_copy); #include EXPORT_SYMBOL(ia64_sal); +EXPORT_SYMBOL(physical_node_map); -#ifdef CONFIG_IA64_SGI_SN2 #include EXPORT_SYMBOL(sal_lock); EXPORT_SYMBOL(sn_partid); EXPORT_SYMBOL(sn_local_partid); EXPORT_SYMBOL(sn_system_serial_number_string); EXPORT_SYMBOL(sn_partition_serial_number); -#endif + +EXPORT_SYMBOL(sn_mmiob); /* added by tduffy 04.08.01 to fix depmod issues */ #include -#ifdef BUS_INT_WAR -extern void sn_add_polled_interrupt(int, int); -extern void sn_delete_polled_interrupt(int); -EXPORT_SYMBOL(sn_add_polled_interrupt); -EXPORT_SYMBOL(sn_delete_polled_interrupt); -#endif - extern nasid_t master_nasid; EXPORT_SYMBOL(master_nasid); + +EXPORT_SYMBOL(sn_flush_all_caches); diff --git a/arch/ia64/sn/kernel/sv.c b/arch/ia64/sn/kernel/sv.c index 84bedef9f6e..0fa601f9100 100644 --- a/arch/ia64/sn/kernel/sv.c +++ b/arch/ia64/sn/kernel/sv.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff --git a/arch/ia64/tools/Makefile b/arch/ia64/tools/Makefile deleted file mode 100644 index ce1fe06d9d9..00000000000 --- a/arch/ia64/tools/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -CFLAGS = -g -O2 -Wall $(CPPFLAGS) - -TARGET = include/asm-ia64/offsets.h - -src = $(obj) - -clean-files := print_offsets.s print_offsets offsets.h - -$(TARGET): $(obj)/offsets.h - @if ! cmp -s $(obj)/offsets.h ${TARGET}; then \ - echo -e "*** Updating ${TARGET}..."; \ - cp $(obj)/offsets.h ${TARGET}; \ - else \ - echo "*** ${TARGET} is up to date"; \ - fi - -# -# If we're cross-compiling, we use the cross-compiler to translate -# print_offsets.c into an assembly file and then awk to translate this -# file into offsets.h. This avoids having to use a simulator to -# generate this file. This is based on an idea suggested by Asit -# Mallick. If we're running natively, we can of course just build -# print_offsets and run it. --davidm -# - -ifeq ($(CROSS_COMPILE),) - -$(obj)/offsets.h: $(obj)/print_offsets - $(obj)/print_offsets > $(obj)/offsets.h - -comma := , - -$(obj)/print_offsets: $(src)/print_offsets.c FORCE - [ -r $(TARGET) ] || echo "#define IA64_TASK_SIZE 0" > $(TARGET) - $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \ - $(src)/print_offsets.c -o $@ - -FORCE: - -else - -$(obj)/offsets.h: $(obj)/print_offsets.s - $(AWK) -f $(src)/print_offsets.awk $^ > $@ - -$(obj)/print_offsets.s: $(src)/print_offsets.c - [ -r $(TARGET) ] || echo "#define IA64_TASK_SIZE 0" > $(TARGET) - $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -S $^ -o $@ - -endif - -.PHONY: all modules modules_install diff --git a/arch/ia64/tools/print_offsets.awk b/arch/ia64/tools/print_offsets.awk deleted file mode 100644 index bd015fcba2e..00000000000 --- a/arch/ia64/tools/print_offsets.awk +++ /dev/null @@ -1,72 +0,0 @@ -BEGIN { - print "#ifndef _ASM_IA64_OFFSETS_H" - print "#define _ASM_IA64_OFFSETS_H" - print "/*" - print " * DO NOT MODIFY" - print " *" - print " * This file was generated by arch/ia64/tools/print_offsets.awk." - print " *" - print " */" - print "" - print "#define CLONE_IDLETASK_BIT 12" - print "#define CLONE_SETTLS_BIT 19" -} - -# look for .tab: -# stringz "name" -# data value -# sequence - -/.*[.]size/ { - inside_table = 0 -} - -/\/\/ end/ { - inside_table = 0 -} - -/.*[.]rodata/ { - inside_table = 0 -} - -{ - if (inside_table) { - if ($1 == "//") getline; - name=$2 - getline - getline - if ($1 == "//") getline; - value=$2 - len = length(name) - name = substr(name, 2, len - 2) - len -= 2 - if (len == 0) - print "" - else { - len += 8 - if (len >= 40) { - space=" " - } else { - space="" - while (len < 40) { - len += 8 - space = space"\t" - } - } - printf("#define %s%s%lu\t/* 0x%lx */\n", name, space, value, value) - } - } -} - -/tab:/ { - inside_table = 1 -} - -/tab\#:/ { - inside_table = 1 -} - -END { - print "" - print "#endif /* _ASM_IA64_OFFSETS_H */" -} diff --git a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c deleted file mode 100644 index 8ce471f532b..00000000000 --- a/arch/ia64/tools/print_offsets.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Utility to generate asm-ia64/offsets.h. - * - * Copyright (C) 1999-2003 Hewlett-Packard Co - * David Mosberger-Tang - * - * Note that this file has dual use: when building the kernel - * natively, the file is translated into a binary and executed. When - * building the kernel in a cross-development environment, this file - * gets translated into an assembly file which, in turn, is processed - * by awk to generate offsets.h. So if you make any changes to this - * file, be sure to verify that the awk procedure still works (see - * print_offsets.awk). - */ -#include - -#include - -#include -#include -#include -#include - -#include "../kernel/sigframe.h" - -#ifdef offsetof -# undef offsetof -#endif - -/* - * We _can't_ include the host's standard header file, as those are in - * potential conflict with the what the Linux kernel declares for the - * target system. - */ -extern int printf (const char *, ...); - -#define offsetof(type,field) ((char *) &((type *) 0)->field - (char *) 0) - -struct - { - const char name[256]; - unsigned long value; - } -tab[] = - { - { "IA64_TASK_SIZE", sizeof (struct task_struct) }, - { "IA64_THREAD_INFO_SIZE", sizeof (struct thread_info) }, - { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, - { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, - { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, - { "IA64_CPU_SIZE", sizeof (struct cpuinfo_ia64) }, - { "SIGFRAME_SIZE", sizeof (struct sigframe) }, - { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, - { "", 0 }, /* spacer */ - { "IA64_TASK_CLEAR_CHILD_TID_OFFSET",offsetof (struct task_struct, clear_child_tid) }, - { "IA64_TASK_GROUP_LEADER_OFFSET", offsetof (struct task_struct, group_leader) }, - { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, - { "IA64_TASK_REAL_PARENT_OFFSET", offsetof (struct task_struct, real_parent) }, - { "IA64_TASK_TGID_OFFSET", offsetof (struct task_struct, tgid) }, - { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, - { "IA64_TASK_THREAD_ON_USTACK_OFFSET", offsetof (struct task_struct, thread.on_ustack) }, - { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, - { "IA64_PT_REGS_CR_IIP_OFFSET", offsetof (struct pt_regs, cr_iip) }, - { "IA64_PT_REGS_CR_IFS_OFFSET", offsetof (struct pt_regs, cr_ifs) }, - { "IA64_PT_REGS_AR_UNAT_OFFSET", offsetof (struct pt_regs, ar_unat) }, - { "IA64_PT_REGS_AR_PFS_OFFSET", offsetof (struct pt_regs, ar_pfs) }, - { "IA64_PT_REGS_AR_RSC_OFFSET", offsetof (struct pt_regs, ar_rsc) }, - { "IA64_PT_REGS_AR_RNAT_OFFSET", offsetof (struct pt_regs, ar_rnat) }, - { "IA64_PT_REGS_AR_BSPSTORE_OFFSET",offsetof (struct pt_regs, ar_bspstore) }, - { "IA64_PT_REGS_PR_OFFSET", offsetof (struct pt_regs, pr) }, - { "IA64_PT_REGS_B6_OFFSET", offsetof (struct pt_regs, b6) }, - { "IA64_PT_REGS_LOADRS_OFFSET", offsetof (struct pt_regs, loadrs) }, - { "IA64_PT_REGS_R1_OFFSET", offsetof (struct pt_regs, r1) }, - { "IA64_PT_REGS_R2_OFFSET", offsetof (struct pt_regs, r2) }, - { "IA64_PT_REGS_R3_OFFSET", offsetof (struct pt_regs, r3) }, - { "IA64_PT_REGS_R12_OFFSET", offsetof (struct pt_regs, r12) }, - { "IA64_PT_REGS_R13_OFFSET", offsetof (struct pt_regs, r13) }, - { "IA64_PT_REGS_R14_OFFSET", offsetof (struct pt_regs, r14) }, - { "IA64_PT_REGS_R15_OFFSET", offsetof (struct pt_regs, r15) }, - { "IA64_PT_REGS_R8_OFFSET", offsetof (struct pt_regs, r8) }, - { "IA64_PT_REGS_R9_OFFSET", offsetof (struct pt_regs, r9) }, - { "IA64_PT_REGS_R10_OFFSET", offsetof (struct pt_regs, r10) }, - { "IA64_PT_REGS_R11_OFFSET", offsetof (struct pt_regs, r11) }, - { "IA64_PT_REGS_R16_OFFSET", offsetof (struct pt_regs, r16) }, - { "IA64_PT_REGS_R17_OFFSET", offsetof (struct pt_regs, r17) }, - { "IA64_PT_REGS_R18_OFFSET", offsetof (struct pt_regs, r18) }, - { "IA64_PT_REGS_R19_OFFSET", offsetof (struct pt_regs, r19) }, - { "IA64_PT_REGS_R20_OFFSET", offsetof (struct pt_regs, r20) }, - { "IA64_PT_REGS_R21_OFFSET", offsetof (struct pt_regs, r21) }, - { "IA64_PT_REGS_R22_OFFSET", offsetof (struct pt_regs, r22) }, - { "IA64_PT_REGS_R23_OFFSET", offsetof (struct pt_regs, r23) }, - { "IA64_PT_REGS_R24_OFFSET", offsetof (struct pt_regs, r24) }, - { "IA64_PT_REGS_R25_OFFSET", offsetof (struct pt_regs, r25) }, - { "IA64_PT_REGS_R26_OFFSET", offsetof (struct pt_regs, r26) }, - { "IA64_PT_REGS_R27_OFFSET", offsetof (struct pt_regs, r27) }, - { "IA64_PT_REGS_R28_OFFSET", offsetof (struct pt_regs, r28) }, - { "IA64_PT_REGS_R29_OFFSET", offsetof (struct pt_regs, r29) }, - { "IA64_PT_REGS_R30_OFFSET", offsetof (struct pt_regs, r30) }, - { "IA64_PT_REGS_R31_OFFSET", offsetof (struct pt_regs, r31) }, - { "IA64_PT_REGS_AR_CCV_OFFSET", offsetof (struct pt_regs, ar_ccv) }, - { "IA64_PT_REGS_AR_FPSR_OFFSET", offsetof (struct pt_regs, ar_fpsr) }, - { "IA64_PT_REGS_B0_OFFSET", offsetof (struct pt_regs, b0) }, - { "IA64_PT_REGS_B7_OFFSET", offsetof (struct pt_regs, b7) }, - { "IA64_PT_REGS_F6_OFFSET", offsetof (struct pt_regs, f6) }, - { "IA64_PT_REGS_F7_OFFSET", offsetof (struct pt_regs, f7) }, - { "IA64_PT_REGS_F8_OFFSET", offsetof (struct pt_regs, f8) }, - { "IA64_PT_REGS_F9_OFFSET", offsetof (struct pt_regs, f9) }, - { "IA64_SWITCH_STACK_CALLER_UNAT_OFFSET", offsetof (struct switch_stack, caller_unat) }, - { "IA64_SWITCH_STACK_AR_FPSR_OFFSET", offsetof (struct switch_stack, ar_fpsr) }, - { "IA64_SWITCH_STACK_F2_OFFSET", offsetof (struct switch_stack, f2) }, - { "IA64_SWITCH_STACK_F3_OFFSET", offsetof (struct switch_stack, f3) }, - { "IA64_SWITCH_STACK_F4_OFFSET", offsetof (struct switch_stack, f4) }, - { "IA64_SWITCH_STACK_F5_OFFSET", offsetof (struct switch_stack, f5) }, - { "IA64_SWITCH_STACK_F10_OFFSET", offsetof (struct switch_stack, f10) }, - { "IA64_SWITCH_STACK_F11_OFFSET", offsetof (struct switch_stack, f11) }, - { "IA64_SWITCH_STACK_F12_OFFSET", offsetof (struct switch_stack, f12) }, - { "IA64_SWITCH_STACK_F13_OFFSET", offsetof (struct switch_stack, f13) }, - { "IA64_SWITCH_STACK_F14_OFFSET", offsetof (struct switch_stack, f14) }, - { "IA64_SWITCH_STACK_F15_OFFSET", offsetof (struct switch_stack, f15) }, - { "IA64_SWITCH_STACK_F16_OFFSET", offsetof (struct switch_stack, f16) }, - { "IA64_SWITCH_STACK_F17_OFFSET", offsetof (struct switch_stack, f17) }, - { "IA64_SWITCH_STACK_F18_OFFSET", offsetof (struct switch_stack, f18) }, - { "IA64_SWITCH_STACK_F19_OFFSET", offsetof (struct switch_stack, f19) }, - { "IA64_SWITCH_STACK_F20_OFFSET", offsetof (struct switch_stack, f20) }, - { "IA64_SWITCH_STACK_F21_OFFSET", offsetof (struct switch_stack, f21) }, - { "IA64_SWITCH_STACK_F22_OFFSET", offsetof (struct switch_stack, f22) }, - { "IA64_SWITCH_STACK_F23_OFFSET", offsetof (struct switch_stack, f23) }, - { "IA64_SWITCH_STACK_F24_OFFSET", offsetof (struct switch_stack, f24) }, - { "IA64_SWITCH_STACK_F25_OFFSET", offsetof (struct switch_stack, f25) }, - { "IA64_SWITCH_STACK_F26_OFFSET", offsetof (struct switch_stack, f26) }, - { "IA64_SWITCH_STACK_F27_OFFSET", offsetof (struct switch_stack, f27) }, - { "IA64_SWITCH_STACK_F28_OFFSET", offsetof (struct switch_stack, f28) }, - { "IA64_SWITCH_STACK_F29_OFFSET", offsetof (struct switch_stack, f29) }, - { "IA64_SWITCH_STACK_F30_OFFSET", offsetof (struct switch_stack, f30) }, - { "IA64_SWITCH_STACK_F31_OFFSET", offsetof (struct switch_stack, f31) }, - { "IA64_SWITCH_STACK_R4_OFFSET", offsetof (struct switch_stack, r4) }, - { "IA64_SWITCH_STACK_R5_OFFSET", offsetof (struct switch_stack, r5) }, - { "IA64_SWITCH_STACK_R6_OFFSET", offsetof (struct switch_stack, r6) }, - { "IA64_SWITCH_STACK_R7_OFFSET", offsetof (struct switch_stack, r7) }, - { "IA64_SWITCH_STACK_B0_OFFSET", offsetof (struct switch_stack, b0) }, - { "IA64_SWITCH_STACK_B1_OFFSET", offsetof (struct switch_stack, b1) }, - { "IA64_SWITCH_STACK_B2_OFFSET", offsetof (struct switch_stack, b2) }, - { "IA64_SWITCH_STACK_B3_OFFSET", offsetof (struct switch_stack, b3) }, - { "IA64_SWITCH_STACK_B4_OFFSET", offsetof (struct switch_stack, b4) }, - { "IA64_SWITCH_STACK_B5_OFFSET", offsetof (struct switch_stack, b5) }, - { "IA64_SWITCH_STACK_AR_PFS_OFFSET", offsetof (struct switch_stack, ar_pfs) }, - { "IA64_SWITCH_STACK_AR_LC_OFFSET", offsetof (struct switch_stack, ar_lc) }, - { "IA64_SWITCH_STACK_AR_UNAT_OFFSET", offsetof (struct switch_stack, ar_unat) }, - { "IA64_SWITCH_STACK_AR_RNAT_OFFSET", offsetof (struct switch_stack, ar_rnat) }, - { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET", offsetof (struct switch_stack, ar_bspstore) }, - { "IA64_SWITCH_STACK_PR_OFFSET", offsetof (struct switch_stack, pr) }, - { "IA64_SIGCONTEXT_IP_OFFSET", offsetof (struct sigcontext, sc_ip) }, - { "IA64_SIGCONTEXT_AR_BSP_OFFSET", offsetof (struct sigcontext, sc_ar_bsp) }, - { "IA64_SIGCONTEXT_AR_FPSR_OFFSET", offsetof (struct sigcontext, sc_ar_fpsr) }, - { "IA64_SIGCONTEXT_AR_RNAT_OFFSET", offsetof (struct sigcontext, sc_ar_rnat) }, - { "IA64_SIGCONTEXT_AR_UNAT_OFFSET", offsetof (struct sigcontext, sc_ar_unat) }, - { "IA64_SIGCONTEXT_B0_OFFSET", offsetof (struct sigcontext, sc_br[0]) }, - { "IA64_SIGCONTEXT_CFM_OFFSET", offsetof (struct sigcontext, sc_cfm) }, - { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, - { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, - { "IA64_SIGCONTEXT_PR_OFFSET", offsetof (struct sigcontext, sc_pr) }, - { "IA64_SIGCONTEXT_R12_OFFSET", offsetof (struct sigcontext, sc_gr[12]) }, - { "IA64_SIGCONTEXT_RBS_BASE_OFFSET",offsetof (struct sigcontext, sc_rbs_base) }, - { "IA64_SIGCONTEXT_LOADRS_OFFSET", offsetof (struct sigcontext, sc_loadrs) }, - { "IA64_SIGFRAME_ARG0_OFFSET", offsetof (struct sigframe, arg0) }, - { "IA64_SIGFRAME_ARG1_OFFSET", offsetof (struct sigframe, arg1) }, - { "IA64_SIGFRAME_ARG2_OFFSET", offsetof (struct sigframe, arg2) }, - { "IA64_SIGFRAME_HANDLER_OFFSET", offsetof (struct sigframe, handler) }, - { "IA64_SIGFRAME_SIGCONTEXT_OFFSET", offsetof (struct sigframe, sc) }, - /* for assembly files which can't include sched.h: */ - { "IA64_CLONE_VFORK", CLONE_VFORK }, - { "IA64_CLONE_VM", CLONE_VM }, - /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ - { "IA64_CPUINFO_ITM_DELTA_OFFSET", offsetof (struct cpuinfo_ia64, itm_delta) }, - { "IA64_CPUINFO_ITM_NEXT_OFFSET", offsetof (struct cpuinfo_ia64, itm_next) }, - { "IA64_CPUINFO_NSEC_PER_CYC_OFFSET", offsetof (struct cpuinfo_ia64, nsec_per_cyc) }, - { "IA64_TIMESPEC_TV_NSEC_OFFSET", offsetof (struct timespec, tv_nsec) }, - -}; - -static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; - -int -main (int argc, char **argv) -{ - const char *space; - int i, num_tabs; - size_t len; - - printf ("#ifndef _ASM_IA64_OFFSETS_H\n"); - printf ("#define _ASM_IA64_OFFSETS_H\n\n"); - - printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by " - "arch/ia64/tools/print_offsets.\n *\n */\n\n"); - - for (i = 0; i < (int) (sizeof (tab) / sizeof (tab[0])); ++i) - { - if (tab[i].name[0] == '\0') - printf ("\n"); - else - { - len = strlen (tab[i].name); - - num_tabs = (40 - len) / 8; - if (num_tabs <= 0) - space = " "; - else - space = strchr(tabs, '\0') - (40 - len) / 8; - - printf ("#define %s%s%lu\t/* 0x%lx */\n", - tab[i].name, space, tab[i].value, tab[i].value); - } - } - - printf ("\n#define CLONE_IDLETASK_BIT %ld\n", ia64_fls (CLONE_IDLETASK)); - printf ("\n#define CLONE_SETTLS_BIT %ld\n", ia64_fls (CLONE_SETTLS)); - - printf ("\n#endif /* _ASM_IA64_OFFSETS_H */\n"); - return 0; -} diff --git a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S index 3d9f69fefaa..d28370bd122 100644 --- a/arch/ia64/vmlinux.lds.S +++ b/arch/ia64/vmlinux.lds.S @@ -3,8 +3,9 @@ #include #include #include +#include -#define LOAD_OFFSET PAGE_OFFSET +#define LOAD_OFFSET KERNEL_START + KERNEL_TR_PAGE_SIZE #include OUTPUT_FORMAT("elf64-ia64-little") @@ -23,22 +24,22 @@ SECTIONS } v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ - phys_start = _start - PAGE_OFFSET; + phys_start = _start - LOAD_OFFSET; . = KERNEL_START; _text = .; _stext = .; - .text : AT(ADDR(.text) - PAGE_OFFSET) + .text : AT(ADDR(.text) - LOAD_OFFSET) { *(.text.ivt) *(.text) } - .text2 : AT(ADDR(.text2) - PAGE_OFFSET) + .text2 : AT(ADDR(.text2) - LOAD_OFFSET) { *(.text2) } #ifdef CONFIG_SMP - .text.lock : AT(ADDR(.text.lock) - PAGE_OFFSET) + .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } #endif _etext = .; @@ -47,17 +48,24 @@ SECTIONS /* Exception table */ . = ALIGN(16); - __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET) + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { __start___ex_table = .; *(__ex_table) __stop___ex_table = .; } - __mckinley_e9_bundles : AT(ADDR(__mckinley_e9_bundles) - PAGE_OFFSET) + .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) + { + __start___vtop_patchlist = .; + *(.data.patch.vtop) + __end____vtop_patchlist = .; + } + + .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) { __start___mckinley_e9_bundles = .; - *(__mckinley_e9_bundles) + *(.data.patch.mckinley_e9) __end___mckinley_e9_bundles = .; } @@ -67,7 +75,7 @@ SECTIONS #if defined(CONFIG_IA64_GENERIC) /* Machine Vector */ . = ALIGN(16); - .machvec : AT(ADDR(.machvec) - PAGE_OFFSET) + .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) { machvec_start = .; *(.machvec) @@ -77,9 +85,9 @@ SECTIONS /* Unwind info & table: */ . = ALIGN(8); - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) { *(.IA_64.unwind_info*) } - .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) + .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) { ia64_unw_start = .; *(.IA_64.unwind*) @@ -88,24 +96,24 @@ SECTIONS RODATA - .opd : AT(ADDR(.opd) - PAGE_OFFSET) + .opd : AT(ADDR(.opd) - LOAD_OFFSET) { *(.opd) } /* Initialization code and data: */ . = ALIGN(PAGE_SIZE); __init_begin = .; - .init.text : AT(ADDR(.init.text) - PAGE_OFFSET) + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; *(.init.text) _einittext = .; } - .init.data : AT(ADDR(.init.data) - PAGE_OFFSET) + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } - .init.ramfs : AT(ADDR(.init.ramfs) - PAGE_OFFSET) + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) @@ -113,19 +121,19 @@ SECTIONS } . = ALIGN(16); - .init.setup : AT(ADDR(.init.setup) - PAGE_OFFSET) + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { __setup_start = .; *(.init.setup) __setup_end = .; } - __param : AT(ADDR(__param) - PAGE_OFFSET) + __param : AT(ADDR(__param) - LOAD_OFFSET) { __start___param = .; *(__param) __stop___param = .; } - .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET) + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { __initcall_start = .; *(.initcall1.init) @@ -138,7 +146,7 @@ SECTIONS __initcall_end = .; } __con_initcall_start = .; - .con_initcall.init : AT(ADDR(.con_initcall.init) - PAGE_OFFSET) + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { *(.con_initcall.init) } __con_initcall_end = .; __security_initcall_start = .; @@ -149,24 +157,24 @@ SECTIONS __init_end = .; /* The initial task and kernel stack */ - .data.init_task : AT(ADDR(.data.init_task) - PAGE_OFFSET) + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { *(.data.init_task) } - .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET) + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { *(__special_page_section) __start_gate_section = .; - *(.text.gate) + *(.data.gate) __stop_gate_section = .; } + . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */ - . = ALIGN(SMP_CACHE_BYTES); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET) + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { *(.data.cacheline_aligned) } /* Per-cpu data: */ . = ALIGN(PERCPU_PAGE_SIZE); __phys_per_cpu_start = .; - .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - PAGE_OFFSET) + .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET) { __per_cpu_start = .; *(.data.percpu) @@ -174,24 +182,24 @@ SECTIONS } . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */ - .data : AT(ADDR(.data) - PAGE_OFFSET) + .data : AT(ADDR(.data) - LOAD_OFFSET) { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } . = ALIGN(16); __gp = . + 0x200000; /* gp must be 16-byte aligned for exc. table */ - .got : AT(ADDR(.got) - PAGE_OFFSET) + .got : AT(ADDR(.got) - LOAD_OFFSET) { *(.got.plt) *(.got) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ - .sdata : AT(ADDR(.sdata) - PAGE_OFFSET) + .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) { *(.sdata) } _edata = .; _bss = .; - .sbss : AT(ADDR(.sbss) - PAGE_OFFSET) + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - PAGE_OFFSET) + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss) *(COMMON) } _end = .; diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index ed458156178..072625710e2 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -376,81 +376,7 @@ config KCORE_AOUT endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config ZORRO bool "Amiga Zorro (AutoConfig) bus support" @@ -647,6 +573,8 @@ endif endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/block/Kconfig" @@ -680,417 +608,7 @@ config SCSI module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CD-ROM)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT for - SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config ST_EXTRA_DEVS - int "Maximum number of SCSI tapes that can be loaded as modules" - depends on CHR_DEV_ST - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional tapes that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config A3000_SCSI - tristate "A3000 WD33C93A support" - depends on AMIGA && SCSI - help - If you have an Amiga 3000 and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. This driver is - also available as a module ( = code which can be inserted in and - removed from the running kernel whenever you want). The module is - called wd33c93. If you want to compile it as a module, say M here - and read . - -config A4000T_SCSI - bool "A4000T SCSI support (EXPERIMENTAL)" - depends on AMIGA && EXPERIMENTAL - help - Support for the NCR53C710 SCSI controller on the Amiga 4000T. - -config A2091_SCSI - tristate "A2091 WD33C93A support" - depends on ZORRO && SCSI - help - If you have a Commodore A2091 SCSI controller, say Y. Otherwise, - say N. This driver is also available as a module ( = code which can - be inserted in and removed from the running kernel whenever you - want). The module is called wd33c93. If you want to compile it as - a module, say M here and read . - -config GVP11_SCSI - tristate "GVP Series II WD33C93A support" - depends on ZORRO && SCSI - ---help--- - If you have a Great Valley Products Series II SCSI controller, - answer Y. Also say Y if you have a later model of GVP SCSI - controller (such as the GVP A4008 or a Combo board). Otherwise, - answer N. This driver does NOT work for the T-Rex series of - accelerators from TekMagic and GVP-M. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). The module will be called gvp11. If you want to compile it - as a module, say M here and read . - -config CYBERSTORM_SCSI - tristate "CyberStorm SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with an original (MkI) Phase5 Cyberstorm - accelerator board and the optional Cyberstorm SCSI controller, - answer Y. Otherwise, say N. - -config CYBERSTORMII_SCSI - tristate "CyberStorm Mk II SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board - and the optional Cyberstorm SCSI controller, say Y. Otherwise, - answer N. - -config BLZ2060_SCSI - tristate "Blizzard 2060 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Blizzard 2060 accelerator board - and want to use the onboard SCSI controller, say Y. Otherwise, - answer N. - -config BLZ1230_SCSI - tristate "Blizzard 1230IV/1260 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard - 1260 accelerator, and the optional SCSI module, say Y. Otherwise, - say N. - -config FASTLANE_SCSI - tristate "Fastlane SCSI support" - depends on ZORRO && SCSI - help - If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use - one in the near future, say Y to this question. Otherwise, say N. - -config A4091_SCSI - bool "A4091 SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller - (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade - plan at the time the Amiga business was sold to DKB. - -config WARPENGINE_SCSI - bool "WarpEngine SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - Support for MacroSystem Development's WarpEngine Amiga SCSI-2 - controller. Info at - . - -config BLZ603EPLUS_SCSI - bool "Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ - accelerator, say Y. Otherwise, say N. - -config OKTAGON_SCSI - tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL && SCSI - help - If you have the BSC Oktagon SCSI disk controller for the Amiga, say - Y to this question. If you're in doubt about whether you have one, - see the picture at - . - -# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI -# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI -config ATARI_SCSI - tristate "Atari native SCSI support" - depends on ATARI && SCSI - ---help--- - If you have an Atari with built-in NCR5380 SCSI controller (TT, - Falcon, ...) say Y to get it supported. Of course also, if you have - a compatible SCSI controller (e.g. for Medusa). This driver is also - available as a module ( = code which can be inserted in and removed - from the running kernel whenever you want). The module is called - atari_scsi. If you want to compile it as a module, say M here and - read . This driver supports both - styles of NCR integration into the system: the TT style (separate - DMA), and the Falcon style (via ST-DMA, replacing ACSI). It does - NOT support other schemes, like in the Hades (without DMA). - -config ATARI_SCSI_TOSHIBA_DELAY - bool "Long delays for Toshiba CD-ROMs" - depends on ATARI_SCSI - help - This option increases the delay after a SCSI arbitration to - accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to - use a Toshiba CD-ROM drive; otherwise, the option is not needed and - would impact performance a bit, so say N. - -config ATARI_SCSI_RESET_BOOT - bool "Reset SCSI-devices at boottime" - depends on ATARI_SCSI - help - Reset the devices on your Atari whenever it boots. This makes the - boot process fractionally longer but may assist recovery from errors - that leave the devices with SCSI operations partway completed. - -config TT_DMA_EMUL - bool "Hades SCSI DMA emulator" - depends on ATARI_SCSI && HADES - help - This option enables code which emulates the TT SCSI DMA chip on the - Hades. This increases the SCSI transfer rates at least ten times - compared to PIO transfers. - -config MAC_SCSI - bool "Macintosh NCR5380 SCSI" - depends on MAC - help - This is the NCR 5380 SCSI controller included on most of the 68030 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - -config SCSI_MAC_ESP - tristate "Macintosh NCR53c9[46] SCSI" - depends on MAC && SCSI - help - This is the NCR 53c9x SCSI controller found on most of the 68040 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called mac_esp. If you want to compile it as - a module, say M here and read . - -# dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI -config MVME147_SCSI - bool "WD33C93 SCSI driver for MVME147" - depends on MVME147 - help - Support for the on-board SCSI controller on the Motorola MVME147 - single-board computer. - -config MVME16x_SCSI - bool "NCR53C710 SCSI driver for MVME16x" - depends on MVME16x - help - The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config BVME6000_SCSI - bool "NCR53C710 SCSI driver for BVME6000" - depends on BVME6000 - help - The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config SUN3_SCSI - tristate "Sun3 NCR5380 SCSI" - depends on SUN3 && SCSI - help - This option will enable support for the OBIO (onboard io) NCR5380 - SCSI controller found in the Sun 3/50 and 3/60, as well as for - "Sun3" type VME scsi controllers also based on the NCR5380. - General Linux information on the Sun 3 series (now discontinued) - is at . - -config SUN3X_ESP - bool "Sun3x ESP SCSI" - depends on SUN3X - help - The ESP was an on-board SCSI controller used on Sun 3/80 - machines. Say Y here to compile in support for it. - -endmenu +source "drivers/scsi/Kconfig" endmenu diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 47f8c211f28..52f2b970705 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -501,16 +501,7 @@ config KCORE_AOUT config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. - -config BINFMT_ZFLAT - bool " Enable ZFLAT support" - depends on BINFMT_FLAT - help - Supoprt FLAT format compressed binaries +source "fs/Kconfig.binfmt" endmenu @@ -524,6 +515,8 @@ config PM endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S index c9ac716240a..fa0152a1ab0 100644 --- a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S +++ b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S @@ -174,6 +174,7 @@ _start: nop +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -195,6 +196,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c index 5d09dcf110b..a038092a2e4 100644 --- a/arch/m68knommu/platform/5249/config.c +++ b/arch/m68knommu/platform/5249/config.c @@ -95,7 +95,13 @@ int mcf_timerirqpending(int timer) void config_BSP(char *commandp, int size) { mcf_setimr(MCFSIM_IMR_MASKALL); + +#if defined(CONFIG_BOOTPARAM) + strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); + commandp[size-1] = 0; +#else memset(commandp, 0, size); +#endif mach_sched_init = coldfire_timer_init; mach_tick = coldfire_tick; diff --git a/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S index c2905669e9f..c5aad9dc5f5 100644 --- a/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S +++ b/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S @@ -103,6 +103,7 @@ _start: move.l #0x80000100, %d0 /* Setup cache mask */ movec %d0, %CACR /* Enable cache */ +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -124,6 +125,12 @@ _copy_romfs: cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + + /* * Zero out the bss region. */ diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c index 78dbaac8c5a..1809554f0e2 100644 --- a/arch/m68knommu/platform/5272/config.c +++ b/arch/m68knommu/platform/5272/config.c @@ -104,7 +104,10 @@ void config_BSP(char *commandp, int size) mcf_disableall(); -#if defined(CONFIG_NETtel) +#if defined(CONFIG_BOOTPARAM) + strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); + commandp[size-1] = 0; +#elif defined(CONFIG_NETtel) /* Copy command line from FLASH to local buffer... */ memcpy(commandp, (char *) 0xf0004000, size); commandp[size-1] = 0; diff --git a/arch/mips/Kconfig-shared b/arch/mips/Kconfig-shared index 7acb2c681fe..e70459b7d43 100644 --- a/arch/mips/Kconfig-shared +++ b/arch/mips/Kconfig-shared @@ -1135,37 +1135,7 @@ config KCORE_ELF config KCORE_AOUT bool -config BINFMT_AOUT - bool - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. +source "fs/Kconfig.binfmt" config BINFMT_IRIX bool "Include IRIX binary compatibility" @@ -1209,31 +1179,6 @@ config BINFMT_ELF32 bool default y if MIPS32_O32 || MIPS32_N32 -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. - config PM bool "Power Management support (EXPERIMENTAL)" depends on EXPERIMENTAL && SOC_AU1X00 @@ -1246,6 +1191,8 @@ source "drivers/parport/Kconfig" source "drivers/pnp/Kconfig" +source "drivers/base/Kconfig" + source "drivers/block/Kconfig" diff --git a/arch/mips/defconfig b/arch/mips/defconfig index 4af5de1fdfe..fab4a2129fc 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig @@ -126,8 +126,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_IRIX=y # CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_IRIX=y # # Memory Technology Devices (MTD) @@ -145,6 +145,11 @@ CONFIG_BINFMT_IRIX=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -185,24 +190,10 @@ CONFIG_SCSI_CONSTANTS=y # SCSI low-level drivers # CONFIG_SGIWD93_SCSI=y -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips/defconfig-atlas b/arch/mips/defconfig-atlas index da27bedc836..50198ccd31b 100644 --- a/arch/mips/defconfig-atlas +++ b/arch/mips/defconfig-atlas @@ -119,8 +119,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -138,6 +138,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -189,8 +194,6 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -199,11 +202,8 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set @@ -214,7 +214,6 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set diff --git a/arch/mips/defconfig-capcella b/arch/mips/defconfig-capcella index 3389aac75bb..6eb30aa4e14 100644 --- a/arch/mips/defconfig-capcella +++ b/arch/mips/defconfig-capcella @@ -138,6 +138,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-cobalt b/arch/mips/defconfig-cobalt index b6dcc90f167..1be0bdbac48 100644 --- a/arch/mips/defconfig-cobalt +++ b/arch/mips/defconfig-cobalt @@ -132,6 +132,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476 index dade6fbd0d8..ddbe9c4810c 100644 --- a/arch/mips/defconfig-ddb5476 +++ b/arch/mips/defconfig-ddb5476 @@ -135,6 +135,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ddb5477 b/arch/mips/defconfig-ddb5477 index 8b194a52090..62ebad1857f 100644 --- a/arch/mips/defconfig-ddb5477 +++ b/arch/mips/defconfig-ddb5477 @@ -136,6 +136,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation index 9ae4dc1548f..368bc46fd94 100644 --- a/arch/mips/defconfig-decstation +++ b/arch/mips/defconfig-decstation @@ -135,6 +135,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -175,24 +180,10 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_DECNCR=y # CONFIG_SCSI_DECSII is not set -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips/defconfig-e55 b/arch/mips/defconfig-e55 index 988c61a03f4..3f7440ba548 100644 --- a/arch/mips/defconfig-e55 +++ b/arch/mips/defconfig-e55 @@ -134,6 +134,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-eagle b/arch/mips/defconfig-eagle index 39e7e97c516..d091b5b0723 100644 --- a/arch/mips/defconfig-eagle +++ b/arch/mips/defconfig-eagle @@ -213,6 +213,11 @@ CONFIG_MTD_PHYSMAP_BUSWIDTH=4 # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ev64120 b/arch/mips/defconfig-ev64120 index 20f589bafef..6dc0eb8218b 100644 --- a/arch/mips/defconfig-ev64120 +++ b/arch/mips/defconfig-ev64120 @@ -124,8 +124,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -143,6 +143,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ev96100 b/arch/mips/defconfig-ev96100 index 02f0a20621f..bda4e126cf0 100644 --- a/arch/mips/defconfig-ev96100 +++ b/arch/mips/defconfig-ev96100 @@ -121,8 +121,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -140,6 +140,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-hp-lj b/arch/mips/defconfig-hp-lj index 504b877d544..30bab02b68d 100644 --- a/arch/mips/defconfig-hp-lj +++ b/arch/mips/defconfig-hp-lj @@ -198,6 +198,11 @@ CONFIG_MTD_NAND_IDS=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22 index 4af5de1fdfe..fab4a2129fc 100644 --- a/arch/mips/defconfig-ip22 +++ b/arch/mips/defconfig-ip22 @@ -126,8 +126,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_IRIX=y # CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_IRIX=y # # Memory Technology Devices (MTD) @@ -145,6 +145,11 @@ CONFIG_BINFMT_IRIX=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -185,24 +190,10 @@ CONFIG_SCSI_CONSTANTS=y # SCSI low-level drivers # CONFIG_SGIWD93_SCSI=y -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips/defconfig-it8172 b/arch/mips/defconfig-it8172 index c377480e364..6bb114f6854 100644 --- a/arch/mips/defconfig-it8172 +++ b/arch/mips/defconfig-it8172 @@ -194,6 +194,11 @@ CONFIG_MTD_PHYSMAP_BUSWIDTH=4 # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ivr b/arch/mips/defconfig-ivr index e3e9fefeeed..6afe09cdd98 100644 --- a/arch/mips/defconfig-ivr +++ b/arch/mips/defconfig-ivr @@ -138,6 +138,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-jmr3927 b/arch/mips/defconfig-jmr3927 index 3219c718ed4..ce651a078cc 100644 --- a/arch/mips/defconfig-jmr3927 +++ b/arch/mips/defconfig-jmr3927 @@ -114,8 +114,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -133,6 +133,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-lasat200 b/arch/mips/defconfig-lasat200 index 289ec8f3220..0188e00c59a 100644 --- a/arch/mips/defconfig-lasat200 +++ b/arch/mips/defconfig-lasat200 @@ -201,6 +201,11 @@ CONFIG_MTD_LASAT=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-malta b/arch/mips/defconfig-malta index dae0c9f34ec..ab8cf309a8d 100644 --- a/arch/mips/defconfig-malta +++ b/arch/mips/defconfig-malta @@ -142,6 +142,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # CONFIG_BLK_DEV_FD=y @@ -181,24 +186,10 @@ CONFIG_BLK_DEV_SD=y # # SCSI low-level drivers # -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips/defconfig-mpc30x b/arch/mips/defconfig-mpc30x index 6ab6b7e92d4..c3b6088217d 100644 --- a/arch/mips/defconfig-mpc30x +++ b/arch/mips/defconfig-mpc30x @@ -137,6 +137,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-ocelot b/arch/mips/defconfig-ocelot index 5e295018347..10acacaaae0 100644 --- a/arch/mips/defconfig-ocelot +++ b/arch/mips/defconfig-ocelot @@ -116,8 +116,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -135,6 +135,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-osprey b/arch/mips/defconfig-osprey index b4da9df108c..8ca4bf9b99d 100644 --- a/arch/mips/defconfig-osprey +++ b/arch/mips/defconfig-osprey @@ -133,6 +133,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-pb1000 b/arch/mips/defconfig-pb1000 index 929f7050edb..5aee4d76f11 100644 --- a/arch/mips/defconfig-pb1000 +++ b/arch/mips/defconfig-pb1000 @@ -200,6 +200,11 @@ CONFIG_MTD_CFI_AMDSTD=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-pb1100 b/arch/mips/defconfig-pb1100 index 98437b20575..bc433137b03 100644 --- a/arch/mips/defconfig-pb1100 +++ b/arch/mips/defconfig-pb1100 @@ -200,6 +200,11 @@ CONFIG_MTD_CFI_INTELEXT=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-pb1500 b/arch/mips/defconfig-pb1500 index 53b2273ffb6..2461e7ff385 100644 --- a/arch/mips/defconfig-pb1500 +++ b/arch/mips/defconfig-pb1500 @@ -157,6 +157,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200 index a5a81ba49ea..2ab4500ffbc 100644 --- a/arch/mips/defconfig-rm200 +++ b/arch/mips/defconfig-rm200 @@ -146,6 +146,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # CONFIG_BLK_DEV_FD=y @@ -202,7 +207,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -217,7 +221,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 diff --git a/arch/mips/defconfig-sb1250-swarm b/arch/mips/defconfig-sb1250-swarm index 63db65abb80..ec21c2ec8c5 100644 --- a/arch/mips/defconfig-sb1250-swarm +++ b/arch/mips/defconfig-sb1250-swarm @@ -141,8 +141,8 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_IRIX is not set # CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_IRIX is not set # # Memory Technology Devices (MTD) @@ -160,6 +160,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-sead b/arch/mips/defconfig-sead index 3990cf32804..91170d78408 100644 --- a/arch/mips/defconfig-sead +++ b/arch/mips/defconfig-sead @@ -131,6 +131,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-tb0226 b/arch/mips/defconfig-tb0226 index df02744273a..f2b123279be 100644 --- a/arch/mips/defconfig-tb0226 +++ b/arch/mips/defconfig-tb0226 @@ -137,6 +137,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # CONFIG_BLK_DEV_FD=y @@ -199,24 +204,10 @@ CONFIG_SCSI_CONSTANTS=y # # SCSI low-level drivers # -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips/defconfig-tb0229 b/arch/mips/defconfig-tb0229 index ecf3f6beaea..8d984117dc7 100644 --- a/arch/mips/defconfig-tb0229 +++ b/arch/mips/defconfig-tb0229 @@ -139,6 +139,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/defconfig-workpad b/arch/mips/defconfig-workpad index 181ee58cd19..cdd42a95e7f 100644 --- a/arch/mips/defconfig-workpad +++ b/arch/mips/defconfig-workpad @@ -134,6 +134,11 @@ CONFIG_BINFMT_ELF=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h index 96a875fcec5..7b52a1b197a 100644 --- a/arch/mips/kernel/syscalls.h +++ b/arch/mips/kernel/syscalls.h @@ -269,3 +269,5 @@ SYS(sys_remap_file_pages, 5) SYS(sys_set_tid_address, 1) SYS(sys_restart_syscall, 0) /* XXX */ SYS(sys_fadvise64, 6) +SYS(sys_statfs64, 3) /* 4255 */ +SYS(sys_fstatfs64, 2) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a0d048853d2..96ebda32053 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -72,7 +72,7 @@ int (*board_be_handler)(struct pt_regs *regs, int is_fixup); * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... */ -void show_stack(unsigned long *sp) +void show_stack(struct task_struct *task, unsigned long *sp) { const int field = 2 * sizeof(unsigned long); long stackdata; @@ -101,11 +101,10 @@ void show_stack(unsigned long *sp) printk("\n"); } -void show_trace(unsigned long *stack) +void show_trace(struct task_struct *task, unsigned long *stack) { const int field = 2 * sizeof(unsigned long); unsigned long addr; - int i; if (!stack) stack = (unsigned long*)&stack; @@ -114,7 +113,6 @@ void show_trace(unsigned long *stack) #ifdef CONFIG_KALLSYMS printk("\n"); #endif - i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { @@ -127,7 +125,7 @@ void show_trace(unsigned long *stack) void show_trace_task(struct task_struct *tsk) { - show_trace((long *)tsk->thread.reg29); + show_trace(tsk, (long *)tsk->thread.reg29); } /* @@ -137,7 +135,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } void show_code(unsigned int *pc) @@ -226,8 +224,8 @@ void show_registers(struct pt_regs *regs) show_regs(regs); printk("Process %s (pid: %d, stackpage=%0*lx)\n", current->comm, current->pid, field, (unsigned long) current); - show_stack((long *) regs->regs[29]); - show_trace((long *) regs->regs[29]); + show_stack(current, (long *) regs->regs[29]); + show_trace(current, (long *) regs->regs[29]); show_code((unsigned int *) regs->cp0_epc); printk("\n"); } diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig index 80028fbc7c7..2a3394cb9c2 100644 --- a/arch/mips64/defconfig +++ b/arch/mips64/defconfig @@ -122,12 +122,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -145,6 +145,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -195,8 +200,6 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -205,11 +208,8 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set @@ -220,7 +220,6 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set diff --git a/arch/mips64/defconfig-atlas b/arch/mips64/defconfig-atlas index c3e277af925..d5918f2a431 100644 --- a/arch/mips64/defconfig-atlas +++ b/arch/mips64/defconfig-atlas @@ -111,12 +111,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -134,6 +134,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -173,24 +178,10 @@ CONFIG_BLK_DEV_SD=y # # SCSI low-level drivers # -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips64/defconfig-decstation b/arch/mips64/defconfig-decstation index 72919d09de1..dd7d60bec89 100644 --- a/arch/mips64/defconfig-decstation +++ b/arch/mips64/defconfig-decstation @@ -110,12 +110,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -133,6 +133,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -172,24 +177,10 @@ CONFIG_SCSI_CONSTANTS=y # SCSI low-level drivers # CONFIG_SCSI_DECNCR=y -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22 index d8e23ef1247..c23cee38fe2 100644 --- a/arch/mips64/defconfig-ip22 +++ b/arch/mips64/defconfig-ip22 @@ -121,12 +121,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y CONFIG_MIPS32_N32=y CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -144,6 +144,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -184,24 +189,10 @@ CONFIG_SCSI_CONSTANTS=y # SCSI low-level drivers # CONFIG_SGIWD93_SCSI=y -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27 index 80028fbc7c7..2a3394cb9c2 100644 --- a/arch/mips64/defconfig-ip27 +++ b/arch/mips64/defconfig-ip27 @@ -122,12 +122,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -145,6 +145,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -195,8 +200,6 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -205,11 +208,8 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set @@ -220,7 +220,6 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set diff --git a/arch/mips64/defconfig-ip32 b/arch/mips64/defconfig-ip32 index 766d5967539..b9a09505544 100644 --- a/arch/mips64/defconfig-ip32 +++ b/arch/mips64/defconfig-ip32 @@ -117,12 +117,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -CONFIG_BINFMT_MISC=y # # Memory Technology Devices (MTD) @@ -140,6 +140,11 @@ CONFIG_BINFMT_MISC=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set @@ -198,8 +203,6 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -208,11 +211,8 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set @@ -223,7 +223,6 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set diff --git a/arch/mips64/defconfig-malta b/arch/mips64/defconfig-malta index 3d9d9f63a7a..adabc4e5416 100644 --- a/arch/mips64/defconfig-malta +++ b/arch/mips64/defconfig-malta @@ -118,12 +118,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -141,6 +141,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # CONFIG_BLK_DEV_FD=y @@ -180,24 +185,10 @@ CONFIG_BLK_DEV_SD=y # # SCSI low-level drivers # -# CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_PCI2000 is not set -# CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set # diff --git a/arch/mips64/defconfig-rm200 b/arch/mips64/defconfig-rm200 index 8246c6ff561..aaa0b2849a2 100644 --- a/arch/mips64/defconfig-rm200 +++ b/arch/mips64/defconfig-rm200 @@ -123,12 +123,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -146,6 +146,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # CONFIG_BLK_DEV_FD=y @@ -202,7 +207,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set @@ -217,7 +221,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 diff --git a/arch/mips64/defconfig-sb1250-swarm b/arch/mips64/defconfig-sb1250-swarm index d19a71d0276..4b58596e1df 100644 --- a/arch/mips64/defconfig-sb1250-swarm +++ b/arch/mips64/defconfig-sb1250-swarm @@ -135,12 +135,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -158,6 +158,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips64/defconfig-sead b/arch/mips64/defconfig-sead index e8f3ee0ccd5..d3b87da637e 100644 --- a/arch/mips64/defconfig-sead +++ b/arch/mips64/defconfig-sead @@ -107,12 +107,12 @@ CONFIG_MMU=y # CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y # CONFIG_MIPS32_N32 is not set CONFIG_BINFMT_ELF32=y -# CONFIG_BINFMT_MISC is not set # # Memory Technology Devices (MTD) @@ -130,6 +130,11 @@ CONFIG_BINFMT_ELF32=y # CONFIG_PNP is not set # +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# # Block devices # # CONFIG_BLK_DEV_FD is not set diff --git a/arch/mips64/kernel/binfmt_elfn32.c b/arch/mips64/kernel/binfmt_elfn32.c index c6a7b285215..26d7590817e 100644 --- a/arch/mips64/kernel/binfmt_elfn32.c +++ b/arch/mips64/kernel/binfmt_elfn32.c @@ -54,11 +54,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include #include #include - -struct timeval32 -{ - int tv_sec, tv_usec; -}; +#include #define elf_prstatus elf_prstatus32 struct elf_prstatus32 @@ -71,10 +67,10 @@ struct elf_prstatus32 pid_t pr_ppid; pid_t pr_pgrp; pid_t pr_sid; - struct timeval32 pr_utime; /* User time */ - struct timeval32 pr_stime; /* System time */ - struct timeval32 pr_cutime; /* Cumulative user time */ - struct timeval32 pr_cstime; /* Cumulative system time */ + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime;/* Cumulative user time */ + struct compat_timeval pr_cstime;/* Cumulative system time */ elf_gregset_t pr_reg; /* GP registers */ int pr_fpvalid; /* True if math co-processor being used. */ }; diff --git a/arch/mips64/kernel/binfmt_elfo32.c b/arch/mips64/kernel/binfmt_elfo32.c index 91f7f7fb5f1..efe211c287f 100644 --- a/arch/mips64/kernel/binfmt_elfo32.c +++ b/arch/mips64/kernel/binfmt_elfo32.c @@ -56,11 +56,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include #include #include - -struct timeval32 -{ - int tv_sec, tv_usec; -}; +#include #define elf_prstatus elf_prstatus32 struct elf_prstatus32 @@ -73,10 +69,10 @@ struct elf_prstatus32 pid_t pr_ppid; pid_t pr_pgrp; pid_t pr_sid; - struct timeval32 pr_utime; /* User time */ - struct timeval32 pr_stime; /* System time */ - struct timeval32 pr_cutime; /* Cumulative user time */ - struct timeval32 pr_cstime; /* Cumulative system time */ + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime;/* Cumulative user time */ + struct compat_timeval pr_cstime;/* Cumulative system time */ elf_gregset_t pr_reg; /* GP registers */ int pr_fpvalid; /* True if math co-processor being used. */ }; diff --git a/arch/mips64/kernel/scall_n32.S b/arch/mips64/kernel/scall_n32.S index 7cf4f7ef892..425cb9a1a0b 100644 --- a/arch/mips64/kernel/scall_n32.S +++ b/arch/mips64/kernel/scall_n32.S @@ -330,3 +330,5 @@ EXPORT(sysn32_call_table) PTR sys_restart_syscall PTR sys_semtimedop /* 6215 */ PTR sys_fadvise64 + PTR sys_statfs64 + PTR sys_fstatfs64 diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S index 9efbb451097..c7a9a8a31fc 100644 --- a/arch/mips64/kernel/scall_o32.S +++ b/arch/mips64/kernel/scall_o32.S @@ -558,6 +558,8 @@ out: jr ra sys sys_set_tid_address 1 sys sys_restart_syscall 0 sys sys_fadvise64 6 + sys sys_statfs64 3 /* 4255 */ + sys sys_fstatfs64 2 .endm .macro sys function, nargs diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c index f9c06cb74fd..6981d96fa4d 100644 --- a/arch/mips64/kernel/traps.c +++ b/arch/mips64/kernel/traps.c @@ -72,7 +72,7 @@ int (*board_be_handler)(struct pt_regs *regs, int is_fixup); * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... */ -void show_stack(unsigned long *sp) +void show_stack(struct task_struct *task, unsigned long *sp) { const int field = 2 * sizeof(unsigned long); long stackdata; @@ -101,11 +101,10 @@ void show_stack(unsigned long *sp) printk("\n"); } -void show_trace(unsigned long *stack) +void show_trace(struct task_struct *task, unsigned long *stack) { const int field = 2 * sizeof(unsigned long); unsigned long addr; - int i; if (!stack) stack = (unsigned long*)&stack; @@ -114,7 +113,6 @@ void show_trace(unsigned long *stack) #ifdef CONFIG_KALLSYMS printk("\n"); #endif - i = 1; while (((long) stack & (THREAD_SIZE-1)) != 0) { addr = *stack++; if (kernel_text_address(addr)) { @@ -127,7 +125,7 @@ void show_trace(unsigned long *stack) void show_trace_task(struct task_struct *tsk) { - show_trace((long *)tsk->thread.reg29); + show_trace(tsk, (long *)tsk->thread.reg29); } /* @@ -137,7 +135,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } void show_code(unsigned int *pc) @@ -226,8 +224,8 @@ void show_registers(struct pt_regs *regs) show_regs(regs); printk("Process %s (pid: %d, stackpage=%0*lx)\n", current->comm, current->pid, field, (unsigned long) current); - show_stack((long *) regs->regs[29]); - show_trace((long *) regs->regs[29]); + show_stack(current, (long *) regs->regs[29]); + show_trace(current, (long *) regs->regs[29]); show_code((unsigned int *) regs->cp0_epc); printk("\n"); } diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 567e32f52ee..8d4a3849d16 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -166,69 +166,12 @@ config KCORE_ELF depends on PROC_FS default y -config BINFMT_SOM - tristate "Kernel support for SOM binaries" - depends on HPUX - help - SOM is a binary executable format inherited from HP/UX. Say Y here - to be able to load and execute SOM binaries directly. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu +source "drivers/base/Kconfig" + # source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 3b06e7dab0a..ba7e4cb86f5 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -808,42 +808,11 @@ config KCORE_ELF "-g" option to preserve debugging information. It is mainly used for examining kernel data structures on the live kernel. -config BINFMT_ELF - bool - default y - help - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. - config KERNEL_ELF bool default y -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" source "drivers/pci/Kconfig" @@ -1194,6 +1163,8 @@ config PIN_TLB depends on ADVANCED_OPTIONS && 8xx endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/pnp/Kconfig" diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index fbb47dea767..5aec043dad4 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -191,37 +191,7 @@ config KCORE_ELF "-g" option to preserve debugging information. It is mainly used for examining kernel data structures on the live kernel. -config BINFMT_ELF - bool "Kernel support for 64-bit ELF binaries" - help - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" source "drivers/pci/Kconfig" @@ -271,6 +241,8 @@ config CMDLINE endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 949425d44cb..c22a54fe544 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -129,7 +129,6 @@ struct task_struct *__switch_to(struct task_struct *prev, return last; } -static void show_tsk_stack(struct task_struct *p, unsigned long sp); char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); void show_regs(struct pt_regs * regs) @@ -172,7 +171,7 @@ void show_regs(struct pt_regs * regs) printk("NIP [%016lx] ", regs->nip); printk("%s\n", ppc_find_proc_name((unsigned *)regs->nip, name_buf, 256)); - show_tsk_stack(current, regs->gpr[1]); + show_stack(current, (unsigned long *)regs->gpr[1]); } void exit_thread(void) @@ -517,22 +516,26 @@ unsigned long get_wchan(struct task_struct *p) return 0; } -static void show_tsk_stack(struct task_struct *p, unsigned long sp) +void show_stack(struct task_struct *p, unsigned long *_sp) { unsigned long ip; unsigned long stack_page = (unsigned long)p->thread_info; int count = 0; char name_buf[256]; + unsigned long sp = (unsigned long)_sp; if (!p) return; + if (sp == 0) + sp = p->thread.ksp; printk("Call Trace:\n"); do { if (__get_user(sp, (unsigned long *)sp)) break; - if (sp < (stack_page + sizeof(struct thread_struct)) || - sp >= (stack_page + THREAD_SIZE)) + if (sp < stack_page + sizeof(struct thread_struct)) + break; + if (sp >= stack_page + THREAD_SIZE) break; if (__get_user(ip, (unsigned long *)(sp + 16))) break; @@ -544,10 +547,10 @@ static void show_tsk_stack(struct task_struct *p, unsigned long sp) void dump_stack(void) { - show_tsk_stack(current, (unsigned long)_get_SP()); + show_stack(current, (unsigned long *)_get_SP()); } void show_trace_task(struct task_struct *tsk) { - show_tsk_stack(tsk, tsk->thread.ksp); + show_stack(tsk, (unsigned long *)tsk->thread.ksp); } diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index f8e6159a496..bb9d8087572 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -192,78 +192,8 @@ endchoice config KCORE_ELF bool default y - ---help--- - If you enabled support for /proc file system then the file - /proc/kcore will contain the kernel core image. This can be used - in gdb: - - $ cd /usr/src/linux ; gdb vmlinux /proc/kcore - - You have two choices here: ELF and A.OUT. Selecting ELF will make - /proc/kcore appear in ELF core format as defined by the Executable - and Linking Format specification. Selecting A.OUT will choose the - old "a.out" format which may be necessary for some old versions - of binutils or on some architectures. - - This is especially useful if you have compiled the kernel with the - "-g" option to preserve debugging information. It is mainly used - for examining kernel data structures on the live kernel so if you - don't understand what this means or are not a kernel hacker, just - leave it at its default value ELF. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config PROCESS_DEBUG bool "Show crashed user process info" @@ -299,6 +229,8 @@ config PCMCIA bool default n +source "drivers/base/Kconfig" + menu "SCSI support" config SCSI diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 75e0f176116..024e44605cb 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -763,65 +763,12 @@ config KCORE_AOUT endchoice -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_FLAT - tristate "Kernel support for FLAT binaries" - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 93e0c3ddfef..2c001bf47c0 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -277,81 +277,7 @@ config KCORE_ELF don't understand what this means or are not a kernel hacker, just leave it at its default value ELF. -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config SUNOS_EMUL bool "SunOS binary emulation" @@ -393,6 +319,8 @@ config PRINTER endmenu +source "drivers/base/Kconfig" + source "drivers/video/Kconfig" source "drivers/mtd/Kconfig" @@ -576,232 +504,7 @@ config SCSI module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CDrom)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives can not be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage - and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives - as well. Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called osst. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SCSI - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers. - - This support is also available as a module called esp ( = code - which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -config SCSI_QLOGICPTI - tristate "PTI Qlogic,ISP Driver" - depends on SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - This support is also available as a module called qlogicpti ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -endmenu +source "drivers/scsi/Kconfig" endmenu diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 9378537b55b..0504d477b61 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -408,9 +408,9 @@ void __init sbus_time_init(void) mon = MSTK_REG_MONTH(mregs); year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; mregs->creg &= ~MSTK_CREG_READ; spin_unlock_irq(&mostek_lock); #ifdef CONFIG_SUN4 @@ -441,9 +441,9 @@ void __init sbus_time_init(void) intersil_start(iregs); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec); } #endif diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 69d4ce35b02..f82247c5470 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -415,59 +415,7 @@ config BINFMT_AOUT32 If you want to run SunOS binaries (see SunOS binary emulation below) or other a.out binaries, say Y. If unsure, say N. -config BINFMT_ELF - tristate "Kernel support for 64-bit ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config SUNOS_EMUL bool "SunOS binary emulation" @@ -573,6 +521,8 @@ config WATCHDOG_RIO endmenu +source "drivers/base/Kconfig" + source "drivers/video/Kconfig" source "drivers/serial/Kconfig" @@ -748,642 +698,7 @@ config SCSI module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CDrom)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives can not be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage - and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives - as well. Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called osst. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SCSI - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers. - - This support is also available as a module called esp ( = code - which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -config SCSI_QLOGICPTI - tristate "PTI Qlogic, ISP Driver" - depends on SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - This support is also available as a module called qlogicpti ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - - -choice - prompt "Adaptec AIC7xxx support" - optional - depends on SCSI && PCI - -source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" - -config SCSI_AIC7XXX_OLD - tristate "Old driver" - ---help--- - WARNING This driver is an older aic7xxx driver and is no longer - under active development. Adaptec, Inc. is writing a new driver to - take the place of this one, and it is recommended that whenever - possible, people should use the new Adaptec written driver instead - of this one. This driver will eventually be phased out entirely. - - This is support for the various aic7xxx based Adaptec SCSI - controllers. These include the 274x EISA cards; 284x VLB cards; - 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and - motherboard based SCSI controllers from Adaptec. It does not support - the AAA-13x RAID controllers from Adaptec, nor will it likely ever - support them. It does not support the 2920 cards from Adaptec that - use the Future Domain SCSI controller chip. For those cards, you - need the "Future Domain 16xx SCSI support" driver. - - In general, if the controller is based on an Adaptec SCSI controller - chip from the aic777x series or the aic78xx series, this driver - should work. The only exception is the 7810 which is specifically - not supported (that's the RAID controller chip on the AAA-13x - cards). - - Note that the AHA2920 SCSI host adapter is *not* supported by this - driver; choose "Future Domain 16xx SCSI support" instead if you have - one of those. - - Information on the configuration options for this controller can be - found by checking the help file for each of the available - configuration options. You should read - at a minimum before - contacting the maintainer with any questions. The SCSI-HOWTO, - available from , can also - be of great help. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called aic7xxx_old. - -config AIC7XXX_OLD_TCQ_ON_BY_DEFAULT - bool "Enable Tagged Command Queueing (TCQ) by default" - depends on SCSI_AIC7XXX_OLD - ---help--- - This option causes the aic7xxx driver to attempt to use Tagged - Command Queueing (TCQ) on all devices that claim to support it. - - TCQ is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. Because the device is - intelligent, it can optimize its operations (like head positioning) - based on its own request queue. Not all devices implement this - correctly. - - If you say Y here, you can still turn off TCQ on troublesome devices - with the use of the tag_info boot parameter. See the file - for more information on that and - other aic7xxx setup commands. If this option is turned off, you may - still enable TCQ on known good devices by use of the tag_info boot - parameter. - - If you are unsure about your devices then it is safest to say N - here. - - However, TCQ can increase performance on some hard drives by as much - as 50% or more, so it is recommended that if you say N here, you - should at least read the file so - you will know how to enable this option manually should your drives - prove to be safe in regards to TCQ. - - Conversely, certain drives are known to lock up or cause bus resets - when TCQ is enabled on them. If you have a Western Digital - Enterprise SCSI drive for instance, then don't even bother to enable - TCQ on it as the drive will become unreliable, and it will actually - reduce performance. - -config AIC7XXX_OLD_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC7XXX_OLD - default "8" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - Reasonable figures are in the range of 8 to 24 commands per device, - but depending on hardware could be increased or decreased from that - figure. If the number is too high for any particular device, the - driver will automatically compensate usually after only 10 minutes - of uptime. It will not hinder performance if some of your devices - eventually have their command depth reduced, but is a waste of - memory if all of your devices end up reducing this number down to a - more reasonable figure. - - NOTE: Certain very broken drives are known to lock up when given - more commands than they like to deal with. Quantum Fireball drives - are the most common in this category. For the Quantum Fireball - drives it is suggested to use no more than 8 commands per device. - - Default: 8 - -config AIC7XXX_OLD_PROC_STATS - bool "Collect statistics to report in /proc" - depends on SCSI_AIC7XXX_OLD - ---help--- - This option tells the driver to keep track of how many commands have - been sent to each particular device and report that information to - the user via the /proc/scsi/aic7xxx/n file, where n is the number of - the aic7xxx controller you want the information on. This adds a - small amount of overhead to each and every SCSI command the aic7xxx - driver handles, so if you aren't really interested in this - information, it is best to leave it disabled. This will only work if - you also say Y to "/proc file system support", below. - - If unsure, say N. - -endchoice - -config SCSI_SYM53C8XX_2 - tristate "SYM53C8XX Version 2 SCSI support" - depends on PCI && SCSI - ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers. - - If your system has problems using this new major version of the - SYM53C8XX driver, you may switch back to driver version 1. - - Please read for more - information. - -config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - int "DMA addressing mode" - depends on SCSI_SYM53C8XX_2 - default "1" - ---help--- - This option only applies to PCI-SCSI chip that are PCI DAC capable - (875A, 895A, 896, 1010-33, 1010-66, 1000). - - When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed. - When set to 1, 40 bit DMA addressing (with upper 24 bits of address - set to zero) is supported. The addressable range is here 1 TB. - When set to 2, full 64 bits of address for DMA are supported, but only - 16 segments of 4 GB can be addressed. The addressable range is so - limited to 64 GB. - - The safest value is 0 (32 bit DMA addressing) that is guessed to still - fit most of real machines. - - The preferred value 1 (40 bit DMA addressing) should make happy - properly engineered PCI DAC capable host bridges. You may configure - this option for Intel platforms with more than 4 GB of memory. - - The still experimental value 2 (64 bit DMA addressing with 16 x 4GB - segments limitation) can be used on systems that require PCI address - bits past bit 39 to be set for the addressing of memory using PCI - DAC cycles. - -config SCSI_SYM53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on SCSI_SYM53C8XX_2 - default "16" - help - This is the default value of the command queue depth the driver will - announce to the generic SCSI layer for devices that support tagged - command queueing. This value can be changed from the boot command line. - This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. - -config SCSI_SYM53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_SYM53C8XX_2 - default "64" - help - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The driver supports up to 256 queued commands per device. - This value is used as a compiled-in hard limit. - -config SCSI_SYM53C8XX_IOMAPPED - bool "use normal IO" - depends on SCSI_SYM53C8XX_2 - help - If you say Y here, the driver will preferently use normal IO rather than - memory mapped IO. - -config SCSI_NCR53C8XX - tristate "NCR53C8XX SCSI support" - depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI - ---help--- - This is the BSD ncr driver adapted to Linux for the NCR53C8XX family - of PCI-SCSI controllers. This driver supports parity checking, - tagged command queuing and fast synchronous data transfers up to 80 - MB/s with wide FAST-40 LVD devices and controllers. - - Recent versions of the 53C8XX chips are better supported by the - option "SYM53C8XX SCSI support", below. - - Note: there is yet another driver for the 53c8xx family of - controllers ("NCR53c7,8xx SCSI support" above). If you want to use - them both, you need to say M to both and build them as modules, but - only one may be active at a time. If you have a 53c8xx board, you - probably do not want to use the "NCR53c7,8xx SCSI support". - - Please read for more - information. - -config SCSI_SYM53C8XX - tristate "SYM53C8XX SCSI support" - depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI - ---help--- - This driver supports all the features of recent 53C8XX chips (used - in PCI SCSI controllers), notably the hardware phase mismatch - feature of the SYM53C896. - - Older versions of the 53C8XX chips are not supported by this - driver. If your system uses either a 810 rev. < 16, a 815, or a 825 - rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX - driver ("NCR53C8XX SCSI support" above) or configure both the - NCR53C8XX and this SYM53C8XX drivers either as module or linked to - the kernel image. - - When both drivers are linked into the kernel, the SYM53C8XX driver - is called first at initialization and you can use the 'excl=ioaddr' - driver boot option to exclude attachment of adapters by the - SYM53C8XX driver. For example, entering - 'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents - adapters at io address 0xb400 and 0xc000 from being attached by the - SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them. - The 'excl' option is also supported by the NCR53C8XX driver. - - Please read for more - information. - -config SCSI_NCR53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "8" - ---help--- - "Tagged command queuing" is a feature of SCSI-2 which improves - performance: the host adapter can send several SCSI commands to a - device's queue even if previous commands haven't finished yet. - Because the device is intelligent, it can optimize its operations - (like head positioning) based on its own request queue. Some SCSI - devices don't implement this properly; if you want to disable this - feature, enter 0 or 1 here (it doesn't matter which). - - The default value is 8 and should be supported by most hard disks. - This value can be overridden from the boot command line using the - 'tags' option as follows (example): - 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to - 4, set queue depth to 16 for target 2 and target 3 on controller 0 - and set queue depth to 10 for target 0 / lun 2 on controller 1. - - The normal answer therefore is to go with the default 8 and to use - a boot command line option for devices that need to use a different - command queue depth. - - There is no safe option other than using good SCSI devices. - -config SCSI_NCR53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "32" - ---help--- - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. - Modern hard disks are able to support 64 tags and even more, but - do not seem to be faster when more than 32 tags are being used. - - So, the normal answer here is to go with the default value 32 unless - you are using very large hard disks with large cache (>= 1 MB) that - are able to take advantage of more than 32 tagged commands. - - There is no safe option and the default answer is recommended. - -config SCSI_NCR53C8XX_SYNC - int "synchronous transfers frequency in MHz" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "10" - ---help--- - The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers - are respectively the maximum data transfer rates in mega-transfers - per second for each class. For example, a FAST-20 Wide 16 device is - able to transfer data at 20 million 16 bit packets per second for a - total rate of 40 MB/s. - - You may specify 0 if you want to only use asynchronous data - transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. - Note that 80 should normally be ok since the driver decreases the - value automatically according to the controller's capabilities. - - Your answer to this question is ignored for controllers with NVRAM, - since the driver will get this information from the user set-up. It - also can be overridden using a boot setup option, as follows - (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate - for FAST-20 synchronous data transfer (20 mega-transfers per - second). - - The normal answer therefore is not to go with the default but to - select the maximum value 80 allowing the driver to use the maximum - value supported by each controller. If this causes problems with - your SCSI devices, you should come back and decrease the value. - - There is no safe option other than using good cabling, right - terminations and SCSI conformant devices. - -config SCSI_NCR53C8XX_PROFILE - bool "enable profiling" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - help - This option allows you to enable profiling information gathering. - These statistics are not very accurate due to the low frequency - of the kernel clock (100 Hz on i386) and have performance impact - on systems that use very fast devices. - - The normal answer therefore is N. - -config SCSI_NCR53C8XX_PQS_PDS - bool "include support for the NCR PQS/PDS SCSI card" - depends on (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && SCSI_SYM53C8XX - help - Say Y here if you have a special SCSI adapter produced by NCR - corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need - this if you do not have one of these adapters. However, since this - device is detected as a specific PCI device, this option is quite - safe. - - The common answer here is N, but answering Y is safe. - -config SCSI_NCR53C8XX_NO_DISCONNECT - bool "not allow targets to disconnect" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 - help - This option is only provided for safety if you suspect some SCSI - device of yours to not support properly the target-disconnect - feature. In that case, you would say Y here. In general however, to - not allow targets to disconnect is not reasonable if there is more - than 1 device on a SCSI bus. The normal answer therefore is N. - -config SCSI_NCR53C8XX_SYMBIOS_COMPAT - bool "assume boards are SYMBIOS compatible (EXPERIMENTAL)" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && EXPERIMENTAL - ---help--- - This option allows you to enable some features depending on GPIO - wiring. These General Purpose Input/Output pins can be used for - vendor specific features or implementation of the standard SYMBIOS - features. Genuine SYMBIOS controllers use GPIO0 in output for - controller LED and GPIO3 bit as a flag indicating - singled-ended/differential interface. The Tekram DC-390U/F boards - uses a different GPIO wiring. - - Your answer to this question is ignored if all your controllers have - NVRAM, since the driver is able to detect the board type from the - NVRAM format. - - If all the controllers in your system are genuine SYMBIOS boards or - use BIOS and drivers from SYMBIOS, you would want to say Y here, - otherwise N. N is the safe answer. - -config SCSI_QLOGIC_ISP - tristate "Qlogic ISP SCSI support" - depends on PCI && SCSI - ---help--- - This driver works for all QLogic PCI SCSI host adapters (IQ-PCI, - IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter - card is supported by the "AM53/79C974 PCI SCSI" driver.) - - If you say Y here, make sure to choose "BIOS" at the question "PCI - access mode". - - Please read the file . You - should also read the SCSI-HOWTO, available from - . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called qlogicisp. If you want to compile it as - a module, say M here and read . - -config SCSI_QLOGIC_FC - tristate "Qlogic ISP FC SCSI support" - depends on PCI && SCSI - help - This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called qlogicfc. If you want to compile it as - a module, say M here and read . - -config SCSI_QLOGIC_FC_FIRMWARE - bool - depends on SCSI_QLOGIC_FC - default y - -endmenu +source "drivers/scsi/Kconfig" endmenu diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 91854621d0a..f4ffbef0047 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -90,6 +90,11 @@ CONFIG_WATCHDOG_CP1XXX=m CONFIG_WATCHDOG_RIO=m # +# Generic Driver Options +# +CONFIG_FW_LOADER=m + +# # Graphics support # CONFIG_FB=y @@ -266,39 +271,72 @@ CONFIG_BLK_DEV_IDE_MODES=y CONFIG_SCSI=y # -# SCSI support type (disk, tape, CDrom) +# SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=m CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=m # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers # -CONFIG_SCSI_SUNESP=y -CONFIG_SCSI_QLOGICPTI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +CONFIG_SCSI_DMX3191D=m +# CONFIG_SCSI_EATA is not set +CONFIG_SCSI_EATA_PIO=m +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_INITIO is not set +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLOGICPTI=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SUNESP=y # # Fibre Channel support @@ -966,17 +1004,19 @@ CONFIG_RAMFS=y # # Miscellaneous filesystems # -# CONFIG_ADFS_FS is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=m -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=m CONFIG_BEFS_FS=m # CONFIG_BEFS_DEBUG is not set CONFIG_BFS_FS=m CONFIG_EFS_FS=m -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m CONFIG_HPFS_FS=m -# CONFIG_QNX4FS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y @@ -997,12 +1037,22 @@ CONFIG_EXPORTFS=m CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m -# CONFIG_SMB_FS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m -# CONFIG_NCP_FS is not set +CONFIG_NCP_FS=m +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set CONFIG_CODA_FS=m # CONFIG_INTERMEZZO_FS is not set -# CONFIG_AFS_FS is not set +CONFIG_AFS_FS=m +CONFIG_RXRPC=m # # Partition Types @@ -1010,6 +1060,7 @@ CONFIG_CODA_FS=m # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y CONFIG_SUN_PARTITION=y +CONFIG_SMB_NLS=y CONFIG_NLS=y # @@ -1210,6 +1261,7 @@ CONFIG_USB_HPUSBSCSI=m # # USB Network adaptors # +CONFIG_USB_AX8817X=m CONFIG_USB_CATC=m CONFIG_USB_KAWETH=m CONFIG_USB_PEGASUS=m diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 061e6f75925..2c3727f3276 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -703,9 +703,9 @@ static void __init set_system_time(void) } xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; if (mregs) { tmp = mostek_read(mregs + MOSTEK_CREG); @@ -743,9 +743,9 @@ void __init clock_probe(void) (unsigned int) (long) &unix_tod); prom_feval(obp_gettod); xtime.tv_sec = unix_tod; - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; return; } diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 6c81b99be27..44dd2f0ff75 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -62,14 +62,7 @@ config MODE_SKAS config NET bool "Networking support" -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" +source "fs/Kconfig.binfmt" config HOSTFS tristate "Host filesystem" @@ -178,6 +171,8 @@ endmenu source "init/Kconfig" +source "drivers/base/Kconfig" + source "arch/um/Kconfig_char" source "arch/um/Kconfig_block" diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig index 90736a33dbd..6b16845261f 100644 --- a/arch/v850/Kconfig +++ b/arch/v850/Kconfig @@ -243,21 +243,14 @@ config KCORE_AOUT config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. - -config BINFMT_ZFLAT - bool " Enable ZFLAT support" - depends on BINFMT_FLAT - help - Support FLAT format compressed binaries +source "fs/Kconfig.binfmt" endmenu ############################################################################# +source "drivers/base/Kconfig" + source drivers/mtd/Kconfig source drivers/parport/Kconfig diff --git a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S index ba801a88250..7391ab36f1a 100644 --- a/arch/v850/vmlinux.lds.S +++ b/arch/v850/vmlinux.lds.S @@ -95,7 +95,10 @@ *(.initcall6.init) \ *(.initcall7.init) \ . = ALIGN (4) ; \ - ___initcall_end = . ; + ___initcall_end = . ; \ + ___con_initcall_start = .; \ + *(.con_initcall.init) \ + ___con_initcall_end = .; /* Contents of `init' section for a kernel that's loaded into RAM. */ #define RAMK_INIT_CONTENTS \ @@ -234,3 +237,13 @@ _jiffies = _jiffies_64 ; # include "rte_ma1_cb.ld" # endif #endif + +#ifdef CONFIG_RTE_CB_NB85E +# ifdef CONFIG_ROM_KERNEL +# include "rte_nb85e_cb-rom.ld" +# elif defined(CONFIG_RTE_CB_MULTI) +# include "rte_nb85e_cb-multi.ld" +# else +# include "rte_nb85e_cb.ld" +# endif +#endif diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index c7a2194eff0..f264d889d13 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -375,31 +375,7 @@ config KCORE_ELF depends on PROC_FS default y -config BINFMT_ELF - bool - default y - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. Once you have registered such a binary class with the kernel, - you can start one of those programs simply by typing in its name at a shell - prompt; Linux will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config IA32_EMULATION bool "IA32 Emulation" @@ -421,6 +397,8 @@ config UID16 endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/parport/Kconfig" diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 6a53ca726f0..08d5301c5d7 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -49,12 +49,12 @@ config ACPI_HT_ONLY Full ACPI support (CONFIG_ACPI) is preferred. Use this option only if you wish to limit ACPI's role to processor enumeration. - There is no command-line option to disable this, but the kernel - will fall back to the MPS table if the MADT is not present. + In this configuration, ACPI defaults to off. It must be enabled + on the command-line with the "acpismp=force" option. config ACPI_BOOT bool - depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY || X86 && ACPI + depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY default y config ACPI_SLEEP @@ -135,6 +135,31 @@ config ACPI_NUMA bool "NUMA support" if NUMA && (IA64 && !IA64_HP_SIM || X86 && ACPI && !ACPI_HT_ONLY && !X86_64) default y if IA64 && IA64_SGI_SN +config ACPI_ASUS + tristate "ASUS/Medion Laptop Extras" + depends on X86 && ACPI && !ACPI_HT_ONLY + ---help--- + This driver provides support for extra features of ACPI-compatible + ASUS laptops. As some of Medion laptops are made by ASUS, it may also + support some Medion laptops (such as 9675 for example). It makes all + the extra buttons generate standard ACPI events that go through + /proc/acpi/events, and (on some models) adds support for changing the + display brightness and output, switching the LCD backlight on and off, + and most importantly, allows you to blink those fancy LEDs intended + for reporting mail and wireless status. + + All settings are changed via /proc/acpi/asus directory entries. Owner + and group for these entries can be set with asus_uid and asus_gid + parameters. + + More information and a userspace daemon for handling the extra buttons + at . + + If you have an ACPI-compatible ASUS laptop, say Y or M here. This + driver is still under development, so if your laptop is unsupported or + something works not quite as expected, please use the mailing list + available on the above page (acpi4asus-user@lists.sourceforge.net) + config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on X86 && ACPI && !ACPI_HT_ONLY diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 5db5f58e152..f5f7c06e2a5 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -44,5 +44,6 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o +obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_BUS) += scan.o diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c new file mode 100644 index 00000000000..bb9c1a32927 --- /dev/null +++ b/drivers/acpi/asus_acpi.c @@ -0,0 +1,951 @@ +/* + * asus_acpi.c - Asus Laptop ACPI Extras + * + * + * Copyright (C) 2002, 2003 Julien Lerouge, Karol Kozimor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The development page for this driver is located at + * http://sourceforge.net/projects/acpi4asus/ + * + * Credits: + * Johann Wiesner - Small compile fixes + * John Belmonte - ACPI code for Toshiba laptop was a good starting point. + * + * TODO + * add Fn key status + * Add mode selection on module loading (parameter) -> still necessary ? + * Complete display switching -- may require dirty hacks? + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ASUS_ACPI_VERSION "0.24a" + +#define PROC_ASUS "asus" //the directory +#define PROC_MLED "mled" +#define PROC_WLED "wled" +#define PROC_INFOS "info" +#define PROC_LCD "lcd" +#define PROC_BRN "brn" +#define PROC_DISP "disp" + +#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver" +#define ACPI_HOTK_CLASS "hotkey" +#define ACPI_HOTK_DEVICE_NAME "Hotkey" +#define ACPI_HOTK_HID "ATK0100" + +/* + * Some events we use, same for all Asus + */ +#define BR_UP 0x10 +#define BR_DOWN 0x20 + +/* + * Flags for hotk status + */ +#define MLED_ON 0x01 //is MLED ON ? +#define WLED_ON 0x02 + +MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); +MODULE_DESCRIPTION(ACPI_HOTK_NAME); +MODULE_LICENSE("GPL"); + + +static uid_t asus_uid = 0; +static gid_t asus_gid = 0; +MODULE_PARM(asus_uid, "i"); +MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n"); +MODULE_PARM(asus_gid, "i"); +MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n"); + + +/* For each model, all features implemented */ +struct model_data { + char *name; //name of the laptop + char *mt_mled; //method to handle mled + char *mled_status; //node to handle mled reading + char *mt_wled; //method to handle wled + char *wled_status; //node to handle wled reading + char *mt_lcd_switch; //method to turn LCD ON/OFF + char *lcd_status; //node to read LCD panel state + char *brightness_up; //method to set brightness up + char *brightness_down; //guess what ? + char *brightness_set; //method to set absolute brightness + char *brightness_get; //method to get absolute brightness + char *brightness_status;//node to get brightness + char *display_set; //method to set video output + char *display_get; //method to get video output +}; + +/* + * This is the main structure, we can use it to store anything interesting + * about the hotk device + */ +struct asus_hotk { + struct acpi_device *device; //the device we are in + acpi_handle handle; //the handle of the hotk device + char status; //status of the hotk, for LEDs, ... + struct model_data *methods; //methods available on the laptop + u8 brightness; //brighness level + enum { + L2X = 0, //L200D -> TODO check Q11 (Fn+F8) + // Calling this method simply hang the + // computer, ISMI method hangs the laptop. + L3X, //L3C + L3D, //L3400D + M2X, //M2400E + S1X, //S1300A -> TODO special keys do not work ? + D1X, //D1 + L1X, //L1400B + A1X, //A1340D, A1300F + J1X, //S200 (J1) + //TODO A1370D does not seems to have a ATK device + // L8400 model doesn't have ATK + END_MODEL, + } model; //Models currently supported + u16 event_count[128]; //count for each event TODO make this better +}; + +/* Here we go */ +#define L3X_PREFIX "\\_SB.PCI0.PX40.ECD0." +#define S1X_PREFIX "\\_SB.PCI0.PX40." +#define L1X_PREFIX S1X_PREFIX +#define A1X_PREFIX "\\_SB.PCI0.ISA.EC0." +#define J1X_PREFIX A1X_PREFIX + +static struct model_data model_conf[END_MODEL] = { + /* + * name| mled |mled read| wled |wled read| lcd sw |lcd read | + * br up|br down | br set | br read | br status|set disp | get disp + * + * br set and read shall be in hotk device ! + * same for set disp + * + * TODO I have seen a SWBX and AIBX method on some models, like L1400B, + * it seems to be a kind of switch, but what for ? + * + */ + {"L2X", "MLED", "\\SGP6", "WLED", "\\RCP3", "\\Q10", "\\SGP0", + "\\Q0E", "\\Q0F", NULL, NULL, NULL, "SDSP", "\\INFB"}, + + {"L3X", "MLED", NULL, "WLED", NULL, L3X_PREFIX "_Q10", "\\GL32", + L3X_PREFIX "_Q0F", L3X_PREFIX "_Q0E", "SPLV", "GPLV", "\\BLVL", "SDSP", + "\\_SB.PCI0.PCI1.VGAC.NMAP"}, + + {"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG", + "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"}, + + {"M2X", "MLED", NULL, "WLED", NULL, "\\Q10", "\\GP06", + "\\Q0E","\\Q0F", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"}, + + {"S1X", "MLED", "\\EMLE", "WLED", NULL, S1X_PREFIX "Q10", "\\PNOF", + S1X_PREFIX "Q0F", S1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, + + {"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11", + "\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"}, + + {"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF", + L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, + + {"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI", + A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL}, + + {"J1X", "MLED", "\\MAIL", NULL, NULL, J1X_PREFIX "_Q10", "\\BKLI", + J1X_PREFIX "_Q0B", J1X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL} +}; + +/* procdir we use */ +static struct proc_dir_entry *asus_proc_dir = NULL; + +/* + * This header is made available to allow proper configuration given model, + * revision number , ... this info cannot go in struct asus_hotk because it is + * available before the hotk + */ +static struct acpi_table_header *asus_info = NULL; + +/* + * The hotkey driver declaration + */ +static int asus_hotk_add(struct acpi_device *device); +static int asus_hotk_remove(struct acpi_device *device, int type); +static struct acpi_driver asus_hotk_driver = { + .name = ACPI_HOTK_NAME, + .class = ACPI_HOTK_CLASS, + .ids = ACPI_HOTK_HID, + .ops = { + .add = asus_hotk_add, + .remove = asus_hotk_remove, + }, +}; + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; //list of input parameters (an int here) + union acpi_object in_obj; //the only param we use + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *) method, ¶ms, output); + return (status == AE_OK); +} + + +static int read_acpi_int(acpi_handle handle, const char *method, int *val) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char*) method, NULL, &output); + *val = out_obj.integer.value; + return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); +} + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static int +proc_read_info(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + char buf[16]; //enough for all info + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + + len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); + len += + sprintf(page + len, "Model reference : %s\n", + hotk->methods->name); + if (asus_info) { + snprintf(buf, 5, "%s", asus_info->signature); + len += sprintf(page + len, "ACPI signature : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->length); + len += sprintf(page + len, "Table length : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->revision); + len += sprintf(page + len, "ACPI minor version : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->checksum); + len += sprintf(page + len, "Checksum : %s\n", buf); + snprintf(buf, 7, "%s", asus_info->oem_id); + len += sprintf(page + len, "OEM identification : %s\n", buf); + snprintf(buf, 9, "%s", asus_info->oem_table_id); + len += sprintf(page + len, "OEM table id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->oem_revision); + len += sprintf(page + len, "OEM rev number : 0x%s\n", buf); + snprintf(buf, 5, "%s", asus_info->asl_compiler_id); + len += sprintf(page + len, "ASL comp vendor ID : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); + len += sprintf(page + len, "ASL comp rev number: 0x%s\n", buf); + } + + return len; +} + + +/* + * proc file handlers + */ +static int +proc_read_mled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + int led_status = 0; + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + if (hotk->methods->mled_status) { + if (read_acpi_int(NULL, hotk->methods->mled_status, + &led_status)) + len = sprintf(page, "%d\n", led_status); + else + printk(KERN_NOTICE "Asus ACPI: Error reading MLED " + "status\n"); + } else { + len = sprintf(page, "%d\n", (hotk->status & MLED_ON) ? 1 : 0); + } + + return len; +} + + +static int +proc_write_mled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int led_out = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + led_out = ~value & 1; + + hotk->status = + (value) ? (hotk->status | MLED_ON) : (hotk->status & ~MLED_ON); + + /* We don't have to check mt_mled exists if we are here :) */ + if (!write_acpi_int(hotk->handle, hotk->methods->mt_mled, led_out, + NULL)) + printk(KERN_NOTICE "Asus ACPI: MLED write failed\n"); + + + + return count; +} + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static int +proc_read_wled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + int led_status; + + if (hotk->methods->wled_status) { + if (read_acpi_int(NULL, hotk->methods->mled_status, + &led_status)) + len = sprintf(page, "%d\n", led_status); + else + printk(KERN_NOTICE "Asus ACPI: Error reading WLED " + "status\n"); + } else { + len = sprintf(page, "%d\n", (hotk->status & WLED_ON) ? 1 : 0); + } + + return len; +} + +static int +proc_write_wled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int led_out = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + led_out = value & 1; + + hotk->status = + (value) ? (hotk->status | WLED_ON) : (hotk->status & ~WLED_ON); + + /* We don't have to check if mt_wled exists if we are here :) */ + if (!write_acpi_int(hotk->handle, hotk->methods->mt_wled, led_out, + NULL)) + printk(KERN_NOTICE "Asus ACPI: WLED write failed\n"); + + + return count; +} + + +static int get_lcd_state(struct asus_hotk *hotk) +{ + int lcd = 0; + + /* We don't have to check anything, if we are here */ + if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) + printk(KERN_NOTICE "Asus ACPI: Error reading LCD status\n"); + + if (hotk->model == L2X) + lcd = ~lcd; + + return (lcd & 1); +} + + +static int +proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + return sprintf(page, "%d\n", get_lcd_state((struct asus_hotk *) data)); +} + + +static int +proc_write_lcd(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int lcd = 0; + acpi_status status = 0; + int lcd_status = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + lcd = value & 1; + + lcd_status = get_lcd_state(hotk); + + if (lcd_status != lcd) { + /* switch */ + status = + acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Asus ACPI: Error switching LCD\n"); + } + + return count; +} + + +/* + * Change the brightness level + */ +static void set_brightness(int value, struct asus_hotk *hotk) +{ + acpi_status status = 0; + + /* ATKD laptop */ + if(hotk->methods->brightness_set) { + if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, + value, NULL)) + printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n"); + return; + } + + /* HOTK laptop if we are here, act as appropriate */ + value -= hotk->brightness; + while (value != 0) { + status = acpi_evaluate_object(NULL, (value > 0) ? + hotk->methods->brightness_up : + hotk->methods->brightness_down, + NULL, NULL); + (value > 0) ? value-- : value++; + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n"); + } + return; +} + +static int read_brightness(struct asus_hotk *hotk) +{ + int value; + + if(hotk->methods->brightness_get) { /* ATKD laptop */ + if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, + &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n"); + } else if (hotk->methods->brightness_status) { /* For D1 for example */ + if (!read_acpi_int(NULL, hotk->methods->brightness_status, + &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n"); + } else /* HOTK laptop */ + value = hotk->brightness; + return value; +} + +static int +proc_read_brn(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return sprintf(page, "%d\n", read_brightness(hotk)); +} + +static int +proc_write_brn(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%d", &value) == 1) { + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + set_brightness(value, hotk); + } else { + printk(KERN_NOTICE "Asus ACPI: Error reading user input\n"); + } + + return count; +} + +static void set_display(int value, struct asus_hotk *hotk) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(hotk->handle, hotk->methods->display_set, + value, NULL)) + printk(KERN_NOTICE "Asus ACPI: Error setting display\n"); + return; +} + +/* + * Now, *this* one could be more user-friendly, but so far, no-one has + * complained. The significance of bits is the same as in proc_write_disp() + */ + +static int +proc_read_disp(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int value = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading display status\n"); + return sprintf(page, "%d\n", value); +} + +/* + * Preliminary support for display switching. As of now: 0x01 should activate + * the LCD output, 0x02 should do for CRT, and 0x04 for TV-Out. Any combination + * (bitwise) of these will suffice. I never actually tested 3 displays hooked up + * simultaneously, so be warned. + */ + +static int +proc_write_disp(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%d", &value) == 1) + set_display(value, hotk); + else { + printk(KERN_NOTICE "Asus ACPI: Error reading user input\n"); + } + + return count; +} + +static int asus_hotk_add_fs(struct acpi_device *device) +{ + struct proc_dir_entry *proc; + struct asus_hotk *hotk = acpi_driver_data(device); + mode_t mode; + + /* + * If parameter uid or gid is not changed, keep the default setting for + * our proc entries (-rw-rw-rw-) else, it means we care about security, + * and then set to -rw-rw---- + */ + + if ((asus_uid == 0) && (asus_gid == 0)){ + mode = S_IFREG | S_IRUGO | S_IWUGO; + }else{ + mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; + } + + acpi_device_dir(device) = asus_proc_dir; + if (!acpi_device_dir(device)) + return(-ENODEV); + + proc = create_proc_entry(PROC_INFOS, mode, acpi_device_dir(device)); + if (proc) { + proc->read_proc = proc_read_info; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_INFOS + " fs entry\n"); + } + + if (hotk->methods->mt_wled) { + proc = create_proc_entry(PROC_WLED, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_wled; + proc->read_proc = proc_read_wled; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_WLED + " fs entry\n"); + } + } + + if (hotk->methods->mt_mled) { + proc = create_proc_entry(PROC_MLED, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_mled; + proc->read_proc = proc_read_mled; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_MLED + " fs entry\n"); + } + } + + /* + * We need both read node and write method as LCD switch is also accessible + * from keyboard + */ + if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { + proc = create_proc_entry(PROC_LCD, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_lcd; + proc->read_proc = proc_read_lcd; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_LCD + " fs entry\n"); + } + } + + if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || + (hotk->methods->brightness_get && hotk->methods->brightness_get)) { + proc = create_proc_entry(PROC_BRN, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_brn; + proc->read_proc = proc_read_brn; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_BRN + " fs entry\n"); + } + } + + if (hotk->methods->display_set) { + proc = create_proc_entry(PROC_DISP, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_disp; + proc->read_proc = proc_read_disp; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_DISP + " fs entry\n"); + } + } + + return (AE_OK); +} + + +static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +{ + /* TODO Find a better way to handle events count. Here, in data, we receive + * the hotk, so we can make anything !! + */ + struct asus_hotk *hotk = (struct asus_hotk *) data; + + if (!hotk) + return; + + if ((event & ~((u32) BR_UP)) < 16) { + hotk->brightness = (event & ~((u32) BR_UP)); + } else if ((event & ~((u32) BR_DOWN)) < 16 ) { + hotk->brightness = (event & ~((u32) BR_DOWN)); + } + + acpi_bus_generate_event(hotk->device, event, + hotk->event_count[event % 128]++); + + return; +} + +/* + * This function is used to initialize the hotk with right values. In this + * method, we can make all the detection we want, and modify the hotk struct + */ +static int asus_hotk_get_info(struct asus_hotk *hotk) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *model = NULL; + + /* + * We have to write 0 on init this far for all ASUS models + */ + if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + printk(KERN_NOTICE " Hotkey initialization failed\n"); + return -ENODEV; + } + + /* + * Here, we also use asus_info to make decision. For example, on INIT + * method, S1X and L1X models both reports to be L84F, but they don't + * have the same methods (L1X has WLED, S1X don't) + */ + model = (union acpi_object *) buffer.pointer; + if (model->type == ACPI_TYPE_STRING) { + printk(KERN_NOTICE " %s model detected, ", model->string.pointer); + } + + hotk->model = END_MODEL; + if (strncmp(model->string.pointer, "L3D", 3) == 0) + hotk->model = L3D; + /* + * L2B has same settings that L3X, except for GL32, but as + * there is no node to get the LCD status, and as GL32 is never + * used anywhere else, I assume it's safe, even if lcd get is + * broken for this model (TODO fix it ?) + */ + else if (strncmp(model->string.pointer, "L3", 2) == 0 || + strncmp(model->string.pointer, "L2B", 3) == 0) + hotk->model = L3X; + else if (strncmp(model->string.pointer, "M2", 2) == 0) + hotk->model = M2X; + else if (strncmp(model->string.pointer, "L2", 2) == 0) + hotk->model = L2X; + else if (strncmp(model->string.pointer, "L8", 2) == 0) + /* S1300A reports L84F, but L1400B too */ + if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) + hotk->model = L1X; + else + hotk->model = S1X; + else if (strncmp(model->string.pointer, "D1", 2) == 0) + hotk->model = D1X; + else if (strncmp(model->string.pointer, "A1", 2) == 0) + hotk->model = A1X; + else if (strncmp(model->string.pointer, "J1", 2) == 0) + hotk->model = J1X; + + + if (hotk->model == END_MODEL) { + /* By default use the same values, as I don't know others */ + printk("unsupported, trying default values, contact the " + "developers\n"); + hotk->model = L2X; + } else { + printk("supported\n"); + } + + hotk->methods = &model_conf[hotk->model]; + + acpi_os_free(model); + + return AE_OK; +} + + + +static int asus_hotk_check(struct asus_hotk *hotk) +{ + int result = 0; + + if (!hotk) + return(-EINVAL); + + result = acpi_bus_get_status(hotk->device); + if (result) + return(result); + + if (hotk->device->status.present) { + result = asus_hotk_get_info(hotk); + } else { + printk(KERN_NOTICE " Hotkey device not present, aborting\n"); + return(-EINVAL); + } + + return(result); +} + + + +static int asus_hotk_add(struct acpi_device *device) +{ + struct asus_hotk *hotk = NULL; + acpi_status status = AE_OK; + int result; + + if (!device) + return(-EINVAL); + + hotk = + (struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); + if (!hotk) + return(-ENOMEM); + memset(hotk, 0, sizeof(struct asus_hotk)); + + hotk->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_HOTK_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_HOTK_CLASS); + acpi_driver_data(device) = hotk; + hotk->device = device; + + + result = asus_hotk_check(hotk); + if (result) + goto end; + + result = asus_hotk_add_fs(device); + if (result) + goto end; + + /* + * We install the handler, it will receive the hotk in parameter, so, we + * could add other data to the hotk struct + */ + status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify, hotk); + if (ACPI_FAILURE(status)) { + printk(KERN_NOTICE + " Error installing notify handler\n"); + } else { + printk(KERN_DEBUG + " Notify Handler installed successfully\n"); + } + + /* For HOTK laptops: init the hotk->brightness value */ + if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) && + (hotk->methods->brightness_up && hotk->methods->brightness_down)) { + status = acpi_evaluate_object(NULL, hotk->methods->brightness_down, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE " Error changing brightness\n"); + status = acpi_evaluate_object(NULL, hotk->methods->brightness_up, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE " Error changing brightness\n"); + } + + end: + if (result) { + kfree(hotk); + } + + return(result); +} + + + + +static int asus_hotk_remove(struct acpi_device *device, int type) +{ + acpi_status status = 0; + struct asus_hotk *hotk = NULL; + + if (!device || !acpi_driver_data(device)) + return(-EINVAL); + + hotk = (struct asus_hotk *) acpi_driver_data(device); + + status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Error removing notify handler\n"); + + kfree(hotk); + + return(0); +} + + + + +static int __init asus_acpi_init(void) +{ + int result = 0; + acpi_status status = 0; + struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; + + printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", + ASUS_ACPI_VERSION); + /* + * Here is the code to know the model we are running on. We need to + * know this before calling the acpi_bus_register_driver function, in + * case the HID for the laptop we are running on is different from + * ACPI_HOTK_HID, which I have never seen yet :) + * + * This information is then available in the global var asus_info + */ + status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt); + if (ACPI_FAILURE(status)) { + printk(KERN_NOTICE " Couldn't get the DSDT table header\n"); + } else { + asus_info = (struct acpi_table_header *) dsdt.pointer; + } + + asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); + if (!asus_proc_dir) + return(-ENODEV); + asus_proc_dir->owner = THIS_MODULE; + + result = acpi_bus_register_driver(&asus_hotk_driver); + if (result < 0) { + printk(KERN_NOTICE " Error registering " ACPI_HOTK_NAME " \n"); + remove_proc_entry(PROC_ASUS, acpi_root_dir); + return(-ENODEV); + } + + return(0); +} + + + +static void __exit asus_acpi_exit(void) +{ + acpi_bus_unregister_driver(&asus_hotk_driver); + remove_proc_entry(PROC_ASUS, acpi_root_dir); + + acpi_os_free(asus_info); + + return; +} + +module_init(asus_acpi_init); +module_exit(asus_acpi_exit); diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index 55495cc5051..0c47ecea305 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -306,7 +306,6 @@ acpi_ds_method_data_set_value ( { acpi_status status; struct acpi_namespace_node *node; - union acpi_operand_object *new_desc = object; ACPI_FUNCTION_TRACE ("ds_method_data_set_value"); @@ -325,28 +324,16 @@ acpi_ds_method_data_set_value ( } /* - * If the object has just been created and is not attached to anything, - * (the reference count is 1), then we can just store it directly into - * the arg/local. Otherwise, we must copy it. + * Increment ref count so object can't be deleted while installed. + * NOTE: We do not copy the object in order to preserve the call by + * reference semantics of ACPI Control Method invocation. + * (See ACPI specification 2.0_c) */ - if (object->common.reference_count > 1) { - status = acpi_ut_copy_iobject_to_iobject (object, &new_desc, walk_state); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object Copied %p, new %p\n", - object, new_desc)); - } - else { - /* Increment ref count so object can't be deleted while installed */ - - acpi_ut_add_reference (new_desc); - } + acpi_ut_add_reference (object); /* Install the object */ - node->object = new_desc; + node->object = object; return_ACPI_STATUS (status); } diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index 4cb089d54c6..0108b47fadf 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -186,11 +186,13 @@ acpi_ev_gpe_detect ( } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, - "GPE block at %8.8X%8.8X - Values: Enable %02X Status %02X\n", + "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", + ACPI_HIDWORD (gpe_register_info->status_address.address), + ACPI_LODWORD (gpe_register_info->status_address.address), + gpe_register_info->status, ACPI_HIDWORD (gpe_register_info->enable_address.address), ACPI_LODWORD (gpe_register_info->enable_address.address), - gpe_register_info->enable, - gpe_register_info->status)); + gpe_register_info->enable)); /* First check if there is anything active at all in this register */ diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index c24a11d9aae..0849a14560c 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -76,9 +76,14 @@ acpi_ev_valid_gpe_event ( /* No need for spin lock since we are not changing any list elements */ + /* Walk the GPE interrupt levels */ + gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_block) { gpe_block = gpe_xrupt_block->gpe_block_list_head; + + /* Walk the GPE blocks on this interrupt level */ + while (gpe_block) { if ((&gpe_block->event_info[0] <= gpe_event_info) && (&gpe_block->event_info[((acpi_size) gpe_block->register_count) * 8] > gpe_event_info)) { @@ -155,7 +160,7 @@ unlock_and_exit: * * PARAMETERS: Callback from walk_namespace * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * control method under the _GPE portion of the namespace. @@ -164,10 +169,10 @@ unlock_and_exit: * * The name of each GPE control method is of the form: * "_Lnn" or "_Enn" - * Where: - * L - means that the GPE is level triggered - * E - means that the GPE is edge triggered - * nn - is the GPE number [in HEX] + * Where: + * L - means that the GPE is level triggered + * E - means that the GPE is edge triggered + * nn - is the GPE number [in HEX] * ******************************************************************************/ @@ -196,7 +201,8 @@ acpi_ev_save_method_info ( name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd character of the method name + * Edge/Level determination is based on the 2nd character + * of the method name */ switch (name[1]) { case 'L': @@ -249,15 +255,14 @@ acpi_ev_save_method_info ( gpe_event_info->flags = type; gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; - /* - * Enable the GPE (SCIs should be disabled at this point) - */ + /* Enable the GPE (SCIs should be disabled at this point) */ + status = acpi_hw_enable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); return_ACPI_STATUS (AE_OK); @@ -867,8 +872,8 @@ acpi_ev_gpe_initialize (void) } /* - * GPE0 and GPE1 do not have to be contiguous in the GPE number space, - * But, GPE0 always starts at zero. + * GPE0 and GPE1 do not have to be contiguous in the GPE number + * space. However, GPE0 always starts at GPE number zero. */ gpe_number_max = acpi_gbl_FADT->gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 757ef213ede..85e2acdf3c1 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -222,7 +222,7 @@ acpi_ex_opcode_1A_1T_1R ( union acpi_operand_object *return_desc2 = NULL; u32 temp32; u32 i; - u32 j; + u32 power_of_ten; acpi_integer digit; @@ -291,61 +291,70 @@ acpi_ex_opcode_1A_1T_1R ( case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ /* - * The 64-bit ACPI integer can hold 16 4-bit BCD integers + * The 64-bit ACPI integer can hold 16 4-bit BCD characters + * (if table is 32-bit, integer can hold 8 BCD characters) + * Convert each 4-bit BCD value */ + power_of_ten = 1; return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Get one BCD digit */ + digit = operand[0]->integer.value; - digit = (acpi_integer) ((operand[0]->integer.value >> (i * 4)) & 0xF); + /* Convert each BCD digit (each is one nybble wide) */ + + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + /* Get the least significant 4-bit BCD digit */ + + temp32 = ((u32) digit) & 0xF; /* Check the range of the digit */ - if (digit > 9) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD digit too large: %d\n", - (u32) digit)); + if (temp32 > 9) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "BCD digit too large (not decimal): 0x%X\n", + temp32)); + status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } - if (digit > 0) { - /* Sum into the result with the appropriate power of 10 */ + /* Sum the digit into the result with the current power of 10 */ - for (j = 0; j < i; j++) { - digit *= 10; - } + return_desc->integer.value += (((acpi_integer) temp32) * power_of_ten); - return_desc->integer.value += digit; - } + /* Shift to next BCD digit */ + + digit >>= 4; + + /* Next power of 10 */ + + power_of_ten *= 10; } break; case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ - if (operand[0]->integer.value > ACPI_MAX_BCD_VALUE) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD overflow: %8.8X%8.8X\n", - ACPI_HIDWORD(operand[0]->integer.value), - ACPI_LODWORD(operand[0]->integer.value))); - status = AE_AML_NUMERIC_OVERFLOW; - goto cleanup; - } - return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Divide by nth factor of 10 */ + digit = operand[0]->integer.value; - temp32 = 0; - digit = operand[0]->integer.value; - for (j = 0; j < i; j++) { - (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32); - } + /* Each BCD digit is one nybble wide */ - /* Create the BCD digit from the remainder above */ + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32); - if (digit > 0) { - return_desc->integer.value += ((acpi_integer) temp32 << (i * 4)); - } + /* Insert the BCD digit that resides in the remainder from above */ + + return_desc->integer.value |= (((acpi_integer) temp32) << (i * 4)); + } + + /* Overflow if there is any data left in Digit */ + + if (digit > 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Integer too large to convert to BCD: %8.8X%8.8X\n", + ACPI_HIDWORD(operand[0]->integer.value), + ACPI_LODWORD(operand[0]->integer.value))); + status = AE_AML_NUMERIC_OVERFLOW; + goto cleanup; } break; diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index acd9da27a3a..517dbaec622 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -190,8 +190,8 @@ acpi_ex_store ( case ACPI_TYPE_INTEGER: ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n", - ACPI_HIWORD (source_desc->integer.value), - ACPI_LOWORD (source_desc->integer.value))); + ACPI_HIDWORD (source_desc->integer.value), + ACPI_LODWORD (source_desc->integer.value))); break; diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index ea3dbe74ef5..8d4c003ac19 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -134,7 +134,7 @@ acpi_ex_system_do_stall ( acpi_ex_exit_interpreter (); - acpi_os_stall (how_long); + acpi_os_sleep (0, (how_long / 1000) + 1); /* And now we must get the interpreter again */ @@ -142,7 +142,7 @@ acpi_ex_system_do_stall ( } else { - acpi_os_sleep (0, (how_long / 1000) + 1); + acpi_os_stall (how_long); } return (status); diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 090684c6ea1..d58e97e3e72 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -289,7 +289,10 @@ acpi_ex_digits_needed ( /* * acpi_integer is unsigned, so we don't worry about a '-' */ - current_value = value; + if ((current_value = value) == 0) { + return_VALUE (1); + } + num_digits = 0; while (current_value) { diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index 25e05b13844..b18cbfa6bef 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -56,7 +56,7 @@ * * FUNCTION: acpi_hw_clear_acpi_status * - * PARAMETERS: none + * PARAMETERS: Flags - Lock the hardware or not * * RETURN: none * @@ -65,7 +65,8 @@ ******************************************************************************/ acpi_status -acpi_hw_clear_acpi_status (void) +acpi_hw_clear_acpi_status ( + u32 flags) { acpi_status status; @@ -77,10 +78,11 @@ acpi_hw_clear_acpi_status (void) ACPI_BITMASK_ALL_FIXED_STATUS, (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); - - status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + if (flags & ACPI_MTX_LOCK) { + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, @@ -104,7 +106,9 @@ acpi_hw_clear_acpi_status (void) status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); unlock_and_exit: - (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + if (flags & ACPI_MTX_LOCK) { + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + } return_ACPI_STATUS (status); } @@ -237,8 +241,9 @@ acpi_hw_get_bit_register_info ( * * FUNCTION: acpi_get_register * - * PARAMETERS: register_id - Index of ACPI Register to access - * use_lock - Lock the hardware + * PARAMETERS: register_id - ID of ACPI bit_register to access + * return_value - Value that was read from the register + * Flags - Lock the hardware or not * * RETURN: Value is read from specified Register. Value returned is * normalized to bit0 (is shifted all the way right) @@ -290,7 +295,8 @@ acpi_get_register ( *return_value = register_value; - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %X\n", register_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %8.8X register %X\n", + register_value, bit_reg_info->parent_register)); } return_ACPI_STATUS (status); @@ -443,7 +449,8 @@ unlock_and_exit: ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "ACPI Register Write actual %X\n", register_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n", + value, register_value, bit_reg_info->parent_register)); return_ACPI_STATUS (status); } @@ -751,10 +758,15 @@ acpi_hw_low_level_read ( default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); - status = AE_BAD_PARAMETER; - break; + return (AE_BAD_PARAMETER); } + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, + ACPI_HIDWORD (reg->address), + ACPI_LODWORD (reg->address), + acpi_ut_get_region_name (reg->address_space_id))); + return (status); } @@ -832,9 +844,14 @@ acpi_hw_low_level_write ( default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); - status = AE_BAD_PARAMETER; - break; + return (AE_BAD_PARAMETER); } + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, + ACPI_HIDWORD (reg->address), + ACPI_LODWORD (reg->address), + acpi_ut_get_region_name (reg->address_space_id))); + return (status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 37dc30a49bd..87642c75686 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -231,7 +231,7 @@ acpi_enter_sleep_state ( return_ACPI_STATUS (status); } - status = acpi_hw_clear_acpi_status(); + status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -355,7 +355,7 @@ acpi_enter_sleep_state_s4bios ( ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios"); acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_hw_clear_acpi_status(); + acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); acpi_hw_disable_non_wakeup_gpes(); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 10a02822ef5..5caecd1a7d7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -69,8 +69,6 @@ static int acpi_irq_irq = 0; static OSD_HANDLER acpi_irq_handler = NULL; static void *acpi_irq_context = NULL; -extern struct pci_ops *pci_root_ops; - acpi_status acpi_os_initialize(void) { @@ -79,7 +77,7 @@ acpi_os_initialize(void) * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */ #ifdef CONFIG_ACPI_PCI - if (!pci_root_ops) { + if (!raw_pci_ops) { printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; } @@ -446,15 +444,9 @@ acpi_os_write_memory( #ifdef CONFIG_ACPI_PCI acpi_status -acpi_os_read_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) +acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value, u32 width) { - int result = 0; - int size = 0; - struct pci_bus bus; + int result, size; if (!value) return AE_BAD_PARAMETER; @@ -470,27 +462,19 @@ acpi_os_read_pci_configuration ( size = 4; break; default: - BUG(); + return AE_ERROR; } - bus.number = pci_id->bus; - result = pci_root_ops->read(&bus, PCI_DEVFN(pci_id->device, - pci_id->function), - reg, size, value); + result = raw_pci_ops->read(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, size, value); return (result ? AE_ERROR : AE_OK); } acpi_status -acpi_os_write_pci_configuration ( - struct acpi_pci_id *pci_id, - u32 reg, - acpi_integer value, - u32 width) +acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integer value, u32 width) { - int result = 0; - int size = 0; - struct pci_bus bus; + int result, size; switch (width) { case 8: @@ -503,13 +487,12 @@ acpi_os_write_pci_configuration ( size = 4; break; default: - BUG(); + return AE_ERROR; } - bus.number = pci_id->bus; - result = pci_root_ops->write(&bus, PCI_DEVFN(pci_id->device, - pci_id->function), - reg, size, value); + result = raw_pci_ops->write(pci_id->segment, pci_id->bus, + pci_id->device, pci_id->function, reg, size, value); + return (result ? AE_ERROR : AE_OK); } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20a1a9fecc7..ce3d0f9a25b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -44,8 +44,6 @@ ACPI_MODULE_NAME ("pci_root") #define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" -extern struct pci_ops *pci_root_ops; - static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_remove (struct acpi_device *device, int type); diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c index 4b412360e41..099eb723b64 100644 --- a/drivers/acpi/tables/tbconvrt.c +++ b/drivers/acpi/tables/tbconvrt.c @@ -287,10 +287,14 @@ acpi_tb_convert_fadt1 ( (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + - ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + } } @@ -379,11 +383,15 @@ acpi_tb_convert_fadt2 ( ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id; - acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + - ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + } } diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index b16c01e8355..5012037926c 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -203,10 +203,12 @@ acpi_ut_set_integer_width ( if (revision <= 1) { acpi_gbl_integer_bit_width = 32; + acpi_gbl_integer_nybble_width = 8; acpi_gbl_integer_byte_width = 4; } else { acpi_gbl_integer_bit_width = 64; + acpi_gbl_integer_nybble_width = 16; acpi_gbl_integer_byte_width = 8; } } diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 2bacc8f75e1..407748d0c4c 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -2710,12 +2710,13 @@ he_close(struct atm_vcc *vcc) remove_wait_queue(&he_vcc->tx_waitq, &wait); set_current_state(TASK_RUNNING); + spin_lock_irqsave(&he_dev->global_lock, flags); + if (timeout == 0) { hprintk("close tx timeout cid 0x%x\n", cid); goto close_tx_incomplete; } - spin_lock_irqsave(&he_dev->global_lock, flags); while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); udelay(250); diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig new file mode 100644 index 00000000000..6d06c9f16d5 --- /dev/null +++ b/drivers/base/Kconfig @@ -0,0 +1,10 @@ +menu "Generic Driver Options" + +config FW_LOADER + tristate "Hotplug firmware loading support" + ---help--- + This option is provided for the case where no in-kernel-tree modules + require hotplug firmware loading support, but a module built outside + the kernel tree does. + +endmenu diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 800228c1608..334fcc6c6ee 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -3,4 +3,5 @@ obj-y := core.o sys.o interface.o power.o bus.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o +obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o memblk.o diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c new file mode 100644 index 00000000000..b186dba8d2d --- /dev/null +++ b/drivers/base/firmware_class.c @@ -0,0 +1,505 @@ +/* + * firmware_class.c - Multi purpose firmware loading support + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Please see Documentation/firmware_class/ for more information. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "base.h" + +MODULE_AUTHOR("Manuel Estrada Sainz "); +MODULE_DESCRIPTION("Multi purpose firmware loading support"); +MODULE_LICENSE("GPL"); + +static int loading_timeout = 10; /* In seconds */ + +struct firmware_priv { + char fw_id[FIRMWARE_NAME_MAX]; + struct completion completion; + struct bin_attribute attr_data; + struct firmware *fw; + int loading; + int abort; + int alloc_size; + struct timer_list timeout; +}; + +static ssize_t +firmware_timeout_show(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", loading_timeout); +} + +/** + * firmware_timeout_store: + * Description: + * Sets the number of seconds to wait for the firmware. Once + * this expires an error will be return to the driver and no + * firmware will be provided. + * + * Note: zero means 'wait for ever' + * + **/ +static ssize_t +firmware_timeout_store(struct class *class, const char *buf, size_t count) +{ + loading_timeout = simple_strtol(buf, NULL, 10); + return count; +} + +static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); + +static void fw_class_dev_release(struct class_device *class_dev); +int firmware_class_hotplug(struct class_device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + +static struct class firmware_class = { + .name = "firmware", + .hotplug = firmware_class_hotplug, + .release = fw_class_dev_release, +}; + +int +firmware_class_hotplug(struct class_device *class_dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int i = 0; + char *scratch = buffer; + + if (buffer_size < (FIRMWARE_NAME_MAX + 10)) + return -ENOMEM; + if (num_envp < 1) + return -ENOMEM; + + envp[i++] = scratch; + scratch += sprintf(scratch, "FIRMWARE=%s", fw_priv->fw_id) + 1; + return 0; +} + +static ssize_t +firmware_loading_show(struct class_device *class_dev, char *buf) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + return sprintf(buf, "%d\n", fw_priv->loading); +} + +/** + * firmware_loading_store: - loading control file + * Description: + * The relevant values are: + * + * 1: Start a load, discarding any previous partial load. + * 0: Conclude the load and handle the data to the driver code. + * -1: Conclude the load with an error and discard any written data. + **/ +static ssize_t +firmware_loading_store(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int prev_loading = fw_priv->loading; + + fw_priv->loading = simple_strtol(buf, NULL, 10); + + switch (fw_priv->loading) { + case -1: + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); + break; + case 1: + kfree(fw_priv->fw->data); + fw_priv->fw->data = NULL; + fw_priv->fw->size = 0; + fw_priv->alloc_size = 0; + break; + case 0: + if (prev_loading == 1) + complete(&fw_priv->completion); + break; + } + + return count; +} + +static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + +static ssize_t +firmware_data_read(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + + if (offset > fw->size) + return 0; + if (offset + count > fw->size) + count = fw->size - offset; + + memcpy(buffer, fw->data + offset, count); + return count; +} +static int +fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) +{ + u8 *new_data; + + if (min_size <= fw_priv->alloc_size) + return 0; + + new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE); + if (!new_data) { + printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); + /* Make sure that we don't keep incomplete data */ + fw_priv->abort = 1; + return -ENOMEM; + } + fw_priv->alloc_size += PAGE_SIZE; + if (fw_priv->fw->data) { + memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); + vfree(fw_priv->fw->data); + } + fw_priv->fw->data = new_data; + BUG_ON(min_size > fw_priv->alloc_size); + return 0; +} + +/** + * firmware_data_write: + * + * Description: + * + * Data written to the 'data' attribute will be later handled to + * the driver as a firmware image. + **/ +static ssize_t +firmware_data_write(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + int retval; + + retval = fw_realloc_buffer(fw_priv, offset + count); + if (retval) + return retval; + + memcpy(fw->data + offset, buffer, count); + + fw->size = max_t(size_t, offset + count, fw->size); + + return count; +} +static struct bin_attribute firmware_attr_data_tmpl = { + .attr = {.name = "data", .mode = 0644}, + .size = 0, + .read = firmware_data_read, + .write = firmware_data_write, +}; + +static void +fw_class_dev_release(struct class_device *class_dev) +{ + kfree(class_dev); +} + +static void +firmware_class_timeout(u_long data) +{ + struct firmware_priv *fw_priv = (struct firmware_priv *) data; + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); +} + +static inline void +fw_setup_class_device_id(struct class_device *class_dev, struct device *dev) +{ + /* XXX warning we should watch out for name collisions */ + strncpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE); + class_dev->class_id[BUS_ID_SIZE - 1] = '\0'; +} +static int +fw_setup_class_device(struct class_device **class_dev_p, + const char *fw_name, struct device *device) +{ + int retval = 0; + struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), + GFP_KERNEL); + struct class_device *class_dev = kmalloc(sizeof (struct class_device), + GFP_KERNEL); + + if (!fw_priv || !class_dev) { + retval = -ENOMEM; + goto error_kfree; + } + memset(fw_priv, 0, sizeof (*fw_priv)); + memset(class_dev, 0, sizeof (*class_dev)); + + init_completion(&fw_priv->completion); + memcpy(&fw_priv->attr_data, &firmware_attr_data_tmpl, + sizeof (firmware_attr_data_tmpl)); + + strncpy(&fw_priv->fw_id[0], fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id[FIRMWARE_NAME_MAX - 1] = '\0'; + + fw_setup_class_device_id(class_dev, device); + class_dev->dev = device; + + fw_priv->timeout.function = firmware_class_timeout; + fw_priv->timeout.data = (u_long) fw_priv; + init_timer(&fw_priv->timeout); + + class_dev->class = &firmware_class; + class_set_devdata(class_dev, fw_priv); + retval = class_device_register(class_dev); + if (retval) { + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + goto error_kfree; + } + + retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data); + if (retval) { + printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", + __FUNCTION__); + goto error_unreg_class_dev; + } + + retval = class_device_create_file(class_dev, + &class_device_attr_loading); + if (retval) { + printk(KERN_ERR "%s: class_device_create_file failed\n", + __FUNCTION__); + goto error_remove_data; + } + + fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL); + if (!fw_priv->fw) { + printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", + __FUNCTION__); + retval = -ENOMEM; + goto error_remove_loading; + } + memset(fw_priv->fw, 0, sizeof (*fw_priv->fw)); + + goto out; + +error_remove_loading: + class_device_remove_file(class_dev, &class_device_attr_loading); +error_remove_data: + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); +error_unreg_class_dev: + class_device_unregister(class_dev); +error_kfree: + kfree(fw_priv); + kfree(class_dev); + *class_dev_p = NULL; +out: + *class_dev_p = class_dev; + return retval; +} +static void +fw_remove_class_device(struct class_device *class_dev) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + class_device_remove_file(class_dev, &class_device_attr_loading); + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); + class_device_unregister(class_dev); +} + +/** + * request_firmware: - request firmware to hotplug and wait for it + * Description: + * @firmware will be used to return a firmware image by the name + * of @name for device @device. + * + * Should be called from user context where sleeping is allowed. + * + * @name will be use as $FIRMWARE in the hotplug environment and + * should be distinctive enough not to be confused with any other + * firmware image for this or any other device. + **/ +int +request_firmware(const struct firmware **firmware, const char *name, + struct device *device) +{ + struct class_device *class_dev; + struct firmware_priv *fw_priv; + int retval; + + if (!firmware) + return -EINVAL; + + *firmware = NULL; + + retval = fw_setup_class_device(&class_dev, name, device); + if (retval) + goto out; + + fw_priv = class_get_devdata(class_dev); + + if (loading_timeout) { + fw_priv->timeout.expires = jiffies + loading_timeout * HZ; + add_timer(&fw_priv->timeout); + } + + wait_for_completion(&fw_priv->completion); + + del_timer(&fw_priv->timeout); + fw_remove_class_device(class_dev); + + if (fw_priv->fw->size && !fw_priv->abort) { + *firmware = fw_priv->fw; + } else { + retval = -ENOENT; + vfree(fw_priv->fw->data); + kfree(fw_priv->fw); + } + kfree(fw_priv); +out: + return retval; +} + +/** + * release_firmware: - release the resource associated with a firmware image + **/ +void +release_firmware(const struct firmware *fw) +{ + if (fw) { + vfree(fw->data); + kfree(fw); + } +} + +/** + * register_firmware: - provide a firmware image for later usage + * + * Description: + * Make sure that @data will be available by requesting firmware @name. + * + * Note: This will not be possible until some kind of persistence + * is available. + **/ +void +register_firmware(const char *name, const u8 *data, size_t size) +{ + /* This is meaningless without firmware caching, so until we + * decide if firmware caching is reasonable just leave it as a + * noop */ +} + +/* Async support */ +struct firmware_work { + struct work_struct work; + struct module *module; + const char *name; + struct device *device; + void *context; + void (*cont)(const struct firmware *fw, void *context); +}; + +static void +request_firmware_work_func(void *arg) +{ + struct firmware_work *fw_work = arg; + const struct firmware *fw; + if (!arg) + return; + request_firmware(&fw, fw_work->name, fw_work->device); + fw_work->cont(fw, fw_work->context); + release_firmware(fw); + module_put(fw_work->module); + kfree(fw_work); +} + +/** + * request_firmware_nowait: + * + * Description: + * Asynchronous variant of request_firmware() for contexts where + * it is not possible to sleep. + * + * @cont will be called asynchronously when the firmware request is over. + * + * @context will be passed over to @cont. + * + * @fw may be %NULL if firmware request fails. + * + **/ +int +request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)) +{ + struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), + GFP_ATOMIC); + if (!fw_work) + return -ENOMEM; + if (!try_module_get(module)) { + kfree(fw_work); + return -EFAULT; + } + + *fw_work = (struct firmware_work) { + .module = module, + .name = name, + .device = device, + .context = context, + .cont = cont, + }; + INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work); + + schedule_work(&fw_work->work); + return 0; +} + +static int __init +firmware_class_init(void) +{ + int error; + error = class_register(&firmware_class); + if (error) { + printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__); + } + error = class_create_file(&firmware_class, &class_attr_timeout); + if (error) { + printk(KERN_ERR "%s: class_create_file failed\n", + __FUNCTION__); + class_unregister(&firmware_class); + } + return error; + +} +static void __exit +firmware_class_exit(void) +{ + class_remove_file(&firmware_class, &class_attr_timeout); + class_unregister(&firmware_class); +} + +module_init(firmware_class_init); +module_exit(firmware_class_exit); + +EXPORT_SYMBOL(release_firmware); +EXPORT_SYMBOL(request_firmware); +EXPORT_SYMBOL(request_firmware_nowait); +EXPORT_SYMBOL(register_firmware); +EXPORT_SYMBOL(firmware_class); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index e8a4daa442e..e306d2e2636 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -74,6 +74,8 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) sysfs_remove_file(&s->kobj,&a->attr); } +EXPORT_SYMBOL(sysdev_create_file); +EXPORT_SYMBOL(sysdev_remove_file); /* * declare system_subsys @@ -171,6 +173,9 @@ int sys_device_register(struct sys_device * sysdev) /* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; + /* But make sure we point to the right type for sysfs translation */ + sysdev->kobj.ktype = &ktype_sysdev; + /* set the kobject name */ snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d", cls->kset.kobj.name,sysdev->id); @@ -218,9 +223,6 @@ void sys_device_unregister(struct sys_device * sysdev) if (drv->remove) drv->remove(sysdev); } - - list_del_init(&sysdev->entry); - up_write(&system_subsys.rwsem); kobject_unregister(&sysdev->kobj); diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 98b77227cf3..8ad5d01e4d4 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -698,7 +698,7 @@ cciss_scsi_detect(int ctlr) { struct Scsi_Host *sh; - sh = scsi_register(&cciss_driver_template, sizeof(struct ctlr_info *)); + sh = scsi_host_alloc(&cciss_driver_template, sizeof(struct ctlr_info *)); if (sh == NULL) return 0; @@ -1357,7 +1357,7 @@ cciss_unregister_scsi(int ctlr) if (sa->registered) { spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); scsi_remove_host(sa->scsi_host); - scsi_unregister(sa->scsi_host); + scsi_host_put(sa->scsi_host); spin_lock_irqsave(CCISS_LOCK(ctlr), flags); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 93f6160dd98..6287b0064d9 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -49,8 +49,6 @@ static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; static int queue_nr_requests; unsigned long blk_max_low_pfn, blk_max_pfn; -int blk_nohighio = 0; - static wait_queue_head_t congestion_wqh[2]; /* @@ -2334,7 +2332,6 @@ EXPORT_SYMBOL(blk_queue_hardsect_size); EXPORT_SYMBOL(blk_queue_segment_boundary); EXPORT_SYMBOL(blk_queue_dma_alignment); EXPORT_SYMBOL(blk_rq_map_sg); -EXPORT_SYMBOL(blk_nohighio); EXPORT_SYMBOL(blk_dump_rq_flags); EXPORT_SYMBOL(submit_bio); EXPORT_SYMBOL(blk_phys_contig_segment); diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 0509a67c2eb..bbfc4eaa392 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -269,7 +269,10 @@ static struct backing_dev_info rd_backing_dev_info = { static int rd_open(struct inode * inode, struct file * filp) { - int unit = minor(inode->i_rdev); + unsigned unit = minor(inode->i_rdev); + + if (unit >= NUM_RAMDISKS) + return -ENODEV; /* * Immunize device against invalidate_buffers() and prune_icache(). diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 3e5b1fe6452..fba8f81379e 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -242,7 +242,7 @@ void kd_mksound(unsigned int hz, unsigned int ticks) del_timer(&kd_mksound_timer); if (hz) { - list_for_each(node,&kbd_handler.h_list) { + list_for_each_prev(node,&kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 7ab294eb7b8..f0b8aa4d1fc 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -339,7 +339,6 @@ int moxa_init(void) { int i, n, numBoards; struct moxa_str *ch; - int ret1, ret2; printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); moxaDriver = alloc_tty_driver(MAX_PORTS + 1); @@ -615,7 +614,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) } ch->asyncflags |= ASYNC_CLOSING; - ch->cflag = *tty->termios->c_cflag; + ch->cflag = tty->termios->c_cflag; if (ch->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 3080b464e95..8aeb7cbbe9b 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -258,12 +259,27 @@ static struct file_operations raw_ctl_fops = { static int __init raw_init(void) { + int i; + register_chrdev(RAW_MAJOR, "raw", &raw_fops); + devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), + S_IFCHR | S_IRUGO | S_IWUGO, + "raw/rawctl"); + for (i = 1; i < MAX_RAW_MINORS; i++) + devfs_mk_cdev(MKDEV(RAW_MAJOR, i), + S_IFCHR | S_IRUGO | S_IWUGO, + "raw/raw%d", i); return 0; } static void __exit raw_exit(void) { + int i; + + for (i = 1; i < MAX_RAW_MINORS; i++) + devfs_remove("raw/raw%d", i); + devfs_remove("raw/rawctl"); + devfs_remove("raw"); unregister_chrdev(RAW_MAJOR, "raw"); } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index ca5ad249ab8..a24ada1612f 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -75,6 +75,7 @@ */ #include +#include #include #include #include @@ -2279,7 +2280,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = fg_console; break; case TIOCL_SCROLLCONSOLE: - if (get_user(lines, (char *)arg+1)) { + if (get_user(lines, (s32 *)((char *)arg+4))) { ret = -EFAULT; } else { scrollfront(lines); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index e5de162fbd8..0b985c9d3ed 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -872,6 +872,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, return -EINVAL; for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons[i].d) + continue; if (vlin) vc_cons[i].d->vc_scan_lines = vlin; if (clin) diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 1ca20003620..103a4a9b3e7 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -177,17 +177,18 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev) if(force_addr) { dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n", ali15x3_smba); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(ALI15X3_dev, SMBBA, &a)) - return -ENODEV; + if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, + SMBBA, + ali15x3_smba)) + goto error; + if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev, + SMBBA, &a)) + goto error; if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { /* make sure it works */ dev_err(&ALI15X3_dev->dev, "force address failed - not supported?\n"); - return -ENODEV; + goto error; } } /* check if whole device is enabled */ @@ -219,6 +220,9 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev) dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); return 0; +error: + release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); + return -ENODEV; } /* Internally used pause function */ diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 701520b0c86..d88704e8b53 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -27,6 +27,7 @@ 82801BA 2443 82801CA/CAM 2483 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) + 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part @@ -121,7 +122,8 @@ static int i801_setup(struct pci_dev *dev) return -ENODEV; I801_dev = dev; - if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) + if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || + (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3)) isich4 = 1; else isich4 = 0; @@ -585,6 +587,12 @@ static struct pci_device_id i801_ids[] __devinitdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801EB_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { 0, } }; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index fcd73271a1e..a533dfbf883 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -62,6 +62,20 @@ config SENSORS_LM85 in the lm_sensors package, which you can download at http://www.lm-sensors.nu +config SENSORS_LM78 + tristate " National Semiconductors LM78 and compatibles" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for National Semiconductor LM78, + LM78-J and LM79. This can also be built as a module which can be + inserted and removed while the kernel is running. + + The module will be called lm78. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + config SENSORS_VIA686A tristate " VIA686A" depends on I2C && EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 3921d68eb52..30dbdafb268 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM75) += lm75.o +obj-$(CONFIG_SENSORS_LM78) += lm78.o obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83781D) += w83781d.o diff --git a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c index aa636bf09dd..739ce6e2bc3 100644 --- a/drivers/i2c/chips/adm1021.c +++ b/drivers/i2c/chips/adm1021.c @@ -88,8 +88,8 @@ SENSORS_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1 these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ /* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) +#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) /* Initial values */ @@ -172,8 +172,18 @@ show(temp_input); show(remote_temp_max); show(remote_temp_hyst); show(remote_temp_input); -show(alarms); -show(die_code); + +#define show2(value) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + \ + adm1021_update_client(client); \ + return sprintf(buf, "%d\n", data->value); \ +} +show2(alarms); +show2(die_code); #define set(value, reg) \ static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ diff --git a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c new file mode 100644 index 00000000000..2dbdf60a87f --- /dev/null +++ b/drivers/i2c/chips/lm78.c @@ -0,0 +1,895 @@ +/* + lm78.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(lm78, lm78j, lm79); + +/* Many LM78 constants specified below */ + +/* Length of ISA address segment */ +#define LM78_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define LM78_ADDR_REG_OFFSET 5 +#define LM78_DATA_REG_OFFSET 6 + +/* The LM78 registers */ +#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define LM78_REG_IN(nr) (0x20 + (nr)) + +#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) +#define LM78_REG_FAN(nr) (0x28 + (nr)) + +#define LM78_REG_TEMP 0x27 +#define LM78_REG_TEMP_OVER 0x39 +#define LM78_REG_TEMP_HYST 0x3a + +#define LM78_REG_ALARM1 0x41 +#define LM78_REG_ALARM2 0x42 + +#define LM78_REG_VID_FANDIV 0x47 + +#define LM78_REG_CONFIG 0x40 +#define LM78_REG_CHIPID 0x49 +#define LM78_REG_I2C_ADDR 0x48 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-128C to +127C) + REG: 1C/bit, two's complement */ +static inline u8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -128000, 127000) ; + return nval<0 ? (nval-500)/1000+0x100 : (nval+500)/1000; +} + +static inline int TEMP_FROM_REG(u8 val) +{ + return (val>=0x80 ? val-0x100 : val) * 1000; +} + +/* VID: mV + REG: (see doc/vid) */ +static inline int VID_FROM_REG(u8 val) +{ + return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; +} + +/* ALARMS: chip-specific bitmask + REG: (same) */ +#define ALARMS_FROM_REG(val) (val) + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static inline u8 DIV_TO_REG(int val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} +#define DIV_FROM_REG(val) (1 << (val)) + +/* Initial limits. To keep them sane, we use the 'standard' translation as + specified in the LM78 sheet. Use the config file to set better limits. */ +#define LM78_INIT_IN_0(vid) ((vid)==3500 ? 2800 : (vid)) +#define LM78_INIT_IN_1(vid) ((vid)==3500 ? 2800 : (vid)) +#define LM78_INIT_IN_2 3300 +#define LM78_INIT_IN_3 (((5000) * 100)/168) +#define LM78_INIT_IN_4 (((12000) * 10)/38) +#define LM78_INIT_IN_5 (((-12000) * -604)/2100) +#define LM78_INIT_IN_6 (((-5000) * -604)/909) + +#define LM78_INIT_IN_PERCENTAGE 10 + +#define LM78_INIT_IN_MIN_0(vid) (LM78_INIT_IN_0(vid) - \ + LM78_INIT_IN_0(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_0(vid) (LM78_INIT_IN_0(vid) + \ + LM78_INIT_IN_0(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_1(vid) (LM78_INIT_IN_1(vid) - \ + LM78_INIT_IN_1(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_1(vid) (LM78_INIT_IN_1(vid) + \ + LM78_INIT_IN_1(vid) * LM78_INIT_IN_PERCENTAGE / 100) + +#define LM78_INIT_IN_MIN_2 \ + (LM78_INIT_IN_2 - LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_2 \ + (LM78_INIT_IN_2 + LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_3 \ + (LM78_INIT_IN_3 - LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_3 \ + (LM78_INIT_IN_3 + LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_4 \ + (LM78_INIT_IN_4 - LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_4 \ + (LM78_INIT_IN_4 + LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_5 \ + (LM78_INIT_IN_5 - LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_5 \ + (LM78_INIT_IN_5 + LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_6 \ + (LM78_INIT_IN_6 - LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_6 \ + (LM78_INIT_IN_6 + LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) + +#define LM78_INIT_FAN_MIN_1 3000 +#define LM78_INIT_FAN_MIN_2 3000 +#define LM78_INIT_FAN_MIN_3 3000 + +#define LM78_INIT_TEMP_OVER 60000 +#define LM78_INIT_TEMP_HYST 50000 + +/* There are some complications in a module like this. First off, LM78 chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + LM78 chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the LM78 at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered LM78, we need to keep some data in memory. That + data is pointed to by lm78_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm78 client is + allocated. */ +struct lm78_data { + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; /* Register value */ + u8 temp_over; /* Register value */ + u8 temp_hyst; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u16 alarms; /* Register encoding, combined */ +}; + + +static int lm78_attach_adapter(struct i2c_adapter *adapter); +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm78_detach_client(struct i2c_client *client); + +static int lm78_read_value(struct i2c_client *client, u8 register); +static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); +static void lm78_update_client(struct i2c_client *client); +static void lm78_init_client(struct i2c_client *client); + + +static struct i2c_driver lm78_driver = { + .owner = THIS_MODULE, + .name = "lm78", + .id = I2C_DRIVERID_LM78, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm78_attach_adapter, + .detach_client = lm78_detach_client, +}; + +/* 7 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_min[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_max[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, char *buf) \ +{ \ + return show_in(dev, buf, 0x##offset); \ +} \ +static DEVICE_ATTR(in_input##offset, S_IRUGO, \ + show_in##offset, NULL) \ +static ssize_t \ + show_in##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_in_min(dev, buf, 0x##offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, char *buf) \ +{ \ + return show_in_max(dev, buf, 0x##offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, 0x##offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, 0x##offset); \ +} \ +static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min) \ +static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max) + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); +show_in_offset(6); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_over = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_hyst = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); + return count; +} + +static DEVICE_ATTR(temp_input, S_IRUGO, show_temp, NULL) +static DEVICE_ATTR(temp_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over) +static DEVICE_ATTR(temp_min, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst) + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->fan_div[nr] = DIV_TO_REG(val); + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + lm78_write_value(client, LM78_REG_VID_FANDIV, reg); + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +{ \ + return show_fan(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_fan_min(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +{ \ + return show_fan_div(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, 0x##offset - 1); \ +} \ +static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min) + +static ssize_t set_fan_1_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +/* Fan 3 divisor is locked in H/W */ +static DEVICE_ATTR(fan_div1, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div) +static DEVICE_ATTR(fan_div2, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div) +static DEVICE_ATTR(fan_div3, S_IRUGO, show_fan_3_div, NULL) + +/* VID */ +static ssize_t show_vid(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); +} +static DEVICE_ATTR(vid, S_IRUGO, show_vid, NULL); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This function is called when: + * lm78_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm78_driver is still present) */ +static int lm78_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; + return i2c_detect(adapter, &addr_data, lm78_detect); +} + +/* This function is called by i2c_detect */ +int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, err; + struct i2c_client *new_client; + struct lm78_data *data; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -ENODEV; + goto ERROR0; + } + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, LM78_EXTENT, "lm78")) { + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm78_{read,write}_value. */ + + if (!(new_client = kmalloc((sizeof(struct i2c_client)) + + sizeof(struct lm78_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(new_client, 0, sizeof(struct i2c_client) + + sizeof(struct lm78_data)); + + data = (struct lm78_data *) (new_client + 1); + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm78_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { + err = -ENODEV; + goto ERROR2; + } + if (!is_isa && (lm78_read_value( + new_client, LM78_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = lm78_read_value(new_client, LM78_REG_CHIPID); + if (i == 0x00 || i == 0x20) + kind = lm78; + else if (i == 0x40) + kind = lm78j; + else if ((i & 0xfe) == 0xc0) + kind = lm79; + else { + if (kind == 0) + printk(KERN_WARNING "lm78.o: Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == lm78) { + client_name = "LM78 chip"; + } else if (kind == lm78j) { + client_name = "LM78-J chip"; + } else if (kind == lm79) { + client_name = "LM79 chip"; + } else { + dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?", + kind); + err = -ENODEV; + goto ERROR2; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in_input0); + device_create_file(&new_client->dev, &dev_attr_in_min0); + device_create_file(&new_client->dev, &dev_attr_in_max0); + device_create_file(&new_client->dev, &dev_attr_in_input1); + device_create_file(&new_client->dev, &dev_attr_in_min1); + device_create_file(&new_client->dev, &dev_attr_in_max1); + device_create_file(&new_client->dev, &dev_attr_in_input2); + device_create_file(&new_client->dev, &dev_attr_in_min2); + device_create_file(&new_client->dev, &dev_attr_in_max2); + device_create_file(&new_client->dev, &dev_attr_in_input3); + device_create_file(&new_client->dev, &dev_attr_in_min3); + device_create_file(&new_client->dev, &dev_attr_in_max3); + device_create_file(&new_client->dev, &dev_attr_in_input4); + device_create_file(&new_client->dev, &dev_attr_in_min4); + device_create_file(&new_client->dev, &dev_attr_in_max4); + device_create_file(&new_client->dev, &dev_attr_in_input5); + device_create_file(&new_client->dev, &dev_attr_in_min5); + device_create_file(&new_client->dev, &dev_attr_in_max5); + device_create_file(&new_client->dev, &dev_attr_in_input6); + device_create_file(&new_client->dev, &dev_attr_in_min6); + device_create_file(&new_client->dev, &dev_attr_in_max6); + device_create_file(&new_client->dev, &dev_attr_temp_input); + device_create_file(&new_client->dev, &dev_attr_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp_max); + device_create_file(&new_client->dev, &dev_attr_fan_input1); + device_create_file(&new_client->dev, &dev_attr_fan_min1); + device_create_file(&new_client->dev, &dev_attr_fan_div1); + device_create_file(&new_client->dev, &dev_attr_fan_input2); + device_create_file(&new_client->dev, &dev_attr_fan_min2); + device_create_file(&new_client->dev, &dev_attr_fan_div2); + device_create_file(&new_client->dev, &dev_attr_fan_input3); + device_create_file(&new_client->dev, &dev_attr_fan_min3); + device_create_file(&new_client->dev, &dev_attr_fan_div3); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_vid); + + /* Initialize the LM78 chip */ + lm78_init_client(new_client); + return 0; + +ERROR2: + kfree(new_client); +ERROR1: + if (is_isa) + release_region(address, LM78_EXTENT); +ERROR0: + return err; +} + +static int lm78_detach_client(struct i2c_client *client) +{ + int err; + + /* release ISA region first */ + if(i2c_is_isa_client(client)) + release_region(client->addr, LM78_EXTENT); + + /* now it's safe to scrap the rest */ + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitely! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_read_value(struct i2c_client *client, u8 reg) +{ + int res; + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + res = inb_p(client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitely! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + outb_p(value, client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM78. It should set limits, etc. */ +static void lm78_init_client(struct i2c_client *client) +{ + struct lm78_data *data = i2c_get_clientdata(client); + int vid; + + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + lm78_write_value(client, LM78_REG_CONFIG, 0x80); + + vid = lm78_read_value(client, LM78_REG_VID_FANDIV) & 0x0f; + if (data->type == lm79) + vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & 0x01) << 4; + else + vid |= 0x10; + vid = VID_FROM_REG(vid); + + lm78_write_value(client, LM78_REG_IN_MIN(0), + IN_TO_REG(LM78_INIT_IN_MIN_0(vid))); + lm78_write_value(client, LM78_REG_IN_MAX(0), + IN_TO_REG(LM78_INIT_IN_MAX_0(vid))); + lm78_write_value(client, LM78_REG_IN_MIN(1), + IN_TO_REG(LM78_INIT_IN_MIN_1(vid))); + lm78_write_value(client, LM78_REG_IN_MAX(1), + IN_TO_REG(LM78_INIT_IN_MAX_1(vid))); + lm78_write_value(client, LM78_REG_IN_MIN(2), + IN_TO_REG(LM78_INIT_IN_MIN_2)); + lm78_write_value(client, LM78_REG_IN_MAX(2), + IN_TO_REG(LM78_INIT_IN_MAX_2)); + lm78_write_value(client, LM78_REG_IN_MIN(3), + IN_TO_REG(LM78_INIT_IN_MIN_3)); + lm78_write_value(client, LM78_REG_IN_MAX(3), + IN_TO_REG(LM78_INIT_IN_MAX_3)); + lm78_write_value(client, LM78_REG_IN_MIN(4), + IN_TO_REG(LM78_INIT_IN_MIN_4)); + lm78_write_value(client, LM78_REG_IN_MAX(4), + IN_TO_REG(LM78_INIT_IN_MAX_4)); + lm78_write_value(client, LM78_REG_IN_MIN(5), + IN_TO_REG(LM78_INIT_IN_MIN_5)); + lm78_write_value(client, LM78_REG_IN_MAX(5), + IN_TO_REG(LM78_INIT_IN_MAX_5)); + lm78_write_value(client, LM78_REG_IN_MIN(6), + IN_TO_REG(LM78_INIT_IN_MIN_6)); + lm78_write_value(client, LM78_REG_IN_MAX(6), + IN_TO_REG(LM78_INIT_IN_MAX_6)); + lm78_write_value(client, LM78_REG_FAN_MIN(0), + FAN_TO_REG(LM78_INIT_FAN_MIN_1, 2)); + lm78_write_value(client, LM78_REG_FAN_MIN(1), + FAN_TO_REG(LM78_INIT_FAN_MIN_2, 2)); + lm78_write_value(client, LM78_REG_FAN_MIN(2), + FAN_TO_REG(LM78_INIT_FAN_MIN_3, 2)); + lm78_write_value(client, LM78_REG_TEMP_OVER, + TEMP_TO_REG(LM78_INIT_TEMP_OVER)); + lm78_write_value(client, LM78_REG_TEMP_HYST, + TEMP_TO_REG(LM78_INIT_TEMP_HYST)); + + /* Start monitoring */ + lm78_write_value(client, LM78_REG_CONFIG, + (lm78_read_value(client, LM78_REG_CONFIG) & 0xf7) + | 0x01); + +} + +static void lm78_update_client(struct i2c_client *client) +{ + struct lm78_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + + dev_dbg(&client->dev, "Starting lm78 update\n"); + + for (i = 0; i <= 6; i++) { + data->in[i] = + lm78_read_value(client, LM78_REG_IN(i)); + data->in_min[i] = + lm78_read_value(client, LM78_REG_IN_MIN(i)); + data->in_max[i] = + lm78_read_value(client, LM78_REG_IN_MAX(i)); + } + for (i = 0; i < 3; i++) { + data->fan[i] = + lm78_read_value(client, LM78_REG_FAN(i)); + data->fan_min[i] = + lm78_read_value(client, LM78_REG_FAN_MIN(i)); + } + data->temp = lm78_read_value(client, LM78_REG_TEMP); + data->temp_over = + lm78_read_value(client, LM78_REG_TEMP_OVER); + data->temp_hyst = + lm78_read_value(client, LM78_REG_TEMP_HYST); + i = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->vid = i & 0x0f; + if (data->type == lm79) + data->vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & + 0x01) << 4; + else + data->vid |= 0x10; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + + (lm78_read_value(client, LM78_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + + data->fan_div[2] = 1; + } + + up(&data->update_lock); +} + +static int __init sm_lm78_init(void) +{ + return i2c_add_driver(&lm78_driver); +} + +static void __exit sm_lm78_exit(void) +{ + i2c_del_driver(&lm78_driver); +} + + + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_lm78_init); +module_exit(sm_lm78_exit); diff --git a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c index cffe8bb66b6..a704f5959b5 100644 --- a/drivers/i2c/chips/lm85.c +++ b/drivers/i2c/chips/lm85.c @@ -148,20 +148,17 @@ static int lm85_scaling[] = { /* .001 Volts */ #define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) #define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)) #define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n])) -/* #define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) -*/ -#define INS_FROM_REG(n,val) ( ( (val*4*lm85_scaling[n]) + (192*4/2) ) / (192*4) ) /* FAN speed is measured using 90kHz clock */ #define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) #define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) -/* Temperature is reported in .01 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127)) -#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25) +/* Temperature is reported in .001 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,-127,127)) +#define TEMPEXT_FROM_REG(val,ext) ((val)*1000 + (ext)*250) #define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0)) -#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/250,-127,127)) #define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) #define PWM_FROM_REG(val) (val) @@ -437,10 +434,13 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->fan_min[nr] = FAN_TO_REG(val); lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); return count; } @@ -528,10 +528,13 @@ static ssize_t set_pwm(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->pwm[nr] = PWM_TO_REG(val); lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); + up(&data->update_lock); return count; } static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) @@ -590,10 +593,13 @@ static ssize_t set_in_min(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->in_min[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); return count; } static ssize_t show_in_max(struct device *dev, char *buf, int nr) @@ -609,10 +615,13 @@ static ssize_t set_in_max(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->in_max[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); return count; } #define show_in_reg(offset) \ @@ -673,10 +682,13 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->temp_min[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); + up(&data->update_lock); return count; } static ssize_t show_temp_max(struct device *dev, char *buf, int nr) @@ -692,10 +704,13 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->temp_max[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); + up(&data->update_lock); return count; } #define show_temp_reg(offset) \ diff --git a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c index 1abf6dd0035..6676a84d78b 100644 --- a/drivers/i2c/chips/w83781d.c +++ b/drivers/i2c/chips/w83781d.c @@ -28,6 +28,7 @@ asb100 "bach" (type_name = as99127f) 0x30 0x0694 yes no w83781d 7 3 0 3 0x10 0x5ca3 yes yes w83627hf 9 3 2 3 0x20 0x5ca3 yes yes(LPC) + w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) @@ -299,8 +300,8 @@ struct w83781d_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ + struct i2c_client *lm75[2]; /* for secondary I2C addresses */ + /* array of 2 pointers to subclients */ u8 in[9]; /* Register value - 8 & 9 for 782D only */ u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ @@ -1043,12 +1044,12 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, const char *client_name; struct w83781d_data *data = i2c_get_clientdata(new_client); - if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), - GFP_KERNEL))) { + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); + memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); id = i2c_adapter_id(adapter); @@ -1066,25 +1067,33 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | ((force_subclients[3] & 0x07) << 4)); - data->lm75[0].addr = force_subclients[2]; + data->lm75[0]->addr = force_subclients[2]; } else { val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); + data->lm75[0]->addr = 0x48 + (val1 & 0x07); } if (kind != w83783s) { + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); + if (force_subclients[0] == id && force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; + data->lm75[1]->addr = force_subclients[3]; } else { - data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); + data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); } - if (data->lm75[0].addr == data->lm75[1].addr) { + if (data->lm75[0]->addr == data->lm75[1]->addr) { dev_err(&new_client->dev, "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); + data->lm75[0]->addr); err = -EBUSY; - goto ERROR_SC_1; + goto ERROR_SC_2; } } @@ -1103,19 +1112,19 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, for (i = 0; i <= 1; i++) { /* store all data in w83781d */ - i2c_set_clientdata(&data->lm75[i], NULL); - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strlcpy(data->lm75[i].dev.name, client_name, + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &w83781d_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->dev.name, client_name, DEVICE_NAME_SIZE); - if ((err = i2c_attach_client(&(data->lm75[i])))) { + if ((err = i2c_attach_client(data->lm75[i]))) { dev_err(&new_client->dev, "Subclient %d " "registration at address 0x%x " - "failed.\n", i, data->lm75[i].addr); + "failed.\n", i, data->lm75[i]->addr); if (i == 1) - goto ERROR_SC_2; - goto ERROR_SC_1; + goto ERROR_SC_3; + goto ERROR_SC_2; } if (kind == w83783s) break; @@ -1124,10 +1133,14 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, return 0; /* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); ERROR_SC_2: - i2c_detach_client(&(data->lm75[0])); + if (NULL != data->lm75[1]) + kfree(data->lm75[1]); ERROR_SC_1: - kfree(data->lm75); + if (NULL != data->lm75[0]) + kfree(data->lm75[0]); ERROR_SC_0: return err; } @@ -1273,7 +1286,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = w83782d; else if (val1 == 0x40 && vendid == winbond && !is_isa) kind = w83783s; - else if (val1 == 0x20 && vendid == winbond) + else if ((val1 == 0x20 || val1 == 0x90) && vendid == winbond) kind = w83627hf; else if (val1 == 0x30 && vendid == asus && !is_isa) kind = as99127f; @@ -1297,7 +1310,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } else if (kind == w83783s) { client_name = "W83783S chip"; } else if (kind == w83627hf) { - client_name = "W83627HF chip"; + if (val1 == 0x90) + client_name = "W83627THF chip"; + else + client_name = "W83627HF chip"; } else if (kind == as99127f) { client_name = "AS99127F chip"; } else if (kind == w83697hf) { @@ -1326,7 +1342,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind, new_client))) goto ERROR3; } else { - data->lm75 = NULL; + data->lm75[0] = NULL; + data->lm75[1] = NULL; } device_create_file_in(new_client, 0); @@ -1409,20 +1426,11 @@ ERROR0: static int w83781d_detach_client(struct i2c_client *client) { - struct w83781d_data *data = i2c_get_clientdata(client); int err; - /* release ISA region or I2C subclients first */ - if (i2c_is_isa_client(client)) { + if (i2c_is_isa_client(client)) release_region(client->addr, W83781D_EXTENT); - } else { - i2c_detach_client(&data->lm75[0]); - if (data->type != w83783s) - i2c_detach_client(&data->lm75[1]); - kfree(data->lm75); - } - /* now it's safe to scrap the rest */ if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); @@ -1484,7 +1492,7 @@ w83781d_read_value(struct i2c_client *client, u16 reg) res = i2c_smbus_read_byte_data(client, reg & 0xff); } else { /* switch to subclient */ - cl = &data->lm75[bank - 1]; + cl = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ @@ -1555,7 +1563,7 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) value & 0xff); } else { /* switch to subclient */ - cl = &data->lm75[bank - 1]; + cl = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x52: /* CONFIG */ diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 5b7d079bf96..3f2405966a1 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -1,8 +1,9 @@ /* - * linux/drivers/ide/pci/sis5513.c Version 0.14ac Sept 11, 2002 + * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 * * Copyright (C) 1999-2000 Andre Hedrick * Copyright (C) 2002 Lionel Bouton , Maintainer + * Copyright (C) 2003 Vojtech Pavlik * May be copied or modified under the terms of the GNU General Public License * * @@ -14,31 +15,33 @@ * for checking code correctness, providing patches. * * - * Original tests and design on the SiS620/5513 chipset. - * ATA100 tests and design on the SiS735/5513 chipset. + * Original tests and design on the SiS620 chipset. + * ATA100 tests and design on the SiS735 chipset. * ATA16/33 support from specs * ATA133 support for SiS961/962 by L.C. Chang + * ATA133 961/962/963 fixes by Vojtech Pavlik * * Documentation: - * SiS chipset documentation available under NDA to companies not - * individuals only. + * SiS chipset documentation available under NDA to companies only + * (not to individuals). */ /* - * Notes/Special cases: - * - SiS5513 derivatives usually have the same PCI IDE register layout when - * supporting the same UDMA modes. - * - There are exceptions : - * . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support - * ATA_100 - * . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously - * south and northbridge were integrated, making IDE (a southbridge function) - * capabilities easily deduced from the northbridge PCI id. With ATA_133, - * chipsets started to be split in the usual north/south bridges chips - * -> the driver needs to detect the correct southbridge when faced to newest - * northbridges. - * . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the - * configuration space is moved from 0x40 to 0x70. + * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original + * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 + * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. + * + * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, + * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We + * can figure out that we have a more modern and more capable 5513 by looking + * for the respective NorthBridge IDs. + * + * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 + * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI + * ID, while the now ATA-133 capable 5513 still has the same PCI ID. + * Fortunately the 5513 can be 'unmasked' by fiddling with some config space + * bits, changing its device id to the true one - 5517 for 961 and 5518 for + * 962/963. */ #include @@ -57,94 +60,23 @@ #include #include -#include #include +#include "ide-timing.h" #include "ide_modes.h" #include "sis5513.h" -/* When DEBUG is defined it outputs initial PCI config register - values and changes made to them by the driver */ -// #define DEBUG -/* When BROKEN_LEVEL is defined it limits the DMA mode - at boot time to its value */ -// #define BROKEN_LEVEL XFER_SW_DMA_0 - -/* Miscellaneous flags */ -#define SIS5513_LATENCY 0x01 - /* registers layout and init values are chipset family dependant */ -/* 1/ define families */ -#define ATA_00 0x00 + #define ATA_16 0x01 #define ATA_33 0x02 #define ATA_66 0x03 -#define ATA_100a 0x04 // SiS730 is ATA100 with ATA66 layout +#define ATA_100a 0x04 // SiS730/SiS550 is ATA100 with ATA66 layout #define ATA_100 0x05 #define ATA_133a 0x06 // SiS961b with 133 support -#define ATA_133 0x07 // SiS962 -/* 2/ variable holding the controller chipset family value */ -static u8 chipset_family; - - -/* - * Debug code: following IDE config registers' changes - */ -#ifdef DEBUG -/* Copy of IDE Config registers fewer will be used - * Some odd chipsets hang if unused registers are accessed - * -> We only access them in #DEBUG code (then we'll see if SiS did - * it right from day one) */ -static u8 ide_regs_copy[0xff]; - -/* Read config registers, print differences from previous read */ -static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) { - int i; - u8 reg_val; - u8 changed=0; - - printk("SIS5513: %s, changed registers:\n", info); - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, ®_val); - if (reg_val != ide_regs_copy[i]) { - printk("%02x: %02x -> %02x\n", - i, ide_regs_copy[i], reg_val); - ide_regs_copy[i]=reg_val; - changed=1; - } - } - - if (!changed) { - printk("none\n"); - } -} - -/* Load config registers, no printing */ -static void sis5513_load_registers(struct pci_dev* dev) { - int i; - - for(i=0; i<=0xff; i++) { - pci_read_config_byte(dev, i, &(ide_regs_copy[i])); - } -} - -/* Print config space registers a la "lspci -vxxx" */ -static void sis5513_print_registers(struct pci_dev* dev, char* marker) { - int i,j; - - sis5513_load_registers(dev); - printk("SIS5513 %s\n", marker); - - for(i=0; i<=0xf; i++) { - printk("SIS5513 dump: %d" "0:", i); - for(j=0; j<=0xf; j++) { - printk(" %02x", ide_regs_copy[(i<<16)+j]); - } - printk("\n"); - } -} -#endif +#define ATA_133 0x07 // SiS962/963 +static u8 chipset_family; /* * Devices supported @@ -155,42 +87,38 @@ static const struct { u8 chipset_family; u8 flags; } SiSHostChipInfo[] = { - { "SiS752", PCI_DEVICE_ID_SI_752, ATA_133, 0 }, - { "SiS751", PCI_DEVICE_ID_SI_751, ATA_133, 0 }, - { "SiS750", PCI_DEVICE_ID_SI_750, ATA_133, 0 }, - { "SiS748", PCI_DEVICE_ID_SI_748, ATA_133, 0 }, - { "SiS746", PCI_DEVICE_ID_SI_746, ATA_133, 0 }, - { "SiS745", PCI_DEVICE_ID_SI_745, ATA_133, 0 }, - { "SiS740", PCI_DEVICE_ID_SI_740, ATA_133, 0 }, - { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100, SIS5513_LATENCY }, - { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a, SIS5513_LATENCY }, - { "SiS655", PCI_DEVICE_ID_SI_655, ATA_133, 0 }, - { "SiS652", PCI_DEVICE_ID_SI_652, ATA_133, 0 }, - { "SiS651", PCI_DEVICE_ID_SI_651, ATA_133, 0 }, - { "SiS650", PCI_DEVICE_ID_SI_650, ATA_133, 0 }, - { "SiS648", PCI_DEVICE_ID_SI_648, ATA_133, 0 }, - { "SiS646", PCI_DEVICE_ID_SI_646, ATA_133, 0 }, - { "SiS645", PCI_DEVICE_ID_SI_645, ATA_133, 0 }, - { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100, SIS5513_LATENCY }, - { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66, SIS5513_LATENCY }, - { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66, SIS5513_LATENCY }, - { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66, SIS5513_LATENCY }, - { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a, 0}, - { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66, 0}, - { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66, 0}, - { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33, 0}, - { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33, 0}, - { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33, 0}, - { "SiS5591", PCI_DEVICE_ID_SI_5591, ATA_33, 0}, - { "SiS5513", PCI_DEVICE_ID_SI_5513, ATA_16, 0}, - { "SiS5511", PCI_DEVICE_ID_SI_5511, ATA_16, 0}, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, + { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, + { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, + { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, + { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, + + { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, + { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, + + { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, + { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, + { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, + { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, + { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, + + { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, + { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, + { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, + { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, + { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, + { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, + + { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, + { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, + { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, }; /* Cycle time bits and values vary across chip dma capabilities These three arrays hold the register layout and the values to set. Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ -/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ +/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { @@ -249,8 +177,6 @@ static u8 rco_time_value[][8] = { {40,12,4,12,5,34,12,5}, }; -static struct pci_dev *host_dev = NULL; - /* * Printing configuration */ @@ -334,6 +260,7 @@ static char* get_drives_info (char *buffer, u8 pos) } pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, ®dw0); pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, ®dw1); + p += sprintf(p, "Drive %d:\n", pos); } @@ -372,11 +299,12 @@ static char* get_drives_info (char *buffer, u8 pos) p += sprintf(p, "\n"); } - if (chipset_family < ATA_133) { /* else case TODO */ + + if (chipset_family < ATA_133) { /* else case TODO */ + /* Data Active */ p += sprintf(p, " Data Active Time "); switch(chipset_family) { - case ATA_00: case ATA_16: /* confirmed */ case ATA_33: case ATA_66: @@ -387,7 +315,6 @@ static char* get_drives_info (char *buffer, u8 pos) } p += sprintf(p, " \t Data Active Time "); switch(chipset_family) { - case ATA_00: case ATA_16: case ATA_33: case ATA_66: @@ -493,39 +420,16 @@ static int sis_get_info (char *buffer, char **addr, off_t offset, int count) len = (p - buffer) - offset; *addr = buffer + offset; - + return len > count ? count : len; } #endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ static u8 sis5513_ratemask (ide_drive_t *drive) { -#if 0 u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 }; u8 mode = rates[chipset_family]; -#else - u8 mode; - switch(chipset_family) { - case ATA_133: - case ATA_133a: - mode = 4; - break; - case ATA_100: - case ATA_100a: - mode = 3; - break; - case ATA_66: - mode = 2; - break; - case ATA_33: - return 1; - case ATA_16: - case ATA_00: - default: - return 0; - } -#endif if (!eighty_ninty_three(drive)) mode = min(mode, (u8)1); return mode; @@ -543,20 +447,12 @@ static void config_drive_art_rwp (ide_drive_t *drive) u8 reg4bh = 0; u8 rw_prefetch = (0x11 << drive->dn); -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn); - sis5513_load_verify_registers(dev, "config_drive_art_rwp start"); -#endif - if (drive->media != ide_disk) return; pci_read_config_byte(dev, 0x4b, ®4bh); if ((reg4bh & rw_prefetch) != rw_prefetch) pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp end"); -#endif } @@ -571,10 +467,6 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; u16 xfer_pio = drive->id->eide_pio_modes; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif - config_drive_art_rwp(drive); pio = ide_get_best_pio_mode(drive, 255, pio, NULL); @@ -594,12 +486,6 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) timing = (xfer_pio >= pio) ? xfer_pio : pio; -#ifdef DEBUG - printk("SIS5513: config_drive_art_rwp_pio, " - "drive %d, pio %d, timing %d\n", - drive->dn, pio, timing); -#endif - /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ drive_pci = 0x40; /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */ @@ -645,41 +531,24 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) pci_read_config_dword(dev, drive_pci, &test3); test3 &= 0xc0c00fff; if (test3 & 0x08) { - test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; } else { - test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24; + test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; + test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; + test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; } pci_write_config_dword(dev, drive_pci, test3); } - -#ifdef DEBUG - sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start"); -#endif } static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) { -#if 0 - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, (XFER_PIO_0 + pio)); -#else - u8 speed; - - switch(pio) { - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: speed = XFER_PIO_0; break; - } - + if (pio == 255) + pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, speed); -#endif + return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); } static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) @@ -690,24 +559,8 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) u8 drive_pci, reg, speed; u32 regdw; -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset start"); -#endif - -#ifdef BROKEN_LEVEL -#ifdef DEBUG - printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL); -#endif - if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL; -#endif - speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed); -#ifdef DEBUG - printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n", - drive->dn, xferspeed); -#endif - /* See config_art_rwp_pio for drive pci config registers */ drive_pci = 0x40; if (chipset_family >= ATA_133) { @@ -746,14 +599,14 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) regdw &= 0xfffff00f; /* check if ATA133 enable */ if (regdw & 0x08) { - regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; } else { /* if ATA133 disable, we should not set speed above UDMA5 */ if (speed > XFER_UDMA_5) speed = XFER_UDMA_5; - regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8; + regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; } pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); } else { @@ -763,7 +616,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) << cycle_time_offset[chipset_family]); /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0] + reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] << cycle_time_offset[chipset_family]; pci_write_config_byte(dev, drive_pci+1, reg); } @@ -782,9 +635,7 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) case XFER_PIO_0: default: return((int) config_chipset_for_pio(drive, 0)); } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "sis5513_tune_chipset end"); -#endif + return ((int) ide_config_drive_speed(drive, speed)); } @@ -863,18 +714,34 @@ static int sis5513_config_xfer_rate (ide_drive_t *drive) return sis5513_config_drive_xfer_rate(drive); } -/* Helper function used at init time - * returns a PCI device revision ID - * (used to detect different IDE controller versions) - */ -static u8 __init devfn_rev(int device, int function) +/* + Future simpler config_xfer_rate : + When ide_find_best_mode is made bad-drive aware + - remove config_drive_xfer_rate and config_chipset_for_dma, + - replace config_xfer_rate with the following + +static int sis5513_config_xfer_rate (ide_drive_t *drive) { - u8 revision; - /* Find device */ - struct pci_dev* dev = pci_find_slot(0,PCI_DEVFN(device,function)); - pci_read_config_byte(dev, PCI_REVISION_ID, &revision); - return revision; + u16 w80 = HWIF(drive)->udma_four; + u16 speed; + + config_drive_art_rwp(drive); + config_art_rwp_pio(drive, 5); + + speed = ide_find_best_mode(drive, + XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | + (chipset_family >= ATA_33 ? XFER_UDMA : 0) | + (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | + (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | + (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); + + sis5513_tune_chipset(drive, speed); + + if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) + return HWIF(drive)->ide_dma_on(drive); + return HWIF(drive)->ide_dma_off_quietly(drive); } +*/ /* Chip detection and general config */ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name) @@ -882,71 +749,86 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char struct pci_dev *host; int i = 0; - /* Find the chip */ - for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) { - host = pci_find_device (PCI_VENDOR_ID_SI, - SiSHostChipInfo[i].host_id, - NULL); + chipset_family = 0; + + for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { + + host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); + if (!host) continue; - host_dev = host; chipset_family = SiSHostChipInfo[i].chipset_family; + + /* Special case for SiS630 : 630S/ET is ATA_100a */ + if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { + u8 hostrev; + pci_read_config_byte(host, PCI_REVISION_ID, &hostrev); + if (hostrev >= 0x30) + chipset_family = ATA_100a; + } - /* check 100/133 chipset family */ - if (chipset_family == ATA_133) { - u32 reg54h; - u16 devid; - pci_read_config_dword(dev, 0x54, ®54h); - /* SiS962 and above report 0x5518 dev id if high bit is cleared */ - pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff)); - pci_read_config_word(dev, 0x02, &devid); - /* restore register 0x54 */ - pci_write_config_dword(dev, 0x54, reg54h); - - /* devid 5518 here means SiS962 or later - which supports ATA133. - These are refered by chipset_family = ATA133 - */ - if (devid != 0x5518) { - u8 reg49h; - /* SiS961 family */ - pci_read_config_byte(dev, 0x49, ®49h); - /* check isa bridge device rev id */ - if (((devfn_rev(2,0) & 0xff) == 0x10) && (reg49h & 0x80)) - chipset_family = ATA_133a; - else - chipset_family = ATA_100; + printk(KERN_INFO "SIS5513: %s %s controller\n", + SiSHostChipInfo[i].name, chipset_capability[chipset_family]); + } + + if (!chipset_family) { /* Belongs to pci-quirks */ + + u32 idemisc; + u16 trueid; + + /* Disable ID masking and register remapping */ + pci_read_config_dword(dev, 0x54, &idemisc); + pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_dword(dev, 0x54, idemisc); + + if (trueid == 0x5518) { + printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133; } - } - printk(SiSHostChipInfo[i].name); - printk(" %s controller", chipset_capability[chipset_family]); - printk("\n"); + } -#ifdef DEBUG - sis5513_print_registers(dev, "pci_init_sis5513 start"); -#endif + if (!chipset_family) { /* Belongs to pci-quirks */ - if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) { - u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency); - } + struct pci_dev *lpc_bridge; + u16 trueid; + u8 prefctl; + u8 idecfg; + u8 sbrev; - /* Special case for SiS630 : 630S/ET is ATA_100a */ - if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { - /* check host device rev id */ - if (devfn_rev(0,0) >= 0x30) { - chipset_family = ATA_100a; + pci_read_config_byte(dev, 0x4a, &idecfg); + pci_write_config_byte(dev, 0x4a, idecfg | 0x10); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_byte(dev, 0x4a, idecfg); + + if (trueid == 0x5517) { /* SiS 961/961B */ + + lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */ + pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); + pci_read_config_byte(dev, 0x49, &prefctl); + + if (sbrev == 0x10 && (prefctl & 0x80)) { + printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n"); + chipset_family = ATA_133a; + } else { + printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n"); + chipset_family = ATA_100; + } } - } } + if (!chipset_family) + return -1; + /* Make general config ops here 1/ tell IDE channels to operate in Compatibility mode only 2/ tell old chips to allow per drive IDE timings */ - if (host_dev) { + + { u8 reg; u16 regw; + switch(chipset_family) { case ATA_133: /* SiS962 operation mode */ @@ -959,6 +841,8 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char break; case ATA_133a: case ATA_100: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); /* Set compatibility bit */ pci_read_config_byte(dev, 0x49, ®); if (!(reg & 0x01)) { @@ -967,6 +851,9 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char break; case ATA_100a: case ATA_66: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + /* On ATA_66 chips the bit was elsewhere */ pci_read_config_byte(dev, 0x52, ®); if (!(reg & 0x04)) { @@ -987,8 +874,6 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char pci_write_config_byte(dev, 0x52, reg|0x08); } break; - case ATA_00: - default: break; } #if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) @@ -999,9 +884,7 @@ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char } #endif } -#ifdef DEBUG - sis5513_load_verify_registers(dev, "pci_init_sis5513 end"); -#endif + return 0; } @@ -1044,7 +927,7 @@ static void __init init_hwif_sis5513 (ide_hwif_t *hwif) hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (!host_dev) + if (!chipset_family) return; if (!(hwif->udma_four)) @@ -1102,19 +985,16 @@ static void sis5513_ide_exit(void) module_init(sis5513_ide_init); module_exit(sis5513_ide_exit); -MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick"); +MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); MODULE_DESCRIPTION("PCI driver module for SIS IDE"); MODULE_LICENSE("GPL"); /* * TODO: - * - Get ridden of SisHostChipInfo[] completness dependancy. - * - Study drivers/ide/ide-timing.h. - * - Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them - * or remove ATA_00 define + * - CLEANUP + * - Use drivers/ide/ide-timing.h ! * - More checks in the config registers (force values instead of * relying on the BIOS setting them correctly). * - Further optimisations ? * . for example ATA66+ regs 0x48 & 0x4A */ - diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index a4875b4c0d4..6db114d1641 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -707,7 +707,7 @@ static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host) return hi; /* Register our host with the SCSI stack. */ - scsi_host = scsi_register (&scsi_driver_template, 0); + scsi_host = scsi_host_alloc(&scsi_driver_template, 0); if (!scsi_host) { SBP2_ERR("failed to register scsi host"); return NULL; @@ -716,7 +716,7 @@ static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host) hi = hpsb_create_hostinfo(&sbp2_highlevel, host, sizeof(*hi)); if (!hi) { SBP2_ERR("failed to allocate hostinfo"); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); } hpsb_set_hostinfo_key(&sbp2_highlevel, host, (unsigned long)scsi_host); @@ -732,7 +732,7 @@ static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host) * enabled (scsi-host uses classdata member of the device). */ if (scsi_add_host(hi->scsi_host, NULL)) { SBP2_ERR("failed to add scsi host"); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); hpsb_destroy_hostinfo(&sbp2_highlevel, host); } @@ -753,7 +753,7 @@ static void sbp2_remove_host(struct hpsb_host *host) if (hi) { scsi_remove_host(hi->scsi_host); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); } } diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index c26dea75fb7..431883c5faa 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -84,6 +84,7 @@ static int gameport_measure_speed(struct gameport *gameport) if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t; } + gameport_close(gameport); return 59659 / (tx < 1 ? 1 : tx); #else @@ -93,11 +94,10 @@ static int gameport_measure_speed(struct gameport *gameport) j = jiffies; while (j == jiffies); j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); } + gameport_close(gameport); return t * HZ / 1000; #endif - - gameport_close(gameport); } static void gameport_find_dev(struct gameport *gameport) diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index f8245f98d76..ec5ece71ab6 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -46,6 +46,7 @@ MODULE_LICENSE("GPL"); MODULE_PARM(gc, "2-6i"); MODULE_PARM(gc_2,"2-6i"); MODULE_PARM(gc_3,"2-6i"); +MODULE_PARM(gc_psx_delay, "i"); #define GC_SNES 1 #define GC_NES 2 @@ -213,7 +214,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) * */ -#define GC_PSX_DELAY 60 /* 60 usec */ +#define GC_PSX_DELAY 25 /* 25 usec */ #define GC_PSX_LENGTH 8 /* talk to the controller in bytes */ #define GC_PSX_MOUSE 1 /* Mouse */ @@ -230,6 +231,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) #define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */ #define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */ +static int gc_psx_delay = GC_PSX_DELAY; static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; @@ -246,10 +248,10 @@ static int gc_psx_command(struct gc *gc, int b) for (i = 0; i < 8; i++, b >>= 1) { cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); - udelay(GC_PSX_DELAY); + udelay(gc_psx_delay); data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); - udelay(GC_PSX_DELAY); + udelay(gc_psx_delay); } return data; } @@ -265,9 +267,9 @@ static int gc_psx_read_packet(struct gc *gc, unsigned char *data) unsigned long flags; parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(GC_PSX_DELAY * 2); + udelay(gc_psx_delay * 2); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ - udelay(GC_PSX_DELAY * 2); + udelay(gc_psx_delay * 2); local_irq_save(flags); @@ -649,9 +651,15 @@ static int __init gc_setup_3(char *str) for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1]; return 1; } +static int __init gc_psx_setup(char *str) +{ + get_option(&str, &gc_psx_delay); + return 1; +} __setup("gc=", gc_setup); __setup("gc_2=", gc_setup_2); __setup("gc_3=", gc_setup_3); +__setup("gc_psx_delay=", gc_psx_setup); #endif int __init gc_init(void) diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 23bc5f96a90..af8263e0221 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -378,10 +378,10 @@ static int sw_parse(unsigned char *buf, struct sw *sw) for (j = 0; j < 6; j++) input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1)); - input_report_key(dev, BTN_TR, GB(26,1)); - input_report_key(dev, BTN_START, GB(27,1)); - input_report_key(dev, BTN_MODE, GB(38,1)); - input_report_key(dev, BTN_SELECT, GB(39,1)); + input_report_key(dev, BTN_TR, !GB(26,1)); + input_report_key(dev, BTN_START, !GB(27,1)); + input_report_key(dev, BTN_MODE, !GB(38,1)); + input_report_key(dev, BTN_SELECT, !GB(39,1)); input_sync(dev); @@ -602,7 +602,6 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev) gameport->phys, gameport->io, gameport->speed); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ - m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */ udelay(SW_TIMEOUT); dbg("Init 1: Mode %d. Length %d.", m , i); @@ -676,6 +675,8 @@ static void sw_connect(struct gameport *gameport, struct gameport_dev *dev) } else sw->type = SW_ID_PP; break; + case 66: + sw->bits = 3; case 198: sw->length = 22; case 64: diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 367587382e2..56a514ae145 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -89,7 +89,7 @@ static unsigned char atkbd_set3_keycode[512] = { #define ATKBD_CMD_GETID 0x02f2 #define ATKBD_CMD_ENABLE 0x00f4 #define ATKBD_CMD_RESET_DIS 0x00f5 -#define ATKBD_CMD_RESET_BAT 0x01ff +#define ATKBD_CMD_RESET_BAT 0x02ff #define ATKBD_CMD_SETALL_MB 0x00f8 #define ATKBD_CMD_RESEND 0x00fe #define ATKBD_CMD_EX_ENABLE 0x10ea @@ -255,7 +255,8 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) while (atkbd->cmdcnt && timeout--) { - if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_RESET_BAT) + if (atkbd->cmdcnt == 1 && + command == ATKBD_CMD_RESET_BAT && timeout > 100000) timeout = 100000; if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && @@ -271,6 +272,9 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; + if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) + atkbd->cmdcnt = 0; + if (atkbd->cmdcnt) { atkbd->cmdcnt = 0; return -1; diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2d10fcffdd6..bcf30aa5930 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -49,11 +49,11 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i udev = (struct uinput_device *)dev->private; - udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; udev->buff[udev->head].type = type; udev->buff[udev->head].code = code; udev->buff[udev->head].value = value; do_gettimeofday(&udev->buff[udev->head].time); + udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; wake_up_interruptible(&udev->waitq); @@ -82,6 +82,7 @@ static int uinput_create_device(struct uinput_device *udev) udev->dev->event = uinput_dev_event; udev->dev->upload_effect = uinput_dev_upload_effect; udev->dev->erase_effect = uinput_dev_erase_effect; + udev->dev->private = udev; init_waitqueue_head(&(udev->waitq)); @@ -264,7 +265,7 @@ static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t return -ENODEV; while ((udev->head != udev->tail) && - (retval + sizeof(struct uinput_device) <= count)) { + (retval + sizeof(struct input_event) <= count)) { if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), sizeof(struct input_event))) return -EFAULT; udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index e1d5332a15c..68ca6d745b8 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -19,7 +19,9 @@ config MOUSE_PS2 Say Y here if you have a PS/2 mouse connected to your system. This includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 mice with wheels and extra buttons, Microsoft, Logitech or Genius - compatible. + compatible. Support for Synaptics TouchPads is also included. + For Synaptics TouchPad support in XFree86 you'll need this XFree86 + driver: http://w1.894.telia.com/~u89404340/touchpad/index.html If unsure, say Y. @@ -28,19 +30,6 @@ config MOUSE_PS2 The module will be called psmouse. If you want to compile it as a module, say M here and read . -config MOUSE_PS2_SYNAPTICS - bool "Synaptics TouchPad" - default n - depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2 - ---help--- - Say Y here if you have a Synaptics TouchPad connected to your system. - This touchpad is found on many modern laptop computers. - Note that you also need a user space driver to interpret the data - generated by the kernel. A compatible driver for XFree86 is available - from http://... - - If unsure, say Y. - config MOUSE_SERIAL tristate "Serial mouse" depends on INPUT && INPUT_MOUSE && SERIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 6a52702cb1c..8c1b9008772 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -14,7 +14,4 @@ obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o -psmouse-objs := psmouse-base.o -ifeq ($(CONFIG_MOUSE_PS2_SYNAPTICS),y) - psmouse-objs += synaptics.o -endif +psmouse-objs := psmouse-base.o logips2pp.o synaptics.o diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c new file mode 100644 index 00000000000..ce5d80c854f --- /dev/null +++ b/drivers/input/mouse/logips2pp.c @@ -0,0 +1,228 @@ +/* + * Logitech PS/2++ mouse driver + * + * Copyright (c) 1999-2003 Vojtech Pavlik + * Copyright (c) 2003 Eric Wong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include "psmouse.h" +#include "logips2pp.h" + +/* + * Process a PS2++ or PS2T++ packet. + */ + +void ps2pp_process_packet(struct psmouse *psmouse) +{ + struct input_dev *dev = &psmouse->dev; + unsigned char *packet = psmouse->packet; + + if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { + + switch ((packet[1] >> 4) | (packet[0] & 0x30)) { + + case 0x0d: /* Mouse extra info */ + + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 8) - (int) (packet[2] & 7)); + input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + + break; + + case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ + + input_report_key(dev, BTN_SIDE, (packet[2]) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); + input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); + input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); + + break; + + case 0x0f: /* TouchPad extra info */ + + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); + packet[0] = packet[2] | 0x08; + break; + +#ifdef DEBUG + default: + printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); +#endif + } + + packet[0] &= 0x0f; + packet[1] = 0; + packet[2] = 0; + + } +} + +/* + * ps2pp_cmd() sends a PS2++ command, sliced into two bit + * pieces through the SETRES command. This is needed to send extended + * commands to mice on notebooks that try to understand the PS/2 protocol + * Ugly. + */ + +static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) +{ + unsigned char d; + int i; + + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + d = (command >> i) & 3; + if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) + return -1; + + return 0; +} + +/* + * SmartScroll / CruiseControl for some newer Logitech mice Defaults to + * enabled if we do nothing to it. Of course I put this in because I want it + * disabled :P + * 1 - enabled (if previously disabled, also default) + * 0/2 - disabled + */ + +static void ps2pp_set_smartscroll(struct psmouse *psmouse) +{ + unsigned char param[4]; + + ps2pp_cmd(psmouse, param, 0x32); + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + + if (psmouse_smartscroll == 1) + param[0] = 1; + else + if (psmouse_smartscroll > 2) + return; + + /* else leave param[0] == 0 to disable */ + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); +} + +/* + * Support 800 dpi resolution _only_ if the user wants it (there are good + * reasons to not use it even if the mouse supports it, and of course there are + * also good reasons to use it, let the user decide). + */ + +void ps2pp_set_800dpi(struct psmouse *psmouse) +{ + unsigned char param = 3; + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES); +} + +/* + * Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or + * touchpad. + */ + +int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) +{ + int i; + static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; + static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 }; + static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, + 76, 80, 81, 83, 88, 96, 97, 112, -1 }; + static int logitech_mx[] = { 112, -1 }; + + psmouse->vendor = "Logitech"; + psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); + + if (param[1] < 3) + clear_bit(BTN_MIDDLE, psmouse->dev.keybit); + if (param[1] < 2) + clear_bit(BTN_RIGHT, psmouse->dev.keybit); + + psmouse->type = PSMOUSE_PS2; + + for (i = 0; logitech_ps2pp[i] != -1; i++) + if (logitech_ps2pp[i] == psmouse->model) + psmouse->type = PSMOUSE_PS2PP; + + if (psmouse->type == PSMOUSE_PS2PP) { + + for (i = 0; logitech_4btn[i] != -1; i++) + if (logitech_4btn[i] == psmouse->model) + set_bit(BTN_SIDE, psmouse->dev.keybit); + + for (i = 0; logitech_wheel[i] != -1; i++) + if (logitech_wheel[i] == psmouse->model) { + set_bit(REL_WHEEL, psmouse->dev.relbit); + psmouse->name = "Wheel Mouse"; + } + + for (i = 0; logitech_mx[i] != -1; i++) + if (logitech_mx[i] == psmouse->model) { + set_bit(BTN_SIDE, psmouse->dev.keybit); + set_bit(BTN_EXTRA, psmouse->dev.keybit); + set_bit(BTN_BACK, psmouse->dev.keybit); + set_bit(BTN_FORWARD, psmouse->dev.keybit); + set_bit(BTN_TASK, psmouse->dev.keybit); + psmouse->name = "MX Mouse"; + } + +/* + * Do Logitech PS2++ / PS2T++ magic init. + */ + + if (psmouse->model == 97) { /* TouchPad 3 */ + + set_bit(REL_WHEEL, psmouse->dev.relbit); + set_bit(REL_HWHEEL, psmouse->dev.relbit); + + param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ + psmouse_command(psmouse, param, 0x30d1); + param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ + psmouse_command(psmouse, param, 0x30d1); + + param[0] = 0; + if (!psmouse_command(psmouse, param, 0x13d1) && + param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { + psmouse->name = "TouchPad 3"; + return PSMOUSE_PS2TPP; + } + + } else { + + param[0] = param[1] = param[2] = 0; + ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ + ps2pp_cmd(psmouse, param, 0xDB); + + if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && + (param[2] & 3) == ((param[1] >> 2) & 3)) { + ps2pp_set_smartscroll(psmouse); + return PSMOUSE_PS2PP; + } + } + } + + return 0; +} diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h new file mode 100644 index 00000000000..8eb50abefb0 --- /dev/null +++ b/drivers/input/mouse/logips2pp.h @@ -0,0 +1,17 @@ +/* + * Logitech PS/2++ mouse driver header + * + * Copyright (c) 2003 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _LOGIPS2PP_H +#define _LOGIPS2PP_H +struct psmouse; +void ps2pp_process_packet(struct psmouse *psmouse); +void ps2pp_set_800dpi(struct psmouse *psmouse); +int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param); +#endif diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index e7d699c52fc..030d23149e2 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -19,13 +19,23 @@ #include #include "psmouse.h" #include "synaptics.h" +#include "logips2pp.h" MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PS/2 mouse driver"); MODULE_PARM(psmouse_noext, "1i"); +MODULE_PARM_DESC(psmouse_noext, "Disable any protocol extensions. Useful for KVM switches."); +MODULE_PARM(psmouse_resolution, "i"); +MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi."); +MODULE_PARM(psmouse_smartscroll, "i"); +MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); MODULE_LICENSE("GPL"); +#define PSMOUSE_LOGITECH_SMARTSCROLL 1 + static int psmouse_noext; +int psmouse_resolution; +int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL; static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"}; @@ -45,43 +55,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs * The PS2++ protocol is a little bit complex */ - if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) { - - if ((packet[0] & 0x40) == 0x40 && abs((int)packet[1] - (((int)packet[0] & 0x10) << 4)) > 191 ) { - - switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c)) { - - case 1: /* Mouse extra info */ - - input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 8) - (int) (packet[2] & 7)); - input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); - - break; - - case 3: /* TouchPad extra info */ - - input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); - packet[0] = packet[2] | 0x08; - - break; - -#ifdef DEBUG - default: - printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", - ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0x0c)); -#endif - - } - - packet[0] &= 0x0f; - packet[1] = 0; - packet[2] = 0; - - } - } + if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) + ps2pp_process_packet(psmouse); /* * Scroll wheel on IntelliMice, scroll buttons on NetMice @@ -259,33 +234,6 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) } /* - * psmouse_ps2pp_cmd() sends a PS2++ command, sliced into two bit - * pieces through the SETRES command. This is needed to send extended - * commands to mice on notebooks that try to understand the PS/2 protocol - * Ugly. - */ - -static int psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) -{ - unsigned char d; - int i; - - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) - return -1; - - for (i = 6; i >= 0; i -= 2) { - d = (command >> i) & 3; - if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - - if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) - return -1; - - return 0; -} - -/* * psmouse_extensions() probes for any extensions to the basic PS/2 protocol * the mouse may have. */ @@ -353,73 +301,13 @@ static int psmouse_extensions(struct psmouse *psmouse) psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); + param[1] = 0; psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); if (param[1]) { - - int i; - static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; - static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, -1 }; - static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75, - 76, 80, 81, 83, 88, 96, 97, -1 }; - psmouse->vendor = "Logitech"; - psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); - - if (param[1] < 3) - clear_bit(BTN_MIDDLE, psmouse->dev.keybit); - if (param[1] < 2) - clear_bit(BTN_RIGHT, psmouse->dev.keybit); - - psmouse->type = PSMOUSE_PS2; - - for (i = 0; logitech_ps2pp[i] != -1; i++) - if (logitech_ps2pp[i] == psmouse->model) - psmouse->type = PSMOUSE_PS2PP; - - if (psmouse->type == PSMOUSE_PS2PP) { - - for (i = 0; logitech_4btn[i] != -1; i++) - if (logitech_4btn[i] == psmouse->model) - set_bit(BTN_SIDE, psmouse->dev.keybit); - - for (i = 0; logitech_wheel[i] != -1; i++) - if (logitech_wheel[i] == psmouse->model) { - set_bit(REL_WHEEL, psmouse->dev.relbit); - psmouse->name = "Wheel Mouse"; - } - -/* - * Do Logitech PS2++ / PS2T++ magic init. - */ - - if (psmouse->model == 97) { /* TouchPad 3 */ - - set_bit(REL_WHEEL, psmouse->dev.relbit); - set_bit(REL_HWHEEL, psmouse->dev.relbit); - - param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ - psmouse_command(psmouse, param, 0x30d1); - param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ - psmouse_command(psmouse, param, 0x30d1); - - param[0] = 0; - if (!psmouse_command(psmouse, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) - return PSMOUSE_PS2TPP; - - } else { - param[0] = param[1] = param[2] = 0; - - psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ - psmouse_ps2pp_cmd(psmouse, param, 0xDB); - - if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && - (param[2] & 3) == ((param[1] >> 2) & 3)) - return PSMOUSE_PS2PP; - } - } + int type = ps2pp_detect_model(psmouse, param); + if (type) + return type; } /* @@ -508,6 +396,31 @@ static int psmouse_probe(struct psmouse *psmouse) } /* + * Here we set the mouse resolution. + */ + +static void psmouse_set_resolution(struct psmouse *psmouse) +{ + unsigned char param[1]; + + if (psmouse->type == PSMOUSE_PS2PP && psmouse_resolution > 400) { + ps2pp_set_800dpi(psmouse); + return; + } + + if (!psmouse_resolution || psmouse_resolution >= 200) + param[0] = 3; + else if (psmouse_resolution >= 100) + param[0] = 2; + else if (psmouse_resolution >= 50) + param[0] = 1; + else if (psmouse_resolution) + param[0] = 0; + + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); +} + +/* * psmouse_initialize() initializes the mouse to a sane state. */ @@ -519,7 +432,6 @@ static void psmouse_initialize(struct psmouse *psmouse) * We set the mouse report rate to a highest possible value. * We try 100 first in case mouse fails to set 200. */ - param[0] = 100; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); @@ -530,8 +442,7 @@ static void psmouse_initialize(struct psmouse *psmouse) * We also set the resolution and scaling. */ - param[0] = 3; - psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_set_resolution(psmouse); psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); /* @@ -638,12 +549,28 @@ static struct serio_dev psmouse_dev = { }; #ifndef MODULE -static int __init psmouse_setup(char *str) +static int __init psmouse_noext_setup(char *str) { psmouse_noext = 1; return 1; } -__setup("psmouse_noext", psmouse_setup); + +static int __init psmouse_resolution_setup(char *str) +{ + get_option(&str, &psmouse_resolution); + return 1; +} + +static int __init psmouse_smartscroll_setup(char *str) +{ + get_option(&str, &psmouse_smartscroll); + return 1; +} + +__setup("psmouse_noext", psmouse_noext_setup); +__setup("psmouse_resolution=", psmouse_resolution_setup); +__setup("psmouse_smartscroll=", psmouse_smartscroll_setup); + #endif int __init psmouse_init(void) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index f2e9baa53d3..05a24de18d7 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -46,4 +46,6 @@ struct psmouse { int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); +extern int psmouse_smartscroll; + #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 73ced749126..5fa695eb774 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -171,9 +171,9 @@ static void print_ident(struct synaptics_data *priv) static int query_hardware(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - int retries = 3; + int retries = 0; - while ((retries++ <= 3) && synaptics_reset(psmouse)) + while ((retries++ < 3) && synaptics_reset(psmouse)) printk(KERN_ERR "synaptics reset failed\n"); if (synaptics_identify(psmouse, &priv->identity)) @@ -266,8 +266,7 @@ void synaptics_disconnect(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_parse_hw_state(struct synaptics_data *priv, - struct synaptics_hw_state *hw) +static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw) { unsigned char *buf = priv->proto_buf; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 4acaff4ef07..6e3e029a3bd 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -9,21 +9,11 @@ #ifndef _SYNAPTICS_H #define _SYNAPTICS_H -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs); extern int synaptics_init(struct psmouse *psmouse); extern void synaptics_disconnect(struct psmouse *psmouse); -#else - -static inline void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) {} -static inline int synaptics_init(struct psmouse *psmouse) { return -1; } -static inline void synaptics_disconnect(struct psmouse *psmouse) {} - -#endif - - /* synaptics queries */ #define SYN_QUE_IDENTIFY 0x00 #define SYN_QUE_MODES 0x01 diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 297103a968d..7112bdcda8f 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -1,7 +1,7 @@ /* - * linux/drivers/input/serio/amba_kmi.c + * linux/drivers/input/serio/ambakmi.c * - * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd. * Copyright (C) 2002 Russell King. * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include #include +#include #include #define KMI_BASE (kmi->base) @@ -28,11 +29,10 @@ struct amba_kmi_port { struct serio io; struct amba_kmi_port *next; - void *base; + unsigned char *base; unsigned int irq; unsigned int divisor; - char name[32]; - char phys[16]; + unsigned int open; struct resource *res; }; @@ -73,7 +73,7 @@ static int amba_kmi_open(struct serio *io) writeb(kmi->divisor, KMICLKDIV); writeb(KMICR_EN, KMICR); - ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->phys, kmi); + ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->io.phys, kmi); if (ret) { printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); writeb(0, KMICR); @@ -94,9 +94,7 @@ static void amba_kmi_close(struct serio *io) free_irq(kmi->irq, kmi); } -static struct amba_kmi_port *list; - -static int __init amba_kmi_init_one(char *type, unsigned long base, int irq, int nr) +static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; @@ -110,58 +108,83 @@ static int __init amba_kmi_init_one(char *type, unsigned long base, int irq, int kmi->io.write = amba_kmi_write; kmi->io.open = amba_kmi_open; kmi->io.close = amba_kmi_close; - kmi->io.name = kmi->name; - kmi->io.phys = kmi->phys; + kmi->io.name = dev->dev.name; + kmi->io.phys = dev->dev.bus_id; kmi->io.driver = kmi; - snprintf(kmi->name, sizeof(kmi->name), "AMBA KMI PS/2 %s port", type); - snprintf(kmi->phys, sizeof(kmi->phys), "amba/serio%d", nr); - - kmi->res = request_mem_region(base, KMI_SIZE, kmi->phys); + kmi->res = request_mem_region(dev->res.start, KMI_SIZE, kmi->io.phys); if (!kmi->res) { kfree(kmi); return -EBUSY; } - kmi->base = ioremap(base, KMI_SIZE); + kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { release_resource(kmi->res); kfree(kmi); return -ENOMEM; } - kmi->irq = irq; + kmi->irq = dev->irq; kmi->divisor = 24 / 8 - 1; - kmi->next = list; - list = kmi; + amba_set_drvdata(dev, kmi); serio_register_port(&kmi->io); return 0; } -static int __init amba_kmi_init(void) +static int amba_kmi_remove(struct amba_device *dev) { - amba_kmi_init_one("keyboard", KMI0_BASE, IRQ_KMIINT0, 0); - amba_kmi_init_one("mouse", KMI1_BASE, IRQ_KMIINT1, 1); + struct amba_kmi_port *kmi = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + serio_unregister_port(&kmi->io); + iounmap(kmi->base); + release_resource(kmi->res); + kfree(kmi); return 0; } -static void __exit amba_kmi_exit(void) +static int amba_kmi_resume(struct amba_device *dev, u32 level) { - struct amba_kmi_port *kmi, *next; + struct amba_kmi_port *kmi = amba_get_drvdata(dev); - kmi = list; - while (kmi) { - next = kmi->next; + if (level == RESUME_ENABLE) { + /* kick the serio layer to rescan this port */ + serio_rescan(&kmi->io); + } - serio_unregister_port(&kmi->io); - iounmap(kmi->base); - release_resource(kmi->res); - kfree(kmi); + return 0; +} - kmi = next; - } +static struct amba_id amba_kmi_idtable[] = { + { + .id = 0x00041050, + .mask = 0x000fffff, + }, + { 0, 0 } +}; + +static struct amba_driver ambakmi_driver = { + .drv = { + .name = "kmi-pl050", + }, + .id_table = amba_kmi_idtable, + .probe = amba_kmi_probe, + .remove = amba_kmi_remove, + .resume = amba_kmi_resume, +}; + +static int __init amba_kmi_init(void) +{ + return amba_driver_register(&ambakmi_driver); +} + +static void __exit amba_kmi_exit(void) +{ + return amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 4320ed345ca..378ae8616da 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -58,6 +58,7 @@ struct serio_event { struct list_head node; }; +static DECLARE_MUTEX(serio_sem); static LIST_HEAD(serio_list); static LIST_HEAD(serio_dev_list); static LIST_HEAD(serio_event_list); @@ -90,9 +91,11 @@ void serio_handle_events(void) switch (event->type) { case SERIO_RESCAN : + down(&serio_sem); if (event->serio->dev && event->serio->dev->disconnect) event->serio->dev->disconnect(event->serio); serio_find_dev(event->serio); + up(&serio_sem); break; default: break; @@ -153,30 +156,37 @@ irqreturn_t serio_interrupt(struct serio *serio, void serio_register_port(struct serio *serio) { + down(&serio_sem); list_add_tail(&serio->node, &serio_list); serio_find_dev(serio); + up(&serio_sem); } void serio_unregister_port(struct serio *serio) { + down(&serio_sem); list_del_init(&serio->node); if (serio->dev && serio->dev->disconnect) serio->dev->disconnect(serio); + up(&serio_sem); } void serio_register_device(struct serio_dev *dev) { struct serio *serio; + down(&serio_sem); list_add_tail(&dev->node, &serio_dev_list); list_for_each_entry(serio, &serio_list, node) if (!serio->dev && dev->connect) dev->connect(serio, dev); + up(&serio_sem); } void serio_unregister_device(struct serio_dev *dev) { struct serio *serio; + down(&serio_sem); list_del_init(&dev->node); list_for_each_entry(serio, &serio_list, node) { @@ -184,8 +194,10 @@ void serio_unregister_device(struct serio_dev *dev) dev->disconnect(serio); serio_find_dev(serio); } + up(&serio_sem); } +/* called from serio_dev->connect/disconnect methods under serio_sem */ int serio_open(struct serio *serio, struct serio_dev *dev) { if (serio->open(serio)) @@ -194,6 +206,7 @@ int serio_open(struct serio *serio, struct serio_dev *dev) return 0; } +/* called from serio_dev->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { serio->close(serio); diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile index fd749f59ee4..05e582fb5c0 100644 --- a/drivers/isdn/act2000/Makefile +++ b/drivers/isdn/act2000/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o # Multipart objects. -act2000-objs := module.o capi.o act2000_isa.o +act2000-y := module.o capi.o act2000_isa.o diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile index b8265712e7e..57123e3e497 100644 --- a/drivers/isdn/capi/Makefile +++ b/drivers/isdn/capi/Makefile @@ -13,4 +13,3 @@ obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o kernelcapi-y := kcapi.o capiutil.o capilib.o kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o -kernelcapi-objs := $(kernelcapi-y) diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile index f45e5b51408..dd4a202e0bc 100644 --- a/drivers/isdn/divert/Makefile +++ b/drivers/isdn/divert/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o # Multipart objects. -dss1_divert-objs := isdn_divert.o divert_procfs.o divert_init.o +dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile dissimilarity index 67% index fcde8d01392..fd96828ae34 100644 --- a/drivers/isdn/eicon/Makefile +++ b/drivers/isdn/eicon/Makefile @@ -1,21 +1,19 @@ -# Makefile for the eicon ISDN device driver - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o -obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o - -# Multipart objects. - -eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \ - eicon_io.o -divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \ - fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o - -# Optional parts of multipart objects. - -eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ - xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \ - linsys.o linio.o - -eicon-objs += $(eicon-objs-y) +# Makefile for the eicon ISDN device driver + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o +obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o + +# Multipart objects. + +eicon-y := eicon_mod.o eicon_isa.o eicon_pci.o \ + eicon_idi.o eicon_io.o +eicon-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ + xlog.o kprintf.o fpga.o fourbri.o lincfg.o \ + linchr.o linsys.o linio.o + +divas-y := common.o idi.o bri.o pri.o log.o xlog.o \ + kprintf.o fpga.o fourbri.o lincfg.o \ + linchr.o linsys.o linio.o Divas_mod.o + diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index 1b0ff98d150..b11a085a60f 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -123,7 +123,7 @@ eicon_isa_find_card(int Mem, int Irq, char * Id) int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { int tmp; - int timeout; + unsigned long timeout; eicon_isa_codebuf cbuf; unsigned char *code; eicon_isa_boot *boot; @@ -300,7 +300,7 @@ int eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { eicon_isa_boot *boot; int tmp; - int timeout; + unsigned long timeout; int j; eicon_isa_codebuf cbuf; unsigned char *code; diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c index 14e5658234d..bd9a741467f 100644 --- a/drivers/isdn/hardware/avm/b1pci.c +++ b/drivers/isdn/hardware/avm/b1pci.c @@ -111,7 +111,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.procinfo = b1pci_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; + cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { @@ -239,6 +239,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) goto err_unmap; } + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "b1pciv4"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1dma_register_appl; @@ -249,7 +250,6 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c index 8120237ef68..c304230735d 100644 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ b/drivers/isdn/hardware/avm/b1pcmcia.c @@ -95,6 +95,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq, b1_reset(card->port); b1_getrevision(card); + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "b1pcmcia"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1_register_appl; @@ -105,7 +106,6 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq, cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c index 0cb3091e577..f459f127844 100644 --- a/drivers/isdn/hardware/avm/t1pci.c +++ b/drivers/isdn/hardware/avm/t1pci.c @@ -109,6 +109,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) goto err_unmap; } + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "t1pci"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1dma_register_appl; @@ -119,7 +120,6 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) cinfo->capi_ctrl.procinfo = t1pci_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff --git a/drivers/isdn/hardware/eicon/Makefile b/drivers/isdn/hardware/eicon/Makefile dissimilarity index 86% index 99fe876163f..ce1f5cf4b5a 100644 --- a/drivers/isdn/hardware/eicon/Makefile +++ b/drivers/isdn/hardware/eicon/Makefile @@ -1,24 +1,24 @@ -# Makefile for the Eicon DIVA ISDN drivers. - -# Multipart objects. - -divas-objs := divasmain.o divasfunc.o di.o io.o istream.o diva.o dlist.o divasproc.o diva_dma.o -divacapi-objs := capimain.o capifunc.o message.o capidtmf.o -divadidd-objs := diva_didd.o diddfunc.o dadapter.o -diva_mnt-objs := divamnt.o mntfunc.o debug.o maintidi.o -diva_idi-objs := divasi.o idifunc.o um_idi.o dqueue.o dlist.o - -# Optional parts of multipart objects. - -divas-objs-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o -divas-objs-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o -divas-objs-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o - -divas-objs += $(sort $(divas-objs-y)) - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o -obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o -obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o -obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o +# Makefile for the Eicon DIVA ISDN drivers. + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o +obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o +obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o +obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o + +# Multipart objects. + +divas-y := divasmain.o divasfunc.o di.o io.o istream.o \ + diva.o dlist.o divasproc.o diva_dma.o +divas-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o +divas-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o +divas-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o + +divacapi-y := capimain.o capifunc.o message.o capidtmf.o + +divadidd-y := diva_didd.o diddfunc.o dadapter.o + +diva_mnt-y := divamnt.o mntfunc.o debug.o maintidi.o + +diva_idi-y := divasi.o idifunc.o um_idi.o dqueue.o dlist.o diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile dissimilarity index 74% index 8f5f1409d44..8c384dffc5e 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -1,63 +1,61 @@ -# Makefile for the hisax ISDN device driver - -# Define maximum number of cards - -EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o -obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o -obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o -obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o -obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o -obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o -obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o -obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o - -# Multipart objects. - -hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \ - st5481_hdlc.o -hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o cert.o - -# Optional parts of multipart objects. -hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o -hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o -hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o - -hisax-objs-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o -hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o -hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o -hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o isar.o -hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o -hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o -hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o -hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o -hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o -hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o -hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o -hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o -hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o -#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o - -hisax-objs += $(hisax-objs-y) - -CERT := $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?) -CFLAGS_cert.o := -DCERTIFICATION=$(CERT) +# Makefile for the hisax ISDN device driver + +# Define maximum number of cards + +EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o +obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o +obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o +obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o +obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o +obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o +obj-$(CONFIG_HISAX_FRITZ_CLASSIC) += hisax_isac.o hisax_hscx.o hisax_fcclassic.o +obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o + +# Multipart objects. + +hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ + st5481_b.o st5481_hdlc.o + +hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ + lmgr.o q931.o callc.o fsm.o cert.o +hisax-$(CONFIG_HISAX_EURO) += l3dss1.o +hisax-$(CONFIG_HISAX_NI1) += l3ni1.o +hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o + +hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o +hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o +hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o +hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o \ + isar.o +hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o +hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o +hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o +hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o +hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o +hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o +hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o +hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_W6692) += w6692.o +hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o +#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o + +CERT := $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?) +CFLAGS_cert.o := -DCERTIFICATION=$(CERT) diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index dc983c107b8..77e1a43a077 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -153,6 +153,8 @@ static dev_link_t *avma1cs_attach(void) /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &avma1cs_release; link->release.data = (u_long)link; @@ -186,6 +188,10 @@ static dev_link_t *avma1cs_attach(void) /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + kfree(link); + return NULL; + } memset(local, 0, sizeof(local_info_t)); link->priv = local; diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile index 2db847e6728..da63b636267 100644 --- a/drivers/isdn/hysdn/Makefile +++ b/drivers/isdn/hysdn/Makefile @@ -2,15 +2,10 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_HYSDN) += hysdn.o +obj-$(CONFIG_HYSDN) += hysdn.o # Multipart objects. -hysdn-objs := hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o \ - hysdn_sched.o hysdn_net.o hysdn_init.o - -# Optional parts of multipart objects. - -hysdn-objs-$(CONFIG_HYSDN_CAPI) += hycapi.o - -hysdn-objs += $(hysdn-objs-y) +hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \ + hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o +hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index c9a8b192083..e9e5ec845d1 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -98,7 +98,8 @@ put_log_buffer(hysdn_card * card, char *cp) { struct log_data *ib; struct procdata *pd = card->proclog; - int i, flags; + int i; + unsigned long flags; if (!pd) return; @@ -300,7 +301,8 @@ hysdn_log_close(struct inode *ino, struct file *filep) struct log_data *inf; struct procdata *pd; hysdn_card *card; - int flags, retval = 0; + int retval = 0; + unsigned long flags; lock_kernel(); diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile dissimilarity index 83% index a76150977dc..431662a3a4c 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -1,26 +1,19 @@ -# Makefile for the kernel ISDN subsystem and device drivers. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN) += isdn.o -obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o - -# Multipart objects. - -isdn-objs := isdn_net_lib.o \ - isdn_fsm.o \ - isdn_tty.o isdn_v110.o \ - isdn_common.o \ - -# Optional parts of multipart objects. - -isdn-objs-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o -isdn-objs-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o -isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o -isdn-objs-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o -isdn-objs-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o -isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o -isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o -isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o - -isdn-objs += $(isdn-objs-y) +# Makefile for the kernel ISDN subsystem and device drivers. + +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN) += isdn.o +obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o + +# Multipart objects. + +isdn-y := isdn_net_lib.o isdn_fsm.o isdn_tty.o \ + isdn_v110.o isdn_common.o +isdn-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o +isdn-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o +isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o +isdn-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o +isdn-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o +isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o +isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o +isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c index c48275b7614..16fda695fd4 100644 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ b/drivers/isdn/i4l/isdn_bsdcomp.c @@ -300,7 +300,6 @@ static void bsd_free (void *state) * Finally release the structure itself. */ kfree (db); - MOD_DEC_USE_COUNT; } } @@ -355,8 +354,6 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data) return NULL; } - MOD_INC_USE_COUNT; - /* * If this is the compression buffer then there is no length data. * For decompression, the length information is needed as well. @@ -907,6 +904,7 @@ static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff * *************************************************************/ static struct isdn_ppp_compressor ippp_bsd_compress = { + .owner = THIS_MODULE, .num = CI_BSD_COMPRESS, .alloc = bsd_alloc, .free = bsd_free, diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c index 155e76b1b3d..6e559e89d01 100644 --- a/drivers/isdn/i4l/isdn_ppp_ccp.c +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -259,11 +259,14 @@ ippp_ccp_free(struct ippp_ccp *ccp) { int id; - if (ccp->comp_stat) + if (ccp->comp_stat) { ccp->compressor->free(ccp->comp_stat); - if (ccp->decomp_stat) + module_put(ccp->compressor->owner); + } + if (ccp->decomp_stat) { ccp->decompressor->free(ccp->decomp_stat); - + module_put(ccp->decompressor->owner); + } for (id = 0; id < 256; id++) { if (ccp->reset->rs[id]) ippp_ccp_reset_free_state(ccp, id); @@ -553,13 +556,14 @@ ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) } } -static struct isdn_ppp_compressor *ipc_head = NULL; +static LIST_HEAD(ipc_head); +static spinlock_t ipc_head_lock; int ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, struct isdn_ppp_comp_data *data) { - struct isdn_ppp_compressor *ipc = ipc_head; + struct isdn_ppp_compressor *ipc; int ret; void *stat; int num = data->num; @@ -568,34 +572,48 @@ ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); - for (ipc = ipc_head; ipc; ipc = ipc->next) { - if (ipc->num != num) - continue; - - stat = ipc->alloc(data); - if (!stat) { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } - ret = ipc->init(stat, data, unit, 0); - if(!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - break; + spin_lock(&ipc_head_lock); + list_for_each_entry(ipc, &ipc_head, list) { + if (ipc->num == num && + try_module_get(ipc->owner)) + goto found; + } + spin_unlock(&ipc_head_lock); + return -EINVAL; + + found: + spin_unlock(&ipc_head_lock); + + stat = ipc->alloc(data); + if (!stat) { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + goto err; + } + ret = ipc->init(stat, data, unit, 0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + goto err; + } + if (data->flags & IPPP_COMP_FLAG_XMIT) { + if (ccp->comp_stat) { + ccp->compressor->free(ccp->comp_stat); + module_put(ccp->compressor->owner); } - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (ccp->comp_stat) - ccp->compressor->free(ccp->comp_stat); ccp->comp_stat = stat; ccp->compressor = ipc; - } else { - if (ccp->decomp_stat) - ccp->decompressor->free(ccp->decomp_stat); - ccp->decomp_stat = stat; - ccp->decompressor = ipc; + } else { + if (ccp->decomp_stat) { + ccp->decompressor->free(ccp->decomp_stat); + module_put(ccp->decompressor->owner); } - return 0; + ccp->decomp_stat = stat; + ccp->decompressor = ipc; } + return 0; + + err: + module_put(ipc->owner); return -EINVAL; } @@ -606,36 +624,34 @@ ippp_ccp_get_compressors(unsigned long protos[8]) int i, j; memset(protos, 0, sizeof(unsigned long) * 8); - for (ipc = ipc_head; ipc; ipc = ipc->next) { + + spin_lock(&ipc_head_lock); + list_for_each_entry(ipc, &ipc_head, list) { j = ipc->num / (sizeof(long)*8); i = ipc->num % (sizeof(long)*8); if (j < 8) protos[j] |= 1 << i; } + spin_unlock(&ipc_head_lock); } int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { - ipc->next = ipc_head; - ipc->prev = NULL; - if (ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; + spin_lock(&ipc_head_lock); + list_add_tail(&ipc->list, &ipc_head); + spin_unlock(&ipc_head_lock); + return 0; } int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) { - if (ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if (ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; + spin_lock(&ipc_head_lock); + list_del(&ipc->list); + spin_unlock(&ipc_head_lock); + return 0; } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index dafefea4594..0bd61b05421 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1983,7 +1983,7 @@ modem_write_profile(atemu * m) memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) - group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd); + kill_pg_info(SIGIO, SEND_SIG_PRIV, dev->profd->pgrp); } static struct tty_operations modem_ops = { @@ -2095,11 +2095,10 @@ isdn_tty_init(void) #endif kfree(info->xmit_buf - 4); } - err_unregister_tty: - tty_unregister_driver(&isdn_mdm->tty_modem); + tty_unregister_driver(m->tty_modem); err: - put_tty_driver(&isdn_mdm->tty_modem); - isdn_mdm->tty_modem = NULL; + put_tty_driver(m->tty_modem); + m->tty_modem = NULL; return retval; } @@ -2118,9 +2117,9 @@ isdn_tty_exit(void) #endif kfree(info->xmit_buf - 4); } - tty_unregister_driver(&isdn_mdm->tty_modem); - put_tty_driver(&isdn_mdm->tty_modem); - isdn_mdm->tty_modem = NULL; + tty_unregister_driver(isdn_mdm.tty_modem); + put_tty_driver(isdn_mdm.tty_modem); + isdn_mdm.tty_modem = NULL; } /* diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c index c216f92aaec..dbccc7d3113 100644 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ b/drivers/isdn/i4l/isdn_ttyfax.c @@ -303,7 +303,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info) isdn_ctrl c; int par; struct isdn_slot *slot; - long flags; + unsigned long flags; for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile index 7e60c21b9e6..317cd3c5b8e 100644 --- a/drivers/isdn/isdnloop/Makefile +++ b/drivers/isdn/isdnloop/Makefile @@ -1,6 +1,4 @@ -# # Makefile for the isdnloop ISDN device driver -# # Each configuration option enables a list of files. diff --git a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile index 4646c1491ff..2d026c3242e 100644 --- a/drivers/isdn/pcbit/Makefile +++ b/drivers/isdn/pcbit/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o # Multipart objects. -pcbit-objs := module.o edss1.o drv.o layer2.o capi.o callbacks.o +pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile index 5d819a74372..9cc474cd0c4 100644 --- a/drivers/isdn/sc/Makefile +++ b/drivers/isdn/sc/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_ISDN_DRV_SC) += sc.o # Multipart objects. -sc-objs := shmem.o init.o debug.o packet.o command.o event.o \ - ioctl.o interrupt.o message.o timer.o +sc-y := shmem.o init.o debug.o packet.o command.o event.o \ + ioctl.o interrupt.o message.o timer.o diff --git a/drivers/isdn/tpam/Makefile b/drivers/isdn/tpam/Makefile index 1ae6c509314..5860692b14b 100644 --- a/drivers/isdn/tpam/Makefile +++ b/drivers/isdn/tpam/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_ISDN_DRV_TPAM) += tpam.o # Multipart objects. -tpam-objs := tpam_main.o tpam_nco.o tpam_memory.o tpam_commands.o \ - tpam_queues.o tpam_hdlc.o tpam_crcpc.o +tpam-y := tpam_main.o tpam_nco.o tpam_memory.o \ + tpam_commands.o tpam_queues.o tpam_hdlc.o \ + tpam_crcpc.o diff --git a/drivers/isdn/tpam/tpam_queues.c b/drivers/isdn/tpam/tpam_queues.c index c9841b0ad72..9b55684dde0 100644 --- a/drivers/isdn/tpam/tpam_queues.c +++ b/drivers/isdn/tpam/tpam_queues.c @@ -145,6 +145,7 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs) do { hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); if (waiting_too_long++ > 0xfffffff) { + kfree_skb(skb); spin_unlock(&card->lock); printk(KERN_ERR "TurboPAM(tpam_irq): " "waiting too long...\n"); diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 05d6d1dad63..eaeeb15358f 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -297,13 +297,14 @@ int dm_hash_rename(const char *old, const char *new) /* * rename and move the name cell. */ + unregister_with_devfs(hc); + list_del(&hc->name_list); old_name = hc->name; hc->name = new_name; list_add(&hc->name_list, _name_buckets + hash_str(new_name)); /* rename the device node in devfs */ - unregister_with_devfs(hc); register_with_devfs(hc); up_write(&_hash_lock); diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index c2da3917116..9cccfba214c 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -866,34 +866,6 @@ static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) } /** - * internal_done - legacy scsi glue - * @SCPnt: command - * - * Completion function for a synchronous command - */ - -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -/** - * i2o_scsi_command - issue a scsi command and wait - * @SCPnt: command - * - * Issue a SCSI command and wait for it to complete. - */ - -static int i2o_scsi_command(Scsi_Cmnd * SCpnt) -{ - i2o_scsi_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - -/** * i2o_scsi_abort - abort a running command * @SCpnt: command to abort * @@ -1091,7 +1063,6 @@ static Scsi_Host_Template driver_template = { .detect = i2o_scsi_detect, .release = i2o_scsi_release, .info = i2o_scsi_info, - .command = i2o_scsi_command, .queuecommand = i2o_scsi_queuecommand, .eh_abort_handler = i2o_scsi_abort, .eh_bus_reset_handler = i2o_scsi_bus_reset, diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index dcfb7b40319..140448b42c2 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -53,6 +53,8 @@ Revision History: 2. Bug fix: Fixed VLAN support failure. 3. Bug fix: Fixed receive interrupt coalescing bug. 4. Dynamic IPG support is disabled by default. + 3.0.3 06/05/2003 + 1. Bug fix: Fixed failure to close the interface if SMP is enabled. */ @@ -89,9 +91,9 @@ Revision History: #include "amd8111e.h" #define MODULE_NAME "amd8111e" -#define MODULE_VERSION "3.0.2" +#define MODULE_VERSION "3.0.3" MODULE_AUTHOR("Advanced Micro Devices, Inc."); -MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.2"); +MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3"); MODULE_LICENSE("GPL"); MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); @@ -1171,11 +1173,11 @@ static int amd8111e_close(struct net_device * dev) if(lp->options & OPTION_DYN_IPG_ENABLE) del_timer_sync(&lp->ipg_data.ipg_timer); - /* Update the statistics before closing */ - amd8111e_get_stats(dev); spin_unlock_irq(&lp->lock); - free_irq(dev->irq, dev); + + /* Update the statistics before closing */ + amd8111e_get_stats(dev); lp->opened = 0; return 0; } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 7dc1bd5ff62..9ef8dab49d2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -390,6 +390,7 @@ #include #include #include +#include #include #include #include @@ -497,9 +498,7 @@ static struct bond_parm_tbl bond_lacp_tbl[] = { { NULL, -1}, }; -static int first_pass = 1; -static struct bonding *these_bonds = NULL; -static struct net_device *dev_bonds = NULL; +static LIST_HEAD(bond_dev_list); MODULE_PARM(max_bonds, "i"); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); @@ -952,8 +951,6 @@ static int bond_open(struct net_device *dev) add_timer(alb_timer); } - MOD_INC_USE_COUNT; - if (miimon > 0) { /* link check interval, in milliseconds. */ init_timer(timer); timer->expires = jiffies + (miimon * HZ / 1000); @@ -1027,7 +1024,6 @@ static int bond_close(struct net_device *master) bond_alb_deinitialize(bond); } - MOD_DEC_USE_COUNT; return 0; } @@ -2797,84 +2793,6 @@ static void activebackup_arp_monitor(struct net_device *master) mod_timer(&bond->arp_timer, next_timer); } -typedef uint32_t in_addr_t; - -int -my_inet_aton(char *cp, unsigned long *the_addr) { - static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; - in_addr_t val; - char c; - union iaddr { - uint8_t bytes[4]; - uint32_t word; - } res; - uint8_t *pp = res.bytes; - int digit,base; - - res.word = 0; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!isdigit(c)) goto ret_0; - val = 0; base = 10; digit = 0; - for (;;) { - if (isdigit(c)) { - val = (val * base) + (c - '0'); - c = *++cp; - digit = 1; - } else { - break; - } - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp > res.bytes + 2 || val > 0xff) { - goto ret_0; - } - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) { - goto ret_0; - } - /* - * Did we get a valid digit? - */ - if (!digit) { - goto ret_0; - } - - /* Check whether the last part is in its limits depending on - the number of parts in total. */ - if (val > max[pp - res.bytes]) { - goto ret_0; - } - - if (the_addr != NULL) { - *the_addr = res.word | htonl (val); - } - - return (1); - -ret_0: - return (0); -} - static int bond_sethwaddr(struct net_device *master, struct net_device *slave) { #ifdef BONDING_DEBUG @@ -3411,7 +3329,7 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev) static int bond_get_info(char *buf, char **start, off_t offset, int length) { - bonding_t *bond = these_bonds; + bonding_t *bond; int len = 0; off_t begin = 0; u16 link; @@ -3419,7 +3337,8 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) len += sprintf(buf + len, "%s\n", version); - while (bond != NULL) { + read_lock(&dev_base_lock); + list_for_each_entry(bond, &bond_dev_list, bond_list) { /* * This function locks the mutex, so we can't lock it until * afterwards @@ -3529,93 +3448,48 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) len = 0; } - - bond = bond->next_bond; } + read_unlock(&dev_base_lock); + return len; } static int bond_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct bonding *this_bond = (struct bonding *)these_bonds; - struct bonding *last_bond; struct net_device *event_dev = (struct net_device *)ptr; + struct net_device *master = event_dev->master; - /* while there are bonds configured */ - while (this_bond != NULL) { - if (this_bond == event_dev->priv ) { - switch (event) { - case NETDEV_UNREGISTER: - /* - * remove this bond from a linked list of - * bonds - */ - if (this_bond == these_bonds) { - these_bonds = this_bond->next_bond; - } else { - for (last_bond = these_bonds; - last_bond != NULL; - last_bond = last_bond->next_bond) { - if (last_bond->next_bond == - this_bond) { - last_bond->next_bond = - this_bond->next_bond; - } - } - } - return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER && master != NULL) + bond_release(master, event_dev); - default: - return NOTIFY_DONE; - } - } else if (this_bond->device == event_dev->master) { - switch (event) { - case NETDEV_UNREGISTER: - bond_release(this_bond->device, event_dev); - break; - } - return NOTIFY_DONE; - } - this_bond = this_bond->next_bond; - } return NOTIFY_DONE; } static struct notifier_block bond_netdev_notifier = { - notifier_call: bond_event, + .notifier_call = bond_event, }; static int __init bond_init(struct net_device *dev) { - bonding_t *bond, *this_bond, *last_bond; + bonding_t *bond; int count; #ifdef BONDING_DEBUG printk (KERN_INFO "Begin bond_init for %s\n", dev->name); #endif - bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); - if (bond == NULL) { - return -ENOMEM; - } - memset(bond, 0, sizeof(struct bonding)); + bond = dev->priv; /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->ptrlock); - bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if (bond->stats == NULL) { - kfree(bond); - return -ENOMEM; - } - memset(bond->stats, 0, sizeof(struct net_device_stats)); - + /* space is reserved for stats in alloc_netdev call. */ + bond->stats = (struct net_device_stats *)(bond + 1); bond->next = bond->prev = (slave_t *)bond; bond->current_slave = NULL; bond->current_arp_slave = NULL; bond->device = dev; - dev->priv = bond; /* Initialize the device structure. */ switch (bond_mode) { @@ -3640,8 +3514,6 @@ static int __init bond_init(struct net_device *dev) break; default: printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); - kfree(bond->stats); - kfree(bond); return -EINVAL; } @@ -3651,13 +3523,6 @@ static int __init bond_init(struct net_device *dev) dev->set_multicast_list = set_multicast_list; dev->do_ioctl = bond_ioctl; - /* - * Fill in the fields of the device structure with ethernet-generic - * values. - */ - - ether_setup(dev); - dev->tx_queue_len = 0; dev->flags |= IFF_MASTER|IFF_MULTICAST; #ifdef CONFIG_NET_FASTROUTE @@ -3690,10 +3555,10 @@ static int __init bond_init(struct net_device *dev) if (bond->bond_proc_dir == NULL) { printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", dev->name, dev->name); - kfree(bond->stats); - kfree(bond); return -ENOMEM; } + bond->bond_proc_dir->owner = THIS_MODULE; + bond->bond_proc_info_file = create_proc_info_entry("info", 0, bond->bond_proc_dir, bond_get_info); @@ -3701,26 +3566,13 @@ static int __init bond_init(struct net_device *dev) printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", dev->name, dev->name); remove_proc_entry(dev->name, proc_net); - kfree(bond->stats); - kfree(bond); return -ENOMEM; } + bond->bond_proc_info_file->owner = THIS_MODULE; #endif /* CONFIG_PROC_FS */ - if (first_pass == 1) { - these_bonds = bond; - register_netdevice_notifier(&bond_netdev_notifier); - first_pass = 0; - } else { - last_bond = these_bonds; - this_bond = these_bonds->next_bond; - while (this_bond != NULL) { - last_bond = this_bond; - this_bond = this_bond->next_bond; - } - last_bond->next_bond = bond; - } + list_add_tail(&bond->bond_list, &bond_dev_list); return 0; } @@ -3753,15 +3605,11 @@ bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) return -1; } - static int __init bonding_init(void) { int no; int err; - /* Find a name for this unit */ - static struct net_device *dev_bond = NULL; - printk(KERN_INFO "%s", version); /* @@ -3812,12 +3660,6 @@ static int __init bonding_init(void) max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } - dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), - GFP_KERNEL); - if (dev_bond == NULL) { - return -ENOMEM; - } - memset(dev_bonds, 0, max_bonds*sizeof(struct net_device)); if (miimon < 0) { printk(KERN_WARNING @@ -3958,15 +3800,18 @@ static int __init bonding_init(void) for (arp_ip_count=0 ; (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; arp_ip_count++ ) { - /* TODO: check and log bad ip address */ - if (my_inet_aton(arp_ip_target[arp_ip_count], - &arp_target[arp_ip_count]) == 0) { + /* not complete check, but should be good enough to + catch mistakes */ + if (!isdigit(arp_ip_target[arp_ip_count][0])) { printk(KERN_WARNING "bonding_init(): bad arp_ip_target module " "parameter (%s), ARP monitoring will not be " "performed\n", arp_ip_target[arp_ip_count]); arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); + *(u32 *)(arp_ip_target[arp_ip_count]) = ip; } } @@ -4005,48 +3850,50 @@ static int __init bonding_init(void) primary = NULL; } + register_netdevice_notifier(&bond_netdev_notifier); for (no = 0; no < max_bonds; no++) { - dev_bond->init = bond_init; - - err = dev_alloc_name(dev_bond,"bond%d"); - if (err < 0) { - kfree(dev_bonds); + struct net_device *dev; + char name[IFNAMSIZ]; + + snprintf(name, IFNAMSIZ, "bond%d", no); + + dev = alloc_netdev(sizeof(bonding_t) + + sizeof(struct net_device_stats), + name, ether_setup); + if (!dev) + return -ENOMEM; + + dev->init = bond_init; + SET_MODULE_OWNER(dev); + + if ( (err = register_netdev(dev)) ) { +#ifdef BONDING_DEBUG + printk(KERN_INFO "%s: register_netdev failed %d\n", + dev->name, err); +#endif + kfree(dev); return err; - } - SET_MODULE_OWNER(dev_bond); - if (register_netdev(dev_bond) != 0) { - kfree(dev_bonds); - return -EIO; } - dev_bond++; } return 0; } static void __exit bonding_exit(void) { - struct net_device *dev_bond = dev_bonds; - struct bonding *bond; - int no; + struct bonding *bond, *nxt; unregister_netdevice_notifier(&bond_netdev_notifier); - for (no = 0; no < max_bonds; no++) { - + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + struct net_device *dev = bond->device; #ifdef CONFIG_PROC_FS - bond = (struct bonding *) dev_bond->priv; remove_proc_entry("info", bond->bond_proc_dir); - remove_proc_entry(dev_bond->name, proc_net); + remove_proc_entry(dev->name, proc_net); #endif - unregister_netdev(dev_bond); - kfree(bond->stats); - kfree(dev_bond->priv); - - dev_bond->priv = NULL; - dev_bond++; + unregister_netdev(dev); + kfree(dev); } - kfree(dev_bonds); } module_init(bonding_init); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6388d78abee..3f2b66b4ba8 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -104,7 +104,7 @@ typedef struct bonding { struct proc_dir_entry *bond_proc_dir; struct proc_dir_entry *bond_proc_info_file; #endif /* CONFIG_PROC_FS */ - struct bonding *next_bond; + struct list_head bond_list; struct net_device *device; struct dev_mc_list *mc_list; unsigned short flags; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 0842e54df8b..26ac864936e 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -376,7 +376,6 @@ static int eppconfig(struct baycom_state *bc) char portarg[16]; char *argv[] = { eppconfig_path, "-s", "-p", portarg, "-m", modearg, NULL }; - int ret; /* set up arguments */ sprintf(modearg, "%sclk,%smodem,fclk=%d,bps=%d,divider=%d%s,extstat", @@ -1164,7 +1163,6 @@ static int baycom_setmode(struct baycom_state *bc, const char *modestr) static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct baycom_state *bc; - struct baycom_ioctl bi; struct hdlcdrv_ioctl hi; baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index ce3bd5f5e30..e4d961b00ed 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -721,7 +721,7 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned char iir; int counter = 100; int i; - + int handled = 0; for (i = 0; i < NR_PORTS; i++) { yp = &yam_ports[i]; @@ -735,14 +735,17 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned char lsr = inb(LSR(dev->base_addr)); unsigned char rxb; + handled = 1; + if (lsr & LSR_OE) ++yp->stats.rx_fifo_errors; yp->dcd = (msr & RX_DCD) ? 1 : 0; if (--counter <= 0) { - printk(KERN_ERR "%s: too many irq iir=%d\n", dev->name, iir); - return; + printk(KERN_ERR "%s: too many irq iir=%d\n", + dev->name, iir); + goto out; } if (msr & TX_RDY) { ++yp->nb_mdint; @@ -758,7 +761,8 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } } - return IRQ_HANDLED; +out: + return IRQ_RETVAL(handled); } static int yam_net_get_info(char *buffer, char **start, off_t offset, int length) diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 3c641e56a3f..4e0c3d45904 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -50,7 +50,6 @@ ixgb_eeprom_size(struct ixgb_hw *hw) return (IXGB_EEPROM_SIZE << 1); } -#define SUPPORTED_10000baseT_Full (1 << 11) #define SPEED_10000 10000 static void diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 7f4e64360f1..fdcad85b7cc 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -766,10 +766,14 @@ static int myri_rebuild_header(struct sk_buff *skb) int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - unsigned char *pad = (unsigned char *) hh->hh_data; - struct ethhdr *eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + unsigned char *pad; + struct ethhdr *eth; struct net_device *dev = neigh->dev; + pad = ((unsigned char *) hh->hh_data) + + HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN); + eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -788,7 +792,8 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) /* Called by Address Resolution module to notify changes in address. */ void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } static int myri_change_mtu(struct net_device *dev, int new_mtu) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 81459c1e6fe..9b8c823f5cc 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -225,9 +225,7 @@ MODULE_PARM(pc_debug, "i"); #else #define DEBUG(n, args...) #endif -static char *version = -"xirc2ps_cs.c 1.31 1998/12/09 19:32:55 (dd9jn+kvh)"; - /* !--- CVS revision */ + #define KDBG_XIRC KERN_DEBUG "xirc2ps_cs: " #define KERR_XIRC KERN_ERR "xirc2ps_cs: " #define KWRN_XIRC KERN_WARNING "xirc2ps_cs: " @@ -358,7 +356,6 @@ static dev_link_t *dev_list; typedef struct local_info_t { dev_link_t link; - struct net_device dev; dev_node_t node; struct net_device_stats stats; int card_type; @@ -432,22 +429,10 @@ get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) #define PutByte(reg,value) outb((value), ioaddr+(reg)) #define PutWord(reg,value) outw((value), ioaddr+(reg)) -static void -busy_loop(u_long len) -{ - if (in_interrupt()) { - u_long timeout = jiffies + len; - u_long flags; - save_flags(flags); - sti(); - while (time_before_eq(jiffies, timeout)) - ; - restore_flags(flags); - } else { - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(len); - } -} +#define Wait(n) do { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout(n); \ +} while (0) /*====== Functions used for debugging =================================*/ #if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */ @@ -619,11 +604,12 @@ xirc2ps_attach(void) flush_stale_links(); /* Allocate the device structure */ - local = kmalloc(sizeof(*local), GFP_KERNEL); - if (!local) return NULL; - memset(local, 0, sizeof(*local)); - link = &local->link; dev = &local->dev; - link->priv = dev->priv = local; + dev = alloc_etherdev(sizeof(local_info_t)); + if (!dev) + return NULL; + local = dev->priv; + link = &local->link; + link->priv = dev; init_timer(&link->release); link->release.function = &xirc2ps_release; @@ -645,7 +631,6 @@ xirc2ps_attach(void) dev->get_stats = &do_get_stats; dev->do_ioctl = &do_ioctl; dev->set_multicast_list = &set_multicast_list; - ether_setup(dev); dev->open = &do_open; dev->stop = &do_stop; #ifdef HAVE_TX_TIMEOUT @@ -684,7 +669,7 @@ xirc2ps_attach(void) static void xirc2ps_detach(dev_link_t * link) { - local_info_t *local = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "detach(0x%p)\n", link); @@ -706,10 +691,11 @@ xirc2ps_detach(dev_link_t * link) */ del_timer(&link->release); if (link->state & DEV_CONFIG) { - DEBUG(0, "detach postponed, '%s' still locked\n", - link->dev->dev_name); - link->state |= DEV_STALE_LINK; - return; + xirc2ps_release((unsigned long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } /* Break the link with Card Services */ @@ -719,8 +705,8 @@ xirc2ps_detach(dev_link_t * link) /* Unlink device structure, free it */ *linkp = link->next; if (link->dev) - unregister_netdev(&local->dev); - kfree(local); + unregister_netdev(dev); + kfree(dev); } /* xirc2ps_detach */ @@ -745,7 +731,8 @@ xirc2ps_detach(dev_link_t * link) static int set_card_type(dev_link_t *link, const void *s) { - local_info_t *local = link->priv; + struct net_device *dev = link->priv; + local_info_t *local = dev->priv; #ifdef PCMCIA_DEBUG unsigned cisrev = ((const unsigned char *)s)[2]; #endif @@ -839,8 +826,8 @@ static void xirc2ps_config(dev_link_t * link) { client_handle_t handle = link->handle; - local_info_t *local = link->priv; - struct net_device *dev = &local->dev; + struct net_device *dev = link->priv; + local_info_t *local = dev->priv; tuple_t tuple; cisparse_t parse; ioaddr_t ioaddr; @@ -1195,11 +1182,10 @@ static void xirc2ps_release(u_long arg) { dev_link_t *link = (dev_link_t *) arg; - local_info_t *local = link->priv; - struct net_device *dev = &local->dev; DEBUG(0, "release(0x%p)\n", link); +#if 0 /* * If the device is currently in use, we won't release until it * is actually closed. @@ -1210,8 +1196,10 @@ xirc2ps_release(u_long arg) link->state |= DEV_STALE_CONFIG; return; } +#endif if (link->win) { + struct net_device *dev = link->priv; local_info_t *local = dev->priv; if (local->dingo) iounmap(local->dingo_ccr - 0x0800); @@ -1243,8 +1231,7 @@ xirc2ps_event(event_t event, int priority, event_callback_args_t * args) { dev_link_t *link = args->client_data; - local_info_t *lp = link->priv; - struct net_device *dev = &lp->dev; + struct net_device *dev = link->priv; DEBUG(0, "event(%d)\n", (int)event); @@ -1779,12 +1766,12 @@ hardreset(struct net_device *dev) SelectPage(4); udelay(1); PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ - busy_loop(HZ/25); /* wait 40 msec */ + Wait(HZ/25); /* wait 40 msec */ if (local->mohawk) PutByte(XIRCREG4_GPR1, 1); /* set bit 0: power up */ else PutByte(XIRCREG4_GPR1, 1 | 4); /* set bit 0: power up, bit 2: AIC */ - busy_loop(HZ/50); /* wait 20 msec */ + Wait(HZ/50); /* wait 20 msec */ } static void @@ -1798,9 +1785,9 @@ do_reset(struct net_device *dev, int full) hardreset(dev); PutByte(XIRCREG_CR, SoftReset); /* set */ - busy_loop(HZ/50); /* wait 20 msec */ + Wait(HZ/50); /* wait 20 msec */ PutByte(XIRCREG_CR, 0); /* clear */ - busy_loop(HZ/25); /* wait 40 msec */ + Wait(HZ/25); /* wait 40 msec */ if (local->mohawk) { SelectPage(4); /* set pin GP1 and GP2 to output (0x0c) @@ -1811,7 +1798,7 @@ do_reset(struct net_device *dev, int full) } /* give the circuits some time to power up */ - busy_loop(HZ/2); /* about 500ms */ + Wait(HZ/2); /* about 500ms */ local->last_ptr_value = 0; local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4 @@ -1830,7 +1817,7 @@ do_reset(struct net_device *dev, int full) SelectPage(0x42); PutByte(XIRCREG42_SWC1, 0x80); } - busy_loop(HZ/25); /* wait 40 msec to let it complete */ + Wait(HZ/25); /* wait 40 msec to let it complete */ #ifdef PCMCIA_DEBUG if (pc_debug) { @@ -1889,7 +1876,7 @@ do_reset(struct net_device *dev, int full) printk(KERN_INFO "%s: MII selected\n", dev->name); SelectPage(2); PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08); - busy_loop(HZ/50); + Wait(HZ/50); } else { printk(KERN_INFO "%s: MII detected; using 10mbs\n", dev->name); @@ -1898,7 +1885,7 @@ do_reset(struct net_device *dev, int full) PutByte(XIRCREG42_SWC1, 0xC0); else /* enable 10BaseT */ PutByte(XIRCREG42_SWC1, 0x80); - busy_loop(HZ/25); /* wait 40 msec to let it complete */ + Wait(HZ/25); /* wait 40 msec to let it complete */ } if (full_duplex) PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex)); @@ -1991,7 +1978,7 @@ init_mii(struct net_device *dev) * Fixme: Better to use a timer here! */ for (i=0; i < 35; i++) { - busy_loop(HZ/10); /* wait 100 msec */ + Wait(HZ/10); /* wait 100 msec */ status = mii_rd(ioaddr, 0, 1); if ((status & 0x0020) && (status & 0x0004)) break; @@ -2083,12 +2070,8 @@ exit_xirc2ps_cs(void) { pcmcia_unregister_driver(&xirc2ps_cs_driver); - while (dev_list) { - if (dev_list->state & DEV_CONFIG) - xirc2ps_release((u_long)dev_list); - if (dev_list) /* xirc2ps_release() might already have detached... */ - xirc2ps_detach(dev_list); - } + while (dev_list) + xirc2ps_detach(dev_list); } module_init(init_xirc2ps_cs); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 6f2e082480f..ae9491176cf 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1003,7 +1003,7 @@ pcnet32_init_ring(struct net_device *dev) skb_reserve (rx_skbuff, 2); } - if (lp->rx_dma_addr[i] == NULL) + if (lp->rx_dma_addr[i] == 0) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index ae3c088214f..620b5c4223e 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -1078,7 +1078,10 @@ int plip_hard_header_cache(struct neighbour *neigh, if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) { - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; + + eth = (struct ethhdr*)(((u8*)hh->hh_data) + + HH_DATA_OFF(sizeof(*eth))); plip_rewrite_address (neigh->dev, eth); } diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 3cf67051e96..5edde592420 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -147,7 +147,6 @@ ppp_asynctty_open(struct tty_struct *tty) struct asyncppp *ap; int err; - MOD_INC_USE_COUNT; err = -ENOMEM; ap = kmalloc(sizeof(*ap), GFP_KERNEL); if (ap == 0) @@ -183,7 +182,6 @@ ppp_asynctty_open(struct tty_struct *tty) out_free: kfree(ap); out: - MOD_DEC_USE_COUNT; return err; } @@ -223,7 +221,6 @@ ppp_asynctty_close(struct tty_struct *tty) if (ap->tpkt != 0) kfree_skb(ap->tpkt); kfree(ap); - MOD_DEC_USE_COUNT; } /* @@ -351,6 +348,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty) static struct tty_ldisc ppp_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "ppp", .open = ppp_asynctty_open, diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index f0945464e76..8b45fc142d6 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1061,6 +1061,7 @@ static int pppoe_seq_open(struct inode *inode, struct file *file) } static struct file_operations pppoe_seq_fops = { + .owner = THIS_MODULE, .open = pppoe_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c index c984c37ef75..c408082648e 100644 --- a/drivers/net/rcpci45.c +++ b/drivers/net/rcpci45.c @@ -171,13 +171,14 @@ rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) * will be assigned to the LAN API layer. */ - dev = init_etherdev (NULL, sizeof (*pDpa)); + dev = alloc_etherdev(sizeof(*pDpa)); if (!dev) { printk (KERN_ERR - "(rcpci45 driver:) init_etherdev alloc failed\n"); + "(rcpci45 driver:) alloc_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } + SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -257,6 +258,9 @@ rcpci45_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->do_ioctl = &RCioctl; dev->set_config = &RCconfig; + if ((error = register_netdev(dev))) + goto err_out_free_region; + return 0; /* success */ err_out_free_region: @@ -265,7 +269,6 @@ err_out_free_msgbuf: pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf, pDpa->msgbuf_dma); err_out_free_dev: - unregister_netdev (dev); kfree (dev); err_out: card_idx--; @@ -534,17 +537,6 @@ RCreboot_callback (U32 Status, U32 p1, U32 p2, struct net_device *dev) (PFNCALLBACK) RCreset_callback); } -int -broadcast_packet (unsigned char *address) -{ - int i; - for (i = 0; i < 6; i++) - if (address[i] != 0xff) - return 0; - - return 1; -} - /* * RCrecv_callback() * @@ -717,11 +709,9 @@ rc_timer (unsigned long data) if (retry > REBOOT_REINIT_RETRY_LIMIT) { printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); - printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); + printk (KERN_WARNING "%s shutting down interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; - MOD_DEC_USE_COUNT; - /* FIXME: kill MOD_DEC_USE_COUNT, use dev_put */ } else { printk (KERN_INFO "%s: rescheduling timer...\n", dev->name); diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 7419771e5ed..a8ac494e46e 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -630,7 +630,7 @@ static void shaper_init_priv(struct net_device *dev) * Add a shaper device to the system */ -static int __init shaper_probe(struct net_device *dev) +static void __init shaper_setup(struct net_device *dev) { /* * Set up the shaper. @@ -642,6 +642,7 @@ static int __init shaper_probe(struct net_device *dev) dev->open = shaper_open; dev->stop = shaper_close; + dev->destructor = (void (*)(struct net_device *))kfree; dev->hard_start_xmit = shaper_start_xmit; dev->get_stats = shaper_get_stats; dev->set_multicast_list = NULL; @@ -669,12 +670,6 @@ static int __init shaper_probe(struct net_device *dev) dev->addr_len = 0; dev->tx_queue_len = 10; dev->flags = 0; - - /* - * Shaper is ok - */ - - return 0; } static int shapers = 1; @@ -695,35 +690,38 @@ __setup("shapers=", set_num_shapers); #endif /* MODULE */ -static struct net_device *devs; +static struct net_device **devs; static unsigned int shapers_registered = 0; static int __init shaper_init(void) { - int i, err; + int i; size_t alloc_size; - struct shaper *sp; + struct net_device *dev; + char name[IFNAMSIZ]; if (shapers < 1) return -ENODEV; - alloc_size = (sizeof(*devs) * shapers) + - (sizeof(struct shaper) * shapers); + alloc_size = sizeof(*dev) * shapers; devs = kmalloc(alloc_size, GFP_KERNEL); if (!devs) return -ENOMEM; memset(devs, 0, alloc_size); - sp = (struct shaper *) &devs[shapers]; for (i = 0; i < shapers; i++) { - err = dev_alloc_name(&devs[i], "shaper%d"); - if (err < 0) + + snprintf(name, IFNAMSIZ, "shaper%d", i); + dev = alloc_netdev(sizeof(struct shaper), name, + shaper_setup); + if (!dev) break; - devs[i].init = shaper_probe; - devs[i].priv = &sp[i]; - if (register_netdev(&devs[i])) + + if (register_netdev(dev)) break; + + devs[i] = dev; shapers_registered++; } @@ -740,7 +738,8 @@ static void __exit shaper_exit (void) int i; for (i = 0; i < shapers_registered; i++) - unregister_netdev(&devs[i]); + if (devs[i]) + unregister_netdev(devs[i]); kfree(devs); devs = NULL; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index f195d355c9f..b9399795529 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -124,6 +124,7 @@ static struct mii_chip_info { { "ICS LAN PHY", 0x0015, 0xF440, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, + { "VIA 6103 PHY", 0x0101, 0x8f20, LAN }, {0,}, }; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 8be31903327..c8c314c6a19 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -980,8 +980,8 @@ static void tx_timeout(struct net_device *dev) { int i; for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring), + printk(KERN_DEBUG "%02x %08Zx %08x %08x(%02x) %08x %08x\n", i, + np->tx_ring_dma + i*sizeof(*np->tx_ring), le32_to_cpu(np->tx_ring[i].next_desc), le32_to_cpu(np->tx_ring[i].status), (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff, @@ -1666,7 +1666,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCDEVPRIVATE: for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring), le32_to_cpu(np->tx_ring[i].next_desc), le32_to_cpu(np->tx_ring[i].status), diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index 19b85643801..1c03dba692d 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -37,7 +37,7 @@ config TULIP ---help--- This driver is developed for the SMC EtherPower series Ethernet cards and also works with cards based on the DECchip - 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are + 21140 (Tulip series) chips. Some LinkSys PCI cards are of this type. (If your card is NOT SMC EtherPower 10/100 PCI (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 955561e0415..91ec9bf6f58 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -132,6 +132,9 @@ static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; static spinlock_t spppq_lock = SPIN_LOCK_UNLOCKED; +/* global xmit queue for sending packets while spinlock is held */ +static struct sk_buff_head tx_queue; + static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data); @@ -150,6 +153,20 @@ static void sppp_print_bytes (u8 *p, u16 len); static int debug; +/* Flush global outgoing packet queue to dev_queue_xmit(). + * + * dev_queue_xmit() must be called with interrupts enabled + * which means it can't be called with spinlocks held. + * If a packet needs to be sent while a spinlock is held, + * then put the packet into tx_queue, and call sppp_flush_xmit() + * after spinlock is released. + */ +static void sppp_flush_xmit() +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&tx_queue)) != NULL) + dev_queue_xmit(skb); +} /* * Interface down stub @@ -207,7 +224,8 @@ void sppp_input (struct net_device *dev, struct sk_buff *skb) { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); - + unsigned long flags; + skb->dev=dev; skb->mac.raw=skb->data; @@ -223,7 +241,7 @@ void sppp_input (struct net_device *dev, struct sk_buff *skb) if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", dev->name, skb->len); -drop: kfree_skb(skb); + kfree_skb(skb); return; } @@ -231,13 +249,11 @@ drop: kfree_skb(skb); h = (struct ppp_header *)skb->data; skb_pull(skb,sizeof(struct ppp_header)); + spin_lock_irqsave(&sp->lock, flags); + switch (h->address) { default: /* Invalid PPP packet. */ -invalid: if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; + goto invalid; case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; @@ -261,15 +277,13 @@ invalid: if (sp->pp_flags & PP_DEBUG) goto drop; case PPP_LCP: sppp_lcp_input (sp, skb); - kfree_skb(skb); - return; + goto drop; case PPP_IPCP: if (sp->lcp.state == LCP_STATE_OPENED) sppp_ipcp_input (sp, skb); else printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); - kfree_skb(skb); - return; + goto drop; case PPP_IP: if (sp->ipcp.state == IPCP_STATE_OPENED) { if(sp->pp_flags&PP_DEBUG) @@ -277,7 +291,7 @@ invalid: if (sp->pp_flags & PP_DEBUG) skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; } break; #ifdef IPX @@ -287,7 +301,7 @@ invalid: if (sp->pp_flags & PP_DEBUG) skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; } break; #endif @@ -308,26 +322,36 @@ invalid: if (sp->pp_flags & PP_DEBUG) goto invalid; case CISCO_KEEPALIVE: sppp_cisco_input (sp, skb); - kfree_skb(skb); - return; + goto drop; #ifdef CONFIG_INET case ETH_P_IP: skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; #endif #ifdef CONFIG_IPX case ETH_P_IPX: skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; #endif } break; } + goto drop; + +invalid: + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", + dev->name, h->address, h->control, ntohs (h->protocol)); +drop: kfree_skb(skb); +done: + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); + return; } EXPORT_SYMBOL(sppp_input); @@ -394,10 +418,14 @@ static void sppp_keepalive (unsigned long dummy) ! (dev->flags & IFF_UP)) continue; + spin_lock(&sp->lock); + /* No keepalive in PPP mode if LCP not opened yet. */ if (! (sp->pp_flags & PP_CISCO) && - sp->lcp.state != LCP_STATE_OPENED) + sp->lcp.state != LCP_STATE_OPENED) { + spin_unlock(&sp->lock); continue; + } if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ @@ -424,8 +452,11 @@ static void sppp_keepalive (unsigned long dummy) sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } + + spin_unlock(&sp->lock); } spin_unlock_irqrestore(&spppq_lock, flags); + sppp_flush_xmit(); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } @@ -757,6 +788,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) } } + /* * Send PPP LCP packet. */ @@ -804,7 +836,7 @@ static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, /* Control is high priority so it doesn't get queued behind data */ skb->priority=TC_PRIO_CONTROL; skb->dev = dev; - dev_queue_xmit(skb); + skb_queue_tail(&tx_queue, skb); } /* @@ -846,7 +878,7 @@ static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) sp->obytes += skb->len; skb->priority=TC_PRIO_CONTROL; skb->dev = dev; - dev_queue_xmit(skb); + skb_queue_tail(&tx_queue, skb); } /** @@ -861,10 +893,15 @@ static void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) int sppp_close (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + + spin_lock_irqsave(&sp->lock, flags); sp->pp_link_state = SPPP_LINK_DOWN; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); + spin_unlock_irqrestore(&sp->lock, flags); + return 0; } @@ -883,11 +920,18 @@ EXPORT_SYMBOL(sppp_close); int sppp_open (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + sppp_close(dev); + + spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sppp_lcp_open (sp); } sp->pp_link_state = SPPP_LINK_DOWN; + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); + return 0; } @@ -912,7 +956,11 @@ EXPORT_SYMBOL(sppp_open); int sppp_reopen (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + sppp_close(dev); + + spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sp->lcp.magic = jiffies; @@ -923,6 +971,8 @@ int sppp_reopen (struct net_device *dev) sppp_set_timeout (sp, 1); } sp->pp_link_state=SPPP_LINK_DOWN; + spin_unlock_irqrestore(&sp->lock, flags); + return 0; } @@ -1040,6 +1090,7 @@ void sppp_attach(struct ppp_device *pd) sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sp->pp_if = dev; + spin_lock_init(&sp->lock); /* * Device specific setup. All but interrupt handler and @@ -1290,11 +1341,11 @@ static void sppp_cp_timeout (unsigned long arg) struct sppp *sp = (struct sppp*) arg; unsigned long flags; - spin_lock_irqsave(&spppq_lock, flags); + spin_lock_irqsave(&sp->lock, flags); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { - spin_unlock_irqrestore(&spppq_lock, flags); + spin_unlock_irqrestore(&sp->lock, flags); return; } switch (sp->lcp.state) { @@ -1333,7 +1384,8 @@ static void sppp_cp_timeout (unsigned long arg) } break; } - spin_unlock_irqrestore(&spppq_lock, flags); + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); } static char *sppp_lcp_type_name (u8 type) @@ -1393,6 +1445,8 @@ static void sppp_print_bytes (u_char *p, u16 len) static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) { + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + return NET_RX_DROP; sppp_input(dev,skb); return 0; } @@ -1400,6 +1454,7 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, + .data = (void*)1, /* must be non-NULL to indicate 'new' protocol */ }; static char banner[] __initdata = @@ -1412,6 +1467,7 @@ static int __init sync_ppp_init(void) if(debug) debug=PP_DEBUG; printk(banner); + skb_queue_head_init(&tx_queue); dev_add_pack(&sppp_packet_type); return 0; } diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index b760b186ebd..9706768543f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -888,7 +888,7 @@ typedef struct { #ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) -const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; // A few details needed for WEP (Wireless Equivalent Privacy) diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 14309468dfc..290891cd4a5 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1903,7 +1903,7 @@ static int atmel_get_frag(struct net_device *dev, return 0; } -const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; static int atmel_set_freq(struct net_device *dev, diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index fd766516c5e..ad105b88141 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -425,7 +425,7 @@ static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) { struct mm_struct * mm = 0; struct task_struct * new; - unsigned long cookie; + unsigned long cookie = 0; int in_kernel = 1; unsigned int i; @@ -442,13 +442,15 @@ static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) in_kernel = s->event; add_kernel_ctx_switch(s->event); } else { + struct mm_struct * oldmm = mm; + /* userspace context switch */ new = (struct task_struct *)s->event; - release_mm(mm); + release_mm(oldmm); mm = take_tasks_mm(new); - - cookie = get_exec_dcookie(mm); + if (mm != oldmm) + cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); } } else { diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 035dcbcb970..ea4b43068b2 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -93,7 +93,11 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) continue; device_add(&dev->dev); + + spin_lock(&pci_bus_lock); list_add_tail(&dev->global_list, &pci_devices); + spin_unlock(&pci_bus_lock); + pci_proc_attach_device(dev); pci_create_sysfs_dev_files(dev); @@ -108,7 +112,9 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) * it and then scan for unattached PCI devices. */ if (dev->subordinate && list_empty(&dev->subordinate->node)) { + spin_lock(&pci_bus_lock); list_add_tail(&dev->subordinate->node, &dev->bus->children); + spin_unlock(&pci_bus_lock); pci_bus_add_devices(dev->subordinate); } } diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index e943e451acb..3b2ac2a8c08 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -173,6 +173,24 @@ int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, } EXPORT_SYMBOL(pci_visit_dev); +static void pci_destroy_dev(struct pci_dev *dev) +{ + pci_proc_detach_device(dev); + device_unregister(&dev->dev); + + /* Remove the device from the device lists, and prevent any further + * list accesses from this device */ + spin_lock(&pci_bus_lock); + list_del(&dev->bus_list); + list_del(&dev->global_list); + dev->bus_list.next = dev->bus_list.prev = NULL; + dev->global_list.next = dev->global_list.prev = NULL; + spin_unlock(&pci_bus_lock); + + pci_free_resources(dev); + pci_dev_put(dev); +} + /** * pci_remove_device_safe - remove an unused hotplug device * @dev: the device to remove @@ -186,11 +204,7 @@ int pci_remove_device_safe(struct pci_dev *dev) { if (pci_dev_driver(dev)) return -EBUSY; - device_unregister(&dev->dev); - list_del(&dev->bus_list); - list_del(&dev->global_list); - pci_free_resources(dev); - pci_proc_detach_device(dev); + pci_destroy_dev(dev); return 0; } EXPORT_SYMBOL(pci_remove_device_safe); @@ -237,17 +251,15 @@ void pci_remove_bus_device(struct pci_dev *dev) pci_remove_behind_bridge(dev); pci_proc_detach_bus(b); + spin_lock(&pci_bus_lock); list_del(&b->node); + spin_unlock(&pci_bus_lock); + kfree(b); dev->subordinate = NULL; } - device_unregister(&dev->dev); - list_del(&dev->bus_list); - list_del(&dev->global_list); - pci_free_resources(dev); - pci_proc_detach_device(dev); - pci_put_dev(dev); + pci_destroy_dev(dev); } /** diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 3becefc4024..247714b9f80 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -35,6 +34,7 @@ #define _ACPIPHP_H #include +#include /* for KOBJ_NAME_LEN */ #include "pci_hotplug.h" #define dbg(format, arg...) \ @@ -49,7 +49,7 @@ #define SLOT_MAGIC 0x67267322 /* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ +#define SLOT_NAME_SIZE KOBJ_NAME_LEN /* {_SUN} */ struct acpiphp_bridge; struct acpiphp_slot; @@ -212,11 +212,7 @@ struct acpiphp_func { #define FUNC_HAS_PS2 (0x00000040) #define FUNC_HAS_PS3 (0x00000080) -/* not yet */ -#define SLOT_SUPPORT_66MHZ (0x00010000) -#define SLOT_SUPPORT_100MHZ (0x00020000) -#define SLOT_SUPPORT_133MHZ (0x00040000) -#define SLOT_SUPPORT_PCIX (0x00080000) +#define FUNC_EXISTS (0x10000000) /* to make sure we call _EJ0 only for existing funcs */ /* function prototypes */ diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index cffa85dba2c..b839e6d5e40 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -57,7 +56,7 @@ int acpiphp_debug; static int num_slots; #define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -376,10 +375,8 @@ static int init_acpi (void) */ static void make_slot_name (struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", - slot->acpi_slot->sun, - slot->acpi_slot->bridge->bus, - slot->acpi_slot->device); + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u", + slot->acpi_slot->sun); } /** diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 9ab2cda7954..3af6ad4adbe 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -1,9 +1,9 @@ /* * ACPI PCI HotPlug glue functions to ACPI CA subsystem * - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ @@ -204,7 +204,6 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) if (ACPI_FAILURE(status)) { err("failed to register interrupt notify handler\n"); - kfree(newfunc); return status; } @@ -617,9 +616,8 @@ find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) /* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridges(struct acpi_device *device) +static int add_bridge(acpi_handle handle) { - acpi_handle *handle = device->handle; acpi_status status; unsigned long tmp; int seg, bus; @@ -673,6 +671,12 @@ static int add_bridges(struct acpi_device *device) } +static void remove_bridge (acpi_handle handle) +{ + /* No-op for now .. */ +} + + static int power_on_slot (struct acpiphp_slot *slot) { acpi_status status; @@ -725,9 +729,7 @@ static int power_off_slot (struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_PS3) { - dbg("%s: executing _PS3 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); + if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -740,10 +742,8 @@ static int power_off_slot (struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_EJ0) { - dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - + /* We don't want to call _EJ0 on non-existing functions. */ + if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) { /* _EJ0 method take one argument */ arg_list.count = 1; arg_list.pointer = &arg; @@ -756,6 +756,7 @@ static int power_off_slot (struct acpiphp_slot *slot) retval = -1; goto err_exit; } + func->flags &= (~FUNC_EXISTS); } } @@ -835,6 +836,8 @@ static int enable_device (struct acpiphp_slot *slot) retval = acpiphp_configure_function(func); if (retval) goto err_exit; + + func->flags |= FUNC_EXISTS; } slot->flags |= SLOT_ENABLED; @@ -1029,13 +1032,10 @@ static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *conte } } -static struct acpi_driver acpi_pci_hp_driver = { - .name = "pci_hp", - .class = "", - .ids = ACPI_PCI_HOST_HID, - .ops = { - .add = add_bridges, - } + +static struct acpi_pci_driver acpi_pci_hp_driver = { + .add = add_bridge, + .remove = remove_bridge, }; /** @@ -1044,17 +1044,15 @@ static struct acpi_driver acpi_pci_hp_driver = { */ int acpiphp_glue_init (void) { - acpi_status status; + int num; if (list_empty(&pci_root_buses)) return -1; - status = acpi_bus_register_driver(&acpi_pci_hp_driver); + num = acpi_pci_register_driver(&acpi_pci_hp_driver); - if (ACPI_FAILURE(status)) { - err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); + if (num <= 0) return -1; - } return 0; } @@ -1296,7 +1294,7 @@ u8 acpiphp_get_power_status (struct acpiphp_slot *slot) /* * attention LED ON: 1 - * OFF: 0 + * OFF: 0 * * TBD * no direct attention led status information via ACPI diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c index 6ebbb975d6f..529f170a235 100644 --- a/drivers/pci/hotplug/acpiphp_pci.c +++ b/drivers/pci/hotplug/acpiphp_pci.c @@ -4,7 +4,7 @@ * Copyright (c) 1995,2001 Compaq Computer Corporation * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001,2002 IBM Corp. - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (c) 2002 NEC Corporation * @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c index ea79c3c32b1..5ed1036617c 100644 --- a/drivers/pci/hotplug/acpiphp_res.c +++ b/drivers/pci/hotplug/acpiphp_res.c @@ -5,7 +5,7 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 NEC Corporation * * All rights reserved. @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to , + * Send feedback to , * */ diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index dde99a9f3e3..d7f601cdde3 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -138,10 +138,10 @@ static int pci_device_probe(struct device * dev) drv = to_pci_driver(dev->driver); pci_dev = to_pci_dev(dev); - pci_get_dev(pci_dev); + pci_dev_get(pci_dev); error = __pci_device_probe(drv, pci_dev); if (error) - pci_put_dev(pci_dev); + pci_dev_put(pci_dev); return error; } @@ -156,7 +156,7 @@ static int pci_device_remove(struct device * dev) drv->remove(pci_dev); pci_dev->driver = NULL; } - pci_put_dev(pci_dev); + pci_dev_put(pci_dev); return 0; } @@ -448,18 +448,18 @@ static int pci_bus_match(struct device * dev, struct device_driver * drv) } /** - * pci_get_dev - increments the reference count of the pci device structure + * pci_dev_get - increments the reference count of the pci device structure * @dev: the device being referenced * * Each live reference to a device should be refcounted. * * Drivers for PCI devices should normally record such references in * their probe() methods, when they bind to a device, and release - * them by calling pci_put_dev(), in their disconnect() methods. + * them by calling pci_dev_put(), in their disconnect() methods. * * A pointer to the device with the incremented reference counter is returned. */ -struct pci_dev *pci_get_dev (struct pci_dev *dev) +struct pci_dev *pci_dev_get(struct pci_dev *dev) { struct device *tmp; @@ -474,13 +474,13 @@ struct pci_dev *pci_get_dev (struct pci_dev *dev) } /** - * pci_put_dev - release a use of the pci device structure + * pci_dev_put - release a use of the pci device structure * @dev: device that's been disconnected * * Must be called when a user of a device is finished with it. When the last * user of the device calls this function, the memory of the device is freed. */ -void pci_put_dev(struct pci_dev *dev) +void pci_dev_put(struct pci_dev *dev) { if (dev) put_device(&dev->dev); @@ -504,5 +504,5 @@ EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); EXPORT_SYMBOL(pci_dev_driver); EXPORT_SYMBOL(pci_bus_type); -EXPORT_SYMBOL(pci_get_dev); -EXPORT_SYMBOL(pci_put_dev); +EXPORT_SYMBOL(pci_dev_get); +EXPORT_SYMBOL(pci_dev_put); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 4d33ee733b5..4e13d7141b7 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -18,12 +18,6 @@ #include "pci.h" -#if BITS_PER_LONG == 32 -#define LONG_FORMAT "\t%08lx" -#else -#define LONG_FORMAT "\t%16lx" -#endif - /* show configuration fields */ #define pci_config_attr(field, format_string) \ static ssize_t \ @@ -36,11 +30,11 @@ show_##field (struct device *dev, char *buf) \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -pci_config_attr(vendor, "%04x\n"); -pci_config_attr(device, "%04x\n"); -pci_config_attr(subsystem_vendor, "%04x\n"); -pci_config_attr(subsystem_device, "%04x\n"); -pci_config_attr(class, "%06x\n"); +pci_config_attr(vendor, "0x%04x\n"); +pci_config_attr(device, "0x%04x\n"); +pci_config_attr(subsystem_vendor, "0x%04x\n"); +pci_config_attr(subsystem_device, "0x%04x\n"); +pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); /* show resources */ @@ -50,9 +44,13 @@ pci_show_resources(struct device * dev, char * buf) struct pci_dev * pci_dev = to_pci_dev(dev); char * str = buf; int i; + int max = 7; + + if (pci_dev->subordinate) + max = DEVICE_COUNT_RESOURCE; - for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(pci_dev,i); i++) { - str += sprintf(str,LONG_FORMAT LONG_FORMAT LONG_FORMAT "\n", + for (i = 0; i < max; i++) { + str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", pci_resource_start(pci_dev,i), pci_resource_end(pci_dev,i), pci_resource_flags(pci_dev,i)); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 69b2fff6f65..3288e401d91 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -58,3 +58,6 @@ struct pci_visit { extern int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent); + +/* Lock for read/write access to pci device and bus lists */ +extern spinlock_t pci_bus_lock; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 42f8a6d9222..ee71590f89c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -524,7 +524,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) } device_initialize(&dev->dev); dev->dev.release = pci_release_dev; - pci_get_dev(dev); + pci_dev_get(dev); pci_name_device(dev); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 0073b58e823..e576e7a62a1 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -308,39 +308,45 @@ static struct file_operations proc_bus_pci_operations = { /* iterator */ static void *pci_seq_start(struct seq_file *m, loff_t *pos) { - struct list_head *p = &pci_devices; + struct pci_dev *dev = NULL; loff_t n = *pos; - /* XXX: surely we need some locking for traversing the list? */ + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); while (n--) { - p = p->next; - if (p == &pci_devices) - return NULL; + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + if (dev == NULL) + goto exit; } - return p; +exit: + return dev; } + static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos) { - struct list_head *p = v; + struct pci_dev *dev = v; + (*pos)++; - return p->next != &pci_devices ? (void *)p->next : NULL; + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + return dev; } + static void pci_seq_stop(struct seq_file *m, void *v) { - /* release whatever locks we need */ + if (v) { + struct pci_dev *dev = v; + pci_dev_put(dev); + } } static int show_device(struct seq_file *m, void *v) { - struct list_head *p = v; - const struct pci_dev *dev; + const struct pci_dev *dev = v; const struct pci_driver *drv; int i; - if (p == &pci_devices) + if (dev == NULL) return 0; - dev = pci_dev_g(p); drv = pci_dev_driver(dev); seq_printf(m, "%02x%02x\t%04x%04x\t%x", dev->bus->number, @@ -383,7 +389,8 @@ int pci_proc_attach_device(struct pci_dev *dev) return -EACCES; if (!(de = bus->procdir)) { - sprintf(name, "%02x", bus->number); + if (pci_name_bus(name, bus)) + return -EEXIST; de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir); if (!de) return -ENOMEM; @@ -451,19 +458,18 @@ int pci_proc_detach_bus(struct pci_bus* bus) */ static int show_dev_config(struct seq_file *m, void *v) { - struct list_head *p = v; - struct pci_dev *dev; + struct pci_dev *dev = v; + struct pci_dev *first_dev; struct pci_driver *drv; u32 class_rev; unsigned char latency, min_gnt, max_lat, *class; int reg; - if (p == &pci_devices) { + first_dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL); + if (dev == first_dev) seq_puts(m, "PCI devices found:\n"); - return 0; - } + pci_dev_put(first_dev); - dev = pci_dev_g(p); drv = pci_dev_driver(dev); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ce1b710e088..7bfbb30f94d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -690,6 +690,9 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if ((dev->device == PCI_DEVICE_ID_INTEL_82850_HB) && (dev->subsystem_device == 0x8030)) /* P4T533 */ asus_hides_smbus = 1; + if ((dev->device == PCI_DEVICE_ID_INTEL_7205_0) && + (dev->subsystem_device == 0x8070)) /* P4G8X Deluxe */ + asus_hides_smbus = 1; return; } @@ -838,6 +841,7 @@ static struct pci_fixup pci_fixups[] __devinitdata = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845_HB, asus_hides_smbus_hostbridge }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asus_hides_smbus_hostbridge }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc }, diff --git a/drivers/pci/search.c b/drivers/pci/search.c index c7b30f9b8a5..85c74126ee6 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -1,6 +1,17 @@ +/* + * PCI searching functions. + * + * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang + * Copyright 1997 -- 2000 Martin Mares + * Copyright 2003 -- Greg Kroah-Hartman + */ + #include #include +spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED; + static struct pci_bus * pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) { @@ -52,11 +63,15 @@ pci_find_bus(unsigned char busnr) struct pci_bus * pci_find_next_bus(const struct pci_bus *from) { - struct list_head *n = from ? from->node.next : pci_root_buses.next; + struct list_head *n; struct pci_bus *b = NULL; + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->node.next : pci_root_buses.next; if (n != &pci_root_buses) b = pci_bus_b(n); + spin_unlock(&pci_bus_lock); return b; } @@ -97,24 +112,36 @@ pci_find_slot(unsigned int bus, unsigned int devfn) * device structure is returned. Otherwise, %NULL is returned. * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as + * the pci device returned by this function can disappear at any moment in + * time. */ struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.next : pci_devices.next; + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && (device == PCI_ANY_ID || dev->device == device) && (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) && (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)) - return dev; + goto exit; n = n->next; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } /** @@ -128,6 +155,10 @@ pci_find_subsys(unsigned int vendor, unsigned int device, * returned. Otherwise, %NULL is returned. * A new search is initiated by passing %NULL to the @from argument. * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * NOTE: Do not use this function anymore, use pci_get_device() instead, as + * the pci device returned by this function can disappear at any moment in + * time. */ struct pci_dev * pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) @@ -135,6 +166,77 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev * return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); } +/** + * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its + * device structure is returned, and the reference count to the device is + * incremented. Otherwise, %NULL is returned. A new search is initiated by + * passing %NULL to the @from argument. Otherwise if @from is not %NULL, + * searches continue from next device on the global list. + * The reference count for @from is always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_subsys(unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from) +{ + struct list_head *n; + struct pci_dev *dev; + + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device) && + (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) && + (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)) + goto exit; + n = n->next; + } + dev = NULL; +exit: + pci_dev_put(from); + dev = pci_dev_get(dev); + spin_unlock(&pci_bus_lock); + return dev; +} + +/** + * pci_get_device - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor and @device, a pointer to its device structure is + * returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device on the global list. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor and @device, the reference count to the + * device is incremented and a pointer to its device structure is returned. + * Otherwise, %NULL is returned. A new search is initiated by passing %NULL + * to the @from argument. Otherwise if @from is not %NULL, searches continue + * from next device on the global list. The reference count for @from is + * always decremented if it is not %NULL. + */ +struct pci_dev * +pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from) +{ + return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); +} + /** * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id @@ -151,16 +253,24 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev * struct pci_dev * pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.prev : pci_devices.prev; + struct list_head *n; + struct pci_dev *dev; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + WARN_ON(irqs_disabled()); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.prev : pci_devices.prev; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && (device == PCI_ANY_ID || dev->device == device)) - return dev; + goto exit; n = n->prev; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } @@ -179,15 +289,22 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p struct pci_dev * pci_find_class(unsigned int class, const struct pci_dev *from) { - struct list_head *n = from ? from->global_list.next : pci_devices.next; + struct list_head *n; + struct pci_dev *dev; - while (n != &pci_devices) { - struct pci_dev *dev = pci_dev_g(n); + spin_lock(&pci_bus_lock); + n = from ? from->global_list.next : pci_devices.next; + + while (n && (n != &pci_devices)) { + dev = pci_dev_g(n); if (dev->class == class) - return dev; + goto exit; n = n->next; } - return NULL; + dev = NULL; +exit: + spin_unlock(&pci_bus_lock); + return dev; } EXPORT_SYMBOL(pci_find_bus); @@ -196,3 +313,5 @@ EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); +EXPORT_SYMBOL(pci_get_device); +EXPORT_SYMBOL(pci_get_subsys); diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 5873704aa3c..cbccbaa2486 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o -obj-$(CONFIG_YENTA) += yenta.o +obj-$(CONFIG_YENTA) += yenta_socket.o obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 46b112b1cec..3dfaa5bb588 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -106,11 +106,10 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag pccard_mem_map *mem = &s->cis_mem; if (!(s->features & SS_CAP_STATIC_MAP) && mem->sys_start == 0) { - int low = !(s->features & SS_CAP_PAGE_REGS); validate_mem(s); mem->sys_start = 0; if (find_mem_region(&mem->sys_start, s->map_size, - s->map_size, low, "card services", s)) { + s->map_size, 0, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); return NULL; } diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 372870ce7ee..4e439229dc3 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -816,7 +816,8 @@ static int pccardd(void *__skt) if ((skt->state & SOCKET_PRESENT) && !(status & SS_DETECT)) socket_shutdown(skt); - if (status & SS_DETECT) + if (!(skt->state & SOCKET_PRESENT) && + (status & SS_DETECT)) socket_insert(skt); } if (events & SS_BATDEAD) @@ -2043,8 +2044,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle if (!(s->features & SS_CAP_STATIC_MAP) && find_mem_region(&win->base, win->size, align, - (req->Attributes & WIN_MAP_BELOW_1MB) || - !(s->features & SS_CAP_PAGE_REGS), + (req->Attributes & WIN_MAP_BELOW_1MB), (*handle)->dev_info, s)) return CS_IN_USE; (*handle)->state |= CLIENT_WIN_REQ(w); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index c794a23c8e8..55049c5d182 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -168,7 +168,7 @@ void validate_mem(struct pcmcia_socket *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, char *name, struct pcmcia_socket *s); int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, struct pcmcia_socket *s); + int low, char *name, struct pcmcia_socket *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 04e800fff4b..4f3c7317228 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1471,6 +1471,10 @@ static int __init init_i82365(void) pcmcia_unregister_socket(&socket[i].socket); break; } + class_device_create_file(&socket[i].socket.dev, + &class_device_attr_info); + class_device_create_file(&socket[i].socket.dev, + &class_device_attr_exca); } /* Finally, schedule a polling interrupt */ @@ -1481,9 +1485,6 @@ static int __init init_i82365(void) poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } - - class_device_create_file(&socket[i].socket.dev, &class_device_attr_info); - class_device_create_file(&socket[i].socket.dev, &class_device_attr_exca); return 0; diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 99b7cb2f2dd..9dd5e03e92f 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -139,22 +139,6 @@ static inline int check_io_resource(unsigned long b, unsigned long n, return 0; } -/* FIXME: Fundamentally racy. */ -static inline int check_mem_resource(unsigned long b, unsigned long n, - struct pci_dev *dev) -{ - struct resource *region; - - region = __request_region(resource_parent(b, n, IORESOURCE_MEM, dev), - b, n, "check_mem_resource"); - if (!region) - return -EBUSY; - - release_resource(region); - kfree(region); - return 0; -} - static struct resource *make_resource(unsigned long b, unsigned long n, int flags, char *name) { @@ -340,52 +324,103 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) ======================================================================*/ /* Validation function for cards with a valid CIS */ -static int cis_readable(struct pcmcia_socket *s, u_long base) +static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info) { - cisinfo_t info1, info2; - int ret; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->map_size-1; - s->cis_virt = ioremap(base, s->map_size); - ret = pcmcia_validate_cis(s->clients, &info1); - /* invalidate mapping and CIS cache */ - iounmap(s->cis_virt); - destroy_cis_cache(s); - if ((ret != 0) || (info1.Chains == 0)) - return 0; - s->cis_mem.sys_start = base+s->map_size; - s->cis_mem.sys_stop = base+2*s->map_size-1; - s->cis_virt = ioremap(base+s->map_size, s->map_size); - ret = pcmcia_validate_cis(s->clients, &info2); - iounmap(s->cis_virt); - destroy_cis_cache(s); - return ((ret == 0) && (info1.Chains == info2.Chains)); + int ret = -1; + + s->cis_mem.sys_start = res->start; + s->cis_mem.sys_stop = res->end; + s->cis_virt = ioremap(res->start, s->map_size); + if (s->cis_virt) { + ret = pcmcia_validate_cis(s->clients, info); + /* invalidate mapping and CIS cache */ + iounmap(s->cis_virt); + s->cis_virt = NULL; + destroy_cis_cache(s); + } + s->cis_mem.sys_start = 0; + s->cis_mem.sys_stop = 0; + if ((ret != 0) || (info->Chains == 0)) + return 0; + return 1; } /* Validation function for simple memory cards */ -static int checksum(struct pcmcia_socket *s, u_long base) +static int checksum(struct pcmcia_socket *s, struct resource *res) { - int i, a, b, d; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->map_size-1; - s->cis_virt = ioremap(base, s->map_size); - s->cis_mem.card_start = 0; - s->cis_mem.flags = MAP_ACTIVE; - s->ss_entry->set_mem_map(s, &s->cis_mem); - /* Don't bother checking every word... */ - a = 0; b = -1; - for (i = 0; i < s->map_size; i += 44) { - d = readl(s->cis_virt+i); - a += d; b &= d; - } - iounmap(s->cis_virt); - return (b == -1) ? -1 : (a>>1); + pccard_mem_map map; + int i, a = 0, b = -1, d; + void *virt; + + virt = ioremap(res->start, s->map_size); + if (virt) { + map.map = 0; + map.flags = MAP_ACTIVE; + map.speed = 0; + map.sys_start = res->start; + map.sys_stop = res->end; + map.card_start = 0; + s->ss_entry->set_mem_map(s, &map); + + /* Don't bother checking every word... */ + for (i = 0; i < s->map_size; i += 44) { + d = readl(virt+i); + a += d; + b &= d; + } + + map.flags = 0; + s->ss_entry->set_mem_map(s, &map); + + iounmap(virt); + } + + return (b == -1) ? -1 : (a>>1); +} + +static int +cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) +{ + struct resource *res1, *res2; + cisinfo_t info1, info2; + int ret = 0; + + res1 = request_mem_region(base, size/2, "cs memory probe"); + res2 = request_mem_region(base + size/2, size/2, "cs memory probe"); + + if (res1 && res2) { + ret = readable(s, res1, &info1); + ret += readable(s, res2, &info2); + } + + if (res2) + release_resource(res2); + if (res1) + release_resource(res1); + + return (ret == 2) && (info1.Chains == info2.Chains); } -static int checksum_match(struct pcmcia_socket *s, u_long base) +static int +checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) { - int a = checksum(s, base), b = checksum(s, base+s->map_size); - return ((a == b) && (a >= 0)); + struct resource *res1, *res2; + int a = -1, b = -1; + + res1 = request_mem_region(base, size/2, "cs memory probe"); + res2 = request_mem_region(base + size/2, size/2, "cs memory probe"); + + if (res1 && res2) { + a = checksum(s, res1); + b = checksum(s, res2); + } + + if (res2) + release_resource(res2); + if (res1) + release_resource(res1); + + return (a == b) && (a >= 0); } /*====================================================================== @@ -409,16 +444,16 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) step = 2 * s->map_size; for (i = j = base; i < base+num; i = j + step) { if (!fail) { - for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step, s->cb_dev) == 0) && - cis_readable(s, j)) + for (j = i; j < base+num; j += step) { + if (cis_readable(s, j, step)) break; + } fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step, s->cb_dev) == 0) && - checksum_match(s, j) && checksum_match(s, j + step)) + if (checksum_match(s, j, step) && + checksum_match(s, j + step, step)) break; } if (i != j) { @@ -555,17 +590,19 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, } int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, struct pcmcia_socket *s) + int low, char *name, struct pcmcia_socket *s) { u_long try; resource_map_t *m; int ret = -1; + low = low || !(s->features & SS_CAP_PAGE_REGS); + down(&rsrc_sem); while (1) { for (m = mem_db.next; m != &mem_db; m = m->next) { /* first pass >1MB, second pass <1MB */ - if ((force_low != 0) ^ (m->base < 0x100000)) + if ((low != 0) ^ (m->base < 0x100000)) continue; try = (m->base & ~(align-1)) + *base; @@ -581,9 +618,9 @@ int find_mem_region(u_long *base, u_long num, u_long align, break; } } - if (force_low) + if (low) break; - force_low++; + low++; } out: up(&rsrc_sem); diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta_socket.c similarity index 99% rename from drivers/pcmcia/yenta.c rename to drivers/pcmcia/yenta_socket.c index 90b32f3b0af..f82499e672a 100644 --- a/drivers/pcmcia/yenta.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1,5 +1,5 @@ /* - * Regular cardbus driver ("yenta") + * Regular cardbus driver ("yenta_socket") * * (C) Copyright 1999, 2000 Linus Torvalds * @@ -25,7 +25,7 @@ #include -#include "yenta.h" +#include "yenta_socket.h" #include "i82365.h" diff --git a/drivers/pcmcia/yenta.h b/drivers/pcmcia/yenta_socket.h similarity index 100% rename from drivers/pcmcia/yenta.h rename to drivers/pcmcia/yenta_socket.h diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h dissimilarity index 71% index e991aa70220..d479e099b25 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -1,32 +1,14 @@ -extern struct bus_type pnp_bus_type; -extern spinlock_t pnp_lock; -void *pnp_alloc(long size); -int pnp_interface_attach_device(struct pnp_dev *dev); -void pnp_name_device(struct pnp_dev *dev); -void pnp_fixup_device(struct pnp_dev *dev); -void pnp_free_resources(struct pnp_resources *resources); -int __pnp_add_device(struct pnp_dev *dev); -void __pnp_remove_device(struct pnp_dev *dev); - -/* resource conflict types */ -#define CONFLICT_TYPE_NONE 0x0000 /* there are no conflicts, other than those in the link */ -#define CONFLICT_TYPE_RESERVED 0x0001 /* the resource requested was reserved */ -#define CONFLICT_TYPE_IN_USE 0x0002 /* there is a conflict because the resource is in use */ -#define CONFLICT_TYPE_PCI 0x0004 /* there is a conflict with a pci device */ -#define CONFLICT_TYPE_INVALID 0x0008 /* the resource requested is invalid */ -#define CONFLICT_TYPE_INTERNAL 0x0010 /* resources within the device conflict with each ohter */ -#define CONFLICT_TYPE_PNP_WARM 0x0020 /* there is a conflict with a pnp device that is active */ -#define CONFLICT_TYPE_PNP_COLD 0x0040 /* there is a conflict with a pnp device that is disabled */ - -/* conflict search modes */ -#define SEARCH_WARM 1 /* check for conflicts with active devices */ -#define SEARCH_COLD 0 /* check for conflicts with disabled devices */ - -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode); -int pnp_check_port(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode); -int pnp_check_mem(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode); -int pnp_check_irq(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode); -int pnp_check_dma(struct pnp_dev * dev, int idx); +extern struct bus_type pnp_bus_type; +extern spinlock_t pnp_lock; +void *pnp_alloc(long size); +int pnp_interface_attach_device(struct pnp_dev *dev); +void pnp_name_device(struct pnp_dev *dev); +void pnp_fixup_device(struct pnp_dev *dev); +void pnp_free_option(struct pnp_option *option); +int __pnp_add_device(struct pnp_dev *dev); +void __pnp_remove_device(struct pnp_dev *dev); + +int pnp_check_port(struct pnp_dev * dev, int idx); +int pnp_check_mem(struct pnp_dev * dev, int idx); +int pnp_check_irq(struct pnp_dev * dev, int idx); +int pnp_check_dma(struct pnp_dev * dev, int idx); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 7ca8de1a140..313604dba12 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -104,8 +104,8 @@ static void pnp_free_ids(struct pnp_dev *dev) static void pnp_release_device(struct device *dmdev) { struct pnp_dev * dev = to_pnp_dev(dmdev); - if (dev->possible) - pnp_free_resources(dev->possible); + pnp_free_option(dev->independent); + pnp_free_option(dev->dependent); pnp_free_ids(dev); kfree(dev); } @@ -122,7 +122,7 @@ int __pnp_add_device(struct pnp_dev *dev) list_add_tail(&dev->global_list, &pnp_global); list_add_tail(&dev->protocol_list, &dev->protocol->devices); spin_unlock(&pnp_lock); - pnp_auto_config_dev(dev); + ret = device_register(&dev->dev); if (ret == 0) pnp_interface_attach_device(dev); diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 00f4f9463e9..5ce57358df3 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -168,7 +168,8 @@ static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem pnp_printf(buffer, ", %s\n", s); } -static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct pnp_resources *res, int dep) +static void pnp_print_option(pnp_info_buffer_t *buffer, char *space, + struct pnp_option *option, int dep) { char *s; struct pnp_port *port; @@ -176,49 +177,55 @@ static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct p struct pnp_dma *dma; struct pnp_mem *mem; - switch (res->priority) { - case PNP_RES_PRIORITY_PREFERRED: - s = "preferred"; - break; - case PNP_RES_PRIORITY_ACCEPTABLE: - s = "acceptable"; - break; - case PNP_RES_PRIORITY_FUNCTIONAL: - s = "functional"; - break; - default: - s = "invalid"; - } - if (dep > 0) + if (dep) { + switch (option->priority) { + case PNP_RES_PRIORITY_PREFERRED: + s = "preferred"; + break; + case PNP_RES_PRIORITY_ACCEPTABLE: + s = "acceptable"; + break; + case PNP_RES_PRIORITY_FUNCTIONAL: + s = "functional"; + break; + default: + s = "invalid"; + } pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s); - for (port = res->port; port; port = port->next) + } + + for (port = option->port; port; port = port->next) pnp_print_port(buffer, space, port); - for (irq = res->irq; irq; irq = irq->next) + for (irq = option->irq; irq; irq = irq->next) pnp_print_irq(buffer, space, irq); - for (dma = res->dma; dma; dma = dma->next) + for (dma = option->dma; dma; dma = dma->next) pnp_print_dma(buffer, space, dma); - for (mem = res->mem; mem; mem = mem->next) + for (mem = option->mem; mem; mem = mem->next) pnp_print_mem(buffer, space, mem); } -static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf) + +static ssize_t pnp_show_options(struct device *dmdev, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); - struct pnp_resources * res = dev->possible; - int ret, dep = 0; + struct pnp_option * independent = dev->independent; + struct pnp_option * dependent = dev->dependent; + int ret, dep = 1; + pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) return -ENOMEM; + buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; - while (res){ - if (dep == 0) - pnp_print_resources(buffer, "", res, dep); - else - pnp_print_resources(buffer, " ", res, dep); - res = res->dep; + if (independent) + pnp_print_option(buffer, "", independent, 0); + + while (dependent){ + pnp_print_option(buffer, " ", dependent, dep); + dependent = dependent->next; dep++; } ret = (buffer->curr - buf); @@ -226,97 +233,8 @@ static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf) return ret; } -static DEVICE_ATTR(possible,S_IRUGO,pnp_show_possible_resources,NULL); - -static void pnp_print_conflict_node(pnp_info_buffer_t *buffer, struct pnp_dev * dev) -{ - if (!dev) - return; - pnp_printf(buffer, "'%s'.\n", dev->dev.bus_id); -} - -static void pnp_print_conflict_desc(pnp_info_buffer_t *buffer, int conflict) -{ - if (!conflict) - return; - pnp_printf(buffer, " Conflict Detected: %2x - ", conflict); - switch (conflict) { - case CONFLICT_TYPE_RESERVED: - pnp_printf(buffer, "manually reserved.\n"); - break; - - case CONFLICT_TYPE_IN_USE: - pnp_printf(buffer, "currently in use.\n"); - break; - - case CONFLICT_TYPE_PCI: - pnp_printf(buffer, "PCI device.\n"); - break; - - case CONFLICT_TYPE_INVALID: - pnp_printf(buffer, "invalid.\n"); - break; - - case CONFLICT_TYPE_INTERNAL: - pnp_printf(buffer, "another resource on this device.\n"); - break; - - case CONFLICT_TYPE_PNP_WARM: - pnp_printf(buffer, "active PnP device "); - break; - - case CONFLICT_TYPE_PNP_COLD: - pnp_printf(buffer, "disabled PnP device "); - break; - default: - pnp_printf(buffer, "Unknown conflict.\n"); - break; - } -} - -static void pnp_print_conflict(pnp_info_buffer_t *buffer, struct pnp_dev * dev, int idx, int type) -{ - struct pnp_dev * cdev, * wdev = NULL; - int conflict; - switch (type) { - case IORESOURCE_IO: - conflict = pnp_check_port(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_port_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_port_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_MEM: - conflict = pnp_check_mem(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_mem_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_mem_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_IRQ: - conflict = pnp_check_irq(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_irq_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_irq_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_DMA: - conflict = pnp_check_dma(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_dma_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_dma_conflicts(dev, idx, SEARCH_COLD); - break; - default: - return; - } - - pnp_print_conflict_desc(buffer, conflict); +static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL); - if (wdev) - pnp_print_conflict_node(buffer, wdev); - - if (cdev) { - pnp_print_conflict_desc(buffer, CONFLICT_TYPE_PNP_COLD); - pnp_print_conflict_node(buffer, cdev); - } -} static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) { @@ -332,12 +250,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) buffer->buffer = buf; buffer->curr = buffer->buffer; - pnp_printf(buffer,"mode = "); - if (dev->config_mode & PNP_CONFIG_MANUAL) - pnp_printf(buffer,"manual\n"); - else - pnp_printf(buffer,"auto\n"); - pnp_printf(buffer,"state = "); if (dev->active) pnp_printf(buffer,"active\n"); @@ -350,7 +262,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_port_start(dev, i), pnp_port_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IO); } } for (i = 0; i < PNP_MAX_MEM; i++) { @@ -359,21 +270,18 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_mem_start(dev, i), pnp_mem_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_MEM); } } for (i = 0; i < PNP_MAX_IRQ; i++) { if (pnp_irq_valid(dev, i)) { pnp_printf(buffer,"irq"); pnp_printf(buffer," %ld \n", pnp_irq(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IRQ); } } for (i = 0; i < PNP_MAX_DMA; i++) { if (pnp_dma_valid(dev, i)) { pnp_printf(buffer,"dma"); pnp_printf(buffer," %ld \n", pnp_dma(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_DMA); } } ret = (buffer->curr - buf); @@ -381,7 +289,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) return ret; } -extern int pnp_resolve_conflicts(struct pnp_dev *dev); +extern struct semaphore pnp_res_mutex; static ssize_t pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count) @@ -390,6 +298,12 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count char *buf = (void *)ubuf; int retval = 0; + if (dev->status & PNP_ATTACHED) { + retval = -EBUSY; + pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id); + goto done; + } + while (isspace(*buf)) ++buf; if (!strnicmp(buf,"disable",7)) { @@ -400,41 +314,30 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count retval = pnp_activate_dev(dev); goto done; } - if (!strnicmp(buf,"reset",5)) { - if (!dev->active) - goto done; - retval = pnp_disable_dev(dev); - if (retval) + if (!strnicmp(buf,"fill",4)) { + if (dev->active) goto done; - retval = pnp_activate_dev(dev); + retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"auto",4)) { if (dev->active) goto done; + pnp_init_resources(&dev->res); retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"clear",5)) { if (dev->active) goto done; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); - if (dev->rule) - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - goto done; - } - if (!strnicmp(buf,"resolve",7)) { - retval = pnp_resolve_conflicts(dev); + pnp_init_resources(&dev->res); goto done; } if (!strnicmp(buf,"get",3)) { - spin_lock(&pnp_lock); + down(&pnp_res_mutex); if (pnp_can_read(dev)) dev->protocol->get(dev, &dev->res); - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); goto done; } if (!strnicmp(buf,"set",3)) { @@ -442,9 +345,8 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count if (dev->active) goto done; buf += 3; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); + pnp_init_resources(&dev->res); + down(&pnp_res_mutex); while (1) { while (isspace(*buf)) ++buf; @@ -514,7 +416,7 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count } break; } - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); goto done; } done: @@ -543,7 +445,7 @@ static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL); int pnp_interface_attach_device(struct pnp_dev *dev) { - device_create_file(&dev->dev,&dev_attr_possible); + device_create_file(&dev->dev,&dev_attr_options); device_create_file(&dev->dev,&dev_attr_resources); device_create_file(&dev->dev,&dev_attr_id); return 0; diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index 5f659c17cc3..df1c89a6177 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -31,6 +31,7 @@ * 2002-06-06 Made the use of dma channel 0 configurable * Gerald Teschl * 2002-10-06 Ported to PnP Layer - Adam Belay + * 2003-08-11 Resource Management Updates - Adam Belay */ #include @@ -54,7 +55,6 @@ int isapnp_disable; /* Disable ISA PnP */ int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ -int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ MODULE_AUTHOR("Jaroslav Kysela "); @@ -66,8 +66,6 @@ MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port"); MODULE_PARM(isapnp_reset, "i"); MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards"); MODULE_PARM(isapnp_allow_dma0, "i"); -MODULE_PARM(isapnp_skip_pci_scan, "i"); -MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning"); MODULE_PARM(isapnp_verbose, "i"); MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode"); MODULE_LICENSE("GPL"); @@ -460,6 +458,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si dev->capabilities |= PNP_READ; dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_DISABLE; + pnp_init_resources(&dev->res); return dev; } @@ -468,8 +467,8 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si * Add IRQ resource to resources list. */ -static void __init isapnp_add_irq_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_irq_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_irq *irq; @@ -483,7 +482,7 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev, irq->flags = tmp[2]; else irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_add_irq_resource(dev, depnum, irq); + pnp_register_irq_resource(option, irq); return; } @@ -491,8 +490,8 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev, * Add DMA resource to resources list. */ -static void __init isapnp_add_dma_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_dma_resource(struct pnp_option *option, + int size) { unsigned char tmp[2]; struct pnp_dma *dma; @@ -503,7 +502,7 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev, return; dma->map = tmp[0]; dma->flags = tmp[1]; - pnp_add_dma_resource(dev, depnum, dma); + pnp_register_dma_resource(option, dma); return; } @@ -511,8 +510,8 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev, * Add port resource to resources list. */ -static void __init isapnp_add_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[7]; struct pnp_port *port; @@ -526,7 +525,7 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev, port->align = tmp[5]; port->size = tmp[6]; port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -534,8 +533,8 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev, * Add fixed port resource to resources list. */ -static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_port *port; @@ -548,7 +547,7 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, port->size = tmp[2]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -556,8 +555,8 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, * Add memory resource to resources list. */ -static void __init isapnp_add_mem_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -571,7 +570,7 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev, mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } @@ -579,8 +578,8 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev, * Add 32-bit memory resource to resources list. */ -static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[17]; struct pnp_mem *mem; @@ -594,15 +593,15 @@ static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Add 32-bit fixed memory resource to resources list. */ -static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -615,14 +614,14 @@ static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; mem->align = 0; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Parse card name for ISA PnP device. */ - -static void __init + +static void __init isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) { if (name[0] == '\0') { @@ -634,7 +633,7 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) /* clean whitespace from end of string */ while (size1 > 0 && name[--size1] == ' ') name[size1] = '\0'; - } + } } /* @@ -644,14 +643,17 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) static int __init isapnp_create_device(struct pnp_card *card, unsigned short size) { - int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0; + int number = 0, skip = 0, priority = 0, compat = 0; unsigned char type, tmp[17]; + struct pnp_option *option; struct pnp_dev *dev; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return 1; pnp_add_card_device(card,dev); + while (1) { if (isapnp_read_tag(&type, &size)<0) return 1; @@ -662,15 +664,16 @@ static int __init isapnp_create_device(struct pnp_card *card, if (size >= 5 && size <= 6) { if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - pnp_build_resource(dev,0); - pnp_add_card_device(card,dev); size = 0; skip = 0; + option = pnp_register_independent_option(dev); + if (!option) + return 1; + pnp_add_card_device(card,dev); } else { skip = 1; } - dependent = 0; - depnum = 0; + priority = 0; compat = 0; break; case _STAG_COMPATDEVID: @@ -684,43 +687,43 @@ static int __init isapnp_create_device(struct pnp_card *card, case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; - isapnp_add_irq_resource(dev, depnum, size); + isapnp_parse_irq_resource(option, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; - isapnp_add_dma_resource(dev, depnum, size); + isapnp_parse_dma_resource(option, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); - dependent = 0x100 | tmp[0]; + priority = 0x100 | tmp[0]; size = 0; } - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + option = pnp_register_dependent_option(dev,priority); + if (!option) + return 1; break; case _STAG_ENDDEP: if (size != 0) goto __skip; - dependent = 0; - depnum = 0; + priority = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; - isapnp_add_port_resource(dev, depnum, size); + isapnp_parse_port_resource(option, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; - isapnp_add_fixed_port_resource(dev, depnum, size); + isapnp_parse_fixed_port_resource(option, size); size = 0; break; case _STAG_VENDOR: @@ -728,7 +731,7 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEMRANGE: if (size != 9) goto __skip; - isapnp_add_mem_resource(dev, depnum, size); + isapnp_parse_mem_resource(option, size); size = 0; break; case _LTAG_ANSISTR: @@ -743,13 +746,13 @@ static int __init isapnp_create_device(struct pnp_card *card, case _LTAG_MEM32RANGE: if (size != 17) goto __skip; - isapnp_add_mem32_resource(dev, depnum, size); + isapnp_parse_mem32_resource(option, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; - isapnp_add_fixed_mem32_resource(dev, depnum, size); + isapnp_parse_fixed_mem32_resource(option, size); size = 0; break; case _STAG_END: @@ -859,63 +862,6 @@ static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, pnp_add_card_id(id,card); } - -static int isapnp_parse_current_resources(struct pnp_dev *dev, struct pnp_resource_table * res) -{ - int tmp, ret; - struct pnp_rule_table rule; - if (dev->rule) - rule = *dev->rule; - else { - if (!pnp_generate_rule(dev,1,&rule)) - return -EINVAL; - } - - dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); - if (dev->active) { - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); - if (!ret) - continue; - res->port_resource[tmp].start = ret; - if (rule.port[tmp]) - res->port_resource[tmp].end = ret + rule.port[tmp]->size - 1; - else - res->port_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->port_resource[tmp].flags = IORESOURCE_IO; - } - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); - if (!ret) - continue; - res->mem_resource[tmp].start = ret; - if (rule.mem[tmp]) - res->mem_resource[tmp].end = ret + rule.mem[tmp]->size - 1; - else - res->mem_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->mem_resource[tmp].flags = IORESOURCE_MEM; - } - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); - if (!ret) - continue; - res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; - res->irq_resource[tmp].flags = IORESOURCE_IRQ; - } - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); - if (ret == 4) - continue; - if (rule.dma[tmp]) { /* some isapnp systems forget to set this to 4 so we have to check */ - res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; - res->dma_resource[tmp].flags = IORESOURCE_DMA; - } - } - } - return 0; -} - - /* * Build device list for all present ISA PnP devices. */ @@ -925,7 +871,6 @@ static int __init isapnp_build_device_list(void) int csn; unsigned char header[9], checksum; struct pnp_card *card; - struct pnp_dev *dev; isapnp_wait(); isapnp_key(); @@ -959,13 +904,6 @@ static int __init isapnp_build_device_list(void) card->checksum = isapnp_checksum_value; card->protocol = &isapnp_protocol; - /* read the current resource data */ - card_for_each_dev(card,dev) { - isapnp_device(dev->number); - pnp_init_resource_table(&dev->res); - isapnp_parse_current_resources(dev, &dev->res); - } - pnp_add_card(card); } isapnp_wait(); @@ -1041,12 +979,50 @@ EXPORT_SYMBOL(isapnp_write_dword); EXPORT_SYMBOL(isapnp_wake); EXPORT_SYMBOL(isapnp_device); +static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{ + int tmp, ret; + + dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); + if (dev->active) { + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); + if (!ret) + continue; + res->port_resource[tmp].start = ret; + res->port_resource[tmp].flags = IORESOURCE_IO; + } + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); + if (!ret) + continue; + res->mem_resource[tmp].start = ret; + res->mem_resource[tmp].flags = IORESOURCE_MEM; + } + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); + if (!ret) + continue; + res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; + res->irq_resource[tmp].flags = IORESOURCE_IRQ; + } + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); + if (ret == 4) + continue; + res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; + res->dma_resource[tmp].flags = IORESOURCE_DMA; + } + } + return 0; +} + static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res) { int ret; - pnp_init_resource_table(res); + pnp_init_resources(res); isapnp_cfg_begin(dev->card->number, dev->number); - ret = isapnp_parse_current_resources(dev, res); + ret = isapnp_read_resources(dev, res); isapnp_cfg_end(); return ret; } @@ -1196,7 +1172,6 @@ static int __init isapnp_setup_isapnp(char *str) { (void)((get_option(&str,&isapnp_rdp) == 2) && (get_option(&str,&isapnp_reset) == 2) && - (get_option(&str,&isapnp_skip_pci_scan) == 2) && (get_option(&str,&isapnp_verbose) == 2)); return 1; } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c dissimilarity index 74% index 0b168a7b0c4..34d3620c8e3 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -1,752 +1,542 @@ -/* - * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices - * - * Copyright 2003 Adam Belay - * - */ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_PNP_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif - -#include -#include "base.h" - - -int pnp_max_moves = 4; - - -static int pnp_next_port(struct pnp_dev * dev, int idx) -{ - struct pnp_port *port; - unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_PORT) - return 0; - port = dev->rule->port[idx]; - if (!port) - return 1; - - start = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - flags = &dev->res.port_resource[idx].flags; - - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = port->min; - *end = *start + port->size - 1; - *flags = port->flags | IORESOURCE_IO; - if (!pnp_check_port(dev, idx)) - return 1; - } - - /* run through until pnp_check_port is happy */ - do { - *start += port->align; - *end = *start + port->size - 1; - if (*start > port->max || !port->align) - return 0; - } while (pnp_check_port(dev, idx)); - return 1; -} - -static int pnp_next_mem(struct pnp_dev * dev, int idx) -{ - struct pnp_mem *mem; - unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_MEM) - return 0; - mem = dev->rule->mem[idx]; - if (!mem) - return 1; - - start = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - flags = &dev->res.mem_resource[idx].flags; - - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = mem->min; - *end = *start + mem->size -1; - *flags = mem->flags | IORESOURCE_MEM; - if (!(mem->flags & IORESOURCE_MEM_WRITEABLE)) - *flags |= IORESOURCE_READONLY; - if (mem->flags & IORESOURCE_MEM_CACHEABLE) - *flags |= IORESOURCE_CACHEABLE; - if (mem->flags & IORESOURCE_MEM_RANGELENGTH) - *flags |= IORESOURCE_RANGELENGTH; - if (mem->flags & IORESOURCE_MEM_SHADOWABLE) - *flags |= IORESOURCE_SHADOWABLE; - if (!pnp_check_mem(dev, idx)) - return 1; - } - - /* run through until pnp_check_mem is happy */ - do { - *start += mem->align; - *end = *start + mem->size - 1; - if (*start > mem->max || !mem->align) - return 0; - } while (pnp_check_mem(dev, idx)); - return 1; -} - -static int pnp_next_irq(struct pnp_dev * dev, int idx) -{ - struct pnp_irq *irq; - unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_IRQ) - return 0; - irq = dev->rule->irq[idx]; - if (!irq) - return 1; - - start = &dev->res.irq_resource[idx].start; - end = &dev->res.irq_resource[idx].end; - flags = &dev->res.irq_resource[idx].flags; - - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = irq->flags | IORESOURCE_IRQ; - if (!pnp_check_irq(dev, idx)) - return 1; - } - - mask = irq->map; - for (i = *start + 1; i < 16; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_irq(dev, idx)) - return 1; - } - } - return 0; -} - -static int pnp_next_dma(struct pnp_dev * dev, int idx) -{ - struct pnp_dma *dma; - unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_DMA) - return -EINVAL; - dma = dev->rule->dma[idx]; - if (!dma) - return 1; - - start = &dev->res.dma_resource[idx].start; - end = &dev->res.dma_resource[idx].end; - flags = &dev->res.dma_resource[idx].flags; - - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = dma->flags | IORESOURCE_DMA; - if (!pnp_check_dma(dev, idx)) - return 1; - } - - mask = dma->map; - for (i = *start + 1; i < 8; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_dma(dev, idx)) - return 1; - } - } - return 0; -} - -static int pnp_next_rule(struct pnp_dev *dev) -{ - int depnum = dev->rule->depnum; - int max = pnp_get_max_depnum(dev); - int priority = PNP_RES_PRIORITY_PREFERRED; - - if (depnum < 0) - return 0; - - if (max == 0) { - if (pnp_generate_rule(dev, 0, dev->rule)) { - dev->rule->depnum = -1; - return 1; - } - } - - if(depnum > 0) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - priority = res->priority; - } - - for (; priority <= PNP_RES_PRIORITY_FUNCTIONAL; priority++, depnum = 0) { - depnum += 1; - for (; depnum <= max; depnum++) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - if (res->priority == priority) { - if(pnp_generate_rule(dev, depnum, dev->rule)) { - dev->rule->depnum = depnum; - return 1; - } - } - } - } - return 0; -} - -struct pnp_change { - struct list_head change_list; - struct list_head changes; - struct pnp_resource_table res_bak; - struct pnp_rule_table rule_bak; - struct pnp_dev * dev; -}; - -static void pnp_free_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - list_del(&change->change_list); - kfree(change); - } -} - -static void pnp_undo_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - *change->dev->rule = change->rule_bak; - change->dev->res = change->res_bak; - list_del(&change->change_list); - kfree(change); - } -} - -static struct pnp_change * pnp_add_change(struct pnp_change * parent, struct pnp_dev * dev) -{ - struct pnp_change * change = pnp_alloc(sizeof(struct pnp_change)); - if (!change) - return NULL; - change->res_bak = dev->res; - change->rule_bak = *dev->rule; - change->dev = dev; - INIT_LIST_HEAD(&change->changes); - if (parent) - list_add(&change->change_list, &parent->changes); - return change; -} - -static void pnp_commit_changes(struct pnp_change * parent, struct pnp_change * change) -{ - /* check if it's the root change */ - if (!parent) - return; - if (!list_empty(&change->changes)) - list_splice_init(&change->changes, &parent->changes); -} - -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent); - -static int pnp_next_request(struct pnp_dev * dev, int move, struct pnp_change * parent, struct pnp_change * change) -{ - int i; - struct pnp_dev * cdev; - - for (i = 0; i < PNP_MAX_PORT; i++) { - if (dev->res.port_resource[i].start == 0 - || pnp_check_port_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_port(dev,i)) - return 0; - } - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_port(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (dev->res.mem_resource[i].start == 0 - || pnp_check_mem_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_mem(dev,i)) - return 0; - } - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_mem(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (dev->res.irq_resource[i].start == -1 - || pnp_check_irq_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_irq(dev,i)) - return 0; - } - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_irq(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (dev->res.dma_resource[i].start == -1 - || pnp_check_dma_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_dma(dev,i)) - return 0; - } - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_dma(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - return 1; -} - -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent) -{ - struct pnp_change * change; - move--; - if (!dev->rule) - return 0; - change = pnp_add_change(parent,dev); - if (!change) - return 0; - if (!pnp_can_configure(dev)) - goto fail; - if (!dev->rule->depnum) { - if (!pnp_next_rule(dev)) - goto fail; - } - while (!pnp_next_request(dev, move, parent, change)) { - if(!pnp_next_rule(dev)) - goto fail; - pnp_init_resource_table(&dev->res); - } - if (!parent) { - pnp_free_changes(change); - kfree(change); - } - return 1; - -fail: - if (!parent) - kfree(change); - return 0; -} - -/* this advanced algorithm will shuffle other configs to make room and ensure that the most possible devices have configs */ -static int pnp_advanced_config(struct pnp_dev * dev) -{ - int move; - /* if the device cannot be configured skip it */ - if (!pnp_can_configure(dev)) - return 1; - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) - return -ENOMEM; - } - - spin_lock(&pnp_lock); - for (move = 1; move <= pnp_max_moves; move++) { - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - if (pnp_next_config(dev,move,NULL)) { - spin_unlock(&pnp_lock); - return 1; - } - } - - pnp_init_resource_table(&dev->res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - pnp_err("res: Unable to resolve resource conflicts for the device '%s', some devices may not be usable.", dev->dev.bus_id); - return 0; -} - -int pnp_resolve_conflicts(struct pnp_dev *dev) -{ - int i; - struct pnp_dev * cdev; - - for (i = 0; i < PNP_MAX_PORT; i++) - { - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_MEM; i++) - { - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_IRQ; i++) - { - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_DMA; i++) - { - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - return 1; -} - -/* this is a much faster algorithm but it may not leave resources for other devices to use */ -static int pnp_simple_config(struct pnp_dev * dev) -{ - int i; - spin_lock(&pnp_lock); - if (dev->active) { - spin_unlock(&pnp_lock); - return 1; - } - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) { - spin_unlock(&pnp_lock); - return -ENOMEM; - } - } - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - while (pnp_next_rule(dev)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_next_port(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_next_mem(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (!pnp_next_irq(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (!pnp_next_dma(dev,i)) - continue; - } - goto done; - } - pnp_init_resource_table(&dev->res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - return 0; - -done: - pnp_resolve_conflicts(dev); /* this is required or we will break the advanced configs */ - return 1; -} - -static int pnp_compare_resources(struct pnp_resource_table * resa, struct pnp_resource_table * resb) -{ - int idx; - for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (resa->irq_resource[idx].start != resb->irq_resource[idx].start) - return 1; - } - for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (resa->dma_resource[idx].start != resb->dma_resource[idx].start) - return 1; - } - for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (resa->port_resource[idx].start != resb->port_resource[idx].start) - return 1; - if (resa->port_resource[idx].end != resb->port_resource[idx].end) - return 1; - } - for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (resa->mem_resource[idx].start != resb->mem_resource[idx].start) - return 1; - if (resa->mem_resource[idx].end != resb->mem_resource[idx].end) - return 1; - } - return 0; -} - - -/* - * PnP Device Resource Management - */ - -/** - * pnp_auto_config_dev - determines the best possible resource configuration based on available information - * @dev: pointer to the desired device - * - */ - -int pnp_auto_config_dev(struct pnp_dev *dev) -{ - int error; - if(!dev) - return -EINVAL; - - dev->config_mode = PNP_CONFIG_AUTO; - - if(dev->active) - error = pnp_resolve_conflicts(dev); - else - error = pnp_advanced_config(dev); - return error; -} - -static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struct pnp_resource_table * ntab) -{ - int idx; - for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) - continue; - ctab->irq_resource[idx].start = ntab->irq_resource[idx].start; - ctab->irq_resource[idx].end = ntab->irq_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->irq_resource[idx].flags; - } - for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (ntab->dma_resource[idx].flags & IORESOURCE_AUTO) - continue; - ctab->dma_resource[idx].start = ntab->dma_resource[idx].start; - ctab->dma_resource[idx].end = ntab->dma_resource[idx].end; - ctab->dma_resource[idx].flags = ntab->dma_resource[idx].flags; - } - for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (ntab->port_resource[idx].flags & IORESOURCE_AUTO) - continue; - ctab->port_resource[idx].start = ntab->port_resource[idx].start; - ctab->port_resource[idx].end = ntab->port_resource[idx].end; - ctab->port_resource[idx].flags = ntab->port_resource[idx].flags; - } - for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) - continue; - ctab->irq_resource[idx].start = ntab->mem_resource[idx].start; - ctab->irq_resource[idx].end = ntab->mem_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->mem_resource[idx].flags; - } -} - -/** - * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table - * @dev: pointer to the desired device - * @res: pointer to the new resource config - * - * This function can be used by drivers that want to manually set thier resources. - */ - -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode) -{ - int i; - struct pnp_resource_table * bak; - if (!dev || !res) - return -EINVAL; - if (dev->active) - return -EBUSY; - bak = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!bak) - return -ENOMEM; - *bak = dev->res; - - spin_lock(&pnp_lock); - pnp_process_manual_resources(&dev->res, res); - if (!(mode & PNP_CONFIG_FORCE)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if(pnp_check_port(dev,i)) - goto fail; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if(pnp_check_mem(dev,i)) - goto fail; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if(pnp_check_irq(dev,i)) - goto fail; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if(pnp_check_dma(dev,i)) - goto fail; - } - } - dev->config_mode = PNP_CONFIG_MANUAL; - spin_unlock(&pnp_lock); - - pnp_resolve_conflicts(dev); - kfree(bak); - return 0; - -fail: - dev->res = *bak; - spin_unlock(&pnp_lock); - kfree(bak); - return -EINVAL; -} - -/** - * pnp_activate_dev - activates a PnP device for use - * @dev: pointer to the desired device - * - * finds the best resource configuration and then informs the correct pnp protocol - */ - -int pnp_activate_dev(struct pnp_dev *dev) -{ - if (!dev) - return -EINVAL; - if (dev->active) { - return 0; /* the device is already active */ - } - /* If this condition is true, advanced configuration failed, we need to get this device up and running - * so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */ - if (!pnp_is_active(dev)) { - if (!pnp_simple_config(dev)) { - pnp_err("res: Unable to resolve resource conflicts for the device '%s'.", dev->dev.bus_id); - goto fail; - } - } - - spin_lock(&pnp_lock); /* we lock just in case the device is being configured during this call */ - dev->active = 1; - spin_unlock(&pnp_lock); /* once the device is claimed active we know it won't be configured so we can unlock */ - - if (dev->config_mode & PNP_CONFIG_INVALID) { - pnp_info("res: Unable to activate the PnP device '%s' because its resource configuration is invalid.", dev->dev.bus_id); - goto fail; - } - if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){ - pnp_err("res: Activation failed because the PnP device '%s' is busy.", dev->dev.bus_id); - goto fail; - } - if (!pnp_can_write(dev)) { - pnp_info("res: Unable to activate the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); - goto fail; - } - if (dev->protocol->set(dev, &dev->res)<0) { - pnp_err("res: The protocol '%s' reports that activating the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - goto fail; - } - if (pnp_can_read(dev)) { - struct pnp_resource_table * res = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!res) - goto fail; - dev->protocol->get(dev, res); - if (pnp_compare_resources(&dev->res, res)) /* if this happens we may be in big trouble but it's best just to continue */ - pnp_err("res: The resources requested do not match those set for the PnP device '%s'.", dev->dev.bus_id); - kfree(res); - } else - dev->active = pnp_is_active(dev); - pnp_dbg("res: the device '%s' has been activated.", dev->dev.bus_id); - if (dev->rule) { - kfree(dev->rule); - dev->rule = NULL; - } - return 0; - -fail: - dev->active = 0; /* fixes incorrect active state */ - return -EINVAL; -} - -/** - * pnp_disable_dev - disables device - * @dev: pointer to the desired device - * - * inform the correct pnp protocol so that resources can be used by other devices - */ - -int pnp_disable_dev(struct pnp_dev *dev) -{ - if (!dev) - return -EINVAL; - if (!dev->active) { - return 0; /* the device is already disabled */ - } - if (dev->status != PNP_READY){ - pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id); - return -EINVAL; - } - if (!pnp_can_disable(dev)) { - pnp_info("res: Unable to disable the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); - return -EINVAL; - } - if (dev->protocol->disable(dev)<0) { - pnp_err("res: The protocol '%s' reports that disabling the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - return -1; - } - dev->active = 0; /* just in case the protocol doesn't do this */ - pnp_dbg("res: the device '%s' has been disabled.", dev->dev.bus_id); - return 0; -} - -/** - * pnp_resource_change - change one resource - * @resource: pointer to resource to be changed - * @start: start of region - * @size: size of region - * - */ - -void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) -{ - if (resource == NULL) - return; - resource->flags &= ~IORESOURCE_AUTO; - resource->start = start; - resource->end = start + size - 1; -} - - -EXPORT_SYMBOL(pnp_auto_config_dev); -EXPORT_SYMBOL(pnp_manual_config_dev); -EXPORT_SYMBOL(pnp_activate_dev); -EXPORT_SYMBOL(pnp_disable_dev); -EXPORT_SYMBOL(pnp_resource_change); - - -/* format is: pnp_max_moves=num */ - -static int __init pnp_setup_max_moves(char *str) -{ - get_option(&str,&pnp_max_moves); - return 1; -} - -__setup("pnp_max_moves=", pnp_setup_max_moves); +/* + * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices + * + * based on isapnp.c resource management (c) Jaroslav Kysela + * Copyright 2003 Adam Belay + * + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PNP_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include +#include "base.h" + +DECLARE_MUTEX(pnp_res_mutex); + +static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) +{ + unsigned long *start, *end, *flags; + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_PORT) { + pnp_err("More than 4 ports is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) + return 1; + + start = &dev->res.port_resource[idx].start; + end = &dev->res.port_resource[idx].end; + flags = &dev->res.port_resource[idx].flags; + + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size - 1; + *flags = *flags | rule->flags | IORESOURCE_IO; + + /* run through until pnp_check_port is happy */ + while (!pnp_check_port(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) + return 0; + } + return 1; +} + +static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) +{ + unsigned long *start, *end, *flags; + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_MEM) { + pnp_err("More than 8 mems is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) + return 1; + + start = &dev->res.mem_resource[idx].start; + end = &dev->res.mem_resource[idx].end; + flags = &dev->res.mem_resource[idx].flags; + + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size -1; + *flags = *flags | rule->flags | IORESOURCE_MEM; + + /* convert pnp flags to standard Linux flags */ + if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) + *flags |= IORESOURCE_READONLY; + if (rule->flags & IORESOURCE_MEM_CACHEABLE) + *flags |= IORESOURCE_CACHEABLE; + if (rule->flags & IORESOURCE_MEM_RANGELENGTH) + *flags |= IORESOURCE_RANGELENGTH; + if (rule->flags & IORESOURCE_MEM_SHADOWABLE) + *flags |= IORESOURCE_SHADOWABLE; + + /* run through until pnp_check_mem is happy */ + while (!pnp_check_mem(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) + return 0; + } + return 1; +} + +static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx) +{ + unsigned long *start, *end, *flags; + int i; + + /* IRQ priority: this table is good for i386 */ + static unsigned short xtab[16] = { + 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 + }; + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_IRQ) { + pnp_err("More than 2 irqs is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) + return 1; + + start = &dev->res.irq_resource[idx].start; + end = &dev->res.irq_resource[idx].end; + flags = &dev->res.irq_resource[idx].flags; + + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_IRQ; + + for (i = 0; i < 16; i++) { + if(rule->map & (1<= PNP_MAX_DMA) { + pnp_err("More than 2 dmas is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) + return 1; + + start = &dev->res.dma_resource[idx].start; + end = &dev->res.dma_resource[idx].end; + flags = &dev->res.dma_resource[idx].flags; + + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_DMA; + + for (i = 0; i < 8; i++) { + if(rule->map & (1<irq_resource[idx].name = NULL; + table->irq_resource[idx].start = -1; + table->irq_resource[idx].end = -1; + table->irq_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_DMA; idx++) { + table->dma_resource[idx].name = NULL; + table->dma_resource[idx].start = -1; + table->dma_resource[idx].end = -1; + table->dma_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_PORT; idx++) { + table->port_resource[idx].name = NULL; + table->port_resource[idx].start = 0; + table->port_resource[idx].end = 0; + table->port_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_MEM; idx++) { + table->mem_resource[idx].name = NULL; + table->mem_resource[idx].start = 0; + table->mem_resource[idx].end = 0; + table->mem_resource[idx].flags = IORESOURCE_AUTO; + } + up(&pnp_res_mutex); +} + +/** + * pnp_clean_resources - clears resources that were not manually set + * @res - the resources to clean + * + */ +static void pnp_clean_resources(struct pnp_resource_table * res) +{ + int idx; + for (idx = 0; idx < PNP_MAX_IRQ; idx++) { + if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO)) + continue; + res->irq_resource[idx].start = -1; + res->irq_resource[idx].end = -1; + res->irq_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_DMA; idx++) { + if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) + continue; + res->dma_resource[idx].start = -1; + res->dma_resource[idx].end = -1; + res->dma_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_PORT; idx++) { + if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) + continue; + res->port_resource[idx].start = 0; + res->port_resource[idx].end = 0; + res->port_resource[idx].flags = IORESOURCE_AUTO; + } + for (idx = 0; idx < PNP_MAX_MEM; idx++) { + if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) + continue; + res->mem_resource[idx].start = 0; + res->mem_resource[idx].end = 0; + res->mem_resource[idx].flags = IORESOURCE_AUTO; + } +} + +/** + * pnp_assign_resources - assigns resources to the device based on the specified dependent number + * @dev: pointer to the desired device + * @depnum: the dependent function number + * + * Only set depnum to 0 if the device does not have dependent options. + */ +int pnp_assign_resources(struct pnp_dev *dev, int depnum) +{ + struct pnp_port *port; + struct pnp_mem *mem; + struct pnp_irq *irq; + struct pnp_dma *dma; + int nport = 0, nmem = 0, nirq = 0, ndma = 0; + + if (!pnp_can_configure(dev)) + return -ENODEV; + + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); /* start with a fresh slate */ + if (dev->independent) { + port = dev->independent->port; + mem = dev->independent->mem; + irq = dev->independent->irq; + dma = dev->independent->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } + } + + if (depnum) { + struct pnp_option *dep; + int i; + for (i=1,dep=dev->dependent; inext) + if(!dep) + goto fail; + port =dep->port; + mem = dep->mem; + irq = dep->irq; + dma = dep->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } + } else if (dev->dependent) + goto fail; + + up(&pnp_res_mutex); + return 1; + +fail: + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + return 0; +} + +/** + * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table + * @dev: pointer to the desired device + * @res: pointer to the new resource config + * + * This function can be used by drivers that want to manually set thier resources. + */ +int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode) +{ + int i; + struct pnp_resource_table * bak; + if (!dev || !res) + return -EINVAL; + if (!pnp_can_configure(dev)) + return -ENODEV; + bak = pnp_alloc(sizeof(struct pnp_resource_table)); + if (!bak) + return -ENOMEM; + *bak = dev->res; + + down(&pnp_res_mutex); + dev->res = *res; + if (!(mode & PNP_CONFIG_FORCE)) { + for (i = 0; i < PNP_MAX_PORT; i++) { + if(pnp_check_port(dev,i)) + goto fail; + } + for (i = 0; i < PNP_MAX_MEM; i++) { + if(pnp_check_mem(dev,i)) + goto fail; + } + for (i = 0; i < PNP_MAX_IRQ; i++) { + if(pnp_check_irq(dev,i)) + goto fail; + } + for (i = 0; i < PNP_MAX_DMA; i++) { + if(pnp_check_dma(dev,i)) + goto fail; + } + } + up(&pnp_res_mutex); + + pnp_auto_config_dev(dev); + kfree(bak); + return 0; + +fail: + dev->res = *bak; + up(&pnp_res_mutex); + kfree(bak); + return -EINVAL; +} + +/** + * pnp_auto_config_dev - automatically assigns resources to a device + * @dev: pointer to the desired device + * + */ +int pnp_auto_config_dev(struct pnp_dev *dev) +{ + struct pnp_option *dep; + int i = 1; + + if(!dev) + return -EINVAL; + + if(!pnp_can_configure(dev)) { + pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id); + return -ENODEV; + } + + if (!dev->dependent) { + if (pnp_assign_resources(dev, 0)) + return 1; + else + return 0; + } + + dep = dev->dependent; + do { + if (pnp_assign_resources(dev, i)) + return 1; + + /* if this dependent resource failed, try the next one */ + dep = dep->next; + i++; + } while (dep); + + pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id); + return 0; +} + +/** + * pnp_activate_dev - activates a PnP device for use + * @dev: pointer to the desired device + * + * does not validate or set resources so be careful. + */ +int pnp_activate_dev(struct pnp_dev *dev) +{ + if (!dev) + return -EINVAL; + if (dev->active) { + return 0; /* the device is already active */ + } + + /* ensure resources are allocated */ + if (!pnp_auto_config_dev(dev)) + return -EBUSY; + + if (!pnp_can_write(dev)) { + pnp_info("Device %s does not supported activation.", dev->dev.bus_id); + return -EINVAL; + } + + if (dev->protocol->set(dev, &dev->res)<0) { + pnp_err("Failed to activate device %s.", dev->dev.bus_id); + return -EIO; + } + + dev->active = 1; + pnp_info("Device %s activated.", dev->dev.bus_id); + + return 1; +} + +/** + * pnp_disable_dev - disables device + * @dev: pointer to the desired device + * + * inform the correct pnp protocol so that resources can be used by other devices + */ +int pnp_disable_dev(struct pnp_dev *dev) +{ + if (!dev) + return -EINVAL; + if (!dev->active) { + return 0; /* the device is already disabled */ + } + + if (!pnp_can_disable(dev)) { + pnp_info("Device %s does not supported disabling.", dev->dev.bus_id); + return -EINVAL; + } + if (dev->protocol->disable(dev)<0) { + pnp_err("Failed to disable device %s.", dev->dev.bus_id); + return -EIO; + } + + dev->active = 0; + pnp_info("Device %s disabled.", dev->dev.bus_id); + + /* release the resources so that other devices can use them */ + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + + return 1; +} + +/** + * pnp_resource_change - change one resource + * @resource: pointer to resource to be changed + * @start: start of region + * @size: size of region + * + */ +void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) +{ + if (resource == NULL) + return; + resource->flags &= ~IORESOURCE_AUTO; + resource->start = start; + resource->end = start + size - 1; +} + + +EXPORT_SYMBOL(pnp_assign_resources); +EXPORT_SYMBOL(pnp_manual_config_dev); +EXPORT_SYMBOL(pnp_auto_config_dev); +EXPORT_SYMBOL(pnp_activate_dev); +EXPORT_SYMBOL(pnp_disable_dev); +EXPORT_SYMBOL(pnp_resource_change); +EXPORT_SYMBOL(pnp_init_resources); diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 1c370c9f1ab..56a5f43716f 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -935,6 +935,10 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node) dev->capabilities |= PNP_REMOVABLE; dev->protocol = &pnpbios_protocol; + /* clear out the damaged flags */ + if (!dev->active) + pnp_init_resources(&dev->res); + pnp_add_device(dev); pnpbios_interface_attach_device(node); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index dcb4570cd65..883f845a8d1 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -30,7 +30,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) { struct pnp_port *port, *port2, *port3; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; /* * Unfortunately the isapnp_add_port_resource is too tightly bound @@ -38,7 +38,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) * two extra ports (at offset 0x400 and 0x800 from the one given) by * hand. */ - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { port2 = pnp_alloc(sizeof(struct pnp_port)); if (!port2) return; @@ -62,9 +62,9 @@ static void quirk_awe32_resources(struct pnp_dev *dev) static void quirk_cmi8330_resources(struct pnp_dev *dev) { - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { struct pnp_irq *irq; struct pnp_dma *dma; @@ -82,7 +82,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) static void quirk_sb16audio_resources(struct pnp_dev *dev) { struct pnp_port *port; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; int changed = 0; /* @@ -91,7 +91,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) * auto-configured. */ - for( ; res ; res = res->dep ) { + for( ; res ; res = res->next ) { port = res->port; if(!port) continue; @@ -118,11 +118,11 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev) * doesn't allow a DMA channel of 0, afflicted card is an * OPL3Sax where x=4. */ - struct pnp_resources *res; + struct pnp_option *res; int max; - res = dev->possible; + res = dev->dependent; max = 0; - for (res = res->dep; res; res = res->dep) { + for (; res; res = res->next) { if (res->dma->map > max) max = res->dma->map; } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 7e738da9e6e..3259ed7c378 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -10,18 +10,19 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include "base.h" -int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */ +int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: + * -1=off (:default), 0=off (set by user), 1=on */ int pnp_skip_pci_scan; /* skip PCI resource scanning */ int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */ @@ -30,88 +31,75 @@ int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memor /* - * possible resource registration + * option registration */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) +static struct pnp_option * pnp_build_option(int priority) { - struct pnp_resources *res, *ptr, *ptra; + struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); - res = pnp_alloc(sizeof(struct pnp_resources)); - if (!res) + /* check if pnp_alloc ran out of memory */ + if (!option) return NULL; - ptr = dev->possible; - if (ptr) { /* add to another list */ - ptra = ptr->dep; - while (ptra && ptra->dep) - ptra = ptra->dep; - if (!ptra) - ptr->dep = res; - else - ptra->dep = res; - } else - dev->possible = res; - if (dependent) { - res->priority = dependent & 0xff; - if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL) - res->priority = PNP_RES_PRIORITY_INVALID; - } else - res->priority = PNP_RES_PRIORITY_PREFERRED; - return res; + + option->priority = priority & 0xff; + /* make sure the priority is valid */ + if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) + option->priority = PNP_RES_PRIORITY_INVALID; + + return option; } -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { - int i; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) return NULL; - res = dev->possible; - if (!res) - return NULL; - for (i = 0; i < depnum; i++) - { - if (res->dep) - res = res->dep; - else - return NULL; - } - return res; + + option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); + + /* this should never happen but if it does we'll try to continue */ + if (dev->independent) + pnp_err("independent resource already registered"); + dev->independent = option; + return option; } -int pnp_get_max_depnum(struct pnp_dev *dev) +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { - int num = 0; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) - return -EINVAL; - res = dev->possible; - if (!res) - return -EINVAL; - while (res->dep){ - res = res->dep; - num++; - } - return num; + return NULL; + + option = pnp_build_option(priority); + + if (dev->dependent) { + struct pnp_option *parent = dev->dependent; + while (parent->next) + parent = parent->next; + parent->next = option; + } else + dev->dependent = option; + return option; } -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { int i; - struct pnp_resources *res; struct pnp_irq *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->irq; + + ptr = option->irq; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->irq = data; + option->irq = data; + #ifdef CONFIG_PCI for (i=0; i<16; i++) if (data->map & (1<dma; + + ptr = option->dma; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->dma = data; + option->dma = data; + return 0; } -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data) +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { - struct pnp_resources *res; struct pnp_port *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->port; + + ptr = option->port; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->port = data; + option->port = data; + return 0; } -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data) +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { - struct pnp_resources *res; struct pnp_mem *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->mem; + + ptr = option->mem; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->mem = data; + option->mem = data; return 0; } @@ -221,18 +208,18 @@ static void pnp_free_mem(struct pnp_mem *mem) } } -void pnp_free_resources(struct pnp_resources *resources) +void pnp_free_option(struct pnp_option *option) { - struct pnp_resources *next; - - while (resources) { - next = resources->dep; - pnp_free_port(resources->port); - pnp_free_irq(resources->irq); - pnp_free_dma(resources->dma); - pnp_free_mem(resources->mem); - kfree(resources); - resources = next; + struct pnp_option *next; + + while (option) { + next = option->next; + pnp_free_port(option->port); + pnp_free_irq(option->irq); + pnp_free_dma(option->dma); + pnp_free_mem(option->mem); + kfree(option); + option = next; } } @@ -253,50 +240,23 @@ void pnp_free_resources(struct pnp_resources *resources) (*(enda) >= *(startb) && *(enda) <= *(endb)) || \ (*(starta) < *(startb) && *(enda) > *(endb))) -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *port, *end, *tport, *tend; - struct pnp_dev *tdev; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.port_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ - pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) - continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; - if (ranged_conflict(port,end,tport,tend)) - return tdev; - } - } - } - return NULL; -} - int pnp_check_port(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *port, *end, *tport, *tend; port = &dev->res.port_resource[idx].start; end = &dev->res.port_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.port_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { - if (check_region(*port, length(port,end))) - return CONFLICT_TYPE_IN_USE; + if (__check_region(&ioport_resource, *port, length(port,end))) + return 0; } /* check if the resource is reserved */ @@ -304,7 +264,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx) int rport = pnp_reserve_io[tmp << 1]; int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; if (ranged_conflict(port,end,&rport,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -313,61 +273,44 @@ int pnp_check_port(struct pnp_dev * dev, int idx) tport = &dev->res.port_resource[tmp].start; tend = &dev->res.port_resource[tmp].end; if (ranged_conflict(port,end,tport,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *addr, *end, *taddr, *tend; - struct pnp_dev *tdev; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.mem_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; - if (ranged_conflict(addr,end,taddr,tend)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { + tport = &tdev->res.port_resource[tmp].start; + tend = &tdev->res.port_resource[tmp].end; + if (ranged_conflict(port,end,tport,tend)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_mem(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *addr, *end, *taddr, *tend; addr = &dev->res.mem_resource[idx].start; end = &dev->res.mem_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.mem_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { - if (__check_region(&iomem_resource, *addr, length(addr,end))) - return CONFLICT_TYPE_IN_USE; + if (check_mem_region(*addr, length(addr,end))) + return 0; } /* check if the resource is reserved */ @@ -375,7 +318,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) int raddr = pnp_reserve_mem[tmp << 1]; int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; if (ranged_conflict(addr,end,&raddr,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -384,40 +327,25 @@ int pnp_check_mem(struct pnp_dev * dev, int idx) taddr = &dev->res.mem_resource[tmp].start; tend = &dev->res.mem_resource[tmp].end; if (ranged_conflict(addr,end,taddr,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * irq = &dev->res.irq_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.irq_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if ((tdev->res.irq_resource[tmp].start == *irq)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { + taddr = &tdev->res.mem_resource[tmp].start; + tend = &tdev->res.mem_resource[tmp].end; + if (ranged_conflict(addr,end,taddr,tend)) + return 0; } } } - return NULL; + + return 1; } static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) @@ -428,27 +356,28 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) int pnp_check_irq(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long * irq = &dev->res.irq_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.irq_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (*irq < 0 || *irq > 15) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 16; tmp++) { if (pnp_reserve_irq[tmp] == *irq) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { if (dev->res.irq_resource[tmp].start == *irq) - return CONFLICT_TYPE_INTERNAL; + return 0; } } @@ -458,233 +387,94 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) struct pci_dev * pci = NULL; while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { if (pci->irq == *irq) - return CONFLICT_TYPE_PCI; + return 0; } } #endif - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL)) - return CONFLICT_TYPE_IN_USE; + return 0; free_irq(*irq, NULL); } - /* check for warm conflicts */ - if (pnp_check_irq_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - - -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * dma = &dev->res.dma_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.dma_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if ((tdev->res.dma_resource[tmp].start == *dma)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { + if ((tdev->res.irq_resource[tmp].start == *irq)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_dma(struct pnp_dev * dev, int idx) { int tmp, mindma = 1; + struct pnp_dev *tdev; unsigned long * dma = &dev->res.dma_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.dma_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (pnp_allow_dma0 == 1) mindma = 0; if (*dma < mindma || *dma == 4 || *dma > 7) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 8; tmp++) { if (pnp_reserve_dma[tmp] == *dma) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { if (dev->res.dma_resource[tmp].start == *dma) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_dma(*dma, "pnp")) - return CONFLICT_TYPE_IN_USE; + return 0; free_dma(*dma); } - /* check for warm conflicts */ - if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - return 0; -} - - -/** - * pnp_init_resource_table - Resets a resource table to default values. - * @table: pointer to the desired resource table - * - */ - -void pnp_init_resource_table(struct pnp_resource_table *table) -{ - int idx; - for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - table->irq_resource[idx].name = NULL; - table->irq_resource[idx].start = -1; - table->irq_resource[idx].end = -1; - table->irq_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_DMA; idx++) { - table->dma_resource[idx].name = NULL; - table->dma_resource[idx].start = -1; - table->dma_resource[idx].end = -1; - table->dma_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_PORT; idx++) { - table->port_resource[idx].name = NULL; - table->port_resource[idx].start = 0; - table->port_resource[idx].end = 0; - table->port_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_MEM; idx++) { - table->mem_resource[idx].name = NULL; - table->mem_resource[idx].start = 0; - table->mem_resource[idx].end = 0; - table->mem_resource[idx].flags = IORESOURCE_AUTO; - } -} - - -/** - * pnp_generate_rule - Creates a rule table structure based on depnum and device. - * @dev: pointer to the desired device - * @depnum: dependent function, if not valid will return an error - * @rule: pointer to a rule structure to record data to - * - */ - -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) -{ - int nport = 0, nirq = 0, ndma = 0, nmem = 0; - struct pnp_resources * res; - struct pnp_port * port; - struct pnp_mem * mem; - struct pnp_irq * irq; - struct pnp_dma * dma; - - if (depnum < 0 || !rule) - return -EINVAL; - - /* independent */ - res = pnp_find_resources(dev, 0); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; - } - - /* dependent */ - if (depnum == 0) - return 1; - res = pnp_find_resources(dev, depnum); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; + /* check for conflicts with other pnp devices */ + pnp_for_each_dev(tdev) { + if (tdev == dev) + continue; + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { + if ((tdev->res.dma_resource[tmp].start == *dma)) + return 0; + } + } } - /* clear the remaining values */ - for (; nport < PNP_MAX_PORT; nport++) - rule->port[nport] = NULL; - for (; nmem < PNP_MAX_MEM; nmem++) - rule->mem[nmem] = NULL; - for (; nirq < PNP_MAX_IRQ; nirq++) - rule->irq[nirq] = NULL; - for (; ndma < PNP_MAX_DMA; ndma++) - rule->dma[ndma] = NULL; return 1; } -EXPORT_SYMBOL(pnp_build_resource); -EXPORT_SYMBOL(pnp_find_resources); -EXPORT_SYMBOL(pnp_get_max_depnum); -EXPORT_SYMBOL(pnp_add_irq_resource); -EXPORT_SYMBOL(pnp_add_dma_resource); -EXPORT_SYMBOL(pnp_add_port_resource); -EXPORT_SYMBOL(pnp_add_mem_resource); -EXPORT_SYMBOL(pnp_init_resource_table); -EXPORT_SYMBOL(pnp_generate_rule); +EXPORT_SYMBOL(pnp_register_dependent_option); +EXPORT_SYMBOL(pnp_register_independent_option); +EXPORT_SYMBOL(pnp_register_irq_resource); +EXPORT_SYMBOL(pnp_register_dma_resource); +EXPORT_SYMBOL(pnp_register_port_resource); +EXPORT_SYMBOL(pnp_register_mem_resource); /* format is: allowdma0 */ diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index c54cf87fb8c..f7a88a86c9c 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c @@ -1,7 +1,7 @@ /* * support.c - provides standard pnp functions for the use of pnp protocol drivers, * - * Copyright 2002 Adam Belay + * Copyright 2003 Adam Belay * * Resource parsing functions are based on those in the linux pnpbios driver. * Copyright Christian Schmidt, Tom Lees, David Hinds, Alan Cox, Thomas Hood, @@ -10,6 +10,7 @@ #include #include +#include #ifdef CONFIG_PNP_DEBUG #define DEBUG @@ -122,7 +123,7 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e return NULL; /* Blank the resource table values */ - pnp_init_resource_table(res); + pnp_init_resources(res); while ((char *)p < (char *)end) { @@ -250,51 +251,51 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e * Possible resource reading functions * */ -static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = ((p[3] << 8) | p[2]) << 8; - mem->max = ((p[5] << 8) | p[4]) << 8; - mem->align = (p[7] << 8) | p[6]; - mem->size = ((p[9] << 8) | p[8]) << 8; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->min = ((p[5] << 8) | p[4]) << 8; + mem->max = ((p[7] << 8) | p[6]) << 8; + mem->align = (p[9] << 8) | p[8]; + mem->size = ((p[11] << 8) | p[10]) << 8; + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2]; - mem->max = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6]; - mem->align = (p[13] << 24) | (p[12] << 16) | (p[11] << 8) | p[10]; - mem->size = (p[17] << 24) | (p[16] << 16) | (p[15] << 8) | p[14]; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; + mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; + mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = mem->max = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2]; - mem->size = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6]; + mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; mem->align = 0; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_irq(unsigned char *p, int size, struct pnp_option *option) { struct pnp_irq * irq; irq = pnp_alloc(sizeof(struct pnp_irq)); @@ -303,11 +304,13 @@ static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev irq->map = (p[2] << 8) | p[1]; if (size > 2) irq->flags = p[3]; - pnp_add_irq_resource(dev,depnum,irq); + else + irq->flags = IORESOURCE_IRQ_HIGHEDGE; + pnp_register_irq_resource(option,irq); return; } -static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_dma(unsigned char *p, int size, struct pnp_option *option) { struct pnp_dma * dma; dma = pnp_alloc(sizeof(struct pnp_dma)); @@ -315,11 +318,11 @@ static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev return; dma->map = p[1]; dma->flags = p[2]; - pnp_add_dma_resource(dev,depnum,dma); + pnp_register_dma_resource(option,dma); return; } -static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -330,11 +333,11 @@ static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev port->align = p[6]; port->size = p[7]; port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } -static void possible_fixed_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -344,7 +347,7 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p port->size = p[3]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -358,12 +361,14 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev *dev) { - int len, depnum = 0, dependent = 0; + int len, priority = 0; + struct pnp_option *option; if (!p) return NULL; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return NULL; while ((char *)p < (char *)end) { @@ -375,21 +380,21 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * { if (len != 9) goto lrg_err; - possible_mem(p,len,depnum,dev); + possible_mem(p,len,option); break; } case LARGE_TAG_MEM32: { if (len != 17) goto lrg_err; - possible_mem32(p,len,depnum,dev); + possible_mem32(p,len,option); break; } case LARGE_TAG_FIXEDMEM32: { if (len != 9) goto lrg_err; - possible_fixed_mem32(p,len,depnum,dev); + possible_fixed_mem32(p,len,option); break; } default: /* an unkown tag */ @@ -410,46 +415,46 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * { if (len < 2 || len > 3) goto sm_err; - possible_irq(p,len,depnum,dev); + possible_irq(p,len,option); break; } case SMALL_TAG_DMA: { if (len != 2) goto sm_err; - possible_dma(p,len,depnum,dev); + possible_dma(p,len,option); break; } case SMALL_TAG_STARTDEP: { if (len > 1) goto sm_err; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (len > 0) - dependent = 0x100 | p[1]; - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + priority = 0x100 | p[1]; + option = pnp_register_dependent_option(dev, priority); + if (!option) + return NULL; break; } case SMALL_TAG_ENDDEP: { if (len != 0) goto sm_err; - depnum = 0; break; } case SMALL_TAG_PORT: { if (len != 7) goto sm_err; - possible_port(p,len,depnum,dev); + possible_port(p,len,option); break; } case SMALL_TAG_FIXEDPORT: { if (len != 3) goto sm_err; - possible_fixed_port(p,len,depnum,dev); + possible_fixed_port(p,len,option); break; } case SMALL_TAG_END: @@ -481,12 +486,12 @@ static void write_mem(unsigned char *p, struct resource * res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = (base >> 8) & 0xff; - p[3] = ((base >> 8) >> 8) & 0xff; p[4] = (base >> 8) & 0xff; p[5] = ((base >> 8) >> 8) & 0xff; - p[8] = (len >> 8) & 0xff; - p[9] = ((len >> 8) >> 8) & 0xff; + p[6] = (base >> 8) & 0xff; + p[7] = ((base >> 8) >> 8) & 0xff; + p[10] = (len >> 8) & 0xff; + p[11] = ((len >> 8) >> 8) & 0xff; return; } @@ -494,32 +499,32 @@ static void write_mem32(unsigned char *p, struct resource * res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = base & 0xff; - p[3] = (base >> 8) & 0xff; - p[4] = (base >> 16) & 0xff; - p[5] = (base >> 24) & 0xff; - p[6] = base & 0xff; - p[7] = (base >> 8) & 0xff; - p[8] = (base >> 16) & 0xff; - p[9] = (base >> 24) & 0xff; - p[14] = len & 0xff; - p[15] = (len >> 8) & 0xff; - p[16] = (len >> 16) & 0xff; - p[17] = (len >> 24) & 0xff; + p[4] = base & 0xff; + p[5] = (base >> 8) & 0xff; + p[6] = (base >> 16) & 0xff; + p[7] = (base >> 24) & 0xff; + p[8] = base & 0xff; + p[9] = (base >> 8) & 0xff; + p[10] = (base >> 16) & 0xff; + p[11] = (base >> 24) & 0xff; + p[16] = len & 0xff; + p[17] = (len >> 8) & 0xff; + p[18] = (len >> 16) & 0xff; + p[19] = (len >> 24) & 0xff; return; } static void write_fixed_mem32(unsigned char *p, struct resource * res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = base & 0xff; - p[3] = (base >> 8) & 0xff; - p[4] = (base >> 16) & 0xff; - p[5] = (base >> 24) & 0xff; - p[6] = len & 0xff; - p[7] = (len >> 8) & 0xff; - p[8] = (len >> 16) & 0xff; - p[9] = (len >> 24) & 0xff; + p[4] = base & 0xff; + p[5] = (base >> 8) & 0xff; + p[6] = (base >> 16) & 0xff; + p[7] = (base >> 24) & 0xff; + p[8] = len & 0xff; + p[9] = (len >> 8) & 0xff; + p[10] = (len >> 16) & 0xff; + p[11] = (len >> 24) & 0xff; return; } @@ -630,7 +635,7 @@ unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, stru { if (len != 2) goto sm_err; - write_dma(p, &res->dma_resource[irq]); + write_dma(p, &res->dma_resource[dma]); dma++; break; } diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index a8d46b1243b..67d21550fef 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -168,7 +168,6 @@ STATIC int NCR_700_abort(Scsi_Cmnd * SCpnt); STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt); -STATIC int NCR_700_proc_directory_info(struct Scsi_Host *, char *, char **, off_t, int, int); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt); @@ -281,7 +280,6 @@ NCR_700_detect(Scsi_Host_Template *tpnt, tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; tpnt->use_clustering = DISABLE_CLUSTERING; - tpnt->proc_info = NCR_700_proc_directory_info; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; tpnt->use_blk_tcq = 1; @@ -293,7 +291,8 @@ NCR_700_detect(Scsi_Host_Template *tpnt, tpnt->proc_name = "53c700"; - if((host = scsi_register(tpnt, 4)) == NULL) + host = scsi_host_alloc(tpnt, 4); + if (!host) return NULL; memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST); @@ -1710,35 +1709,6 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs) } STATIC int -NCR_700_proc_directory_info(struct Scsi_Host *host, char *proc_buf, char **startp, - off_t offset, int bytes_available, int write) -{ - static char buf[4096]; /* 1 page should be sufficient */ - int len = 0; - struct NCR_700_Host_Parameters *hostdata; - Scsi_Device *SDp; - - if(write) { - /* FIXME: Clear internal statistics here */ - return 0; - } - hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - len += sprintf(&buf[len], "Total commands outstanding: %d\n", hostdata->command_slot_count); - len += sprintf(&buf[len],"\ -Target Active Next Tag\n\ -====== ====== ========\n"); - list_for_each_entry(SDp, &host->my_devices, siblings) { - len += sprintf(&buf[len]," %2d:%2d %4d %4d\n", SDp->id, SDp->lun, NCR_700_get_depth(SDp), SDp->current_tag); - } - if((len -= offset) <= 0) - return 0; - if(len > bytes_available) - len = bytes_available; - memcpy(proc_buf, buf + offset, len); - return len; -} - -STATIC int NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *)) { struct NCR_700_Host_Parameters *hostdata = diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index 6b1c75780ac..615bb3a6bde 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -12,6 +12,10 @@ #include +#if defined(CONFIG_53C700_MEM_MAPPED) && defined(CONFIG_53C700_IO_MAPPED) +#define CONFIG_53C700_BOTH_MAPPED +#endif + /* Turn on for general debugging---too verbose for normal use */ #undef NCR_700_DEBUG /* Debug the tag queues, checking hash queue allocation and deallocation @@ -178,6 +182,9 @@ struct NCR_700_Host_Parameters { /* NOTHING BELOW HERE NEEDS ALTERING */ __u32 fast:1; /* if we can alter the SCSI bus clock speed (so can negiotiate sync) */ +#ifdef CONFIG_53C700_BOTH_MAPPED + __u32 mem_mapped; /* set if memory mapped */ +#endif int sync_clock; /* The speed of the SYNC core */ __u32 *script; /* pointer to script location */ @@ -428,11 +435,8 @@ struct NCR_700_Host_Parameters { } \ } -#endif - -#ifdef CONFIG_53C700_MEM_MAPPED static inline __u8 -NCR_700_readb(struct Scsi_Host *host, __u32 reg) +NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -441,7 +445,7 @@ NCR_700_readb(struct Scsi_Host *host, __u32 reg) } static inline __u32 -NCR_700_readl(struct Scsi_Host *host, __u32 reg) +NCR_700_mem_readl(struct Scsi_Host *host, __u32 reg) { __u32 value = __raw_readl(host->base + reg); const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) @@ -456,7 +460,7 @@ NCR_700_readl(struct Scsi_Host *host, __u32 reg) } static inline void -NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +NCR_700_mem_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -465,7 +469,7 @@ NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) } static inline void -NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +NCR_700_mem_writel(__u32 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -478,9 +482,9 @@ NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) __raw_writel(bS_to_host(value), host->base + reg); } -#elif defined(CONFIG_53C700_IO_MAPPED) + static inline __u8 -NCR_700_readb(struct Scsi_Host *host, __u32 reg) +NCR_700_io_readb(struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -489,7 +493,7 @@ NCR_700_readb(struct Scsi_Host *host, __u32 reg) } static inline __u32 -NCR_700_readl(struct Scsi_Host *host, __u32 reg) +NCR_700_io_readl(struct Scsi_Host *host, __u32 reg) { __u32 value = inl(host->base + reg); const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) @@ -505,7 +509,7 @@ NCR_700_readl(struct Scsi_Host *host, __u32 reg) } static inline void -NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +NCR_700_io_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -514,7 +518,7 @@ NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) } static inline void -NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +NCR_700_io_writel(__u32 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -527,4 +531,100 @@ NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) outl(bS_to_host(value), host->base + reg); } + +#ifdef CONFIG_53C700_BOTH_MAPPED + +static inline __u8 +NCR_700_readb(struct Scsi_Host *host, __u32 reg) +{ + __u8 val; + + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + val = NCR_700_mem_readb(host, reg); + else + val = NCR_700_io_readb(host, reg); + + return val; +} + +static inline __u32 +NCR_700_readl(struct Scsi_Host *host, __u32 reg) +{ + __u32 val; + + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + val = NCR_700_mem_readl(host, reg); + else + val = NCR_700_io_readl(host, reg); + + return val; +} + +static inline void +NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + NCR_700_mem_writeb(value, host, reg); + else + NCR_700_io_writeb(value, host, reg); +} + +static inline void +NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + NCR_700_mem_writel(value, host, reg); + else + NCR_700_io_writel(value, host, reg); +} + +static inline void +NCR_700_set_mem_mapped(struct NCR_700_Host_Parameters *hostdata) +{ + hostdata->mem_mapped = 1; +} + +static inline void +NCR_700_set_io_mapped(struct NCR_700_Host_Parameters *hostdata) +{ + hostdata->mem_mapped = 0; +} + + +#elif defined(CONFIG_53C700_IO_MAPPED) + +#define NCR_700_readb NCR_700_io_readb +#define NCR_700_readl NCR_700_io_readl +#define NCR_700_writeb NCR_700_io_writeb +#define NCR_700_writel NCR_700_io_writel + +#define NCR_700_set_io_mapped(x) +#define NCR_700_set_mem_mapped(x) error I/O mapped only + +#elif defined(CONFIG_53C700_MEM_MAPPED) + +#define NCR_700_readb NCR_700_mem_readb +#define NCR_700_readl NCR_700_mem_readl +#define NCR_700_writeb NCR_700_mem_writeb +#define NCR_700_writel NCR_700_mem_writel + +#define NCR_700_set_io_mapped(x) error MEM mapped only +#define NCR_700_set_mem_mapped(x) + +#else +#error neither CONFIG_53C700_MEM_MAPPED nor CONFIG_53C700_IO_MAPPED is set +#endif + #endif diff --git a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c index ed6ed4d5b3c..55a81bbadde 100644 --- a/drivers/scsi/AM53C974.c +++ b/drivers/scsi/AM53C974.c @@ -817,22 +817,6 @@ static const char *AM53C974_info(struct Scsi_Host *instance) return (info); } -/************************************************************************** -* Function : int AM53C974_command (Scsi_Cmnd *SCpnt) * -* * -* Purpose : the unqueued SCSI command function, replaced by the * -* AM53C974_queue_command function * -* * -* Inputs : SCpnt - pointer to command structure * -* * -* Returns :status, see hosts.h for details * -***************************************************************************/ -static int AM53C974_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("AM53C974_command called\n")); - return 0; -} - /************************************************************************** * Function : void initialize_SCp(Scsi_Cmnd *cmd) * * * @@ -2466,7 +2450,6 @@ static Scsi_Host_Template driver_template = { .detect = AM53C974_pci_detect, .release = AM53C974_release, .info = AM53C974_info, - .command = AM53C974_command, .queuecommand = AM53C974_queue_command, .abort = AM53C974_abort, .reset = AM53C974_reset, diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index b160760adcf..883b6ed5dff 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -27,8 +27,8 @@ config CHR_DEV_ST If you want to use a SCSI tape drive under Linux, say Y and read the SCSI-HOWTO, available from , and - in the kernel source. This is NOT for - SCSI CD-ROMs. + in the kernel source. This is NOT + for SCSI CD-ROMs. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -131,11 +131,11 @@ config SCSI_REPORT_LUNS depends on SCSI default y help - If you want to build with SCSI REPORT LUNS support in the kernel, say Y here. - The REPORT LUNS command is useful for devices (such as disk arrays) with - large numbers of LUNs where the LUN values are not contiguous (sparse LUN). - REPORT LUNS scanning is done only for SCSI-3 devices. Most users can safely - answer N here. + If you want support for SCSI REPORT LUNS, say Y here. + The REPORT LUNS command is useful for devices (such as disk arrays) + with large numbers of LUNs where the LUN values are not contiguous + (sparse LUN). REPORT LUNS scanning is done only for SCSI-3 devices. + Most users can safely answer N here. config SCSI_CONSTANTS bool "Verbose SCSI error reporting (kernel size +=12K)" @@ -207,7 +207,7 @@ config BLK_DEV_3W_XXXX_RAID config SCSI_7000FASST tristate "7000FASST SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This driver supports the Western Digital 7000 SCSI host adapter family. Some information is in the source: @@ -220,7 +220,7 @@ config SCSI_7000FASST config SCSI_ACARD tristate "ACARD SCSI support" - depends on SCSI + depends on PCI && SCSI help This driver supports the ACARD 870U/W SCSI host adapter. @@ -285,6 +285,7 @@ source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" config SCSI_AIC7XXX_OLD tristate "Adaptec AIC7xxx support (old driver)" + depends on SCSI help WARNING This driver is an older aic7xxx driver and is no longer under active development. Adaptec, Inc. is writing a new driver to @@ -343,7 +344,7 @@ config SCSI_DPT_I2O config SCSI_ADVANSYS tristate "AdvanSys SCSI support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in @@ -357,7 +358,7 @@ config SCSI_ADVANSYS config SCSI_IN2000 tristate "Always IN2000 SCSI support" - depends on SCSI + depends on ISA && SCSI help This is support for an ISA bus SCSI host adapter. You'll find more information in . If it doesn't work @@ -369,10 +370,10 @@ config SCSI_IN2000 say M here and read . The module will be called in2000. -# does not use pci dma and seems to be isa/onboard only for old machines +# does not use pci dma and seems to be onboard only for old machines config SCSI_AM53C974 tristate "AM53/79C974 PCI SCSI support" - depends on !X86_64 && SCSI && PCI + depends on X86 && PCI && SCSI ---help--- This is support for the AM53/79C974 SCSI host adapters. Please read for details. Also, the @@ -390,7 +391,7 @@ config SCSI_AM53C974 config SCSI_MEGARAID tristate "AMI MegaRAID support" - depends on SCSI + depends on PCI && SCSI help This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 and 467 SCSI host adapters. @@ -402,7 +403,7 @@ config SCSI_MEGARAID config SCSI_BUSLOGIC tristate "BusLogic SCSI support" - depends on SCSI + depends on (PCI || ISA) && SCSI ---help--- This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from @@ -436,7 +437,7 @@ config SCSI_CPQFCTS config SCSI_DMX3191D tristate "DMX3191D SCSI support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for Domex DMX3191D SCSI Host Adapters. @@ -447,7 +448,7 @@ config SCSI_DMX3191D config SCSI_DTC3280 tristate "DTC3180/3280 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for DTC 3180/3280 SCSI Host Adapters. Please read the SCSI-HOWTO, available from @@ -461,7 +462,7 @@ config SCSI_DTC3280 config SCSI_EATA tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- This driver supports all EATA/DMA-compliant SCSI host adapters. DPT ISA and all EISA I/O addresses are probed looking for the "EATA" @@ -527,7 +528,7 @@ config SCSI_EATA_PIO config SCSI_FUTURE_DOMAIN tristate "Future Domain 16xx SCSI/AHA-2920A support" - depends on SCSI + depends on (ISA || PCI) && SCSI ---help--- This is support for Future Domain's 16-bit SCSI host adapters (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and @@ -563,7 +564,7 @@ config SCSI_FD_MCS config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- Formerly called GDT SCSI Disk Array Controller Support. @@ -579,7 +580,7 @@ config SCSI_GDTH config SCSI_GENERIC_NCR5380 tristate "Generic NCR5380/53c400 SCSI PIO support" - depends on SCSI + depends on ISA && SCSI ---help--- This is a driver for the old NCR 53c80 series of SCSI controllers on boards using PIO. Most boards such as the Trantor T130 fit this @@ -600,7 +601,7 @@ config SCSI_GENERIC_NCR5380 config SCSI_GENERIC_NCR5380_MMIO tristate "Generic NCR5380/53c400 SCSI MMIO support" - depends on SCSI + depends on ISA && SCSI ---help--- This is a driver for the old NCR 53c80 series of SCSI controllers on boards using memory mapped I/O. @@ -609,10 +610,11 @@ config SCSI_GENERIC_NCR5380_MMIO of the box, you may have to change some settings in . - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called g_NCR5380. If you want to compile it as - a module, say M here and read . + This driver is also available as a module ( = code which can + be inserted in and removed from the running kernel whenever + you want). The module will be called g_NCR5380_mmio. + If you want to compile it as a module, say M here and read + . config SCSI_GENERIC_NCR53C400 bool "Enable NCR53c400 extensions" @@ -699,7 +701,7 @@ config IBMMCA_SCSI_DEV_RESET config SCSI_IPS tristate "IBM ServeRAID support" - depends on X86 && SCSI && PCI + depends on X86 && PCI && SCSI ---help--- This is support for the IBM ServeRAID hardware RAID controllers. See @@ -715,7 +717,7 @@ config SCSI_IPS config SCSI_INITIO tristate "Initio 9100U(W) support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -728,7 +730,7 @@ config SCSI_INITIO config SCSI_INIA100 tristate "Initio INI-A100U2W support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for the Initio INI-A100U2W SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -828,7 +830,7 @@ config SCSI_IZIP_SLOW_CTR config SCSI_NCR53C406A tristate "NCR53c406a SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for the NCR53c406a SCSI host adapter. For user configurable parameters, check out @@ -857,14 +859,12 @@ config 53C700_IO_MAPPED default y config SCSI_LASI700 - tristate "HP LASI SCSI support for 53c700/710" - depends on PARISC && SCSI + tristate "HP Lasi SCSI support for 53c700/710" + depends on GSC && SCSI help - This is a driver for the lasi baseboard in some parisc machines - which is based on the 53c700 chip. Will also support LASI subsystems - based on the 710 chip using 700 emulation mode. - - Unless you know you have a 53c700 or 53c710 based lasi, say N here + This is a driver for the SCSI controller in the Lasi chip found in + many PA-RISC workstations & servers. If you do not know whether you + have a Lasi chip, it is safe to say "Y" here. config 53C700_MEM_MAPPED bool @@ -876,72 +876,15 @@ config 53C700_LE_ON_BE depends on SCSI_LASI700 default y -config SCSI_NCR53C7xx - tristate "NCR53c7,8xx SCSI support" - depends on SCSI && PCI - ---help--- - This is a driver for the 53c7 and 8xx NCR family of SCSI - controllers, not to be confused with the NCR 5380 controllers. It - is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . Please read - for the available boot time - command line options. - - Note: there is another driver for the 53c8xx family of controllers - ("NCR53C8XX SCSI support" below). If you want to use them both, you - need to say M to both and build them as modules, but only one may be - active at a time. If you have a 53c8xx board, it's better to use the - other driver. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called 53c7,8xx. If you want to compile it as - a module, say M here and read . - -config SCSI_NCR53C7xx_sync - bool "always negotiate synchronous transfers" - depends on SCSI_NCR53C7xx - help - In general, this is good; however, it is a bit dangerous since there - are some broken SCSI devices out there. Take your chances. Safe bet - is N. - -config SCSI_NCR53C7xx_FAST - bool "allow FAST-SCSI [10MHz]" - depends on SCSI_NCR53C7xx - help - This will enable 10MHz FAST-SCSI transfers with your host - adapter. Some systems have problems with that speed, so it's safest - to say N here. - -config SCSI_NCR53C7xx_DISCONNECT - bool "allow DISCONNECT" - depends on SCSI_NCR53C7xx - help - This enables the disconnect/reconnect feature of the NCR SCSI - controller. When you say Y here, a slow SCSI device will not lock - the SCSI bus while processing a request, allowing simultaneous use - of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and - providing much better performance when using slow and fast SCSI - devices at the same time. Some devices, however, do not operate - properly with this option enabled, and will cause your SCSI system - to hang, which might cause a system crash. The safe answer - therefore is to say N. - config SCSI_SYM53C8XX_2 tristate "SYM53C8XX Version 2 SCSI support" depends on PCI && SCSI ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers. - - If your system has problems using this new major version of the - SYM53C8XX driver, you may switch back to driver version 1. + This driver supports the whole NCR53C8XX/SYM53C8XX family of + PCI-SCSI controllers. It also supports the subset of LSI53C10XX + Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS + language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI + controllers; you need to use the Fusion MPT driver for that. Please read for more information. @@ -1216,7 +1159,7 @@ config SCSI_MCA_53C9X config SCSI_PAS16 tristate "PAS16 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for a SCSI host adapter. It is explained in section 3.10 of the SCSI-HOWTO, available from @@ -1231,7 +1174,7 @@ config SCSI_PAS16 config SCSI_PCI2000 tristate "PCI2000 support" - depends on SCSI + depends on PCI && SCSI help This is support for the PCI2000I EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1244,7 +1187,7 @@ config SCSI_PCI2000 config SCSI_PCI2220I tristate "PCI2220i support" - depends on SCSI + depends on PCI && SCSI help This is support for the PCI2220i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1257,7 +1200,7 @@ config SCSI_PCI2220I config SCSI_PSI240I tristate "PSI240i support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for the PSI240i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1270,7 +1213,7 @@ config SCSI_PSI240I config SCSI_QLOGIC_FAS tristate "Qlogic FAS SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI! cards as well as any other card based on the FASXX chip @@ -1340,6 +1283,20 @@ config SCSI_QLOGIC_1280 The module will be called qla1280. If you want to compile it as a module, say M here and read . +config SCSI_QLOGICPTI + tristate "PTI Qlogic, ISP Driver" + depends on SBUS && SCSI + help + This driver supports SBUS SCSI controllers from PTI or QLogic. These + controllers are known under Solaris as qpti and in the openprom as + PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are + driven by a different driver. + + This support is also available as a module called qlogicpti ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . + config SCSI_SEAGATE tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" depends on X86 && ISA && SCSI @@ -1355,10 +1312,10 @@ config SCSI_SEAGATE The module will be called seagate. If you want to compile it as a module, say M here and read . -# definitely looks note 64bit safe: +# definitely looks not 64bit safe: config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" - depends on (EISA || MCA && !X86_64) && SCSI + depends on (EISA || MCA) && SCSI ---help--- This driver for NCR53c710 based SCSI host adapters. @@ -1371,7 +1328,7 @@ config 53C700_IO_MAPPED config SCSI_SYM53C416 tristate "Symbios 53c416 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for the sym53c416 SCSI host adapter, the SCSI adapter that comes with some HP scanners. This driver requires that @@ -1392,7 +1349,7 @@ config SCSI_SYM53C416 config SCSI_DC395x tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI && SCSI + depends on PCI && SCSI && EXPERIMENTAL ---help--- This driver supports PCI SCSI host adapters based on the ASIC TRM-S1040 chip, e.g Tekram DC395(U/UW/F) and DC315(U) variants. @@ -1446,7 +1403,7 @@ config SCSI_DC390T_NOGENSUPP config SCSI_T128 tristate "Trantor T128/T128F/T228 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for a SCSI host adapter. It is explained in section 3.11 of the SCSI-HOWTO, available from @@ -1463,7 +1420,7 @@ config SCSI_T128 config SCSI_U14_34F tristate "UltraStor 14F/34F support" - depends on SCSI + depends on ISA && SCSI ---help--- This is support for the UltraStor 14F and 34F SCSI-2 host adapters. The source at contains some @@ -1533,7 +1490,7 @@ config SCSI_ULTRASTOR config SCSI_NSP32 tristate "Workbit NinjaSCSI-32Bi/UDE support" - depends on SCSI + depends on PCI && SCSI help This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1606,7 +1563,7 @@ source "drivers/scsi/arm/Kconfig" config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" - depends on MIPS_JAZZ + depends on MIPS_JAZZ && SCSI help This is the driver for the onboard SCSI host adapter of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM @@ -1625,7 +1582,7 @@ config A3000_SCSI config A4000T_SCSI bool "A4000T SCSI support (EXPERIMENTAL)" - depends on AMIGA && EXPERIMENTAL + depends on AMIGA && SCSI && EXPERIMENTAL help Support for the NCR53C710 SCSI controller on the Amiga 4000T. @@ -1695,7 +1652,7 @@ config FASTLANE_SCSI config A4091_SCSI bool "A4091 SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade @@ -1703,7 +1660,7 @@ config A4091_SCSI config WARPENGINE_SCSI bool "WarpEngine SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help Support for MacroSystem Development's WarpEngine Amiga SCSI-2 controller. Info at @@ -1711,20 +1668,143 @@ config WARPENGINE_SCSI config BLZ603EPLUS_SCSI bool "Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ accelerator, say Y. Otherwise, say N. config OKTAGON_SCSI tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL && SCSI + depends on ZORRO && SCSI && EXPERIMENTAL help If you have the BSC Oktagon SCSI disk controller for the Amiga, say Y to this question. If you're in doubt about whether you have one, see the picture at . +config ATARI_SCSI + tristate "Atari native SCSI support" + depends on ATARI && SCSI + ---help--- + If you have an Atari with built-in NCR5380 SCSI controller (TT, + Falcon, ...) say Y to get it supported. Of course also, if you have + a compatible SCSI controller (e.g. for Medusa). This driver is also + available as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). The module is called + atari_scsi. If you want to compile it as a module, say M here and + read . This driver supports both + styles of NCR integration into the system: the TT style (separate + DMA), and the Falcon style (via ST-DMA, replacing ACSI). It does + NOT support other schemes, like in the Hades (without DMA). + +config ATARI_SCSI_TOSHIBA_DELAY + bool "Long delays for Toshiba CD-ROMs" + depends on ATARI_SCSI + help + This option increases the delay after a SCSI arbitration to + accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to + use a Toshiba CD-ROM drive; otherwise, the option is not needed and + would impact performance a bit, so say N. + +config ATARI_SCSI_RESET_BOOT + bool "Reset SCSI-devices at boottime" + depends on ATARI_SCSI + help + Reset the devices on your Atari whenever it boots. This makes the + boot process fractionally longer but may assist recovery from errors + that leave the devices with SCSI operations partway completed. + +config TT_DMA_EMUL + bool "Hades SCSI DMA emulator" + depends on ATARI_SCSI && HADES + help + This option enables code which emulates the TT SCSI DMA chip on the + Hades. This increases the SCSI transfer rates at least ten times + compared to PIO transfers. + +config MAC_SCSI + bool "Macintosh NCR5380 SCSI" + depends on MAC && SCSI + help + This is the NCR 5380 SCSI controller included on most of the 68030 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + +config SCSI_MAC_ESP + tristate "Macintosh NCR53c9[46] SCSI" + depends on MAC && SCSI + help + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mac_esp. If you want to compile it as + a module, say M here and read . + +config MVME147_SCSI + bool "WD33C93 SCSI driver for MVME147" + depends on MVME147 && SCSI + help + Support for the on-board SCSI controller on the Motorola MVME147 + single-board computer. + +config MVME16x_SCSI + bool "NCR53C710 SCSI driver for MVME16x" + depends on MVME16x && SCSI + help + The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +config BVME6000_SCSI + bool "NCR53C710 SCSI driver for BVME6000" + depends on BVME6000 && SCSI + help + The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +config SCSI_NCR53C7xx_FAST + bool "allow FAST-SCSI [10MHz]" + depends on A4000T_SCSI || A4091_SCSI || BLZ603EPLUS_SCSI || WARPENGINE_SCSI || MVME16x_SCSI || BVME6000_SCSI + help + This will enable 10MHz FAST-SCSI transfers with your host + adapter. Some systems have problems with that speed, so it's safest + to say N here. + +config SUN3_SCSI + tristate "Sun3 NCR5380 SCSI" + depends on SUN3 && SCSI + help + This option will enable support for the OBIO (onboard io) NCR5380 + SCSI controller found in the Sun 3/50 and 3/60, as well as for + "Sun3" type VME scsi controllers also based on the NCR5380. + General Linux information on the Sun 3 series (now discontinued) + is at . + +config SUN3X_ESP + bool "Sun3x ESP SCSI" + depends on SUN3X && SCSI + help + The ESP was an on-board SCSI controller used on Sun 3/80 + machines. Say Y here to compile in support for it. + +config SCSI_SUNESP + tristate "Sparc ESP Scsi Driver" + depends on SBUS && SCSI + help + This is the driver for the Sun ESP SCSI host adapter. The ESP + chipset is present in most SPARC SBUS-based computers. + + This support is also available as a module called esp ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . + config SCSI_PC980155 tristate "NEC PC-9801-55 SCSI support" depends on X86_PC9800 && SCSI diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index d9532de090b..f33795b26e6 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -170,7 +170,6 @@ enum Phase { /* Static function prototypes */ static void NCR53c406a_intr(int, void *, struct pt_regs *); static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *); -static void internal_done(Scsi_Cmnd *); static void wait_intr(void); static void chip_init(void); static void calc_port_addr(void); @@ -205,8 +204,6 @@ static int fast_pio = USE_FAST_PIO; #endif static Scsi_Cmnd *current_SC; -static volatile int internal_done_flag; -static volatile int internal_done_errcode; static char info_msg[256]; /* ================================================================= */ @@ -544,10 +541,13 @@ static int __init NCR53c406a_detect(Scsi_Host_Template * tpnt) } else if (irq_level == 0) { tpnt->can_queue = 0; DEB(printk("NCR53c406a: No interrupts detected\n")); + printk("NCR53c406a driver no longer supports polling interface\n"); + printk("Please email linux-scsi@vger.kernel.org\n"); + #if USE_DMA printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); - goto err_free_scsi; #endif /* USE_DMA */ + goto err_free_scsi; } else { DEB(printk("NCR53c406a: Shouldn't get here!\n")); goto err_free_scsi; @@ -590,6 +590,21 @@ static int __init NCR53c406a_detect(Scsi_Host_Template * tpnt) return 0; } +static int NCR53c406a_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); +#ifdef USE_DMA + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); +#endif + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + + scsi_unregister(shost); + return 0; +} + /* called from init/main.c */ static void __init NCR53c406a_setup(char *str, int *ints) { @@ -649,13 +664,6 @@ static const char *NCR53c406a_info(struct Scsi_Host *SChost) return (info_msg); } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - internal_done_errcode = SCpnt->result; - ++internal_done_flag; -} - - static void wait_intr(void) { unsigned long i = jiffies + WATCHDOG; @@ -709,21 +717,6 @@ static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) return 0; } -static int NCR53c406a_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("NCR53c406a_command called\n")); - NCR53c406a_queue(SCpnt, internal_done); - if (irq_level) - while (!internal_done_flag) - cpu_relax(); - else /* interrupts not supported */ - while (!internal_done_flag) - wait_intr(); - - internal_done_flag = 0; - return internal_done_errcode; -} - static int NCR53c406a_abort(Scsi_Cmnd * SCpnt) { DEB(printk("NCR53c406a_abort called\n")); @@ -1074,8 +1067,8 @@ static Scsi_Host_Template driver_template = .proc_name = "NCR53c406a" /* proc_name */, .name = "NCR53c406a" /* name */, .detect = NCR53c406a_detect /* detect */, + .release = NCR53c406a_release, .info = NCR53c406a_info /* info */, - .command = NCR53c406a_command /* command */, .queuecommand = NCR53c406a_queue /* queuecommand */, .eh_abort_handler = NCR53c406a_abort /* abort */, .eh_bus_reset_handler = NCR53c406a_bus_reset /* reset */, diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 3de8027d03f..f1eb7aaf22e 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -197,6 +197,8 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, hostdata->differential = (((1<clock = NCR_D700_CLOCK_MHZ; + NCR_700_set_io_mapped(hostdata); + /* and register the siop */ host = NCR_700_detect(&NCR_D700_driver_template, hostdata); if (!host) { @@ -223,7 +225,7 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, return 0; irq_failed: - scsi_unregister(host); + scsi_host_put(host); NCR_700_release(host); detect_failed: release_region(host->base, 64); diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 2b011aa1627..6d6f9333a8c 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1518,7 +1518,7 @@ static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* psg) dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = cpu_to_le32(0); - psg->sg[0].addr = cpu_to_le32(NULL); + psg->sg[0].addr = cpu_to_le32(0); psg->sg[0].count = cpu_to_le32(0); if (scsicmd->use_sg) { struct scatterlist *sg; @@ -1558,7 +1558,7 @@ static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* psg) psg->count = cpu_to_le32(1); psg->sg[0].addr = cpu_to_le32(addr); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)addr; + scsicmd->SCp.ptr = (char *)(ulong)addr; byte_count = scsicmd->request_bufflen; } return byte_count; @@ -1574,8 +1574,8 @@ static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg) dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = cpu_to_le32(0); - psg->sg[0].addr[0] = cpu_to_le32(NULL); - psg->sg[0].addr[1] = cpu_to_le32(NULL); + psg->sg[0].addr[0] = cpu_to_le32(0); + psg->sg[0].addr[1] = cpu_to_le32(0); psg->sg[0].count = cpu_to_le32(0); if (scsicmd->use_sg) { struct scatterlist *sg; @@ -1619,7 +1619,7 @@ static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg) psg->sg[0].addr[1] = (u32)(le_addr>>32); psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)addr; + scsicmd->SCp.ptr = (char *)(ulong)addr; byte_count = scsicmd->request_bufflen; } return byte_count; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 1adda2fc8bd..b3ae253d08f 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1515,16 +1515,6 @@ static void internal_done(Scsi_Cmnd *SCpnt) up(SCSEM(SCpnt)); } -static int aha152x_command(Scsi_Cmnd * SCpnt) -{ - DECLARE_MUTEX_LOCKED(sem); - - aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done); - down(&sem); - - return SUCCESS; -} - /* * Abort a command * @@ -3876,7 +3866,6 @@ static Scsi_Host_Template aha152x_driver_template = { .proc_name = "aha152x", .proc_info = aha152x_proc_info, .detect = aha152x_detect, - .command = aha152x_command, .queuecommand = aha152x_queue, .eh_abort_handler = aha152x_abort, .eh_device_reset_handler = aha152x_device_reset, diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 653f6d8ac0c..0014ce5abb2 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -774,23 +774,6 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int aha1542_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n")); - - aha1542_queuecommand(SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - /* Initialize mailboxes */ static void setup_mailboxes(int bse, struct Scsi_Host *shpnt) { @@ -1325,6 +1308,18 @@ unregister: return count; } +static int aha1542_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static int aha1542_restart(struct Scsi_Host *shost) { int i; @@ -1817,7 +1812,7 @@ static Scsi_Host_Template driver_template = { .proc_name = "aha1542", .name = "Adaptec 1542", .detect = aha1542_detect, - .command = aha1542_command, + .release = aha1542_release, .queuecommand = aha1542_queuecommand, .eh_abort_handler = aha1542_abort, .eh_device_reset_handler= aha1542_dev_reset, diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 3795f89c982..ecf9ebff1b4 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -102,6 +102,7 @@ static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start if (len > length) len = length; return len; +} static int aha1740_makecode(unchar *sense, unchar *status) @@ -476,23 +477,6 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int aha1740_command(Scsi_Cmnd * SCpnt) -{ - aha1740_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - /* Query the board for its irq_level. Nothing else matters in enhanced mode on an EISA bus. */ @@ -567,6 +551,16 @@ static int aha1740_detect(Scsi_Host_Template * tpnt) return count; } +static int aha1740_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static int aha1740_biosparam(struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int* ip) { @@ -596,7 +590,7 @@ static Scsi_Host_Template driver_template = { .proc_info = aha1740_proc_info, .name = "Adaptec 174x (EISA)", .detect = aha1740_detect, - .command = aha1740_command, + .release = aha1740_release, .queuecommand = aha1740_queuecommand, .bios_param = aha1740_biosparam, .can_queue = AHA1740_ECBS, diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2022bd980cd..c50c2bb4697 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2098,7 +2098,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) u_long target; template->name = ahd->description; - host = scsi_register(template, sizeof(struct ahd_softc *)); + host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); if (host == NULL) return (ENOMEM); @@ -2308,7 +2308,7 @@ ahd_platform_free(struct ahd_softc *ahd) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); #endif - scsi_unregister(ahd->platform_data->host); + scsi_host_put(ahd->platform_data->host); } /* destroy all of the device and target objects */ diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 43e88edf464..4071cbaab81 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -52,9 +52,11 @@ static int ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, u_long *base2); +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, uint8_t **maddr); +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); @@ -271,6 +273,7 @@ ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, return (0); } +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, @@ -318,6 +321,7 @@ ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, error = ENOMEM; return (error); } +#endif int ahd_pci_map_registers(struct ahd_softc *ahd) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 39047ea53d7..9e1c586ffcd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1725,7 +1725,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) u_int targ_offset; template->name = ahc->description; - host = scsi_register(template, sizeof(struct ahc_softc *)); + host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); if (host == NULL) return (ENOMEM); @@ -1978,7 +1978,7 @@ ahc_platform_free(struct ahc_softc *ahc) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); #endif - scsi_unregister(ahc->platform_data->host); + scsi_host_put(ahc->platform_data->host); } /* destroy all of the device and target objects */ diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c index 89c454b2685..78a28664ed4 100644 --- a/drivers/scsi/amiga7xx.c +++ b/drivers/scsi/amiga7xx.c @@ -134,9 +134,22 @@ int __init amiga7xx_detect(Scsi_Host_Template *tpnt) return num; } +static int amiga7xx_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "Amiga NCR53c710 SCSI", .detect = amiga7xx_detect, + .release = amiga7xx_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 835ec8f4edf..ff23d71dd83 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2993,7 +2993,7 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id) AS_Host *ashost; int ret = -ENOMEM; - host = scsi_register(&acornscsi_template, sizeof(AS_Host)); + host = scsi_host_alloc(&acornscsi_template, sizeof(AS_Host)); if (!host) goto out; @@ -3060,7 +3060,7 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id) err_2: release_region(host->io_port + 0x800, 2); err_1: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -3089,6 +3089,7 @@ static void __devexit acornscsi_remove(struct expansion_card *ec) msgqueue_free(&ashost->scsi.msgs); queue_free(&ashost->queues.disconnected); queue_free(&ashost->queues.issue); + scsi_host_put(host); } static const struct ecard_id acornscsi_cids[] = { diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index 3a658f65a03..724c2533835 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -264,7 +264,6 @@ static Scsi_Host_Template arxescsi_template = { .proc_info = arxescsi_proc_info, .name = "ARXE SCSI card", .info = arxescsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index 680207fe614..b7c9f1365bf 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -262,7 +262,7 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id) struct Scsi_Host *host; int ret = -ENOMEM; - host = scsi_register(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); if (!host) goto out; @@ -304,7 +304,7 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id) out_release: release_region(host->io_port, host->n_io_port); out_free: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -318,7 +318,7 @@ static void __devexit cumanascsi1_remove(struct expansion_card *ec) scsi_remove_host(host); free_irq(host->irq, host); release_region(host->io_port, host->n_io_port); - scsi_unregister(host); + scsi_host_put(host); } static const struct ecard_id cumanascsi1_cids[] = { diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index 14387556af4..c0a6a90b9f4 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -386,7 +386,6 @@ static Scsi_Host_Template cumanascsi2_template = { .proc_info = cumanascsi_2_proc_info, .name = "Cumana SCSI II", .info = cumanascsi_2_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c index 53155015ef9..9b88a2e6af5 100644 --- a/drivers/scsi/arm/ecoscsi.c +++ b/drivers/scsi/arm/ecoscsi.c @@ -177,7 +177,7 @@ static struct Scsi_Host *host; static int __init ecoscsi_init(void) { - host = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata)); if (!host) return 0; @@ -211,7 +211,7 @@ static int __init ecoscsi_init(void) release_reg: release_region(host->io_port, host->n_io_port); unregister_scsi: - scsi_unregister(host); + scsi_host_put(host); return -ENODEV; } @@ -224,7 +224,7 @@ static void __exit ecoscsi_exit(void) if (shpnt->io_port) release_region(shpnt->io_port, shpnt->n_io_port); - scsi_unregister(host); + scsi_host_put(host); return 0; } diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index c0de9f0eb8e..c1c04ab3556 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -492,7 +492,6 @@ static Scsi_Host_Template eesox_template = { .proc_info = eesoxscsi_proc_info, .name = "EESOX SCSI", .info = eesoxscsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 5b5d93ace30..6ba029abf28 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -225,8 +225,7 @@ static void fas216_dumpinfo(FAS216_Info *info) printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", info->dma.transfer_type, info->dma.setup, info->dma.pseudo, info->dma.stop); - printk(" internal_done=%X magic_end=%lX }\n", - info->internal_done, info->magic_end); + printk(" magic_end=%lX }\n", info->magic_end); } #ifdef CHECK_STRUCTURE @@ -2253,74 +2252,6 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) return result; } -/** - * fas216_internal_done - trigger restart of a waiting thread in fas216_command - * @SCpnt: Command to wake - * - * Trigger restart of a waiting thread in fas216_command - */ -static void fas216_internal_done(Scsi_Cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - info->internal_done = 1; -} - -/** - * fas216_command - queue a command for adapter to process. - * @SCpnt: Command to queue - * - * Queue a command for adapter to process. - * Returns: scsi result code. - * Notes: io_request_lock is held, interrupts are disabled. - */ -int fas216_command(Scsi_Cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - /* - * We should only be using this if we don't have an interrupt. - * Provide some "incentive" to use the queueing code. - */ - if (info->scsi.irq != NO_IRQ) - BUG(); - - info->internal_done = 0; - fas216_queue_command(SCpnt, fas216_internal_done); - - /* - * This wastes time, since we can't return until the command is - * complete. We can't sleep either since we may get re-entered! - * However, we must re-enable interrupts, or else we'll be - * waiting forever. - */ - spin_unlock_irq(info->host->host_lock); - - while (!info->internal_done) { - /* - * If we don't have an IRQ, then we must poll the card for - * it's interrupt, and use that to call this driver's - * interrupt routine. That way, we keep the command - * progressing. Maybe we can add some inteligence here - * and go to sleep if we know that the device is going - * to be some time (eg, disconnected). - */ - if (fas216_readb(info, REG_STAT) & STAT_INT) { - spin_lock_irq(info->host->host_lock); - fas216_intr(info); - spin_unlock_irq(info->host->host_lock); - } - } - - spin_lock_irq(info->host->host_lock); - - return SCpnt->result; -} - /* * Error handler timeout function. Indicate that we timed out, * and wake up any error handler process so it can continue. @@ -2942,6 +2873,7 @@ void fas216_remove(struct Scsi_Host *host) scsi_remove_host(host); fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + scsi_host_put(host); } /** diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index d6b6322f9d5..7f079292b44 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -310,8 +310,6 @@ typedef struct { } dma; /* miscellaneous */ - int internal_done; /* flag to indicate request done */ - unsigned long magic_end; } FAS216_Info; @@ -337,13 +335,6 @@ extern int fas216_add (struct Scsi_Host *instance, struct device *dev); */ extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -/* Function: int fas216_command (Scsi_Cmnd *SCpnt) - * Purpose : queue a command for adapter to process. - * Params : SCpnt - Command to queue - * Returns : scsi result code - */ -extern int fas216_command (Scsi_Cmnd *); - /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command * Params : info - interface to service diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c index 1b89074a919..7669085a2a6 100644 --- a/drivers/scsi/arm/oak.c +++ b/drivers/scsi/arm/oak.c @@ -135,7 +135,7 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) struct Scsi_Host *host; int ret = -ENOMEM; - host = scsi_register(&oakscsi_template, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata)); if (!host) goto out; @@ -163,7 +163,7 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) release_region(host->io_port, host->n_io_port); unreg: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -176,7 +176,7 @@ static void __devexit oakscsi_remove(struct expansion_card *ec) scsi_remove_host(host); release_region(host->io_port, host->n_io_port); - scsi_unregister(host); + scsi_host_put(host); } static const struct ecard_id oakscsi_cids[] = { diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index 3d1bf78b644..31320862d25 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -235,18 +235,17 @@ powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) * of the required information. * offset - offset into information that we have read upto. * length - length of buffer - * host_no - host number to return information for * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. */ int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int host_no, int inout) + int length, int inout) { struct powertec_info *info; char *p = buffer; int pos; - If (inout == 1) + if (inout == 1) return powertecscsi_set_proc_info(host, buffer, length); info = (struct powertec_info *)host->hostdata; @@ -296,7 +295,6 @@ static Scsi_Host_Template powertecscsi_template = { .proc_info = powertecscsi_proc_info, .name = "PowerTec SCSI", .info = powertecscsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 20db5c2ce27..dd46f6417b8 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -829,25 +829,6 @@ oktosend: } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int atp870u_command(Scsi_Cmnd * SCpnt) -{ - - atp870u_queuecommand(SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) { unsigned int tmport; @@ -2728,7 +2709,6 @@ static Scsi_Host_Template driver_template = { .detect = atp870u_detect, .release = atp870u_release, .info = atp870u_info, - .command = atp870u_command, .queuecommand = atp870u_queuecommand, .eh_abort_handler = atp870u_abort, .bios_param = atp870u_biosparam, diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h index 14d5b981f11..015e346ca79 100644 --- a/drivers/scsi/atp870u.h +++ b/drivers/scsi/atp870u.h @@ -18,7 +18,6 @@ #define MAX_SENSE 14 static int atp870u_detect(Scsi_Host_Template *); -static int atp870u_command(Scsi_Cmnd *); static int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int atp870u_abort(Scsi_Cmnd *); static int atp870u_biosparam(struct scsi_device *, struct block_device *, diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c index 1fb8cd9890c..615ad7627f8 100644 --- a/drivers/scsi/blz1230.c +++ b/drivers/scsi/blz1230.c @@ -334,7 +334,6 @@ static Scsi_Host_Template driver_template = { .name = "Blizzard1230 SCSI IV", .detect = blz1230_esp_detect, .release = blz1230_esp_release, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c index 9f7ba7890ad..c47cbc182f4 100644 --- a/drivers/scsi/bvme6000.c +++ b/drivers/scsi/bvme6000.c @@ -51,9 +51,22 @@ int bvme6000_scsi_detect(Scsi_Host_Template *tpnt) return 1; } +static int mvme6000_scsi_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "BVME6000 NCR53c710 SCSI", .detect = bvme6000_scsi_detect, + .release = bvme6000_scsi_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index ae0d83fae3e..76bd3891473 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1004,16 +1004,14 @@ print_sense_internal(const char * devclass, #endif } -void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) +void print_sense(const char *devclass, struct scsi_cmnd *cmd) { - print_sense_internal(devclass, SCpnt->sense_buffer, - SCpnt->request); + print_sense_internal(devclass, cmd->sense_buffer, cmd->request); } -void print_req_sense(const char * devclass, Scsi_Request * SRpnt) +void print_req_sense(const char *devclass, struct scsi_request *sreq) { - print_sense_internal(devclass, SRpnt->sr_sense_buffer, - SRpnt->sr_request); + print_sense_internal(devclass, sreq->sr_sense_buffer, sreq->sr_request); } #if (CONSTANTS & CONST_MSG) @@ -1116,13 +1114,13 @@ int print_msg (const unsigned char *msg) { return len; } -void print_Scsi_Cmnd (Scsi_Cmnd *cmd) { +void print_Scsi_Cmnd(struct scsi_cmnd *cmd) { printk("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun); printk(" command = "); - print_command (cmd->cmnd); + print_command(cmd->cmnd); } #if (CONSTANTS & CONST_HOST) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 466ac1c1dea..eedaa157590 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -5726,9 +5726,9 @@ DC395x_init(Scsi_Host_Template * host_template, u32 io_port, u8 irq, /* *$$$$$$$$$$$ MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$ */ - host = scsi_register(host_template, sizeof(struct AdapterCtlBlk)); + host = scsi_host_alloc(host_template, sizeof(struct AdapterCtlBlk)); if (!host) { - dprintkl(KERN_INFO, "pSH scsi_register ERROR\n"); + dprintkl(KERN_INFO, "pSH scsi_host_alloc ERROR\n"); return 0; } DC395x_print_eeprom_settings(index); @@ -5736,7 +5736,7 @@ DC395x_init(Scsi_Host_Template * host_template, u32 io_port, u8 irq, pACB = (struct AdapterCtlBlk *) host->hostdata; if (DC395x_initACB(host, io_port, irq, index)) { - scsi_unregister(host); + scsi_host_put(host); return 0; } DC395x_print_config(pACB); @@ -5755,7 +5755,7 @@ DC395x_init(Scsi_Host_Template * host_template, u32 io_port, u8 irq, } else { dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n"); - scsi_unregister(host); + scsi_host_put(host); host = NULL; } return host; diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c index e52117559cf..fe383a73ee2 100644 --- a/drivers/scsi/dec_esp.c +++ b/drivers/scsi/dec_esp.c @@ -99,13 +99,23 @@ static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *); int dec_esp_detect(Scsi_Host_Template * tpnt); +static int dec_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .proc_name = "esp", .proc_info = &esp_proc_info, .name = "NCR53C94", .detect = dec_esp_detect, + .release = dec_esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index f0c6073faa7..79751a79461 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1949,26 +1949,6 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, case I2ORESCANCMD: adpt_rescan(pHba); break; - case DPT_TARGET_BUSY & 0xFFFF: - case DPT_TARGET_BUSY: - { - TARGET_BUSY_T busy; - struct adpt_device* d; - - if (copy_from_user((void*)&busy, (void*)arg, sizeof(TARGET_BUSY_T))) { - return -EFAULT; - } - - d = adpt_find_device(pHba, busy.channel, busy.id, busy.lun); - if(d == NULL){ - return -ENODEV; - } - busy.isBusy = ((d->pScsi_dev) && (0 != d->pScsi_dev->access_count)) ? 1 : 0; - if (copy_to_user ((char*)arg, &busy, sizeof(busy))) { - return -EFAULT; - } - break; - } default: return -EINVAL; } @@ -2492,10 +2472,6 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) printk(KERN_WARNING"%s: Device (%d,%d,%d) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun); if (pDev->pScsi_dev) { pDev->pScsi_dev->online = FALSE; - if (pDev->pScsi_dev->access_count) { - // A drive that was mounted is no longer there... bad! - printk(KERN_WARNING"%s:Mounted drive taken offline\n",pHba->name); - } } } } diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 0732f345784..f9dc04e895b 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -447,9 +447,20 @@ MODULE_LICENSE("GPL"); #include "NCR5380.c" +static int dtc_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "DTC 3180/3280 ", .detect = dtc_detect, + .release = dtc_release, .queuecommand = dtc_queue_command, .eh_abort_handler = dtc_abort, .eh_bus_reset_handler = dtc_bus_reset, diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 6210c1b85b9..f3d7c97b6d9 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1,6 +1,36 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 + * + Update for new IRQ API. + * + Use "goto" when appropriate. + * + Drop eata.h. + * + Update for new module_param API. + * + Module parameters can now be specified only in the + * same format as the kernel boot options. + * + * boot option old module param + * ----------- ------------------ + * addr,... io_port=addr,... + * lc:[y|n] linked_comm=[1|0] + * mq:xx max_queue_depth=xx + * tm:[0|1|2] tag_mode=[0|1|2] + * et:[y|n] ext_tran=[1|0] + * rs:[y|n] rev_scan=[1|0] + * ip:[y|n] isa_probe=[1|0] + * ep:[y|n] eisa_probe=[1|0] + * pp:[y|n] pci_probe=[1|0] + * + * A valid example using the new parameter format is: + * modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n" + * + * which is equivalent to the old format: + * modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \ + * max_queue_depth=4 eisa_probe=0 + * + * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 + * + Release irq before calling scsi_register. + * * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 * + Release driver_lock before calling scsi_register. * @@ -279,7 +309,7 @@ * This driver is based on the CAM (Common Access Method Committee) * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. * - * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -447,31 +477,8 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#include - -#define MAX_INT_PARAM 10 - -#if defined(MODULE) -#include - -MODULE_PARM(boot_options, "s"); -MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); -MODULE_PARM(linked_comm, "i"); -MODULE_PARM(link_statistics, "i"); -MODULE_PARM(max_queue_depth, "i"); -MODULE_PARM(tag_mode, "i"); -MODULE_PARM(ext_tran, "i"); -MODULE_PARM(rev_scan, "i"); -MODULE_PARM(isa_probe, "i"); -MODULE_PARM(eisa_probe, "i"); -MODULE_PARM(pci_probe, "i"); -MODULE_AUTHOR("Dario Ballabio"); - -#endif - #include #include -#include #include #include #include @@ -491,8 +498,31 @@ MODULE_AUTHOR("Dario Ballabio"); #include "hosts.h" #include #include -#include "eata.h" +static int eata2x_detect(Scsi_Host_Template *); +static int eata2x_release(struct Scsi_Host *); +static int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int eata2x_eh_abort(Scsi_Cmnd *); +static int eata2x_eh_host_reset(Scsi_Cmnd *); +static int eata2x_bios_param(struct scsi_device *, struct block_device *, + sector_t, int *); +static int eata2x_slave_configure(Scsi_Device *); + +static Scsi_Host_Template driver_template = { + .name = "EATA/DMA 2.0x rev. 8.10.00 ", + .detect = eata2x_detect, + .release = eata2x_release, + .queuecommand = eata2x_queuecommand, + .eh_abort_handler = eata2x_eh_abort, + .eh_device_reset_handler = NULL, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = eata2x_eh_host_reset, + .bios_param = eata2x_bios_param, + .slave_configure = eata2x_slave_configure, + .this_id = 7, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING + }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" #endif @@ -818,7 +848,6 @@ static int setup_done = FALSE; static int link_statistics; static int ext_tran = FALSE; static int rev_scan = TRUE; -static char *boot_options; #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) static int tag_mode = TAG_SIMPLE; @@ -856,6 +885,23 @@ static int pci_probe = TRUE; static int pci_probe = FALSE; #endif +#define MAX_INT_PARAM 10 +#define MAX_BOOT_OPTIONS_SIZE 256 +static char boot_options[MAX_BOOT_OPTIONS_SIZE]; + +#if defined(MODULE) +#include +#include + +module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); +MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." \ +" Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); +MODULE_AUTHOR("Dario Ballabio"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EATA/DMA SCSI Driver"); + +#endif + static int eata2x_slave_configure(Scsi_Device *dev) { int j, tqd, utqd; char *tag_suffix, *link_suffix; @@ -1011,19 +1057,20 @@ static int port_detect \ sprintf(name, "%s%d", driver_name, j); - if(!request_region(port_base, REGION_SIZE, driver_name)) { + if (!request_region(port_base, REGION_SIZE, driver_name)) { #if defined(DEBUG_DETECT) printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); #endif - return FALSE; + goto fail; } + spin_lock_irq(&driver_lock); + if (do_dma(port_base, 0, READ_CONFIG_PIO)) { #if defined(DEBUG_DETECT) printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } /* Read the info structure */ @@ -1031,8 +1078,7 @@ static int port_detect \ #if defined(DEBUG_DETECT) printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } info.data_len = DEV2H(info.data_len); @@ -1048,15 +1094,13 @@ static int port_detect \ #if defined(DEBUG_DETECT) printk("%s: signature 0x%04x discarded.\n", name, info.sign); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (info.data_len < EATA_2_0A_SIZE) { printk("%s: config structure size (%d bytes) too short, detaching.\n", name, info.data_len); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } else if (info.data_len == EATA_2_0A_SIZE) protocol_rev = 'A'; @@ -1097,8 +1141,7 @@ static int port_detect \ if (!info.haaval || info.ata) { printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", name, port_base, bus_type, info.haaval, info.ata); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (info.drqvld) { @@ -1145,16 +1188,13 @@ static int port_detect \ SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), driver_name, (void *) &sha[j])) { printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (subversion == ISA && request_dma(dma_channel, driver_name)) { printk("%s: unable to allocate DMA channel %u, detaching.\n", name, dma_channel); - free_irq(irq, &sha[j]); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freeirq; } #if defined(FORCE_CONFIG) @@ -1166,8 +1206,7 @@ static int port_detect \ if (!cf) { printk("%s: config, pci_alloc_consistent failed, detaching.\n", name); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } /* Set board configuration */ @@ -1178,8 +1217,7 @@ static int port_detect \ if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { printk("%s: busy timeout sending configuration, detaching.\n", name); pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } } @@ -1191,13 +1229,7 @@ static int port_detect \ if (sh[j] == NULL) { printk("%s: unable to register host, detaching.\n", name); - - free_irq(irq, &sha[j]); - - if (subversion == ISA) free_dma(dma_channel); - - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } sh[j]->io_port = port_base; @@ -1268,6 +1300,8 @@ static int port_detect \ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); else sprintf(dma_name, "DMA %u", dma_channel); + spin_unlock_irq(&driver_lock); + for (i = 0; i < sh[j]->can_queue; i++) HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); @@ -1277,15 +1311,13 @@ static int port_detect \ sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - eata2x_release(sh[j]); - return FALSE; + goto release; } if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, sizeof(struct mssp), &HD(j)->sp_dma_addr))) { printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); - eata2x_release(sh[j]); - return FALSE; + goto release; } if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) @@ -1297,7 +1329,7 @@ static int port_detect \ tag_mode = TAG_ORDERED; if (j == 0) { - printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n"); + printk("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); printk("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "\ "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), @@ -1342,6 +1374,20 @@ static int port_detect \ } return TRUE; + +freedma: + if (subversion == ISA) free_dma(dma_channel); +freeirq: + free_irq(irq, &sha[j]); +freelock: + spin_unlock_irq(&driver_lock); + release_region(port_base, REGION_SIZE); +fail: + return FALSE; + +release: + eata2x_release(sh[j]); + return FALSE; } static void internal_setup(char *str, int *ints) { @@ -1440,11 +1486,9 @@ static void add_pci_ports(void) { static int eata2x_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; - spin_lock_irq(&driver_lock); - tpnt->proc_name = "eata2x"; - if(boot_options) option_setup(boot_options); + if(strlen(boot_options)) option_setup(boot_options); #if defined(MODULE) /* io_port could have been modified when loading as a module */ @@ -1478,7 +1522,6 @@ static int eata2x_detect(Scsi_Host_Template *tpnt) { } num_boards = j; - spin_unlock_irq(&driver_lock); return j; } @@ -2091,7 +2134,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j, } -static void ihdlr(int irq, unsigned int j) { +static irqreturn_t ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg; struct mssp *spp; @@ -2101,7 +2144,7 @@ static void ihdlr(int irq, unsigned int j) { panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq); /* Check if this board need to be serviced */ - if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) return; + if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) goto none; HD(j)->iocount++; @@ -2113,7 +2156,7 @@ static void ihdlr(int irq, unsigned int j) { reg = inb(sh[j]->io_port + REG_STATUS); printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); - return; + goto none; } spp = &HD(j)->sp; @@ -2148,7 +2191,7 @@ static void ihdlr(int irq, unsigned int j) { printk("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", BN(j), spp->cpp_index, irq, reg, HD(j)->iocount); if (spp->eoc == FALSE || spp->cpp_index < 0 - || spp->cpp_index >= sh[j]->can_queue) return; + || spp->cpp_index >= sh[j]->can_queue) goto handled; /* Find the mailbox to be serviced on this board */ i = spp->cpp_index; @@ -2156,23 +2199,23 @@ static void ihdlr(int irq, unsigned int j) { cpp = &(HD(j)->cp[i]); #if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; #endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; - return; + goto handled; } else if (HD(j)->cp_stat[i] == LOCKED) { HD(j)->cp_stat[i] = FREE; printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == FREE) { printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == IN_RESET) printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); @@ -2319,22 +2362,25 @@ static void ihdlr(int irq, unsigned int j) { if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, HD(j)->iocount); - return; +handled: + return IRQ_HANDLED; +none: + return IRQ_NONE; } static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) { + struct pt_regs *regs) { unsigned int j; unsigned long spin_flags; + irqreturn_t ret; /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; + if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ihdlr(irq, j); + ret = ihdlr(irq, j); spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return IRQ_HANDLED; + return ret; } static int eata2x_release(struct Scsi_Host *shpnt) { @@ -2365,22 +2411,8 @@ static int eata2x_release(struct Scsi_Host *shpnt) { return FALSE; } -static Scsi_Host_Template driver_template = { - .name = "EATA/DMA 2.0x rev. " EATA_VERSION " ", - .detect = eata2x_detect, - .release = eata2x_release, - .queuecommand = eata2x_queuecommand, - .eh_abort_handler = eata2x_eh_abort, - .eh_host_reset_handler = eata2x_eh_host_reset, - .bios_param = eata2x_bios_param, - .slave_configure = eata2x_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; #include "scsi_module.c" #ifndef MODULE __setup("eata=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h deleted file mode 100644 index 161c2d949f7..00000000000 --- a/drivers/scsi/eata.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters. - */ - -static int eata2x_detect(Scsi_Host_Template *); -static int eata2x_release(struct Scsi_Host *); -static int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int eata2x_eh_abort(Scsi_Cmnd *); -static int eata2x_eh_host_reset(Scsi_Cmnd *); -static int eata2x_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int eata2x_slave_configure(Scsi_Device *); - -#define EATA_VERSION "8.03.00" - diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 8505151a9e0..543ea4acb18 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1871,15 +1871,6 @@ static int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } -/* Only queuing supported in this ESP driver. */ -static int esp_command(Scsi_Cmnd *SCpnt) -{ - struct esp *esp = (struct esp *) SCpnt->device->host->hostdata; - - ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id)); - return -1; -} - /* Dump driver state. */ static void esp_dump_cmd(Scsi_Cmnd *SCptr) { @@ -4384,7 +4375,6 @@ static void esp_slave_destroy(Scsi_Device *SDptr) SDptr->hostdata = NULL; } - static Scsi_Host_Template driver_template = { .proc_name = "esp", .proc_info = esp_proc_info, @@ -4394,7 +4384,6 @@ static Scsi_Host_Template driver_template = { .slave_destroy = esp_slave_destroy, .release = esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index b274419e0b5..677c91df0b8 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -1186,24 +1186,6 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - /* flag it done */ - SCpnt->host_scribble = (unsigned char *) 1; -} - -int fd_mcs_command(Scsi_Cmnd * SCpnt) -{ - fd_mcs_queue(SCpnt, internal_done); - /* host_scribble is used for status here */ - SCpnt->host_scribble = NULL; - while (!SCpnt->host_scribble) { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - #if DEBUG_ABORT || DEBUG_RESET static void fd_mcs_print_info(Scsi_Cmnd * SCpnt) { @@ -1431,7 +1413,6 @@ static Scsi_Host_Template driver_template = { .detect = fd_mcs_detect, .release = fd_mcs_release, .info = fd_mcs_info, - .command = fd_mcs_command, .queuecommand = fd_mcs_queue, .eh_abort_handler = fd_mcs_abort, .eh_bus_reset_handler = fd_mcs_bus_reset, diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 1b5e527fb25..a489edf9ac5 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -255,11 +255,6 @@ be increased by changing this value to values which are close to 2. Please let me know if you try any different values. - DO_DETECT: This activates some old scan code which was needed before the - high level drivers got fixed. If you are having trouble with the driver, - turning this on should not hurt, and might help. Please let me know if - this is the case, since this code will be removed from future drivers. - RESELECTION: This is no longer an option, since I gave up trying to implement it in version 4.x of this driver. It did not improve performance at all and made the driver unstable (because I never found one @@ -303,7 +298,6 @@ MODULE_LICENSE("GPL"); #define DEBUG 0 /* Enable debugging output */ #define ENABLE_PARITY 1 /* Enable SCSI Parity */ #define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ -#define DO_DETECT 0 /* Do device detection here (see scsi.c) */ /* END OF USER DEFINABLE OPTIONS */ @@ -863,17 +857,6 @@ struct Scsi_Host *__fdomain_16x0_detect( Scsi_Host_Template *tpnt ) int retcode; struct Scsi_Host *shpnt; struct pci_dev *pdev = NULL; -#if DO_DETECT - int i = 0; - int j = 0; - const int buflen = 255; - Scsi_Cmnd SCinit; - unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 }; - unsigned char do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 }; - unsigned char do_read_capacity[] = { READ_CAPACITY, - 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char buf[buflen]; -#endif if (setup_called) { #if DEBUG_DETECT @@ -984,59 +967,6 @@ struct Scsi_Host *__fdomain_16x0_detect( Scsi_Host_Template *tpnt ) /* Log I/O ports with kernel */ request_region( port_base, 0x10, "fdomain" ); -#if DO_DETECT - - /* These routines are here because of the way the SCSI bus behaves after - a reset. This appropriate behavior was not handled correctly by the - higher level SCSI routines when I first wrote this driver. Now, - however, correct scan routines are part of scsi.c and these routines - are no longer needed. However, this code is still good for - debugging. */ - - SCinit.request_buffer = SCinit.buffer = buf; - SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; - SCinit.use_sg = 0; - SCinit.lun = 0; - - printk( "scsi: detection routine scanning for devices:\n" ); - for (i = 0; i < 8; i++) { - SCinit.target = i; - if (i == tpnt->this_id) /* Skip host adapter */ - continue; - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - printk( " SCSI ID %d: ", i ); - for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) - printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); - memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - unsigned long blocks, size, capacity; - - blocks = (buf[0] << 24) | (buf[1] << 16) - | (buf[2] << 8) | buf[3]; - size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; - capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; - - printk( "%lu MB (%lu byte blocks)", - ((capacity + 5L) / 10L), size ); - } else { - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - } - printk ("\n" ); - } else { - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - } - } - } -#endif - return shpnt; } @@ -1508,31 +1438,6 @@ static int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } -/* The following code, which simulates the old-style command function, was - taken from Tommy Thorn's aha1542.c file. This code is Copyright (C) - 1992 Tommy Thorn. */ - -static volatile int internal_done_flag = 0; -static volatile int internal_done_errcode = 0; - -static void internal_done(Scsi_Cmnd *SCpnt) -{ - internal_done_errcode = SCpnt->result; - ++internal_done_flag; -} - -static int fdomain_16x0_command(Scsi_Cmnd *SCpnt) -{ - fdomain_16x0_queue(SCpnt, internal_done); - - while (!internal_done_flag) - cpu_relax(); - internal_done_flag = 0; - return internal_done_errcode; -} - -/* End of code derived from Tommy Thorn's work. */ - #if DEBUG_ABORT static void print_info(Scsi_Cmnd *SCpnt) { @@ -1833,7 +1738,6 @@ Scsi_Host_Template fdomain_driver_template = { .proc_name = "fdomain", .detect = fdomain_16x0_detect, .info = fdomain_16x0_info, - .command = fdomain_16x0_command, .queuecommand = fdomain_16x0_queue, .eh_abort_handler = fdomain_16x0_abort, .eh_bus_reset_handler = fdomain_16x0_bus_reset, diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c dissimilarity index 65% index 2b5b7b99e1e..42821de2eff 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -1,585 +1,291 @@ -/* - * hosts.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995 Eric Youngdale - * - * mid to lowlevel SCSI driver interface - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli - * Added QLOGIC QLA1280 SCSI controller kernel host support. - * August 4, 1999 Fred Lewis, Intel DuPont - * - * Updated to reflect the new initialization scheme for the higher - * level of scsi drivers (sd/sr/st) - * September 17, 2000 Torben Mathiasen - * - * Restructured scsi_host lists and associated functions. - * September 04, 2002 Mike Anderson (andmike@us.ibm.com) - */ - - -/* - * This file contains the medium level SCSI - * host interface initialization, as well as the scsi_hosts list of SCSI - * hosts currently present in the system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include "hosts.h" - -#include "scsi_priv.h" -#include "scsi_logging.h" - - -static LIST_HEAD(scsi_host_list); -static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED; - -static int scsi_host_next_hn; /* host_no for next new host */ -static char *scsihosts; - -MODULE_PARM(scsihosts, "s"); -MODULE_PARM_DESC(scsihosts, "scsihosts=driver1,driver2,driver3"); -#ifndef MODULE -int __init scsi_setup(char *str) -{ - scsihosts = str; - return 1; -} - -__setup("scsihosts=", scsi_setup); -#endif - -/** - * scsi_find_host_by_num - get a Scsi_Host by host no - * - * @host_no: host number to locate - * - * Return value: - * A pointer to located Scsi_Host or NULL. - **/ -static struct Scsi_Host *scsi_find_host_by_num(unsigned short host_no) -{ - struct Scsi_Host *shost, *shost_found = NULL; - - spin_lock(&scsi_host_list_lock); - list_for_each_entry(shost, &scsi_host_list, sh_list) { - if (shost->host_no > host_no) { - /* - * The list is sorted. - */ - break; - } else if (shost->host_no == host_no) { - shost_found = shost; - break; - } - } - spin_unlock(&scsi_host_list_lock); - return shost_found; -} - -/** - * scsi_alloc_hostnum - choose new SCSI host number based on host name. - * @name: String to store in name field - * - * Return value: - * Pointer to a new Scsi_Host_Name - **/ -static int scsi_alloc_host_num(const char *name) -{ - int hostnum; - int namelen; - const char *start, *end; - - if (name) { - hostnum = 0; - namelen = strlen(name); - start = scsihosts; - while (1) { - int hostlen; - - if (start && start[0] != '\0') { - end = strpbrk(start, ",:"); - if (end) { - hostlen = (end - start); - end++; - } else - hostlen = strlen(start); - /* - * Look for a match on the scsihosts list. - */ - if ((hostlen == namelen) && - (strncmp(name, start, hostlen) == 0) && - (!scsi_find_host_by_num(hostnum))) - return hostnum; - start = end; - } else { - /* - * Look for any unused numbers. - */ - if (!scsi_find_host_by_num(hostnum)) - return hostnum; - } - hostnum++; - } - } else - return scsi_host_next_hn++; -} - - -/** - * scsi_tp_for_each_host - call function for each scsi host off a template - * @shost_tp: a pointer to a scsi host template - * @callback: a pointer to callback function - * - * Return value: - * 0 on Success / 1 on Failure - **/ -int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int - (*callback)(struct Scsi_Host *shost)) -{ - struct list_head *lh, *lh_sf; - struct Scsi_Host *shost; - - spin_lock(&scsi_host_list_lock); - - list_for_each_safe(lh, lh_sf, &scsi_host_list) { - shost = list_entry(lh, struct Scsi_Host, sh_list); - if (shost->hostt == shost_tp) { - spin_unlock(&scsi_host_list_lock); - callback(shost); - spin_lock(&scsi_host_list_lock); - } - } - - spin_unlock(&scsi_host_list_lock); - - return 0; -} - -/** - * scsi_host_legacy_release - default release function for hosts - * @shost: - * - * Description: - * This is the default case for the release function. Its completely - * useless for anything but old ISA adapters - **/ -static int scsi_host_legacy_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); -#ifdef CONFIG_GENERIC_ISA_DMA - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); -#endif - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - - return 0; -} - -/** - * scsi_remove_host - check a scsi host for release and release - * @shost: a pointer to a scsi host to release - * - * Return value: - * 0 on Success / 1 on Failure - **/ -int scsi_remove_host(struct Scsi_Host *shost) -{ - struct scsi_device *sdev; - - /* - * FIXME Do ref counting. We force all of the devices offline to - * help prevent race conditions where other hosts/processors could - * try and get in and queue a command. - */ - list_for_each_entry(sdev, &shost->my_devices, siblings) - sdev->online = FALSE; - - scsi_proc_host_rm(shost); - scsi_forget_host(shost); - scsi_sysfs_remove_host(shost); - - if (shost->hostt->release) - (*shost->hostt->release)(shost); - - return 0; -} - -/** - * scsi_add_host - add a scsi host - * @shost: scsi host pointer to add - * @dev: a struct device of type scsi class - * - * Return value: - * 0 on success / != 0 for error - **/ -int scsi_add_host(struct Scsi_Host *shost, struct device *dev) -{ - Scsi_Host_Template *sht = shost->hostt; - int error; - - printk(KERN_INFO "scsi%d : %s\n", shost->host_no, - sht->info ? sht->info(shost) : sht->name); - - error = scsi_sysfs_add_host(shost, dev); - if (!error) { - scsi_proc_host_add(shost); - scsi_scan_host(shost); - }; - - return error; -} - -/** - * scsi_unregister - unregister a scsi host - * @shost: scsi host to be unregistered - **/ -void scsi_unregister(struct Scsi_Host *shost) -{ - scsi_host_put(shost); -} - -/** - * scsi_free_sdev - free a scsi hosts resources - * @shost: scsi host to free - **/ -void scsi_free_shost(struct Scsi_Host *shost) -{ - /* Remove shost from scsi_host_list */ - spin_lock(&scsi_host_list_lock); - list_del(&shost->sh_list); - spin_unlock(&scsi_host_list_lock); - - /* - * Next, kill the kernel error recovery thread for this host. - */ - if (shost->ehandler) { - DECLARE_COMPLETION(sem); - shost->eh_notify = &sem; - shost->eh_kill = 1; - up(shost->eh_wait); - wait_for_completion(&sem); - shost->eh_notify = NULL; - } - - shost->hostt->present--; - scsi_destroy_command_freelist(shost); - kfree(shost); -} - -/** - * scsi_register - register a scsi host adapter instance. - * @shost_tp: pointer to scsi host template - * @xtr_bytes: extra bytes to allocate for driver - * - * Note: - * We call this when we come across a new host adapter. We only do - * this once we are 100% sure that we want to use this host adapter - - * it is a pain to reverse this, so we try to avoid it - * - * Return value: - * Pointer to a new Scsi_Host - **/ -extern int blk_nohighio; -struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) -{ - struct Scsi_Host *shost, *shost_scr; - int gfp_mask, rval; - DECLARE_COMPLETION(sem); - - /* Check to see if this host has any error handling facilities */ - if(shost_tp->eh_strategy_handler == NULL && - shost_tp->eh_abort_handler == NULL && - shost_tp->eh_device_reset_handler == NULL && - shost_tp->eh_bus_reset_handler == NULL && - shost_tp->eh_host_reset_handler == NULL) { - printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", shost_tp->proc_name); - dump_stack(); - } - if(shost_tp->shost_attrs == NULL) - /* if its not set in the template, use the default */ - shost_tp->shost_attrs = scsi_sysfs_shost_attrs; - if(shost_tp->sdev_attrs == NULL) - shost_tp->sdev_attrs = scsi_sysfs_sdev_attrs; - gfp_mask = GFP_KERNEL; - if (shost_tp->unchecked_isa_dma && xtr_bytes) - gfp_mask |= __GFP_DMA; - - shost = kmalloc(sizeof(struct Scsi_Host) + xtr_bytes, gfp_mask); - if (!shost) { - printk(KERN_ERR "%s: out of memory.\n", __FUNCTION__); - return NULL; - } - - memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes); - - shost->host_no = scsi_alloc_host_num(shost_tp->proc_name); - - spin_lock_init(&shost->default_lock); - scsi_assign_lock(shost, &shost->default_lock); - INIT_LIST_HEAD(&shost->my_devices); - INIT_LIST_HEAD(&shost->eh_cmd_q); - INIT_LIST_HEAD(&shost->starved_list); - - init_waitqueue_head(&shost->host_wait); - shost->dma_channel = 0xff; - - /* These three are default values which can be overridden */ - shost->max_channel = 0; - shost->max_id = 8; - shost->max_lun = 8; - - /* - * All drivers right now should be able to handle 12 byte - * commands. Every so often there are requests for 16 byte - * commands, but individual low-level drivers need to certify that - * they actually do something sensible with such commands. - */ - shost->max_cmd_len = 12; - shost->hostt = shost_tp; - shost->host_blocked = 0; - shost->host_self_blocked = FALSE; - shost->max_host_blocked = shost_tp->max_host_blocked ? shost_tp->max_host_blocked : SCSI_DEFAULT_HOST_BLOCKED; - -#ifdef DEBUG - printk("%s: %x %x: %d\n", __FUNCTION_ (int)shost, - (int)shost->hostt, xtr_bytes); -#endif - - /* - * The next six are the default values which can be overridden if - * need be - */ - shost->this_id = shost_tp->this_id; - shost->can_queue = shost_tp->can_queue; - shost->sg_tablesize = shost_tp->sg_tablesize; - shost->cmd_per_lun = shost_tp->cmd_per_lun; - shost->unchecked_isa_dma = shost_tp->unchecked_isa_dma; - shost->use_clustering = shost_tp->use_clustering; - if (!blk_nohighio) - shost->highmem_io = shost_tp->highmem_io; - if (!shost_tp->max_sectors) { - /* - * Driver imposes no hard sector transfer limit. - * start at machine infinity initially. - */ - shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; - } else - shost->max_sectors = shost_tp->max_sectors; - shost->use_blk_tcq = shost_tp->use_blk_tcq; - - spin_lock(&scsi_host_list_lock); - /* - * FIXME When device naming is complete remove this step that - * orders the scsi_host_list by host number and just do a - * list_add_tail. - */ - list_for_each_entry(shost_scr, &scsi_host_list, sh_list) { - if (shost->host_no < shost_scr->host_no) { - __list_add(&shost->sh_list, shost_scr->sh_list.prev, - &shost_scr->sh_list); - goto found; - } - } - list_add_tail(&shost->sh_list, &scsi_host_list); -found: - spin_unlock(&scsi_host_list_lock); - - rval = scsi_setup_command_freelist(shost); - if (rval) - goto fail; - - scsi_sysfs_init_host(shost); - - shost->eh_notify = &sem; - kernel_thread((int (*)(void *)) scsi_error_handler, (void *) shost, 0); - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - wait_for_completion(&sem); - shost->eh_notify = NULL; - shost->hostt->present++; - return shost; - -fail: - spin_lock(&scsi_host_list_lock); - list_del(&shost->sh_list); - spin_unlock(&scsi_host_list_lock); - kfree(shost); - return NULL; -} - -/** - * scsi_register_host - register a low level host driver - * @shost_tp: pointer to a scsi host driver template - * - * Return value: - * 0 on Success / 1 on Failure. - **/ -int scsi_register_host(Scsi_Host_Template *shost_tp) -{ - struct Scsi_Host *shost; - - BUG_ON(!shost_tp->detect); - - if (!shost_tp->release) { - printk(KERN_WARNING - "scsi HBA driver %s didn't set a release method, " - "please fix the template\n", shost_tp->name); - shost_tp->release = &scsi_host_legacy_release; - } - - shost_tp->detect(shost_tp); - if (!shost_tp->present) - return 0; - - /* - * XXX(hch) use scsi_tp_for_each_host() once it propagates - * error returns properly. - */ - list_for_each_entry(shost, &scsi_host_list, sh_list) - if (shost->hostt == shost_tp) - if (scsi_add_host(shost, NULL)) - goto out_of_space; - - return 0; - -out_of_space: - scsi_unregister_host(shost_tp); /* easiest way to clean up?? */ - return 1; -} - -/** - * scsi_unregister_host - unregister a low level host adapter driver - * @shost_tp: scsi host template to unregister. - * - * Description: - * Similarly, this entry point should be called by a loadable module - * if it is trying to remove a low level scsi driver from the system. - * - * Return value: - * 0 on Success / 1 on Failure - * - * Notes: - * rmmod does not care what we return here the module will be - * removed. - **/ -int scsi_unregister_host(Scsi_Host_Template *shost_tp) -{ - scsi_tp_for_each_host(shost_tp, scsi_remove_host); - return 0; - -} - -/** - * scsi_host_lookup - get a reference to a Scsi_Host by host no - * - * @hostnum: host number to locate - * - * Return value: - * A pointer to located Scsi_Host or NULL. - **/ -struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) -{ - struct class *class = class_get(&shost_class); - struct class_device *cdev; - struct Scsi_Host *shost = NULL, *p; - - if (class) { - down_read(&class->subsys.rwsem); - list_for_each_entry(cdev, &class->children, node) { - p = class_to_shost(cdev); - if (p->host_no == hostnum) { - scsi_host_get(p); - shost = p; - break; - } - } - up_read(&class->subsys.rwsem); - } - - return shost; -} - -/** - * *scsi_host_get - inc a Scsi_Host ref count - * @shost: Pointer to Scsi_Host to inc. - **/ -void scsi_host_get(struct Scsi_Host *shost) -{ - get_device(&shost->host_gendev); - class_device_get(&shost->class_dev); -} - -/** - * *scsi_host_put - dec a Scsi_Host ref count - * @shost: Pointer to Scsi_Host to dec. - **/ -void scsi_host_put(struct Scsi_Host *shost) -{ - - class_device_put(&shost->class_dev); - put_device(&shost->host_gendev); -} - -/** - * scsi_host_init - set up the scsi host number list based on any entries - * scsihosts. - **/ -void __init scsi_host_init(void) -{ - char *shost_hn; - - shost_hn = scsihosts; - while (shost_hn) { - scsi_host_next_hn++; - shost_hn = strpbrk(shost_hn, ":,"); - if (shost_hn) - shost_hn++; - } -} - -void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - shost->host_busy++; - sdev->device_busy++; - spin_unlock_irqrestore(shost->host_lock, flags); -} - -void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - shost->host_busy--; - if (shost->in_recovery && shost->host_failed && - (shost->host_busy == shost->host_failed)) - { - up(shost->eh_wait); - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - " thread\n")); - } - spin_unlock_irqrestore(shost->host_lock, flags); -} +/* + * hosts.c Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995 Eric Youngdale + * + * mid to lowlevel SCSI driver interface + * Initial versions: Drew Eckhardt + * Subsequent revisions: Eric Youngdale + * + * + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * Added QLOGIC QLA1280 SCSI controller kernel host support. + * August 4, 1999 Fred Lewis, Intel DuPont + * + * Updated to reflect the new initialization scheme for the higher + * level of scsi drivers (sd/sr/st) + * September 17, 2000 Torben Mathiasen + * + * Restructured scsi_host lists and associated functions. + * September 04, 2002 Mike Anderson (andmike@us.ibm.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" + +#include "scsi_priv.h" +#include "scsi_logging.h" + + +static int scsi_host_next_hn; /* host_no for next new host */ + +/** + * scsi_remove_host - check a scsi host for release and release + * @shost: a pointer to a scsi host to release + * + * Return value: + * 0 on Success / 1 on Failure + **/ +int scsi_remove_host(struct Scsi_Host *shost) +{ + struct scsi_device *sdev; + + /* + * FIXME Do ref counting. We force all of the devices offline to + * help prevent race conditions where other hosts/processors could + * try and get in and queue a command. + */ + list_for_each_entry(sdev, &shost->my_devices, siblings) + sdev->online = FALSE; + + scsi_proc_host_rm(shost); + scsi_forget_host(shost); + scsi_sysfs_remove_host(shost); + + return 0; +} + +/** + * scsi_add_host - add a scsi host + * @shost: scsi host pointer to add + * @dev: a struct device of type scsi class + * + * Return value: + * 0 on success / != 0 for error + **/ +int scsi_add_host(struct Scsi_Host *shost, struct device *dev) +{ + struct scsi_host_template *sht = shost->hostt; + int error; + + printk(KERN_INFO "scsi%d : %s\n", shost->host_no, + sht->info ? sht->info(shost) : sht->name); + + error = scsi_sysfs_add_host(shost, dev); + if (!error) { + scsi_proc_host_add(shost); + scsi_scan_host(shost); + } + + return error; +} + +/** + * scsi_free_sdev - free a scsi hosts resources + * @shost: scsi host to free + **/ +void scsi_free_shost(struct Scsi_Host *shost) +{ + if (shost->ehandler) { + DECLARE_COMPLETION(sem); + shost->eh_notify = &sem; + shost->eh_kill = 1; + up(shost->eh_wait); + wait_for_completion(&sem); + shost->eh_notify = NULL; + } + + shost->hostt->present--; + scsi_destroy_command_freelist(shost); + kfree(shost); +} + +/** + * scsi_host_alloc - register a scsi host adapter instance. + * @sht: pointer to scsi host template + * @privsize: extra bytes to allocate for driver + * + * Note: + * Allocate a new Scsi_Host and perform basic initialization. + * The host is not published to the scsi midlayer until scsi_add_host + * is called. + * + * Return value: + * Pointer to a new Scsi_Host + **/ +struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) +{ + struct Scsi_Host *shost; + int gfp_mask = GFP_KERNEL, rval; + DECLARE_COMPLETION(complete); + + if (sht->unchecked_isa_dma && privsize) + gfp_mask |= __GFP_DMA; + + /* Check to see if this host has any error handling facilities */ + if (!sht->eh_strategy_handler && !sht->eh_abort_handler && + !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler && + !sht->eh_host_reset_handler) { + printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n" + "ERROR: This is not a safe way to run your " + "SCSI host\n" + "ERROR: The error handling must be added to " + "this driver\n", sht->proc_name); + dump_stack(); + } + + /* if its not set in the template, use the default */ + if (!sht->shost_attrs) + sht->shost_attrs = scsi_sysfs_shost_attrs; + if (!sht->sdev_attrs) + sht->sdev_attrs = scsi_sysfs_sdev_attrs; + + shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); + if (!shost) + return NULL; + memset(shost, 0, sizeof(struct Scsi_Host) + privsize); + + spin_lock_init(&shost->default_lock); + scsi_assign_lock(shost, &shost->default_lock); + INIT_LIST_HEAD(&shost->my_devices); + INIT_LIST_HEAD(&shost->eh_cmd_q); + INIT_LIST_HEAD(&shost->starved_list); + init_waitqueue_head(&shost->host_wait); + + shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */ + shost->dma_channel = 0xff; + + /* These three are default values which can be overridden */ + shost->max_channel = 0; + shost->max_id = 8; + shost->max_lun = 8; + + /* + * All drivers right now should be able to handle 12 byte + * commands. Every so often there are requests for 16 byte + * commands, but individual low-level drivers need to certify that + * they actually do something sensible with such commands. + */ + shost->max_cmd_len = 12; + shost->hostt = sht; + shost->this_id = sht->this_id; + shost->can_queue = sht->can_queue; + shost->sg_tablesize = sht->sg_tablesize; + shost->cmd_per_lun = sht->cmd_per_lun; + shost->unchecked_isa_dma = sht->unchecked_isa_dma; + shost->use_clustering = sht->use_clustering; + shost->use_blk_tcq = sht->use_blk_tcq; + shost->highmem_io = sht->highmem_io; + + if (!sht->max_host_blocked) + shost->max_host_blocked = sht->max_host_blocked; + else + shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED; + + /* + * If the driver imposes no hard sector transfer limit, start at + * machine infinity initially. + */ + if (sht->max_sectors) + shost->max_sectors = sht->max_sectors; + else + shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; + + rval = scsi_setup_command_freelist(shost); + if (rval) + goto fail; + + scsi_sysfs_init_host(shost); + + shost->eh_notify = &complete; + /* XXX(hch): handle error return */ + kernel_thread((int (*)(void *))scsi_error_handler, shost, 0); + wait_for_completion(&complete); + shost->eh_notify = NULL; + shost->hostt->present++; + return shost; + fail: + kfree(shost); + return NULL; +} + +struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize) +{ + struct Scsi_Host *shost = scsi_host_alloc(sht, privsize); + + if (!sht->detect) { + printk(KERN_WARNING "scsi_register() called on new-style " + "template for driver %s\n", sht->name); + dump_stack(); + } + + if (shost) + list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts); + return shost; +} + +void scsi_unregister(struct Scsi_Host *shost) +{ + list_del(&shost->sht_legacy_list); + scsi_host_put(shost); +} + +/** + * scsi_host_lookup - get a reference to a Scsi_Host by host no + * + * @hostnum: host number to locate + * + * Return value: + * A pointer to located Scsi_Host or NULL. + **/ +struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) +{ + struct class *class = class_get(&shost_class); + struct class_device *cdev; + struct Scsi_Host *shost = NULL, *p; + + if (class) { + down_read(&class->subsys.rwsem); + list_for_each_entry(cdev, &class->children, node) { + p = class_to_shost(cdev); + if (p->host_no == hostnum) { + scsi_host_get(p); + shost = p; + break; + } + } + up_read(&class->subsys.rwsem); + } + + return shost; +} + +/** + * *scsi_host_get - inc a Scsi_Host ref count + * @shost: Pointer to Scsi_Host to inc. + **/ +void scsi_host_get(struct Scsi_Host *shost) +{ + get_device(&shost->host_gendev); + class_device_get(&shost->class_dev); +} + +/** + * *scsi_host_put - dec a Scsi_Host ref count + * @shost: Pointer to Scsi_Host to dec. + **/ +void scsi_host_put(struct Scsi_Host *shost) +{ + class_device_put(&shost->class_dev); + put_device(&shost->host_gendev); +} diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h dissimilarity index 91% index 7ba0f6e202d..859aeaf2b8b 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -1,601 +1,70 @@ -/* - * hosts.h Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale - * - * mid to low-level SCSI driver interface header - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - * - * Further modified by Eric Youngdale to support multiple host adapters - * of the same type. - * - * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli - * - * Restructured scsi_host lists and associated functions. - * September 04, 2002 Mike Anderson (andmike@us.ibm.com) - */ - -#ifndef _HOSTS_H -#define _HOSTS_H - -#include -#include -#include - -struct scsi_host_cmd_pool; - - -/* It is senseless to set SG_ALL any higher than this - the performance - * does not get any better, and it wastes memory - */ -#define SG_NONE 0 -#define SG_ALL 0xff - -#define DISABLE_CLUSTERING 0 -#define ENABLE_CLUSTERING 1 - -/* The various choices mean: - * NONE: Self evident. Host adapter is not capable of scatter-gather. - * ALL: Means that the host adapter module can do scatter-gather, - * and that there is no limit to the size of the table to which - * we scatter/gather data. - * Anything else: Indicates the maximum number of chains that can be - * used in one scatter-gather request. - */ - -/* - * The Scsi_Host_Template type has all that is needed to interface with a SCSI - * host in a device independent matter. There is one entry for each different - * type of host adapter that is supported on the system. - */ - -typedef struct SHT -{ - /* Used with loadable modules so that we know when it is safe to unload */ - struct module * module; - - /* The pointer to the /proc/scsi directory entry */ - struct proc_dir_entry *proc_dir; - - /* proc-fs info function. - * Can be used to export driver statistics and other infos to the world - * outside the kernel ie. userspace and it also provides an interface - * to feed the driver with information. Check eata_dma_proc.c for reference - */ - int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); - - /* - * The name pointer is a pointer to the name of the SCSI - * device detected. - */ - const char *name; - - /* - * The detect function shall return non zero on detection, - * indicating the number of host adapters of this particular - * type were found. It should also - * initialize all data necessary for this particular - * SCSI driver. It is passed the host number, so this host - * knows where the first entry is in the scsi_hosts[] array. - * - * Note that the detect routine MUST not call any of the mid level - * functions to queue commands because things are not guaranteed - * to be set up yet. The detect routine can send commands to - * the host adapter as long as the program control will not be - * passed to scsi.c in the processing of the command. Note - * especially that scsi_malloc/scsi_free must not be called. - */ - int (* detect)(struct SHT *); - - /* Used with loadable modules to unload the host structures. Note: - * there is a default action built into the modules code which may - * be sufficient for most host adapters. Thus you may not have to supply - * this at all. - */ - int (*release)(struct Scsi_Host *); - - /* - * The info function will return whatever useful - * information the developer sees fit. If not provided, then - * the name field will be used instead. - */ - const char *(* info)(struct Scsi_Host *); - - /* - * ioctl interface - */ - int (*ioctl)(Scsi_Device *dev, int cmd, void *arg); - - /* - * The command function takes a target, a command (this is a SCSI - * command formatted as per the SCSI spec, nothing strange), a - * data buffer pointer, and data buffer length pointer. The return - * is a status int, bit fielded as follows : - * Byte What - * 0 SCSI status code - * 1 SCSI 1 byte message - * 2 host error return. - * 3 mid level error return - */ - int (* command)(Scsi_Cmnd *); - - /* - * The QueueCommand function works in a similar manner - * to the command function. It takes an additional parameter, - * void (* done)(int host, int code) which is passed the host - * # and exit result when the command is complete. - * Host number is the POSITION IN THE hosts array of THIS - * host adapter. - * - * if queuecommand returns 0, then the HBA has accepted the - * command. The done() function must be called on the command - * when the driver has finished with it. (you may call done on the - * command before queuecommand returns, but in this case you - * *must* return 0 from queuecommand). - * - * queuecommand may also reject the command, in which case it may - * not touch the command and must not call done() for it. - * - * There are two possible rejection returns: - * - * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but - * allow commands to other devices serviced by this host. - * - * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this - * host temporarily. - * - * for compatibility, any other non-zero return is treated the - * same as SCSI_MLQUEUE_HOST_BUSY. - * - * NOTE: "temporarily" means either until the next command for - * this device/host completes, or a period of time determined by - * I/O pressure in the system if there are no other outstanding - * commands. - * */ - int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - - /* - * This is an error handling strategy routine. You don't need to - * define one of these if you don't want to - there is a default - * routine that is present that should work in most cases. For those - * driver authors that have the inclination and ability to write their - * own strategy routine, this is where it is specified. Note - the - * strategy routine is *ALWAYS* run in the context of the kernel eh - * thread. Thus you are guaranteed to *NOT* be in an interrupt handler - * when you execute this, and you are also guaranteed to *NOT* have any - * other commands being queued while you are in the strategy routine. - * When you return from this function, operations return to normal. - * - * See scsi_error.c scsi_unjam_host for additional comments about what - * this function should and should not be attempting to do. - */ - int (*eh_strategy_handler)(struct Scsi_Host *); - int (*eh_abort_handler)(Scsi_Cmnd *); - int (*eh_device_reset_handler)(Scsi_Cmnd *); - int (*eh_bus_reset_handler)(Scsi_Cmnd *); - int (*eh_host_reset_handler)(Scsi_Cmnd *); - - /* - * Old EH handlers, no longer used. Make them warn the user of old - * drivers by using a wrong type - */ - int (*abort)(int); - int (*reset)(int,int); - - /* - * slave_alloc() - Optional - * - * Before the mid layer attempts to scan for a new device where none - * currently exists, it will call this entry in your driver. Should - * your driver need to allocate any structs or perform any other init - * items in order to send commands to a currently unused target/lun - * combo, then this is where you can perform those allocations. This - * is specifically so that drivers won't have to perform any kind of - * "is this a new device" checks in their queuecommand routine, - * thereby making the hot path a bit quicker. - * - * Return values: 0 on success, non-0 on failure - * - * Deallocation: If we didn't find any devices at this ID, you will - * get an immediate call to slave_destroy(). If we find something here - * then you will get a call to slave_configure(), then the device will be - * used for however long it is kept around, then when the device is - * removed from the system (or * possibly at reboot time), you will - * then get a call to slave_detach(). This is assuming you implement - * slave_configure and slave_destroy. However, if you allocate memory - * and hang it off the device struct, then you must implement the - * slave_destroy() routine at a minimum in order to avoid leaking memory - * each time a device is tore down. - */ - int (* slave_alloc)(Scsi_Device *); - - /* - * slave_configure() - Optional - * - * Once the device has responded to an INQUIRY and we know the device - * is online, we call into the low level driver with the Scsi_Device * - * If the low level device driver implements this function, it *must* - * perform the task of setting the queue depth on the device. All other - * tasks are optional and depend on what the driver supports and various - * implementation details. - * - * Things currently recommended to be handled at this time include: - * - * 1. Setting the device queue depth. Proper setting of this is - * described in the comments for scsi_adjust_queue_depth. - * 2. Determining if the device supports the various synchronous - * negotiation protocols. The device struct will already have - * responded to INQUIRY and the results of the standard items - * will have been shoved into the various device flag bits, eg. - * device->sdtr will be true if the device supports SDTR messages. - * 3. Allocating command structs that the device will need. - * 4. Setting the default timeout on this device (if needed). - * 5. Anything else the low level driver might want to do on a device - * specific setup basis... - * 6. Return 0 on success, non-0 on error. The device will be marked - * as offline on error so that no access will occur. If you return - * non-0, your slave_detach routine will never get called for this - * device, so don't leave any loose memory hanging around, clean - * up after yourself before returning non-0 - */ - int (* slave_configure)(Scsi_Device *); - - /* - * slave_destroy() - Optional - * - * Immediately prior to deallocating the device and after all activity - * has ceased the mid layer calls this point so that the low level driver - * may completely detach itself from the scsi device and vice versa. - * The low level driver is responsible for freeing any memory it allocated - * in the slave_alloc or slave_configure calls. - */ - void (* slave_destroy)(Scsi_Device *); - - /* - * This function determines the bios parameters for a given - * harddisk. These tend to be numbers that are made up by - * the host adapter. Parameters: - * size, device, list (heads, sectors, cylinders) - */ - int (* bios_param)(struct scsi_device *, struct block_device *, - sector_t, int []); - - /* - * This determines if we will use a non-interrupt driven - * or an interrupt driven scheme, It is set to the maximum number - * of simultaneous commands a given host adapter will accept. - */ - int can_queue; - - /* - * In many instances, especially where disconnect / reconnect are - * supported, our host also has an ID on the SCSI bus. If this is - * the case, then it must be reserved. Please set this_id to -1 if - * your setup is in single initiator mode, and the host lacks an - * ID. - */ - int this_id; - - /* - * This determines the degree to which the host adapter is capable - * of scatter-gather. - */ - short unsigned int sg_tablesize; - - /* - * if the host adapter has limitations beside segment count - */ - short unsigned int max_sectors; - - /* - * True if this host adapter can make good use of linked commands. - * This will allow more than one command to be queued to a given - * unit on a given host. Set this to the maximum number of command - * blocks to be provided for each device. Set this to 1 for one - * command block per lun, 2 for two, etc. Do not set this to 0. - * You should make sure that the host adapter will do the right thing - * before you try setting this above 1. - */ - short cmd_per_lun; - - /* - * present contains counter indicating how many boards of this - * type were found when we did the scan. - */ - unsigned char present; - - /* - * true if this host adapter uses unchecked DMA onto an ISA bus. - */ - unsigned unchecked_isa_dma:1; - - /* - * true if this host adapter can make good use of clustering. - * I originally thought that if the tablesize was large that it - * was a waste of CPU cycles to prepare a cluster list, but - * it works out that the Buslogic is faster if you use a smaller - * number of segments (i.e. use clustering). I guess it is - * inefficient. - */ - unsigned use_clustering:1; - - /* - * True for emulated SCSI host adapters (e.g. ATAPI) - */ - unsigned emulated:1; - - unsigned highmem_io:1; - - /* - * True if the driver wishes to use the generic block layer - * tag queueing functions - */ - unsigned use_blk_tcq:1; - - /* - * Name of proc directory - */ - char *proc_name; - - /* - * countdown for host blocking with no commands outstanding - */ - unsigned int max_host_blocked; - - /* - * Default value for the blocking. If the queue is empty, host_blocked - * counts down in the request_fn until it restarts host operations as - * zero is reached. - * - * FIXME: This should probably be a value in the template */ - #define SCSI_DEFAULT_HOST_BLOCKED 7 - - /* - * pointer to the sysfs class properties for this host - */ - struct class_device_attribute **shost_attrs; - - /* - * Pointer to the SCSI device properties for this host - */ - struct device_attribute **sdev_attrs; - -} Scsi_Host_Template; - -/* - * The scsi_hosts array is the array containing the data for all - * possible scsi hosts. This is similar to the - * Scsi_Host_Template, except that we have one entry for each - * actual physical host adapter on the system, stored as a linked - * list. Note that if there are 2 aha1542 boards, then there will - * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry. - */ - -struct Scsi_Host -{ -/* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct list_head sh_list; - struct list_head my_devices; - - struct scsi_host_cmd_pool *cmd_pool; - spinlock_t free_list_lock; - struct list_head free_list; /* backup store of cmd structs */ - struct list_head starved_list; - - spinlock_t default_lock; - spinlock_t *host_lock; - - struct list_head eh_cmd_q; - struct task_struct * ehandler; /* Error recovery thread. */ - struct semaphore * eh_wait; /* The error recovery thread waits on - this. */ - struct completion * eh_notify; /* wait for eh to begin or end */ - struct semaphore * eh_action; /* Wait for specific actions on the - host. */ - unsigned int eh_active:1; /* Indicates the eh thread is awake and active if - this is true. */ - unsigned int eh_kill:1; /* set when killing the eh thread */ - wait_queue_head_t host_wait; - Scsi_Host_Template * hostt; - volatile unsigned short host_busy; /* commands actually active on low-level */ - volatile unsigned short host_failed; /* commands that failed. */ - -/* public: */ - unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ - int resetting; /* if set, it means that last_reset is a valid value */ - unsigned long last_reset; - - /* - * These three parameters can be used to allow for wide scsi, - * and for host adapters that support multiple busses - * The first two should be set to 1 more than the actual max id - * or lun (i.e. 8 for normal systems). - */ - unsigned int max_id; - unsigned int max_lun; - unsigned int max_channel; - - /* These parameters should be set by the detect routine */ - unsigned long base; - unsigned long io_port; - unsigned char n_io_port; - unsigned char dma_channel; - unsigned int irq; - - /* - * This is a unique identifier that must be assigned so that we - * have some way of identifying each detected host adapter properly - * and uniquely. For hosts that do not support more than one card - * in the system at one time, this does not need to be set. It is - * initialized to 0 in scsi_register. - */ - unsigned int unique_id; - - /* - * The rest can be copied from the template, or specifically - * initialized, as required. - */ - - /* - * The maximum length of SCSI commands that this host can accept. - * Probably 12 for most host adapters, but could be 16 for others. - * For drivers that don't set this field, a value of 12 is - * assumed. I am leaving this as a number rather than a bit - * because you never know what subsequent SCSI standards might do - * (i.e. could there be a 20 byte or a 24-byte command a few years - * down the road?). - */ - unsigned char max_cmd_len; - - int this_id; - int can_queue; - short cmd_per_lun; - short unsigned int sg_tablesize; - short unsigned int max_sectors; - - unsigned in_recovery:1; - unsigned unchecked_isa_dma:1; - unsigned use_clustering:1; - unsigned highmem_io:1; - unsigned use_blk_tcq:1; - - /* - * Host has requested that no further requests come through for the - * time being. - */ - unsigned host_self_blocked:1; - - /* - * Host uses correct SCSI ordering not PC ordering. The bit is - * set for the minority of drivers whose authors actually read the spec ;) - */ - unsigned reverse_ordering:1; - - /* - * Host has rejected a command because it was busy. - */ - unsigned int host_blocked; - - /* - * Value host_blocked counts down from - */ - unsigned int max_host_blocked; - - /* - * Support for sysfs - */ - struct device host_gendev; - struct class_device class_dev; - - /* - * We should ensure that this is aligned, both for better performance - * and also because some compilers (m68k) don't automatically force - * alignment to a long boundary. - */ - unsigned long hostdata[0] /* Used for storage of host specific stuff */ - __attribute__ ((aligned (sizeof(unsigned long)))); -}; - -#define dev_to_shost(d) \ - container_of(d, struct Scsi_Host, host_gendev) -#define class_to_shost(d) \ - container_of(d, struct Scsi_Host, class_dev) - -/* - * These two functions are used to allocate and free a pseudo device - * which will connect to the host adapter itself rather than any - * physical device. You must deallocate when you are done with the - * thing. This physical pseudo-device isn't real and won't be available - * from any high-level drivers. - */ -extern void scsi_free_host_dev(Scsi_Device *); -extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *); - -extern void scsi_unblock_requests(struct Scsi_Host *); -extern void scsi_block_requests(struct Scsi_Host *); -extern void scsi_report_bus_reset(struct Scsi_Host *, int); -extern void scsi_report_device_reset(struct Scsi_Host *, int, int); - -static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) -{ - shost->host_lock = lock; -} - -static inline void scsi_set_device(struct Scsi_Host *shost, - struct device *dev) -{ - shost->host_gendev.parent = dev; -} - -static inline struct device *scsi_get_device(struct Scsi_Host *shost) -{ - return shost->host_gendev.parent; -} - -struct scsi_driver { - struct module *owner; - struct device_driver gendrv; - - int (*init_command)(struct scsi_cmnd *); - void (*rescan)(struct device *); -}; -#define to_scsi_driver(drv) \ - container_of((drv), struct scsi_driver, gendrv) - -extern int scsi_register_driver(struct device_driver *); -#define scsi_unregister_driver(drv) \ - driver_unregister(drv); - -extern int scsi_register_interface(struct class_interface *); -#define scsi_unregister_interface(intf) \ - class_interface_unregister(intf) - -/* - * HBA allocation/freeing. - */ -extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int); -extern void scsi_unregister(struct Scsi_Host *); - -/* - * HBA registration/unregistration. - */ -extern int scsi_add_host(struct Scsi_Host *, struct device *); -extern int scsi_remove_host(struct Scsi_Host *); - -/* - * Legacy HBA template registration/unregistration. - */ -extern int scsi_register_host(Scsi_Host_Template *); -extern int scsi_unregister_host(Scsi_Host_Template *); - -/** - * scsi_find_device - find a device given the host - * @shost: SCSI host pointer - * @channel: SCSI channel (zero if only one channel) - * @pun: SCSI target number (physical unit number) - * @lun: SCSI Logical Unit Number - **/ -static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost, - int channel, int pun, int lun) { - Scsi_Device *sdev; - - list_for_each_entry (sdev, &shost->my_devices, siblings) - if (sdev->channel == channel && sdev->id == pun - && sdev->lun ==lun) - return sdev; - return NULL; -} - -extern void scsi_sysfs_release_attributes(struct SHT *hostt); - -#endif +/* + * hosts.h Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale + * + * mid to low-level SCSI driver interface header + * Initial versions: Drew Eckhardt + * Subsequent revisions: Eric Youngdale + * + * + * + * Modified by Eric Youngdale eric@andante.org to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + * + * Further modified by Eric Youngdale to support multiple host adapters + * of the same type. + * + * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * + * Restructured scsi_host lists and associated functions. + * September 04, 2002 Mike Anderson (andmike@us.ibm.com) + */ + +#ifndef _HOSTS_H +#define _HOSTS_H + +#include +#include +#include + +#include + +struct scsi_driver { + struct module *owner; + struct device_driver gendrv; + + int (*init_command)(struct scsi_cmnd *); + void (*rescan)(struct device *); +}; +#define to_scsi_driver(drv) \ + container_of((drv), struct scsi_driver, gendrv) + +extern int scsi_register_driver(struct device_driver *); +#define scsi_unregister_driver(drv) \ + driver_unregister(drv); + +extern int scsi_register_interface(struct class_interface *); +#define scsi_unregister_interface(intf) \ + class_interface_unregister(intf) + + +/** + * scsi_find_device - find a device given the host + * @shost: SCSI host pointer + * @channel: SCSI channel (zero if only one channel) + * @pun: SCSI target number (physical unit number) + * @lun: SCSI Logical Unit Number + **/ +static inline struct scsi_device *scsi_find_device(struct Scsi_Host *shost, + int channel, int pun, int lun) { + struct scsi_device *sdev; + + list_for_each_entry (sdev, &shost->my_devices, siblings) + if (sdev->channel == channel && sdev->id == pun + && sdev->lun ==lun) + return sdev; + return NULL; +} + +#endif diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 8932787e351..ec66abd3d54 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -1793,15 +1793,6 @@ static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * scsi_template, int return shpnt; } -static int ibmmca_command(Scsi_Cmnd * cmd) -{ - ibmmca_queuecommand(cmd, internal_done); - cmd->SCp.Status = 0; - while (!cmd->SCp.Status) - barrier(); - return cmd->result; -} - static int ibmmca_release(struct Scsi_Host *shpnt) { release_region(shpnt->io_port, shpnt->n_io_port); @@ -2490,7 +2481,6 @@ static Scsi_Host_Template driver_template = { .name = "IBM SCSI-Subsystem", .detect = ibmmca_detect, .release = ibmmca_release, - .command = ibmmca_command, .queuecommand = ibmmca_queuecommand, .eh_abort_handler = ibmmca_abort, .eh_host_reset_handler = ibmmca_host_reset, diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index c87a24ae250..cfd1e581072 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -612,7 +612,7 @@ static int idescsi_cleanup (ide_drive_t *drive) drive->disk->fops = ide_fops; scsi_remove_host(scsihost); - scsi_unregister(scsihost); + scsi_host_put(scsihost); return 0; } @@ -964,7 +964,7 @@ static int idescsi_attach(ide_drive_t *drive) if (!strstr("ide-scsi", drive->driver_req) || !drive->present || drive->media == ide_disk || - !(host = scsi_register(&idescsi_template,sizeof(idescsi_scsi_t)))) + !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) return 1; host->max_id = 1; @@ -984,7 +984,7 @@ static int idescsi_attach(ide_drive_t *drive) ide_unregister_subdriver(drive); } - scsi_unregister(host); + scsi_host_put(host); return err; } diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index d535b63bfe1..7c3ac1d2312 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -113,7 +113,6 @@ static Scsi_Host_Template driver_template = { .name = "Iomega VPI2 (imm) interface", .detect = imm_detect, .release = imm_release, - .command = imm_command, .queuecommand = imm_queuecommand, .eh_abort_handler = imm_abort, .eh_bus_reset_handler = imm_reset, @@ -858,39 +857,6 @@ static int imm_completion(Scsi_Cmnd * cmd) return 1; /* FINISH_RETURN */ } -/* deprecated synchronous interface */ -int imm_command(Scsi_Cmnd * cmd) -{ - static int first_pass = 1; - int host_no = cmd->device->host->unique_id; - - if (first_pass) { - printk("imm: using non-queuing interface\n"); - first_pass = 0; - } - if (imm_hosts[host_no].cur_cmd) { - printk("IMM: bug in imm_command\n"); - return 0; - } - imm_hosts[host_no].failed = 0; - imm_hosts[host_no].jstart = jiffies; - imm_hosts[host_no].cur_cmd = cmd; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; - - imm_pb_claim(host_no); - - while (imm_engine(&imm_hosts[host_no], cmd)) - schedule(); - - if (cmd->SCp.phase) /* Only disconnect if we have connected */ - imm_disconnect(cmd->device->host->unique_id); - - imm_pb_release(host_no); - imm_hosts[host_no].cur_cmd = 0; - return cmd->result; -} - /* * Since the IMM itself doesn't generate interrupts, we use * the scheduler's task queue to generate a stream of call-backs and diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c index 81d72a06c8a..665a9aa86f1 100644 --- a/drivers/scsi/ini9100u.c +++ b/drivers/scsi/ini9100u.c @@ -147,7 +147,6 @@ static Scsi_Host_Template driver_template = { .name = i91u_REVID, .detect = i91u_detect, .release = i91u_release, - .command = i91u_command, .queuecommand = i91u_queue, .abort = i91u_abort, .reset = i91u_reset, @@ -558,15 +557,6 @@ int i91u_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) } /* - * We only support command in interrupt-driven fashion - */ -int i91u_command(Scsi_Cmnd * SCpnt) -{ - printk("i91u: interrupt driven driver; use i91u_queue()\n"); - return -1; -} - -/* * Abort a queued command * (commands that are on the bus can't be aborted easily) */ diff --git a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c index 5d49cce85b1..c8a2502f2cd 100644 --- a/drivers/scsi/inia100.c +++ b/drivers/scsi/inia100.c @@ -156,11 +156,11 @@ static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB) spin_lock_irqsave(&(pHCB->pSRB_lock), flags); - pSRB->next = NULL; /* Pointer to next */ + pSRB->SCp.ptr = NULL; /* Pointer to next */ if (pHCB->pSRB_head == NULL) pHCB->pSRB_head = pSRB; else - pHCB->pSRB_tail->next = pSRB; /* Pointer to next */ + pHCB->pSRB_tail->SCp.ptr = (char *)pSRB; /* Pointer to next */ pHCB->pSRB_tail = pSRB; spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); return; @@ -179,8 +179,8 @@ static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB) ULONG flags; spin_lock_irqsave(&(pHCB->pSRB_lock), flags); if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) { - pHCB->pSRB_head = pHCB->pSRB_head->next; - pSRB->next = NULL; + pHCB->pSRB_head = (Scsi_Cmnd *) pHCB->pSRB_head->SCp.ptr; + pSRB->SCp.ptr = NULL; } spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); return (pSRB); diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 436b3dbdfd2..b8754073e32 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -725,7 +725,7 @@ ips_release(struct Scsi_Host *sh) { free_irq(ha->irq, ha); IPS_REMOVE_HOST(sh); - scsi_unregister(sh); + scsi_host_put(sh); ips_released_controllers++; @@ -6732,7 +6732,7 @@ static int ips_register_scsi( int index){ struct Scsi_Host *sh; ips_ha_t *ha, *oldha = ips_ha[index]; - sh = scsi_register(&ips_driver_template, sizeof(ips_ha_t)); + sh = scsi_host_alloc(&ips_driver_template, sizeof(ips_ha_t)); if(!sh) { IPS_PRINTK(KERN_WARNING, oldha->pcidev, "Unable to register controller with SCSI subsystem\n"); return -1; @@ -6743,7 +6743,7 @@ ips_register_scsi( int index){ /* Install the interrupt handler with the new ha */ if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n" ); - scsi_unregister(sh); + scsi_host_put(sh); return -1; } diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 29e0115ad68..a42cd20d709 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -139,6 +139,18 @@ int jazz_esp_detect(Scsi_Host_Template *tpnt) return 0; } +static int jazz_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /************************************************************* DMA Functions */ static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) { @@ -278,8 +290,8 @@ static Scsi_Host_Template driver_template = { .proc_info = &esp_proc_info, .name = "ESP 100/100a/200", .detect = jazz_esp_detect, + .release = jazz_esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index f2a16f84607..75e6cf4ead6 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -31,19 +31,14 @@ * machines for me to debug the driver on. */ -#ifndef __hppa__ -#error "lasi700 only compiles on hppa architecture" -#endif - #include +#include #include #include #include #include -#include +#include #include -#include -#include #include #include @@ -54,65 +49,27 @@ #include #include -#include - #include "scsi.h" #include "hosts.h" #include "lasi700.h" #include "53c700.h" -#ifdef MODULE - -char *lasi700; /* command line from insmod */ - MODULE_AUTHOR("James Bottomley"); MODULE_DESCRIPTION("lasi700 SCSI Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(lasi700, "s"); - -#endif - -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -static unsigned long __initdata opt_base; -static int __initdata opt_irq; - -static int __init -param_setup(char *string) -{ - char *pos = string, *next; - - while(pos != NULL && (next = strchr(pos, ':')) != NULL) { - int val = (int)simple_strtoul(++next, NULL, 0); - - if(!strncmp(pos, "addr:", 5)) - opt_base = val; - else if(!strncmp(pos, "irq:", 4)) - opt_irq = val; - - if((pos = strchr(pos, ARG_SEP)) != NULL) - pos++; - } - return 1; -} - -#ifndef MODULE -__setup("lasi700=", param_setup); -#endif -static Scsi_Host_Template __initdata *host_tpnt = NULL; -static int __initdata host_count = 0; static struct parisc_device_id lasi700_scsi_tbl[] = { LASI700_ID_TABLE, LASI710_ID_TABLE, { 0 } }; +static Scsi_Host_Template lasi700_template = { + .name = "LASI SCSI 53c700", + .proc_name = "lasi700", + .this_id = 7, +}; MODULE_DEVICE_TABLE(parisc, lasi700_scsi_tbl); static struct parisc_driver lasi700_driver = { @@ -122,50 +79,36 @@ static struct parisc_driver lasi700_driver = { }; static int __init -lasi700_detect(Scsi_Host_Template *tpnt) -{ - host_tpnt = tpnt; - -#ifdef MODULE - if(lasi700) - param_setup(lasi700); -#endif - - register_parisc_driver(&lasi700_driver); - - return (host_count != 0); -} - -static int __init lasi700_driver_callback(struct parisc_device *dev) { unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; - char *driver_name; + struct NCR_700_Host_Parameters *hostdata; struct Scsi_Host *host; - struct NCR_700_Host_Parameters *hostdata = - kmalloc(sizeof(struct NCR_700_Host_Parameters), - GFP_KERNEL); - if(dev->id.sversion == LASI_700_SVERSION) { - driver_name = "lasi700"; - } else { - driver_name = "lasi710"; - } - snprintf(dev->dev.name, sizeof(dev->dev.name), "%s", driver_name); - if(hostdata == NULL) { + + snprintf(dev->dev.name, sizeof(dev->dev.name), "%s", + (dev->id.sversion == LASI_700_SVERSION) ? + "lasi700" : "lasi710"); + + hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL); + if (!hostdata) { printk(KERN_ERR "%s: Failed to allocate host data\n", - driver_name); + dev->dev.name); return 1; } memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); - if(request_mem_region(base, 64, driver_name) == NULL) { + + if (!request_mem_region(base, 64, dev->dev.name)) { printk(KERN_ERR "%s: Failed to claim memory region\n", - driver_name); - kfree(hostdata); - return 1; + dev->dev.name); + goto out_kfree; } + + hostdata->dev = &dev->dev; + dma_set_mask(&dev->dev, 0xffffffffUL); hostdata->base = base; hostdata->differential = 0; - if(dev->id.sversion == LASI_700_SVERSION) { + + if (dev->id.sversion == LASI_700_SVERSION) { hostdata->clock = LASI700_CLOCK; hostdata->force_le_on_be = 1; } else { @@ -174,26 +117,34 @@ lasi700_driver_callback(struct parisc_device *dev) hostdata->chip710 = 1; hostdata->dmode_extra = DMODE_FC2; } - hostdata->dev = &dev->dev; - dma_set_mask(&dev->dev, 0xffffffffUL); - if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) { - kfree(hostdata); - release_mem_region(host->base, 64); - return 1; - } - scsi_set_device(host, &dev->dev); + + NCR_700_set_mem_mapped(hostdata); + + host = NCR_700_detect(&lasi700_template, hostdata); + if (!host) + goto out_release_mem_region; + host->irq = dev->irq; - if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, driver_name, host)) { + if (request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, + dev->dev.name, host)) { printk(KERN_ERR "%s: irq problem, detaching\n", - driver_name); - scsi_unregister(host); - NCR_700_release(host); - return 1; + dev->dev.name); + goto out_put_host; } - host_count++; + + scsi_add_host(host, &dev->dev); return 0; + + out_put_host: + scsi_host_put(host); + out_release_mem_region: + release_mem_region(base, 64); + out_kfree: + kfree(hostdata); + return 1; } +#if 0 static int lasi700_release(struct Scsi_Host *host) { @@ -207,12 +158,12 @@ lasi700_release(struct Scsi_Host *host) unregister_parisc_driver(&lasi700_driver); return 1; } +#endif -static Scsi_Host_Template driver_template = { - .name = "LASI SCSI 53c700", - .proc_name = "lasi700", - .detect = lasi700_detect, - .release = lasi700_release, - .this_id = 7, -}; -#include "scsi_module.c" +static int __init +lasi700_init(void) +{ + return register_parisc_driver(&lasi700_driver); +} + +module_init(lasi700_init); diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index d5db95619dd..f929dcdcf32 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -464,6 +464,16 @@ int mac_esp_detect(Scsi_Host_Template * tpnt) return chipspresent; } +static int mac_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * I've been wondering what this is supposed to do, for some time. Talking * to Allen Briggs: These machines have an extra register someplace where the @@ -717,8 +727,8 @@ static Scsi_Host_Template driver_template = { .proc_name = "esp", .name = "Mac 53C9x SCSI", .detect = mac_esp_detect, + .release = mac_esp_release, .info = esp_info, - /* .command = esp_command, */ .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index a57e022aa8d..2194e524f12 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -723,7 +723,7 @@ mega_query_adapter(adapter_t *adapter) { dma_addr_t prod_info_dma_handle; mega_inquiry3 *inquiry3; - u8 raw_mbox[sizeof(mbox_t)]; + u8 raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int retval; @@ -732,14 +732,14 @@ mega_query_adapter(adapter_t *adapter) mbox = (mbox_t *)raw_mbox; memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * Try to issue Inquiry3 command * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and * update enquiry3 structure */ - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; inquiry3 = (mega_inquiry3 *)adapter->mega_buffer; @@ -762,10 +762,10 @@ mega_query_adapter(adapter_t *adapter) inq = &ext_inq->raid_inq; - mbox->xferaddr = (u32)dma_handle; + mbox->m_out.xferaddr = (u32)dma_handle; /*issue old 0x04 command to adapter */ - mbox->cmd = MEGA_MBOXCMD_ADPEXTINQ; + mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ; issue_scb_block(adapter, raw_mbox); @@ -790,7 +790,7 @@ mega_query_adapter(adapter_t *adapter) &adapter->product_info, sizeof(mega_product_info), PCI_DMA_FROMDEVICE); - mbox->xferaddr = prod_info_dma_handle; + mbox->m_out.xferaddr = prod_info_dma_handle; raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ @@ -1141,10 +1141,10 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); if( adapter->has_64bit_addr ) { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU64; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } scb->dma_direction = PCI_DMA_FROMDEVICE; @@ -1152,7 +1152,7 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) pthru->numsgelements = mega_build_sglist(adapter, scb, &pthru->dataxferaddr, &pthru->dataxferlen); - mbox->xferaddr = scb->pthru_dma_addr; + mbox->m_out.xferaddr = scb->pthru_dma_addr; return scb; @@ -1175,19 +1175,19 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) mbox = (mbox_t *)scb->raw_mbox; memset(mbox, 0, sizeof(scb->raw_mbox)); - mbox->logdrv = ldrv_num; + mbox->m_out.logdrv = ldrv_num; /* * A little hack: 2nd bit is zero for all scsi read * commands and is set for all scsi write commands */ if( adapter->has_64bit_addr ) { - mbox->cmd = (*cmd->cmnd & 0x02) ? + mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE64: MEGA_MBOXCMD_LREAD64 ; } else { - mbox->cmd = (*cmd->cmnd & 0x02) ? + mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE: MEGA_MBOXCMD_LREAD ; } @@ -1196,13 +1196,13 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) * 6-byte READ(0x08) or WRITE(0x0A) cdb */ if( cmd->cmd_len == 6 ) { - mbox->numsectors = (u32) cmd->cmnd[4]; - mbox->lba = + mbox->m_out.numsectors = (u32) cmd->cmnd[4]; + mbox->m_out.lba = ((u32)cmd->cmnd[1] << 16) | ((u32)cmd->cmnd[2] << 8) | (u32)cmd->cmnd[3]; - mbox->lba &= 0x1FFFFF; + mbox->m_out.lba &= 0x1FFFFF; #if MEGA_HAVE_STATS /* @@ -1213,11 +1213,11 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) if (*cmd->cmnd == READ_6) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1226,10 +1226,10 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) * 10-byte READ(0x28) or WRITE(0x2A) cdb */ if( cmd->cmd_len == 10 ) { - mbox->numsectors = + mbox->m_out.numsectors = (u32)cmd->cmnd[8] | ((u32)cmd->cmnd[7] << 8); - mbox->lba = + mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | @@ -1239,11 +1239,11 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) if (*cmd->cmnd == READ_10) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1252,13 +1252,13 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) * 12-byte READ(0xA8) or WRITE(0xAA) cdb */ if( cmd->cmd_len == 12 ) { - mbox->lba = + mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | (u32)cmd->cmnd[5]; - mbox->numsectors = + mbox->m_out.numsectors = ((u32)cmd->cmnd[6] << 24) | ((u32)cmd->cmnd[7] << 16) | ((u32)cmd->cmnd[8] << 8) | @@ -1268,11 +1268,11 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) if (*cmd->cmnd == READ_12) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1288,8 +1288,8 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) } /* Calculate Scatter-Gather info */ - mbox->numsgelements = mega_build_sglist(adapter, scb, - (u32 *)&mbox->xferaddr, (u32 *)&seg); + mbox->m_out.numsgelements = mega_build_sglist(adapter, scb, + (u32 *)&mbox->m_out.xferaddr, (u32 *)&seg); return scb; @@ -1357,9 +1357,9 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) epthru = mega_prepare_extpassthru(adapter, scb, cmd, channel, target); - mbox->cmd = MEGA_MBOXCMD_EXTPTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU; - mbox->xferaddr = scb->epthru_dma_addr; + mbox->m_out.xferaddr = scb->epthru_dma_addr; } else { @@ -1369,13 +1369,13 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) /* Initialize mailbox */ if( adapter->has_64bit_addr ) { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU64; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } - mbox->xferaddr = scb->pthru_dma_addr; + mbox->m_out.xferaddr = scb->pthru_dma_addr; } return scb; @@ -1593,20 +1593,21 @@ issue_scb(adapter_t *adapter, scb_t *scb) volatile mbox_t *mbox = adapter->mbox; unsigned int i = 0; - if(unlikely(mbox->busy)) { + if(unlikely(mbox->m_in.busy)) { do { udelay(1); i++; - } while( mbox->busy && (i < max_mbox_busy_wait) ); + } while( mbox->m_in.busy && (i < max_mbox_busy_wait) ); - if(mbox->busy) return -1; + if(mbox->m_in.busy) return -1; } /* Copy mailbox data into host structure */ - memcpy((char *)mbox, (char *)scb->raw_mbox, 16); + memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, + sizeof(struct mbox_out)); - mbox->cmdid = scb->idx; /* Set cmdid */ - mbox->busy = 1; /* Set busy */ + mbox->m_out.cmdid = scb->idx; /* Set cmdid */ + mbox->m_in.busy = 1; /* Set busy */ /* @@ -1614,14 +1615,14 @@ issue_scb(adapter_t *adapter, scb_t *scb) */ atomic_inc(&adapter->pend_cmds); - switch (mbox->cmd) { + switch (mbox->m_out.cmd) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->xferaddr; + mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; + mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; @@ -1634,8 +1635,8 @@ issue_scb(adapter_t *adapter, scb_t *scb) scb->state |= SCB_ISSUED; if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->poll = 0; - mbox->ack = 0; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0; WRINDOOR(adapter, adapter->mbox_dma | 0x1); } else { @@ -1661,24 +1662,23 @@ issue_scb_block(adapter_t *adapter, u_char *raw_mbox) volatile mbox_t *mbox = adapter->mbox; u8 byte; - raw_mbox[0x1] = 0xFE; /* Set cmdid */ - raw_mbox[0xF] = 1; /* Set busy */ - /* Wait until mailbox is free */ if(mega_busywait_mbox (adapter)) goto bug_blocked_mailbox; /* Copy mailbox data into host structure */ - memcpy((char *) mbox, raw_mbox, 16); + memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out)); + mbox->m_out.cmdid = 0xFE; + mbox->m_in.busy = 1; switch (raw_mbox[0]) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->xferaddr; + mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; + mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; @@ -1686,22 +1686,22 @@ issue_scb_block(adapter_t *adapter, u_char *raw_mbox) } if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->poll = 0; - mbox->ack = 0; - mbox->numstatus = 0xFF; - mbox->status = 0xFF; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0; + mbox->m_in.numstatus = 0xFF; + mbox->m_in.status = 0xFF; WRINDOOR(adapter, adapter->mbox_dma | 0x1); - while((volatile u8)mbox->numstatus == 0xFF) + while((volatile u8)mbox->m_in.numstatus == 0xFF) cpu_relax(); - mbox->numstatus = 0xFF; + mbox->m_in.numstatus = 0xFF; - while( (volatile u8)mbox->poll != 0x77 ) + while( (volatile u8)mbox->m_in.poll != 0x77 ) cpu_relax(); - mbox->poll = 0; - mbox->ack = 0x77; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0x77; WRINDOOR(adapter, adapter->mbox_dma | 0x2); @@ -1720,7 +1720,7 @@ issue_scb_block(adapter_t *adapter, u_char *raw_mbox) irq_ack(adapter); } - return mbox->status; + return mbox->m_in.status; bug_blocked_mailbox: printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n"); @@ -1767,19 +1767,20 @@ megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs) } set_irq_state(adapter, byte); - while((nstatus = (volatile u8)adapter->mbox->numstatus) + while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) cpu_relax(); - adapter->mbox->numstatus = 0xFF; + adapter->mbox->m_in.numstatus = 0xFF; - status = adapter->mbox->status; + status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); - memcpy(completed, (void *)adapter->mbox->completed, nstatus); + memcpy(completed, (void *)adapter->mbox->m_in.completed, + nstatus); /* Acknowledge interrupt */ irq_ack(adapter); @@ -1843,20 +1844,21 @@ megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs) } WROUTDOOR(adapter, 0x10001234); - while((nstatus = (volatile u8)adapter->mbox->numstatus) + while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) { cpu_relax(); } - adapter->mbox->numstatus = 0xFF; + adapter->mbox->m_in.numstatus = 0xFF; - status = adapter->mbox->status; + status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); - memcpy(completed, (void *)adapter->mbox->completed, nstatus); + memcpy(completed, (void *)adapter->mbox->m_in.completed, + nstatus); /* Acknowledge interrupt */ WRINDOOR(adapter, 0x2); @@ -1986,7 +1988,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) #if MEGA_HAVE_STATS { - int logdrv = mbox->logdrv; + int logdrv = mbox->m_out.logdrv; islogical = adapter->logdrv_chan[cmd->channel]; /* @@ -2065,8 +2067,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) SCSI_STATUS_CHECK_CONDITION */ /* set sense_buffer and result fields */ - if( mbox->cmd == MEGA_MBOXCMD_PASSTHRU || - mbox->cmd == MEGA_MBOXCMD_PASSTHRU64 ) { + if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU || + mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) { memcpy(cmd->sense_buffer, pthru->reqsensearea, 14); @@ -2076,7 +2078,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) (CHECK_CONDITION << 1); } else { - if (mbox->cmd == MEGA_MBOXCMD_EXTPTHRU) { + if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) { memcpy(cmd->sense_buffer, epthru->reqsensearea, 14); @@ -2233,7 +2235,7 @@ mega_free_scb(adapter_t *adapter, scb_t *scb) static inline int mega_busywait_mbox (adapter_t *adapter) { - if (adapter->mbox->busy) + if (adapter->mbox->m_in.busy) return __mega_busywait_mbox(adapter); return 0; } @@ -2245,7 +2247,7 @@ __mega_busywait_mbox (adapter_t *adapter) long counter; for (counter = 0; counter < 10000; counter++) { - if (!mbox->busy) + if (!mbox->m_in.busy) return 0; udelay(100); yield(); } @@ -2400,7 +2402,7 @@ megaraid_release(struct Scsi_Host *host) { adapter_t *adapter; mbox_t *mbox; - u_char raw_mbox[sizeof(mbox_t)]; + u_char raw_mbox[sizeof(struct mbox_out)]; char buf[12] = { 0 }; adapter = (adapter_t *)host->hostdata; @@ -2409,7 +2411,7 @@ megaraid_release(struct Scsi_Host *host) printk(KERN_NOTICE "megaraid: being unloaded..."); /* Flush adapter cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -2419,7 +2421,7 @@ megaraid_release(struct Scsi_Host *host) issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_SYSTEM; /* Issue a blocking (interrupts disabled) command to the card */ @@ -2569,35 +2571,6 @@ megaraid_info(struct Scsi_Host *host) return buffer; } -volatile static int internal_done_flag = 0; -volatile static int internal_done_errcode = 0; - -static DECLARE_WAIT_QUEUE_HEAD (internal_wait); - -static void internal_done (Scsi_Cmnd *cmd) -{ - internal_done_errcode = cmd->result; - internal_done_flag++; - wake_up (&internal_wait); -} - -/* shouldn't be used, but included for completeness */ - -static int -megaraid_command (Scsi_Cmnd *cmd) -{ - internal_done_flag = 0; - - /* Queue command, and wait until it has completed */ - megaraid_queue (cmd, internal_done); - - while (!internal_done_flag) - interruptible_sleep_on (&internal_wait); - - return internal_done_errcode; -} - - /* * Abort a previous SCSI request. Only commands on the pending list can be * aborted. All the commands issued to the F/W must complete. @@ -2979,16 +2952,24 @@ proc_read_mbox(char *page, char **start, off_t offset, int count, int *eof, int len = 0; len = sprintf(page, "Contents of Mail Box Structure\n"); - len += sprintf(page+len, " Fw Command = 0x%02x\n", mbox->cmd); - len += sprintf(page+len, " Cmd Sequence = 0x%02x\n", mbox->cmdid); - len += sprintf(page+len, " No of Sectors= %04d\n", mbox->numsectors); - len += sprintf(page+len, " LBA = 0x%02x\n", mbox->lba); - len += sprintf(page+len, " DTA = 0x%08x\n", mbox->xferaddr); - len += sprintf(page+len, " Logical Drive= 0x%02x\n", mbox->logdrv); + len += sprintf(page+len, " Fw Command = 0x%02x\n", + mbox->m_out.cmd); + len += sprintf(page+len, " Cmd Sequence = 0x%02x\n", + mbox->m_out.cmdid); + len += sprintf(page+len, " No of Sectors= %04d\n", + mbox->m_out.numsectors); + len += sprintf(page+len, " LBA = 0x%02x\n", + mbox->m_out.lba); + len += sprintf(page+len, " DTA = 0x%08x\n", + mbox->m_out.xferaddr); + len += sprintf(page+len, " Logical Drive= 0x%02x\n", + mbox->m_out.logdrv); len += sprintf(page+len, " No of SG Elmt= 0x%02x\n", - mbox->numsgelements); - len += sprintf(page+len, " Busy = %01x\n", mbox->busy); - len += sprintf(page+len, " Status = 0x%02x\n", mbox->status); + mbox->m_out.numsgelements); + len += sprintf(page+len, " Busy = %01x\n", + mbox->m_in.busy); + len += sprintf(page+len, " Status = 0x%02x\n", + mbox->m_in.status); *eof = 1; @@ -3881,7 +3862,7 @@ megaraid_reboot_notify (struct notifier_block *this, unsigned long code, { adapter_t *adapter; struct Scsi_Host *host; - u8 raw_mbox[sizeof(mbox_t)]; + u8 raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int i,j; @@ -3897,7 +3878,7 @@ megaraid_reboot_notify (struct notifier_block *this, unsigned long code, mbox = (mbox_t *)raw_mbox; /* Flush adapter cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -3910,7 +3891,7 @@ megaraid_reboot_notify (struct notifier_block *this, unsigned long code, issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_SYSTEM; issue_scb_block(adapter, raw_mbox); @@ -4643,17 +4624,17 @@ mega_n_to_m(void *arg, megacmd_t *mc) static int mega_is_bios_enabled(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int ret; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; raw_mbox[0] = IS_BIOS_ENABLED; raw_mbox[2] = GET_BIOS; @@ -4676,13 +4657,13 @@ mega_is_bios_enabled(adapter_t *adapter) static void mega_enum_raid_scsi(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int i; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command to find out what channels are raid/scsi @@ -4692,7 +4673,7 @@ mega_enum_raid_scsi(adapter_t *adapter) memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; /* * Non-ROMB firware fail this command, so all channels @@ -4731,7 +4712,7 @@ static void mega_get_boot_drv(adapter_t *adapter) { struct private_bios_data *prv_bios_data; - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; u16 cksum = 0; u8 *cksum_p; @@ -4740,14 +4721,14 @@ mega_get_boot_drv(adapter_t *adapter) mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(raw_mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = BIOS_PVT_DATA; raw_mbox[2] = GET_BIOS_PVT_DATA; memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; adapter->boot_ldrv_enabled = 0; adapter->boot_ldrv = 0; @@ -4797,13 +4778,13 @@ mega_get_boot_drv(adapter_t *adapter) static int mega_support_random_del(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int rval; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command @@ -4826,13 +4807,13 @@ mega_support_random_del(adapter_t *adapter) static int mega_support_ext_cdb(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int rval; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command to find out if controller supports extended CDBs. */ @@ -4944,7 +4925,7 @@ mega_do_del_logdrv(adapter_t *adapter, int logdrv) static void mega_get_max_sgl(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -4953,7 +4934,7 @@ mega_get_max_sgl(adapter_t *adapter) memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; raw_mbox[0] = MAIN_MISC_OPCODE; raw_mbox[2] = GET_MAX_SG_SUPPORT; @@ -4989,7 +4970,7 @@ mega_get_max_sgl(adapter_t *adapter) static int mega_support_cluster(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -4998,7 +4979,7 @@ mega_support_cluster(adapter_t *adapter) memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; /* * Try to get the initiator id. This command will succeed iff the @@ -5367,7 +5348,6 @@ static Scsi_Host_Template driver_template = { .detect = megaraid_detect, .release = megaraid_release, .info = megaraid_info, - .command = megaraid_command, .queuecommand = megaraid_queue, .bios_param = megaraid_biosparam, .max_sectors = MAX_SECTORS_PER_IO, diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 3c07be74d02..060d2ee38da 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -120,8 +120,7 @@ #define NVIRT_CHAN 4 /* # of virtual channels to represent up to 60 logical drives */ - -typedef struct { +struct mbox_out { /* 0x0 */ u8 cmd; /* 0x1 */ u8 cmdid; /* 0x2 */ u16 numsectors; @@ -130,12 +129,20 @@ typedef struct { /* 0xC */ u8 logdrv; /* 0xD */ u8 numsgelements; /* 0xE */ u8 resvd; +} __attribute__ ((packed)); + +struct mbox_in { /* 0xF */ volatile u8 busy; /* 0x10 */ volatile u8 numstatus; /* 0x11 */ volatile u8 status; /* 0x12 */ volatile u8 completed[MAX_FIRMWARE_STATUS]; volatile u8 poll; volatile u8 ack; +} __attribute__ ((packed)); + +typedef struct { + struct mbox_out m_out; + struct mbox_in m_in; } __attribute__ ((packed)) mbox_t; typedef struct { @@ -1001,7 +1008,6 @@ static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *); static void mega_free_scb(adapter_t *, scb_t *); static int megaraid_release (struct Scsi_Host *); -static int megaraid_command (Scsi_Cmnd *); static int megaraid_abort(Scsi_Cmnd *); static int megaraid_reset(Scsi_Cmnd *); static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index fb8440ce37e..6aaa7ef1b39 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -2047,11 +2047,8 @@ static Scsi_Host_Template driver_template = { .name = "MESH", .detect = mesh_detect, .release = mesh_release, - .command = NULL, .queuecommand = mesh_queue, .eh_abort_handler = mesh_abort, - .eh_device_reset_handler = NULL, - .eh_bus_reset_handler = NULL, .eh_host_reset_handler = mesh_host_reset, .can_queue = 20, .this_id = 7, diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c index 45df1200918..25d3e724cf4 100644 --- a/drivers/scsi/mvme16x.c +++ b/drivers/scsi/mvme16x.c @@ -53,9 +53,22 @@ int mvme16x_scsi_detect(Scsi_Host_Template *tpnt) return 1; } +static int mvme16x_scsi_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "MVME16x NCR53c710 SCSI", .detect = mvme16x_scsi_detect, + .release = mvme16x_scsi_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 990fb200e77..5a47034b232 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1621,7 +1621,7 @@ static int nsp32_detect(struct pci_dev *pdev) /* * register this HBA as SCSI device */ - host = scsi_register(&nsp32_template, sizeof(nsp32_hw_data)); + host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data)); if (host == NULL) { nsp32_msg (KERN_ERR, "failed to scsi register"); goto err; @@ -1840,7 +1840,7 @@ static int nsp32_detect(struct pci_dev *pdev) kfree(data->lunt_list); scsi_unregister: - scsi_unregister(host); + scsi_host_put(host); err: return 1; diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index cd933456b86..3826816f776 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -600,9 +600,22 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src #include "NCR5380.c" +static int pas16_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "Pro Audio Spectrum-16 SCSI", .detect = pas16_detect, + .release = pas16_release, .queuecommand = pas16_queue_command, .eh_abort_handler = pas16_abort, .eh_bus_reset_handler = pas16_bus_reset, diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index ab08dd67af1..9477f6e72e1 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -612,41 +612,6 @@ finished:; return 0; } /**************************************************************** - * Name: internal_done :LOCAL - * - * Description: Done handler for non-queued commands - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Nothing. - * - ****************************************************************/ -static void internal_done (Scsi_Cmnd * SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Pci2000_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Pci2000_Command (Scsi_Cmnd *SCpnt) - { - DEB(printk("pci2000_command: ..calling pci2000_queuecommand\n")); - - Pci2000_QueueCommand (SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } -/**************************************************************** * Name: Pci2000_Detect * * Description: Detect and initialize our boards. @@ -856,7 +821,6 @@ static Scsi_Host_Template driver_template = { .name = "PCI-2000 SCSI Intelligent Disk Controller", .detect = Pci2000_Detect, .release = Pci2000_Release, - .command = Pci2000_Command, .queuecommand = Pci2000_QueueCommand, .abort = Pci2000_Abort, .reset = Pci2000_Reset, diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index e72d9b64448..1d8dd533f7d 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -2307,28 +2307,6 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) } return 0; } -static void internal_done(Scsi_Cmnd *SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Pci2220i_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Pci2220i_Command (Scsi_Cmnd *SCpnt) - { - Pci2220i_QueueCommand (SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } /**************************************************************** * Name: ReadFlash * @@ -2924,7 +2902,6 @@ static Scsi_Host_Template driver_template = { .name = "PCI-2220I/PCI-2240I", .detect = Pci2220i_Detect, .release = Pci2220i_Release, - .command = Pci2220i_Command, .queuecommand = Pci2220i_QueueCommand, .abort = Pci2220i_Abort, .reset = Pci2220i_Reset, diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index ab522926535..ce52c02610f 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1222,7 +1222,7 @@ static struct Scsi_Host *__nsp_detect(Scsi_Host_Template *sht) DEBUG(0, "%s: this_id=%d\n", __FUNCTION__, sht->this_id); request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); - host = scsi_register(sht, 0); + host = scsi_host_alloc(sht, 0); if(host == NULL) return NULL; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 835426d022f..a2f58b4b9f5 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -103,7 +103,6 @@ static Scsi_Host_Template driver_template = { .name = "Iomega VPI0 (ppa) interface", .detect = ppa_detect, .release = ppa_release, - .command = ppa_command, .queuecommand = ppa_queuecommand, .eh_abort_handler = ppa_abort, .eh_bus_reset_handler = ppa_reset, @@ -761,39 +760,6 @@ static int ppa_completion(Scsi_Cmnd * cmd) return 1; /* FINISH_RETURN */ } -/* deprecated synchronous interface */ -int ppa_command(Scsi_Cmnd * cmd) -{ - static int first_pass = 1; - int host_no = cmd->device->host->unique_id; - - if (first_pass) { - printk("ppa: using non-queuing interface\n"); - first_pass = 0; - } - if (ppa_hosts[host_no].cur_cmd) { - printk("PPA: bug in ppa_command\n"); - return 0; - } - ppa_hosts[host_no].failed = 0; - ppa_hosts[host_no].jstart = jiffies; - ppa_hosts[host_no].cur_cmd = cmd; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; - - ppa_pb_claim(host_no); - - while (ppa_engine(&ppa_hosts[host_no], cmd)) - schedule(); - - if (cmd->SCp.phase) /* Only disconnect if we have connected */ - ppa_disconnect(cmd->device->host->unique_id); - - ppa_pb_release(host_no); - ppa_hosts[host_no].cur_cmd = 0; - return cmd->result; -} - /* * Since the PPA itself doesn't generate interrupts, we use * the scheduler's task queue to generate a stream of call-backs and diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index 6df9492e870..79c84788aa9 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -496,31 +496,6 @@ int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Psi240i_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Psi240i_Command (Scsi_Cmnd *SCpnt) - { - DEB(printk("psi240i_command: ..calling psi240i_queuecommand\n")); - - Psi240i_QueueCommand (SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } /*************************************************************************** * Name: ReadChipMemory * @@ -655,6 +630,17 @@ host_init_failure: } return count; } + +static int Psi240i_Release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /**************************************************************** * Name: Psi240i_Abort * @@ -722,7 +708,7 @@ static Scsi_Host_Template driver_template = { .proc_name = "psi240i", .name = "PSI-240I EIDE Disk Controller", .detect = Psi240i_Detect, - .command = Psi240i_Command, + .release = Psi240i_Release, .queuecommand = Psi240i_QueueCommand, .abort = Psi240i_Abort, .reset = Psi240i_Reset, diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index e29d6429be8..1b37b716c6e 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -544,46 +544,6 @@ static irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) #if QL_USE_IRQ -static void qlidone(Scsi_Cmnd * cmd) -{ -} /* null function */ - -#endif - -/* - * Synchronous command processing - */ - -static int qlogicfas_command(Scsi_Cmnd * cmd) -{ - int k; -#if QL_USE_IRQ - if (qlirq >= 0) { - qlogicfas_queuecommand(cmd, qlidone); - while (qlcmd != NULL) - { - cpu_relax(); - barrier(); - } - return cmd->result; - } -#endif - - /* - * Non-irq version - */ - - if (cmd->device->id == qinitid) - return (DID_BAD_TARGET << 16); - ql_icmd(cmd); - if ((k = ql_wai())) - return (k << 16); - return ql_pcmd(cmd); - -} - -#if QL_USE_IRQ - /* * Queued command */ @@ -739,6 +699,18 @@ int __devinit qlogicfas_detect(Scsi_Host_Template *sht) return (__qlogicfas_detect(sht) != NULL); } +static int qlogicfas_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * Return bios parameters */ @@ -826,8 +798,8 @@ Scsi_Host_Template qlogicfas_driver_template = { .name = "qlogicfas", .proc_name = "qlogicfas", .detect = qlogicfas_detect, + .release = qlogicfas_release, .info = qlogicfas_info, - .command = qlogicfas_command, .queuecommand = qlogicfas_queuecommand, .eh_abort_handler = qlogicfas_abort, .eh_bus_reset_handler = qlogicfas_bus_reset, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 337597893bb..7ceb0670e88 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -82,7 +83,6 @@ * Data declarations. */ unsigned long scsi_pid; -struct scsi_cmnd *last_cmnd; static unsigned long serial_number; /* @@ -108,26 +108,6 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { "Enclosure ", }; -MODULE_PARM(scsi_logging_level, "i"); -MODULE_PARM_DESC(scsi_logging_level, "SCSI logging level; should be zero or nonzero"); - -#ifndef MODULE -static int __init scsi_logging_setup(char *str) -{ - int tmp; - - if (get_option(&str, &tmp) == 1) { - scsi_logging_level = (tmp ? ~0 : 0); - return 1; - } else { - printk(KERN_INFO "scsi_logging_setup : usage scsi_logging_level=n " - "(n should be 0 or non-zero)\n"); - return 0; - } -} -__setup("scsi_logging=", scsi_logging_setup); -#endif - /* * Function: scsi_allocate_request * @@ -460,29 +440,18 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) goto out; } - if (host->can_queue) { - SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", - host->hostt->queuecommand)); + SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", + host->hostt->queuecommand)); - spin_lock_irqsave(host->host_lock, flags); - rtn = host->hostt->queuecommand(cmd, scsi_done); - spin_unlock_irqrestore(host->host_lock, flags); - if (rtn) { - scsi_queue_insert(cmd, + spin_lock_irqsave(host->host_lock, flags); + rtn = host->hostt->queuecommand(cmd, scsi_done); + spin_unlock_irqrestore(host->host_lock, flags); + if (rtn) { + scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? - rtn : SCSI_MLQUEUE_HOST_BUSY); - SCSI_LOG_MLQUEUE(3, - printk("queuecommand : request rejected\n")); - } - } else { - SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", - host->hostt->command)); - - spin_lock_irqsave(host->host_lock, flags); - cmd->result = host->hostt->command(cmd); - scsi_done(cmd); - spin_unlock_irqrestore(host->host_lock, flags); - rtn = 0; + rtn : SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, + printk("queuecommand : request rejected\n")); } out: @@ -752,16 +721,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd) struct scsi_device *sdev = cmd->device; struct Scsi_Host *shost = sdev->host; struct scsi_request *sreq; - unsigned long flags; - scsi_host_busy_dec_and_test(shost, sdev); - - /* - * XXX(hch): We really want a nice helper for this.. - */ - spin_lock_irqsave(&sdev->sdev_lock, flags); - sdev->device_busy--; - spin_unlock_irqrestore(&sdev->sdev_lock, flags); + scsi_device_unbusy(sdev); /* * Clear the flags which say that the device/host is no longer @@ -983,6 +944,9 @@ void scsi_set_device_offline(struct scsi_device *sdev) MODULE_DESCRIPTION("SCSI core"); MODULE_LICENSE("GPL"); +module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels"); + static int __init init_scsi(void) { int error, i; @@ -1003,7 +967,6 @@ static int __init init_scsi(void) for (i = 0; i < NR_CPUS; i++) INIT_LIST_HEAD(&done_q[i]); - scsi_host_init(); devfs_mk_dir("scsi"); open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); printk(KERN_NOTICE "SCSI subsystem initialized\n"); diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h dissimilarity index 69% index 67097f38fd7..c921daf28e3 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -1,691 +1,239 @@ -/* - * scsi.h Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale - * generic SCSI package header file by - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - */ - -#ifndef _SCSI_H -#define _SCSI_H - -#include /* for CONFIG_SCSI_LOGGING */ -#include - -/* - * These are the values that the SCpnt->sc_data_direction and - * SRpnt->sr_data_direction can take. These need to be set - * The SCSI_DATA_UNKNOWN value is essentially the default. - * In the event that the command creator didn't bother to - * set a value, you will see SCSI_DATA_UNKNOWN. - */ -#define SCSI_DATA_UNKNOWN 0 -#define SCSI_DATA_WRITE 1 -#define SCSI_DATA_READ 2 -#define SCSI_DATA_NONE 3 - -#ifdef CONFIG_PCI -#include -#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE)) -#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir)) -#else -extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) -{ - if (scsi_dir == SCSI_DATA_UNKNOWN) - return PCI_DMA_BIDIRECTIONAL; - if (scsi_dir == SCSI_DATA_WRITE) - return PCI_DMA_TODEVICE; - if (scsi_dir == SCSI_DATA_READ) - return PCI_DMA_FROMDEVICE; - return PCI_DMA_NONE; -} -#endif -#endif - -#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) -#include -#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) -#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) -#else -extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir) -{ - if (scsi_dir == SCSI_DATA_UNKNOWN) - return SBUS_DMA_BIDIRECTIONAL; - if (scsi_dir == SCSI_DATA_WRITE) - return SBUS_DMA_TODEVICE; - if (scsi_dir == SCSI_DATA_READ) - return SBUS_DMA_FROMDEVICE; - return SBUS_DMA_NONE; -} -#endif -#endif - -/* - * Some defs, in case these are not defined elsewhere. - */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define MAX_SCSI_DEVICE_CODE 14 -extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; - -#ifdef DEBUG -#define SCSI_TIMEOUT (5*HZ) -#else -#define SCSI_TIMEOUT (2*HZ) -#endif - -/* - * Use these to separate status msg and our bytes - * - * These are set by: - * - * status byte = set from target device - * msg_byte = return status from host adapter itself. - * host_byte = set by low-level driver to indicate status. - * driver_byte = set by mid-level. - */ -#define status_byte(result) (((result) >> 1) & 0x1f) -#define msg_byte(result) (((result) >> 8) & 0xff) -#define host_byte(result) (((result) >> 16) & 0xff) -#define driver_byte(result) (((result) >> 24) & 0xff) -#define suggestion(result) (driver_byte(result) & SUGGEST_MASK) - -#define sense_class(sense) (((sense) >> 4) & 0x7) -#define sense_error(sense) ((sense) & 0xf) -#define sense_valid(sense) ((sense) & 0x80); - -#define NEEDS_RETRY 0x2001 -#define SUCCESS 0x2002 -#define FAILED 0x2003 -#define QUEUED 0x2004 -#define SOFT_ERROR 0x2005 -#define ADD_TO_MLQUEUE 0x2006 - -/* - * These are the values that scsi_cmd->state can take. - */ -#define SCSI_STATE_TIMEOUT 0x1000 -#define SCSI_STATE_FINISHED 0x1001 -#define SCSI_STATE_FAILED 0x1002 -#define SCSI_STATE_QUEUED 0x1003 -#define SCSI_STATE_UNUSED 0x1006 -#define SCSI_STATE_DISCONNECTING 0x1008 -#define SCSI_STATE_INITIALIZING 0x1009 -#define SCSI_STATE_BHQUEUE 0x100a -#define SCSI_STATE_MLQUEUE 0x100b - -#define IDENTIFY_BASE 0x80 -#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ - ((can_disconnect) ? 0x40 : 0) |\ - ((lun) & 0x07)) - -/* host byte codes */ -#define DID_OK 0x00 /* NO error */ -#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ -#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ -#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ -#define DID_ABORT 0x05 /* Told to abort for some other reason */ -#define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ -#define DID_RESET 0x08 /* Reset by somebody. */ -#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ -#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ -#define DRIVER_OK 0x00 /* Driver status */ - -/* - * These indicate the error that occurred, and what is available. - */ - -#define DRIVER_BUSY 0x01 -#define DRIVER_SOFT 0x02 -#define DRIVER_MEDIA 0x03 -#define DRIVER_ERROR 0x04 - -#define DRIVER_INVALID 0x05 -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 - -#define SUGGEST_RETRY 0x10 -#define SUGGEST_ABORT 0x20 -#define SUGGEST_REMAP 0x30 -#define SUGGEST_DIE 0x40 -#define SUGGEST_SENSE 0x80 -#define SUGGEST_IS_OK 0xff - -#define DRIVER_MASK 0x0f -#define SUGGEST_MASK 0xf0 - -#define MAX_COMMAND_SIZE 16 -#define SCSI_SENSE_BUFFERSIZE 64 - -/* - * SCSI command sets - */ - -#define SCSI_UNKNOWN 0 -#define SCSI_1 1 -#define SCSI_1_CCS 2 -#define SCSI_2 3 -#define SCSI_3 4 - -/* - * Every SCSI command starts with a one byte OP-code. - * The next byte's high three bits are the LUN of the - * device. Any multi-byte quantities are stored high byte - * first, and may have a 5 bit MSB in the same byte - * as the LUN. - */ - -/* - * As the scsi do command functions are intelligent, and may need to - * redo a command, we need to keep track of the last command - * executed on each one. - */ - -#define WAS_RESET 0x01 -#define WAS_TIMEDOUT 0x02 -#define WAS_SENSE 0x04 -#define IS_RESETTING 0x08 -#define IS_ABORTING 0x10 -#define ASKED_FOR_SENSE 0x20 -#define SYNC_RESET 0x40 - -/* - * This specifies "machine infinity" for host templates which don't - * limit the transfer size. Note this limit represents an absolute - * maximum, and may be over the transfer limits allowed for individual - * devices (e.g. 256 for SCSI-1) - */ -#define SCSI_DEFAULT_MAX_SECTORS 1024 - -/* - * This is the crap from the old error handling code. We have it in a special - * place so that we can more easily delete it later on. - */ -#include "scsi_obsolete.h" - -/* - * Forward-declaration of structs for prototypes. - */ -struct Scsi_Host; -struct scsi_target; -struct scatterlist; - -/* - * Add some typedefs so that we can prototyope a bunch of the functions. - */ -typedef struct scsi_device Scsi_Device; -typedef struct scsi_cmnd Scsi_Cmnd; -typedef struct scsi_request Scsi_Request; - -/* - * These are the error handling functions defined in scsi_error.c - */ -extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, - void (*complete) (Scsi_Cmnd *)); -extern int scsi_delete_timer(Scsi_Cmnd * SCset); -extern int scsi_block_when_processing_errors(Scsi_Device *); -extern void scsi_sleep(int); - -/* - * Prototypes for functions in scsicam.c - */ -extern int scsi_partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, - unsigned int *secs); - -/* - * Prototypes for functions in scsi_lib.c - */ -extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, - int block_sectors); - -/* - * Prototypes for functions in scsi.c - */ -extern struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int flags); -extern void scsi_put_command(struct scsi_cmnd *cmd); -extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); -extern int scsi_track_queue_full(Scsi_Device *, int); -extern int scsi_device_get(struct scsi_device *); -extern void scsi_device_put(struct scsi_device *); -extern void scsi_set_device_offline(struct scsi_device *); - -/* - * Newer request-based interfaces. - */ -extern Scsi_Request *scsi_allocate_request(Scsi_Device *); -extern void scsi_release_request(Scsi_Request *); -extern void scsi_wait_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - int timeout, int retries); -extern void scsi_do_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - void (*done) (struct scsi_cmnd *), - int timeout, int retries); - -/* - * Prototypes for functions in scsi_scan.c - */ -extern struct scsi_device *scsi_add_device(struct Scsi_Host *, - uint, uint, uint); -extern int scsi_remove_device(struct scsi_device *); -extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); - -/* - * Prototypes for functions in constants.c - * Some of these used to live in constants.h - */ -extern void print_Scsi_Cmnd (Scsi_Cmnd *); -extern void print_command(unsigned char *); -extern void print_sense(const char *, Scsi_Cmnd *); -extern void print_req_sense(const char *, Scsi_Request *); -extern void print_driverbyte(int scsiresult); -extern void print_hostbyte(int scsiresult); -extern void print_status(unsigned char status); -extern int print_msg(const unsigned char *); -extern const char *scsi_sense_key_string(unsigned char); -extern const char *scsi_extd_sense_format(unsigned char, unsigned char); - - -/* - * The scsi_device struct contains what we know about each given scsi - * device. - * - * FIXME(eric) - One of the great regrets that I have is that I failed to - * define these structure elements as something like sdev_foo instead of foo. - * This would make it so much easier to grep through sources and so forth. - * I propose that all new elements that get added to these structures follow - * this convention. As time goes on and as people have the stomach for it, - * it should be possible to go back and retrofit at least some of the elements - * here with with the prefix. - */ - -struct scsi_device { - struct class_device sdev_classdev; - /* - * This information is private to the scsi mid-layer. - */ - struct list_head siblings; /* list of all devices on this host */ - struct list_head same_target_siblings; /* just the devices sharing same target id */ - struct Scsi_Host *host; - request_queue_t *request_queue; - volatile unsigned short device_busy; /* commands actually active on low-level */ - spinlock_t sdev_lock; /* also the request queue_lock */ - spinlock_t list_lock; - struct list_head cmd_list; /* queue of in use SCSI Command structures */ - struct list_head starved_entry; - Scsi_Cmnd *current_cmnd; /* currently active command */ - unsigned short queue_depth; /* How deep of a queue we want */ - unsigned short last_queue_full_depth; /* These two are used by */ - unsigned short last_queue_full_count; /* scsi_track_queue_full() */ - unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same - jiffie count on our counter, they - could all be from the same event. */ - - unsigned int id, lun, channel; - - unsigned int manufacturer; /* Manufacturer of device, for using - * vendor-specific cmd's */ - unsigned sector_size; /* size in bytes */ - - int access_count; /* Count of open channels/mounts */ - - void *hostdata; /* available to low-level driver */ - char devfs_name[256]; /* devfs junk */ - char type; - char scsi_level; - unsigned char inquiry_len; /* valid bytes in 'inquiry' */ - unsigned char * inquiry; /* INQUIRY response data */ - char * vendor; /* [back_compat] point into 'inquiry' ... */ - char * model; /* ... after scan; point to static string */ - char * rev; /* ... "nullnullnullnull" before scan */ - unsigned char current_tag; /* current tag */ -// unsigned char sync_min_period; /* Not less than this period */ -// unsigned char sync_max_offset; /* Not greater than this offset */ - struct scsi_target *sdev_target; /* used only for single_lun */ - - unsigned online:1; - unsigned writeable:1; - unsigned removable:1; - unsigned random:1; - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ - unsigned locked:1; /* Media removal disabled */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned disconnect:1; /* can disconnect */ - unsigned soft_reset:1; /* Uses soft reset option */ - unsigned sdtr:1; /* Device supports SDTR messages */ - unsigned wdtr:1; /* Device supports WDTR messages */ - unsigned ppr:1; /* Device supports PPR messages */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ - unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags - instead!!! Please fix your driver now!! */ - unsigned simple_tags:1; /* simple queue tag messages are enabled */ - unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ - unsigned single_lun:1; /* Indicates we should only allow I/O to - * one of the luns for the device at a - * time. */ - unsigned was_reset:1; /* There was a bus reset on the bus for - * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned use_10_for_rw:1; /* first try 10-byte read / write */ - unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ - unsigned remap:1; /* support remapping */ -// unsigned sync:1; /* Sync transfer state, managed by host */ -// unsigned wide:1; /* WIDE transfer state, managed by host */ - unsigned no_start_on_add:1; /* do not issue start on add */ - - unsigned int device_blocked; /* Device returned QUEUE_FULL. */ - - unsigned int max_device_blocked; /* what device_blocked counts down from */ - /* default value if the device doesn't override */ - #define SCSI_DEFAULT_DEVICE_BLOCKED 3 - - struct device sdev_driverfs_dev; -}; -#define to_scsi_device(d) \ - container_of(d, struct scsi_device, sdev_driverfs_dev) - - -typedef struct scsi_pointer { - char *ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - dma_addr_t dma_handle; - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -} Scsi_Pointer; - -/* - * This is essentially a slimmed down version of Scsi_Cmnd. The point of - * having this is that requests that are injected into the queue as result - * of things like ioctls and character devices shouldn't be using a - * Scsi_Cmnd until such a time that the command is actually at the head - * of the queue and being sent to the driver. - */ -struct scsi_request { - int sr_magic; - int sr_result; /* Status code from lower level driver */ - unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - struct Scsi_Host *sr_host; - Scsi_Device *sr_device; - Scsi_Cmnd *sr_command; - struct request *sr_request; /* A copy of the command we are - working on */ - unsigned sr_bufflen; /* Size of data buffer */ - void *sr_buffer; /* Data buffer */ - int sr_allowed; - unsigned char sr_data_direction; - unsigned char sr_cmd_len; - unsigned char sr_cmnd[MAX_COMMAND_SIZE]; - void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ - int sr_timeout_per_command; - unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ - unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ - unsigned sr_underflow; /* Return error if less than - this amount is transferred */ - void * upper_private_data; /* reserved for owner (usually upper - level driver) of this request */ -}; - -/* - * FIXME(eric) - one of the great regrets that I have is that I failed to - * define these structure elements as something like sc_foo instead of foo. - * This would make it so much easier to grep through sources and so forth. - * I propose that all new elements that get added to these structures follow - * this convention. As time goes on and as people have the stomach for it, - * it should be possible to go back and retrofit at least some of the elements - * here with with the prefix. - */ -struct scsi_cmnd { - int sc_magic; - - struct scsi_device *device; - unsigned short state; - unsigned short owner; - Scsi_Request *sc_request; - - struct list_head list; /* scsi_cmnd participates in queue lists */ - - struct list_head eh_entry; /* entry for the host eh_cmd_q */ - int eh_state; /* Used for state tracking in error handlr */ - int eh_eflags; /* Used by error handlr */ - void (*done) (struct scsi_cmnd *); /* Mid-level done function */ - /* - A SCSI Command is assigned a nonzero serial_number when internal_cmnd - passes it to the driver's queue command function. The serial_number - is cleared when scsi_done is entered indicating that the command has - been completed. If a timeout occurs, the serial number at the moment - of timeout is copied into serial_number_at_timeout. By subsequently - comparing the serial_number and serial_number_at_timeout fields - during abort or reset processing, we can detect whether the command - has already completed. This also detects cases where the command has - completed and the SCSI Command structure has already being reused - for another command, so that we can avoid incorrectly aborting or - resetting the new command. - */ - - unsigned long serial_number; - unsigned long serial_number_at_timeout; - - int retries; - int allowed; - int timeout_per_command; - int timeout_total; - int timeout; - - /* - * We handle the timeout differently if it happens when a reset, - * abort, etc are in process. - */ - unsigned volatile char internal_timeout; - - unsigned char cmd_len; - unsigned char old_cmd_len; - unsigned char sc_data_direction; - unsigned char sc_old_data_direction; - - /* These elements define the operation we are about to perform */ - unsigned char cmnd[MAX_COMMAND_SIZE]; - unsigned request_bufflen; /* Actual request size */ - - struct timer_list eh_timeout; /* Used to time out the command. */ - void *request_buffer; /* Actual requested buffer */ - - /* These elements define the operation we ultimately want to perform */ - unsigned char data_cmnd[MAX_COMMAND_SIZE]; - unsigned short old_use_sg; /* We save use_sg here when requesting - * sense info */ - unsigned short use_sg; /* Number of pieces of scatter-gather */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned short abort_reason; /* If the mid-level code requests an - * abort, this is the reason. */ - unsigned bufflen; /* Size of data buffer */ - void *buffer; /* Data buffer */ - - unsigned underflow; /* Return error if less than - this amount is transferred */ - unsigned old_underflow; /* save underflow here when reusing the - * command for error handling */ - - unsigned transfersize; /* How much we are guaranteed to - transfer with each SCSI transfer - (ie, between disconnect / - reconnects. Probably == sector - size */ - - int resid; /* Number of bytes requested to be - transferred less actual number - transferred (0 if not supported) */ - - struct request *request; /* The command we are - working on */ - - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - unsigned flags; - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done) (struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - - Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char *host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ - - int result; /* Status code from lower level driver */ - - unsigned char tag; /* SCSI-II queued command tag */ - unsigned long pid; /* Process ID, starts at 0 */ -}; - -/* - * Definitions and prototypes used for scsi mid-level queue. - */ -#define SCSI_MLQUEUE_HOST_BUSY 0x1055 -#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -#define SCSI_MLQUEUE_EH_RETRY 0x1057 - -/* - * Reset request from external source - */ -#define SCSI_TRY_RESET_DEVICE 1 -#define SCSI_TRY_RESET_BUS 2 -#define SCSI_TRY_RESET_HOST 3 - -extern int scsi_reset_provider(Scsi_Device *, int); - -#define MSG_SIMPLE_TAG 0x20 -#define MSG_HEAD_TAG 0x21 -#define MSG_ORDERED_TAG 0x22 - -#define SCSI_NO_TAG (-1) /* identify no tag in use */ - -/** - * scsi_activate_tcq - turn on tag command queueing - * @SDpnt: device to turn on TCQ for - * @depth: queue depth - * - * Notes: - * Eventually, I hope depth would be the maximum depth - * the device could cope with and the real queue depth - * would be adjustable from 0 to depth. - **/ -static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { - if(SDpnt->tagged_supported) { - if(!blk_queue_tagged(SDpnt->request_queue)) - blk_queue_init_tags(SDpnt->request_queue, depth); - scsi_adjust_queue_depth(SDpnt, MSG_ORDERED_TAG, depth); - } -} - -/** - * scsi_deactivate_tcq - turn off tag command queueing - * @SDpnt: device to turn off TCQ for - **/ -static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt, int depth) { - if(blk_queue_tagged(SDpnt->request_queue)) - blk_queue_free_tags(SDpnt->request_queue); - scsi_adjust_queue_depth(SDpnt, 0, depth); -} - -/** - * scsi_populate_tag_msg - place a tag message in a buffer - * @SCpnt: pointer to the Scsi_Cmnd for the tag - * @msg: pointer to the area to place the tag - * - * Notes: - * designed to create the correct type of tag message for the - * particular request. Returns the size of the tag message. - * May return 0 if TCQ is disabled for this device. - **/ -static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) { - struct request *req = SCpnt->request; - - if(!blk_rq_tagged(req)) - return 0; - - if (req->flags & REQ_HARDBARRIER) - *msg++ = MSG_ORDERED_TAG; - else - *msg++ = MSG_SIMPLE_TAG; - - *msg++ = SCpnt->request->tag; - - return 2; -} - -/** - * scsi_find_tag - find a tagged command by device - * @SDpnt: pointer to the ScSI device - * @tag: the tag number - * - * Notes: - * Only works with tags allocated by the generic blk layer. - **/ -static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { - - struct request *req; - - if(tag == SCSI_NO_TAG) - /* single command, look in space */ - return SDpnt->current_cmnd; - - req = blk_queue_find_tag(SDpnt->request_queue, tag); - - if(req == NULL) - return NULL; - - return (Scsi_Cmnd *)req->special; -} - -int scsi_set_medium_removal(Scsi_Device *dev, char state); - -extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, - struct device_attribute *attr); -extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, - struct class_device_attribute *attr); - -#endif /* _SCSI_H */ +/* + * scsi.h Copyright (C) 1992 Drew Eckhardt + * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale + * generic SCSI package header file by + * Initial versions: Drew Eckhardt + * Subsequent revisions: Eric Youngdale + * + * + * + * Modified by Eric Youngdale eric@andante.org to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#ifndef _SCSI_H +#define _SCSI_H + +#include /* for CONFIG_SCSI_LOGGING */ + +#include +#include +#include +#include +#include +#include + +/* + * These are the values that the SCpnt->sc_data_direction and + * SRpnt->sr_data_direction can take. These need to be set + * The SCSI_DATA_UNKNOWN value is essentially the default. + * In the event that the command creator didn't bother to + * set a value, you will see SCSI_DATA_UNKNOWN. + */ +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +#ifdef CONFIG_PCI +#include +#if ((SCSI_DATA_UNKNOWN == PCI_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == PCI_DMA_TODEVICE) && (SCSI_DATA_READ == PCI_DMA_FROMDEVICE) && (SCSI_DATA_NONE == PCI_DMA_NONE)) +#define scsi_to_pci_dma_dir(scsi_dir) ((int)(scsi_dir)) +#else +extern __inline__ int scsi_to_pci_dma_dir(unsigned char scsi_dir) +{ + if (scsi_dir == SCSI_DATA_UNKNOWN) + return PCI_DMA_BIDIRECTIONAL; + if (scsi_dir == SCSI_DATA_WRITE) + return PCI_DMA_TODEVICE; + if (scsi_dir == SCSI_DATA_READ) + return PCI_DMA_FROMDEVICE; + return PCI_DMA_NONE; +} +#endif +#endif + +#if defined(CONFIG_SBUS) && !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) +#include +#if ((SCSI_DATA_UNKNOWN == SBUS_DMA_BIDIRECTIONAL) && (SCSI_DATA_WRITE == SBUS_DMA_TODEVICE) && (SCSI_DATA_READ == SBUS_DMA_FROMDEVICE) && (SCSI_DATA_NONE == SBUS_DMA_NONE)) +#define scsi_to_sbus_dma_dir(scsi_dir) ((int)(scsi_dir)) +#else +extern __inline__ int scsi_to_sbus_dma_dir(unsigned char scsi_dir) +{ + if (scsi_dir == SCSI_DATA_UNKNOWN) + return SBUS_DMA_BIDIRECTIONAL; + if (scsi_dir == SCSI_DATA_WRITE) + return SBUS_DMA_TODEVICE; + if (scsi_dir == SCSI_DATA_READ) + return SBUS_DMA_FROMDEVICE; + return SBUS_DMA_NONE; +} +#endif +#endif + +/* + * Some defs, in case these are not defined elsewhere. + */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define MAX_SCSI_DEVICE_CODE 14 +extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; + +#ifdef DEBUG +#define SCSI_TIMEOUT (5*HZ) +#else +#define SCSI_TIMEOUT (2*HZ) +#endif + +/* + * Use these to separate status msg and our bytes + * + * These are set by: + * + * status byte = set from target device + * msg_byte = return status from host adapter itself. + * host_byte = set by low-level driver to indicate status. + * driver_byte = set by mid-level. + */ +#define status_byte(result) (((result) >> 1) & 0x1f) +#define msg_byte(result) (((result) >> 8) & 0xff) +#define host_byte(result) (((result) >> 16) & 0xff) +#define driver_byte(result) (((result) >> 24) & 0xff) +#define suggestion(result) (driver_byte(result) & SUGGEST_MASK) + +#define sense_class(sense) (((sense) >> 4) & 0x7) +#define sense_error(sense) ((sense) & 0xf) +#define sense_valid(sense) ((sense) & 0x80); + +#define NEEDS_RETRY 0x2001 +#define SUCCESS 0x2002 +#define FAILED 0x2003 +#define QUEUED 0x2004 +#define SOFT_ERROR 0x2005 +#define ADD_TO_MLQUEUE 0x2006 + +#define IDENTIFY_BASE 0x80 +#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ + ((can_disconnect) ? 0x40 : 0) |\ + ((lun) & 0x07)) + +/* host byte codes */ +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ +#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DRIVER_OK 0x00 /* Driver status */ + +/* + * These indicate the error that occurred, and what is available. + */ + +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 + +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 + +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 +#define SUGGEST_IS_OK 0xff + +#define DRIVER_MASK 0x0f +#define SUGGEST_MASK 0xf0 + +/* + * SCSI command sets + */ + +#define SCSI_UNKNOWN 0 +#define SCSI_1 1 +#define SCSI_1_CCS 2 +#define SCSI_2 3 +#define SCSI_3 4 + +/* + * Every SCSI command starts with a one byte OP-code. + * The next byte's high three bits are the LUN of the + * device. Any multi-byte quantities are stored high byte + * first, and may have a 5 bit MSB in the same byte + * as the LUN. + */ + +/* + * As the scsi do command functions are intelligent, and may need to + * redo a command, we need to keep track of the last command + * executed on each one. + */ + +#define WAS_RESET 0x01 +#define WAS_TIMEDOUT 0x02 +#define WAS_SENSE 0x04 +#define IS_RESETTING 0x08 +#define IS_ABORTING 0x10 +#define ASKED_FOR_SENSE 0x20 +#define SYNC_RESET 0x40 + +struct Scsi_Host; +struct scsi_cmnd; +struct scsi_device; +struct scsi_target; +struct scatterlist; + +/* + * Prototypes for functions in constants.c + * Some of these used to live in constants.h + */ +extern void print_Scsi_Cmnd(struct scsi_cmnd *); +extern void print_command(unsigned char *); +extern void print_sense(const char *, struct scsi_cmnd *); +extern void print_req_sense(const char *, struct scsi_request *); +extern void print_driverbyte(int scsiresult); +extern void print_hostbyte(int scsiresult); +extern void print_status(unsigned char status); +extern int print_msg(const unsigned char *); +extern const char *scsi_sense_key_string(unsigned char); +extern const char *scsi_extd_sense_format(unsigned char, unsigned char); + +/* + * Definitions and prototypes used for scsi mid-level queue. + */ +#define SCSI_MLQUEUE_HOST_BUSY 0x1055 +#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 +#define SCSI_MLQUEUE_EH_RETRY 0x1057 + +extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, + struct device_attribute *attr); +extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, + struct class_device_attribute *attr); + +/* + * This is the crap from the old error handling code. We have it in a special + * place so that we can more easily delete it later on. + */ +#include "scsi_obsolete.h" + +/* obsolete typedef junk. */ +#include "scsi_typedefs.h" + +#endif /* _SCSI_H */ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 3bb4c7492d8..d0fbce2272d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1681,7 +1681,7 @@ static int sdebug_driver_probe(struct device * dev) sdbg_host = to_sdebug_host(dev); - hpnt = scsi_register(&sdebug_driver_template, sizeof(sdbg_host)); + hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); if (NULL == hpnt) { printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); error = -ENODEV; @@ -1700,7 +1700,7 @@ static int sdebug_driver_probe(struct device * dev) if (error) { printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); error = -ENODEV; - scsi_unregister(hpnt); + scsi_host_put(hpnt); } @@ -1726,8 +1726,6 @@ static int sdebug_driver_remove(struct device * dev) return -EBUSY; } - scsi_unregister(sdbg_host->shost); - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, dev_list); @@ -1735,5 +1733,6 @@ static int sdebug_driver_remove(struct device * dev) kfree(sdbg_devinfo); } + scsi_host_put(sdbg_host->shost); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 5ef128ef33a..8424c445c6b 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -23,9 +24,9 @@ struct scsi_dev_info_list { static const char spaces[] = " "; /* 16 of them */ -static char *scsi_dev_flags; static unsigned scsi_default_dev_flags; static LIST_HEAD(scsi_dev_info_list); +static __init char scsi_dev_flags[256]; /* * scsi_static_device_list: deprecated list of devices that require @@ -180,6 +181,7 @@ static struct { {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, { NULL, NULL, NULL, 0 }, }; @@ -450,35 +452,15 @@ out: return err; } -MODULE_PARM(scsi_dev_flags, "s"); -MODULE_PARM_DESC(scsi_dev_flags, - "Given scsi_dev_flags=vendor:model:flags, add a black/white list" - " entry for vendor and model with an integer value of flags" +module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); +MODULE_PARM_DESC(dev_flags, + "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white" + " list entries for vendor and model with an integer value of flags" " to the scsi device info list"); -MODULE_PARM(scsi_default_dev_flags, "i"); -MODULE_PARM_DESC(scsi_default_dev_flags, - "scsi default device flag integer value"); -static int __init setup_scsi_dev_flags(char *str) -{ - scsi_dev_flags = str; - return 1; -} - -static int __init setup_scsi_default_dev_flags(char *str) -{ - unsigned int tmp; - if (get_option(&str, &tmp) == 1) { - scsi_default_dev_flags = tmp; - printk(KERN_WARNING "%s %d\n", __FUNCTION__, - scsi_default_dev_flags); - return 1; - } else { - printk(KERN_WARNING "%s: usage scsi_default_dev_flags=intr\n", - __FUNCTION__); - return 0; - } -} +module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(default_dev_flags, + "scsi default device flag integer value"); /** * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove @@ -540,6 +522,3 @@ int scsi_init_devinfo(void) scsi_exit_devinfo(); return error; } - -__setup("scsi_dev_flags=", setup_scsi_dev_flags); -__setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a02e062ab93..c7c407f8481 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -44,6 +44,16 @@ #define BUS_RESET_SETTLE_TIME 10*HZ #define HOST_RESET_SETTLE_TIME 10*HZ +/* called with shost->host_lock held */ +void scsi_eh_wakeup(struct Scsi_Host *shost) +{ + if (shost->host_busy == shost->host_failed) { + up(shost->eh_wait); + SCSI_LOG_ERROR_RECOVERY(5, + printk("Waking error handler thread\n")); + } +} + /** * scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. @@ -76,14 +86,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->in_recovery = 1; shost->host_failed++; - if (shost->host_busy == shost->host_failed) { - up(shost->eh_wait); - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - " thread\n")); - } - + scsi_eh_wakeup(shost); spin_unlock_irqrestore(shost->host_lock, flags); - return 1; } @@ -431,6 +435,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) { struct Scsi_Host *host = scmd->device->host; + DECLARE_MUTEX_LOCKED(sem); unsigned long flags; int rtn = SUCCESS; @@ -444,72 +449,54 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | (scmd->device->lun << 5 & 0xe0); - if (host->can_queue) { - DECLARE_MUTEX_LOCKED(sem); + scsi_add_timer(scmd, timeout, scsi_eh_times_out); - scsi_add_timer(scmd, timeout, scsi_eh_times_out); + /* + * set up the semaphore so we wait for the command to complete. + */ + scmd->device->host->eh_action = &sem; + scmd->request->rq_status = RQ_SCSI_BUSY; - /* - * set up the semaphore so we wait for the command to complete. - */ - scmd->device->host->eh_action = &sem; - scmd->request->rq_status = RQ_SCSI_BUSY; + spin_lock_irqsave(scmd->device->host->host_lock, flags); + host->hostt->queuecommand(scmd, scsi_eh_done); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - host->hostt->queuecommand(scmd, scsi_eh_done); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + down(&sem); - down(&sem); + scmd->device->host->eh_action = NULL; - scmd->device->host->eh_action = NULL; + /* + * see if timeout. if so, tell the host to forget about it. + * in other words, we don't want a callback any more. + */ + if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) { + scsi_eh_eflags_clr(scmd, SCSI_EH_REC_TIMEOUT); + scmd->owner = SCSI_OWNER_LOWLEVEL; /* - * see if timeout. if so, tell the host to forget about it. - * in other words, we don't want a callback any more. + * as far as the low level driver is + * concerned, this command is still active, so + * we must give the low level driver a chance + * to abort it. (db) + * + * FIXME(eric) - we are not tracking whether we could + * abort a timed out command or not. not sure how + * we should treat them differently anyways. */ - if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) { - scsi_eh_eflags_clr(scmd, SCSI_EH_REC_TIMEOUT); - scmd->owner = SCSI_OWNER_LOWLEVEL; - - /* - * as far as the low level driver is - * concerned, this command is still active, so - * we must give the low level driver a chance - * to abort it. (db) - * - * FIXME(eric) - we are not tracking whether we could - * abort a timed out command or not. not sure how - * we should treat them differently anyways. - */ - spin_lock_irqsave(scmd->device->host->host_lock, flags); - if (scmd->device->host->hostt->eh_abort_handler) - scmd->device->host->hostt->eh_abort_handler(scmd); - spin_unlock_irqrestore(scmd->device->host->host_lock, - flags); + spin_lock_irqsave(scmd->device->host->host_lock, flags); + if (scmd->device->host->hostt->eh_abort_handler) + scmd->device->host->hostt->eh_abort_handler(scmd); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - scmd->request->rq_status = RQ_SCSI_DONE; - scmd->owner = SCSI_OWNER_ERROR_HANDLER; + scmd->request->rq_status = RQ_SCSI_DONE; + scmd->owner = SCSI_OWNER_ERROR_HANDLER; - rtn = FAILED; - } - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", - __FUNCTION__, scmd, rtn)); - } else { - int temp; - - /* - * we damn well had better never use this code. there is no - * timeout protection here, since we would end up waiting in - * the actual low level driver, we don't know how to wake it up. - */ - spin_lock_irqsave(host->host_lock, flags); - temp = host->hostt->command(scmd); - spin_unlock_irqrestore(host->host_lock, flags); - - scmd->result = temp; - /* fall through to code below to examine status. */ + rtn = FAILED; } + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", + __FUNCTION__, scmd, rtn)); + /* * now examine the actual status codes to see whether the command * actually did complete normally. diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 4843e64e25b..6458c99bab1 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -90,75 +90,70 @@ static int ioctl_probe(struct Scsi_Host *host, void *buffer) * The output area is then filled in starting from the command byte. */ -static int ioctl_internal_command(Scsi_Device * dev, char *cmd, +static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { + struct scsi_request *sreq; int result; - Scsi_Request *SRpnt; - Scsi_Device *SDpnt; + SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); - if (NULL == (SRpnt = scsi_allocate_request(dev))) { + sreq = scsi_allocate_request(sdev); + if (!sreq) { printk("SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } - SRpnt->sr_data_direction = SCSI_DATA_NONE; - scsi_wait_req(SRpnt, cmd, NULL, 0, timeout, retries); + sreq->sr_data_direction = SCSI_DATA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SRpnt->sr_result)); + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); - if (driver_byte(SRpnt->sr_result) != 0) - switch (SRpnt->sr_sense_buffer[2] & 0xf) { + if (driver_byte(sreq->sr_result)) { + switch (sreq->sr_sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) - dev->lockable = 0; + sdev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ - if (dev->removable && (cmd[0] != TEST_UNIT_READY)) { + if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: - if (dev->removable) { - dev->changed = 1; - SRpnt->sr_result = 0; /* This is no longer considered an error */ - /* gag this error, VFS will log it anyway /axboe */ - /* printk(KERN_INFO "Disc change detected.\n"); */ + if (sdev->removable) { + sdev->changed = 1; + sreq->sr_result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ printk("SCSI error: host %d id %d lun %d return code = %x\n", - dev->host->host_no, - dev->id, - dev->lun, - SRpnt->sr_result); + sdev->host->host_no, + sdev->id, + sdev->lun, + sreq->sr_result); printk("\tSense class %x, sense error %x, extended sense %x\n", - sense_class(SRpnt->sr_sense_buffer[0]), - sense_error(SRpnt->sr_sense_buffer[0]), - SRpnt->sr_sense_buffer[2] & 0xf); + sense_class(sreq->sr_sense_buffer[0]), + sense_error(sreq->sr_sense_buffer[0]), + sreq->sr_sense_buffer[2] & 0xf); } + } - result = SRpnt->sr_result; - + result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - SDpnt = SRpnt->sr_device; - scsi_release_request(SRpnt); - SRpnt = NULL; - + scsi_release_request(sreq); return result; } -int scsi_set_medium_removal(Scsi_Device *dev, char state) +int scsi_set_medium_removal(struct scsi_device *sdev, char state) { char scsi_cmd[MAX_COMMAND_SIZE]; int ret; - if (!dev->removable || !dev->lockable) + if (!sdev->removable || !sdev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; @@ -168,11 +163,10 @@ int scsi_set_medium_removal(Scsi_Device *dev, char state) scsi_cmd[4] = state; scsi_cmd[5] = 0; - ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - + ret = ioctl_internal_command(sdev, scsi_cmd, + IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); if (ret == 0) - dev->locked = state == SCSI_REMOVAL_PREVENT; - + sdev->locked = (state == SCSI_REMOVAL_PREVENT); return ret; } @@ -209,13 +203,13 @@ int scsi_set_medium_removal(Scsi_Device *dev, char state) */ #define OMAX_SB_LEN 16 /* Old sense buffer length */ -int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) +int scsi_ioctl_send_command(struct scsi_device *sdev, + struct scsi_ioctl_command *sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; char *cmd_in; - Scsi_Request *SRpnt; - Scsi_Device *SDpnt; + struct scsi_request *sreq; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; @@ -225,7 +219,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) if (!sic) return -EINVAL; - if (dev->host->unchecked_isa_dma) + if (sdev->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; /* @@ -259,11 +253,11 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; - buf = (char *) kmalloc(buf_needed, gfp_mask); + buf = kmalloc(buf_needed, gfp_mask); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); - if( inlen == 0 ) { + if (inlen == 0) { data_direction = SCSI_DATA_READ; } else if (outlen == 0 ) { data_direction = SCSI_DATA_WRITE; @@ -327,62 +321,34 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) break; } -#ifndef DEBUG_NO_CMD - - - SRpnt = scsi_allocate_request(dev); - if( SRpnt == NULL ) - { + sreq = scsi_allocate_request(sdev); + if (sreq) { result = -EINTR; goto error; } - SRpnt->sr_data_direction = data_direction; - scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries); + sreq->sr_data_direction = data_direction; + scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); /* * If there was an error condition, pass the info back to the user. */ - - result = SRpnt->sr_result; - - if (SRpnt->sr_result) { - int sb_len = sizeof(SRpnt->sr_sense_buffer); + result = sreq->sr_result; + if (result) { + int sb_len = sizeof(sreq->sr_sense_buffer); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; - if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len)) + if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } - SDpnt = SRpnt->sr_device; - scsi_release_request(SRpnt); - SRpnt = NULL; - + scsi_release_request(sreq); error: - if (buf) - kfree(buf); - - + kfree(buf); return result; -#else - { - int i; - printk("scsi_ioctl : device %d. command = ", dev->id); - for (i = 0; i < cmdlen; ++i) - printk("%02x ", cmd[i]); - printk("\nbuffer ="); - for (i = 0; i < 20; ++i) - printk("%02x ", buf[i]); - printk("\n"); - printk("inlen = %d, outlen = %d, cmdlen = %d\n", - inlen, outlen, cmdlen); - printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); - } - return 0; -#endif } /* @@ -395,14 +361,13 @@ error: * device) * any copy_to_user() error on failure there */ -static int -scsi_ioctl_get_pci(Scsi_Device * sdev, void *arg) +static int scsi_ioctl_get_pci(struct scsi_device *sdev, void *arg) { struct device *dev = scsi_get_device(sdev->host); - if (!dev) return -ENXIO; - return copy_to_user(arg, dev->bus_id, - sizeof(dev->bus_id)); + if (!dev) + return -ENXIO; + return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id)); } @@ -411,12 +376,12 @@ scsi_ioctl_get_pci(Scsi_Device * sdev, void *arg) * not take a major/minor number as the dev field. Rather, it takes * a pointer to a scsi_devices[] element, a structure. */ -int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) +int scsi_ioctl(struct scsi_device *sdev, int cmd, void *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; /* No idea how this happens.... */ - if (!dev) + if (!sdev) return -ENXIO; /* @@ -425,24 +390,24 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) * may try and take the device offline, in which case all further * access to the device is prohibited. */ - if (!scsi_block_when_processing_errors(dev)) { + if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; - } switch (cmd) { case SCSI_IOCTL_GET_IDLUN: - if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun))) + if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) return -EFAULT; - __put_user((dev->id & 0xff) - + ((dev->lun & 0xff) << 8) - + ((dev->channel & 0xff) << 16) - + ((dev->host->host_no & 0xff) << 24), - &((Scsi_Idlun *) arg)->dev_id); - __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); + __put_user((sdev->id & 0xff) + + ((sdev->lun & 0xff) << 8) + + ((sdev->channel & 0xff) << 16) + + ((sdev->host->host_no & 0xff) << 24), + &((struct scsi_idlun *)arg)->dev_id); + __put_user(sdev->host->unique_id, + &((struct scsi_idlun *)arg)->host_unique_id); return 0; case SCSI_IOCTL_GET_BUS_NUMBER: - return put_user(dev->host->host_no, (int *) arg); + return put_user(sdev->host->host_no, (int *)arg); /* * The next two ioctls either need to go or need to be changed to * pass tagged queueing changes through the low level drivers. @@ -454,61 +419,56 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) case SCSI_IOCTL_TAGGED_ENABLE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!dev->tagged_supported) + if (!sdev->tagged_supported) return -EINVAL; - dev->tagged_queue = 1; - dev->current_tag = 1; + sdev->tagged_queue = 1; + sdev->current_tag = 1; return 0; case SCSI_IOCTL_TAGGED_DISABLE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!dev->tagged_supported) + if (!sdev->tagged_supported) return -EINVAL; - dev->tagged_queue = 0; - dev->current_tag = 0; + sdev->tagged_queue = 0; + sdev->current_tag = 0; return 0; case SCSI_IOCTL_PROBE_HOST: - return ioctl_probe(dev->host, arg); + return ioctl_probe(sdev->host, arg); case SCSI_IOCTL_SEND_COMMAND: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - return scsi_ioctl_send_command((Scsi_Device *) dev, - (Scsi_Ioctl_Command *) arg); + return scsi_ioctl_send_command(sdev, + (struct scsi_ioctl_command *)arg); case SCSI_IOCTL_DOORLOCK: - return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT); + return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); case SCSI_IOCTL_DOORUNLOCK: - return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW); + return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 1; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, START_STOP_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_STOP_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, START_STOP_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_GET_PCI: - return scsi_ioctl_get_pci(dev, arg); - break; + return scsi_ioctl_get_pci(sdev, arg); default: - if (dev->host->hostt->ioctl) - return dev->host->hostt->ioctl(dev, cmd, arg); - return -EINVAL; + if (sdev->host->hostt->ioctl) + return sdev->host->hostt->ioctl(sdev, cmd, arg); } return -EINVAL; } @@ -518,13 +478,13 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) * fs segment fiddling. */ -int kernel_scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) +int kernel_scsi_ioctl(struct scsi_device *sdev, int cmd, void *arg) { mm_segment_t oldfs; int tmp; oldfs = get_fs(); set_fs(get_ds()); - tmp = scsi_ioctl(dev, cmd, arg); + tmp = scsi_ioctl(sdev, cmd, arg); set_fs(oldfs); return tmp; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 69d586a6ebd..6d17684726e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -95,7 +95,6 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; - unsigned long flags; SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd)); @@ -134,10 +133,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * Decrement the counters, since these commands are no longer * active on the host/device. */ - spin_lock_irqsave(device->request_queue->queue_lock, flags); - device->device_busy--; - spin_unlock_irqrestore(device->request_queue->queue_lock, flags); - scsi_host_busy_dec_and_test(host, device); + scsi_device_unbusy(device); /* * Insert this command at the head of the queue for it's device. @@ -314,6 +310,21 @@ void scsi_setup_cmd_retry(struct scsi_cmnd *cmd) cmd->underflow = cmd->old_underflow; } +void scsi_device_unbusy(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = sdev->host; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + shost->host_busy--; + if (unlikely(shost->in_recovery && shost->host_failed)) + scsi_eh_wakeup(shost); + spin_unlock(shost->host_lock); + spin_lock(&sdev->sdev_lock); + sdev->device_busy--; + spin_unlock_irqrestore(&sdev->sdev_lock, flags); +} + /* * Called for single_lun devices on IO completion. Clear starget_sdev_user, * and call blk_run_queue for all the scsi_devices on the target - @@ -730,17 +741,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, * can choose a block to remap, etc. */ if (driver_byte(result) != 0) { - if (suggestion(result) == SUGGEST_REMAP) { -#ifdef REMAP - /* - * Not yet implemented. A read will fail after being remapped, - * a write will call the strategy routine again. - */ - if (cmd->device->remap) { - result = 0; - } -#endif - } if ((cmd->sense_buffer[0] & 0x7f) == 0x70) { /* * If the device is in the process of becoming ready, @@ -945,6 +945,18 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) cmd = req->special; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { /* + * Just check to see if the device is online. If + * it isn't, we refuse to process ordinary commands + * (we will allow specials just in case someone needs + * to send a command to an offline device without bringing + * it back online) + */ + if(!sdev->online) { + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n", + sdev->host->host_no, sdev->id, sdev->lun); + return BLKPREP_KILL; + } + /* * Now try and find a command block that we can use. */ if (!req->special) { diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c dissimilarity index 90% index efb2ca75dba..7803089da53 100644 --- a/drivers/scsi/scsi_module.c +++ b/drivers/scsi/scsi_module.c @@ -1,71 +1,73 @@ -/* - * scsi_module.c Copyright (1994, 1995) Eric Youngdale. - * - * Support for loading low-level scsi drivers using the linux kernel loadable - * module interface. - * - * To use, the host adapter should first define and initialize the variable - * driver_template (datatype Scsi_Host_Template), and then include this file. - * This should also be wrapped in a #ifdef MODULE/#endif. - * - * The low -level driver must also define a release function which will - * free any irq assignments, release any dma channels, release any I/O - * address space that might be reserved, and otherwise clean up after itself. - * The idea is that the same driver should be able to be reloaded without - * any difficulty. This makes debugging new drivers easier, as you should - * be able to load the driver, test it, unload, modify and reload. - * - * One *very* important caveat. If the driver may need to do DMA on the - * ISA bus, you must have unchecked_isa_dma set in the device template, - * even if this might be changed during the detect routine. This is - * because the shpnt structure will be allocated in a special way so that - * it will be below the appropriate DMA limit - thus if your driver uses - * the hostdata field of shpnt, and the board must be able to access this - * via DMA, the shpnt structure must be in a DMA accessible region of - * memory. This comment would be relevant for something like the buslogic - * driver where there are many boards, only some of which do DMA onto the - * ISA bus. There is no convenient way of specifying whether the host - * needs to be in a ISA DMA accessible region of memory when you call - * scsi_register. - */ - -#include -#include - -static int __init init_this_scsi_driver(void) -{ - driver_template.module = THIS_MODULE; - scsi_register_host(&driver_template); - if (driver_template.present) - return 0; - - scsi_unregister_host(&driver_template); - return -ENODEV; -} - -static void __exit exit_this_scsi_driver(void) -{ - scsi_unregister_host(&driver_template); -} - -module_init(init_this_scsi_driver); -module_exit(exit_this_scsi_driver); - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ +/* + * Copyright (C) 2003 Christoph Hellwig. + * Released under GPL v2. + * + * Support for old-style host templates. + * + * NOTE: Do not use this for new drivers ever. + */ + +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" + + +static int __init init_this_scsi_driver(void) +{ + struct scsi_host_template *sht = &driver_template; + struct Scsi_Host *shost; + struct list_head *l; + int error; + + if (!sht->release) { + printk(KERN_ERR + "scsi HBA driver %s didn't set a release method.\n", + sht->name); + return -EINVAL; + } + + sht->module = THIS_MODULE; + INIT_LIST_HEAD(&sht->legacy_hosts); + + sht->detect(sht); + if (!sht->present) + return -ENODEV; + + list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) { + error = scsi_add_host(shost, NULL); + if (error) + goto fail; + } + return 0; + fail: + l = &shost->sht_legacy_list; + while ((l = l->prev) != &sht->legacy_hosts) + scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list)); + return error; +} + +static void __exit exit_this_scsi_driver(void) +{ + struct scsi_host_template *sht = &driver_template; + struct Scsi_Host *shost, *s; + + list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) + scsi_remove_host(shost); + list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) + sht->release(shost); + + if (list_empty(&sht->legacy_hosts)) + return; + + printk(KERN_WARNING "%s did not call scsi_unregister\n", sht->name); + dump_stack(); + + list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) + scsi_unregister(shost); +} + +module_init(init_this_scsi_driver); +module_exit(exit_this_scsi_driver); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 3a091a0922e..6346005e64c 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -52,13 +52,6 @@ struct scsi_target { }; -/* hosts.c */ -extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); -extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); -extern struct Scsi_Host *scsi_host_lookup(unsigned short); -extern void scsi_host_put(struct Scsi_Host *); -extern void scsi_host_init(void); - /* scsi.c */ extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); extern int scsi_setup_command_freelist(struct Scsi_Host *shost); @@ -80,11 +73,13 @@ extern void scsi_exit_devinfo(void); extern void scsi_times_out(struct scsi_cmnd *cmd); extern void scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); +extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd); +extern void scsi_device_unbusy(struct scsi_device *sdev); extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_next_command(struct scsi_cmnd *cmd); extern void scsi_run_host_queues(struct Scsi_Host *shost); @@ -107,12 +102,11 @@ extern void scsi_exit_procfs(void); #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ -extern void scsi_scan_host(struct Scsi_Host *shost); -extern void scsi_forget_host(struct Scsi_Host *shost); +extern void scsi_scan_host(struct Scsi_Host *); +extern void scsi_forget_host(struct Scsi_Host *); extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); -extern void scsi_host_get(struct Scsi_Host *); -extern void scsi_rescan_device(struct device *dev); +extern void scsi_rescan_device(struct device *); /* scsi_sysfs.c */ extern int scsi_device_register(struct scsi_device *); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 9dfddb3e59a..c07f536454b 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -42,48 +42,15 @@ struct proc_dir_entry *proc_scsi; EXPORT_SYMBOL(proc_scsi); -/* Used if the driver currently has no own support for /proc/scsi */ -static int generic_proc_info(char *buffer, char **start, off_t offset, - int count, const char *(*info)(struct Scsi_Host *), - struct Scsi_Host *shost) -{ - int len, pos, begin = 0; - static const char noprocfs[] = - "The driver does not yet support the proc-fs\n"; - - if (info && shost) - len = sprintf(buffer, "%s\n", info(shost)); - else - len = sprintf(buffer, "%s\n", noprocfs); - - pos = len; - if (pos < offset) { - len = 0; - begin = pos; - } - - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > count) - len = count; - - return len; -} - static int proc_scsi_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { struct Scsi_Host *shost = data; int n; - if (shost->hostt->proc_info == NULL) - n = generic_proc_info(buffer, start, offset, length, - shost->hostt->info, shost); - else - n = shost->hostt->proc_info(shost, buffer, start, offset, - length, 0); - + n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0); *eof = (n < length); + return n; } @@ -95,8 +62,6 @@ static int proc_scsi_write_proc(struct file *file, const char *buf, char *page; char *start; - if (!shost->hostt->proc_info) - return -ENOSYS; if (count > PROC_BLOCK_SIZE) return -EOVERFLOW; @@ -114,10 +79,13 @@ out: void scsi_proc_host_add(struct Scsi_Host *shost) { - Scsi_Host_Template *sht = shost->hostt; + struct scsi_host_template *sht = shost->hostt; struct proc_dir_entry *p; char name[10]; + if (!sht->proc_info) + return; + if (!sht->proc_dir) { sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); if (!sht->proc_dir) { @@ -130,27 +98,29 @@ void scsi_proc_host_add(struct Scsi_Host *shost) sprintf(name,"%d", shost->host_no); p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - shost->hostt->proc_dir, proc_scsi_read, shost); + sht->proc_dir, proc_scsi_read, shost); if (!p) { printk(KERN_ERR "%s: Failed to register host %d in" "%s\n", __FUNCTION__, shost->host_no, - shost->hostt->proc_name); + sht->proc_name); return; } p->write_proc = proc_scsi_write_proc; p->owner = shost->hostt->module; - } void scsi_proc_host_rm(struct Scsi_Host *shost) { + struct scsi_host_template *sht = shost->hostt; char name[10]; - sprintf(name,"%d", shost->host_no); - remove_proc_entry(name, shost->hostt->proc_dir); - if (!shost->hostt->present) - remove_proc_entry(shost->hostt->proc_name, proc_scsi); + if (sht->proc_info) { + sprintf(name,"%d", shost->host_no); + remove_proc_entry(name, sht->proc_dir); + if (!sht->present) + remove_proc_entry(sht->proc_name, proc_scsi); + } } static int proc_print_scsidevice(struct device *dev, void *data) @@ -244,8 +214,8 @@ out: return error; } -static int proc_scsi_write(struct file *file, const char* buf, - size_t length, loff_t *ppos) +static ssize_t proc_scsi_write(struct file *file, const char __user *buf, + size_t length, loff_t *ppos) { int host, channel, id, lun; char *buffer, *p; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 61cdaa7591c..a798bdf9c44 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -72,29 +73,9 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS; static unsigned int max_scsi_luns = 1; #endif -#ifdef MODULE -MODULE_PARM(max_scsi_luns, "i"); -MODULE_PARM_DESC(max_scsi_luns, +module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(max_luns, "last scsi LUN (should be between 1 and 2^32-1)"); -#else - -static int __init scsi_luns_setup(char *str) -{ - unsigned int tmp; - - if (get_option(&str, &tmp) == 1) { - max_scsi_luns = tmp; - return 1; - } else { - printk(KERN_WARNING "scsi_luns_setup: usage max_scsi_luns=n " - "(n should be between 1 and 2^32-1)\n"); - return 0; - } -} - -__setup("max_scsi_luns=", scsi_luns_setup); - -#endif #ifdef CONFIG_SCSI_REPORT_LUNS /* @@ -106,29 +87,10 @@ __setup("max_scsi_luns=", scsi_luns_setup); */ static unsigned int max_scsi_report_luns = 128; -#ifdef MODULE -MODULE_PARM(max_scsi_report_luns, "i"); -MODULE_PARM_DESC(max_scsi_report_luns, +module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(max_report_luns, "REPORT LUNS maximum number of LUNS received (should be" " between 1 and 16384)"); -#else -static int __init scsi_report_luns_setup(char *str) -{ - unsigned int tmp; - - if (get_option(&str, &tmp) == 1) { - max_scsi_report_luns = tmp; - return 1; - } else { - printk(KERN_WARNING "scsi_report_luns_setup: usage" - " max_scsi_report_luns=n (n should be between 1" - " and 16384)\n"); - return 0; - } -} - -__setup("max_scsi_report_luns=", scsi_report_luns_setup); -#endif #endif /** @@ -141,7 +103,8 @@ __setup("max_scsi_report_luns=", scsi_report_luns_setup); * @sreq to unlock a device, storing the (unused) results into result. * Called for BLIST_KEY devices. **/ -static void scsi_unlock_floptical(Scsi_Request *sreq, unsigned char *result) +static void scsi_unlock_floptical(struct scsi_request *sreq, + unsigned char *result) { unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -154,8 +117,7 @@ static void scsi_unlock_floptical(Scsi_Request *sreq, unsigned char *result) scsi_cmd[5] = 0; sreq->sr_cmd_len = 0; sreq->sr_data_direction = SCSI_DATA_READ; - scsi_wait_req(sreq, (void *) scsi_cmd, (void *) result, 0x2a /* size */, - SCSI_TIMEOUT, 3); + scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3); } /** @@ -354,10 +316,10 @@ void scsi_free_sdev(struct scsi_device *sdev) * are copied to the Scsi_Device at @sreq->sr_device (sdev); * any flags value is stored in *@bflags. **/ -static void scsi_probe_lun(Scsi_Request *sreq, char *inq_result, +static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, int *bflags) { - Scsi_Device *sdev = sreq->sr_device; /* a bit ugly */ + struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int possible_inq_resp_len; @@ -522,7 +484,7 @@ static void scsi_set_name(struct scsi_device *sdev, char *inq_result) * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized **/ -static int scsi_add_lun(Scsi_Device *sdev, char *inq_result, int *bflags) +static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) { struct scsi_device *sdev_sibling; struct scsi_target *starget; @@ -579,8 +541,6 @@ static int scsi_add_lun(Scsi_Device *sdev, char *inq_result, int *bflags) printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type); } - sdev->random = (sdev->type == TYPE_TAPE) ? 0 : 1; - scsi_set_name(sdev, inq_result); print_inquiry(inq_result); @@ -623,8 +583,6 @@ static int scsi_add_lun(Scsi_Device *sdev, char *inq_result, int *bflags) sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - scsi_device_register(sdev); - /* * End driverfs/devfs code. */ @@ -687,11 +645,18 @@ static int scsi_add_lun(Scsi_Device *sdev, char *inq_result, int *bflags) sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED; sdev->use_10_for_rw = 1; - sdev->use_10_for_ms = 0; + sdev->use_10_for_ms = 1; if(sdev->host->hostt->slave_configure) sdev->host->hostt->slave_configure(sdev); + /* + * Ok, the device is now all set up, we can + * register it and tell the rest of the kernel + * about it. + */ + scsi_device_register(sdev); + return SCSI_SCAN_LUN_PRESENT; } diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c index 504f89a6eea..77cfb5ad322 100644 --- a/drivers/scsi/scsi_syms.c +++ b/drivers/scsi/scsi_syms.c @@ -31,10 +31,12 @@ */ EXPORT_SYMBOL(scsi_register_driver); EXPORT_SYMBOL(scsi_register_interface); -EXPORT_SYMBOL(scsi_register_host); -EXPORT_SYMBOL(scsi_unregister_host); +EXPORT_SYMBOL(scsi_host_alloc); EXPORT_SYMBOL(scsi_add_host); EXPORT_SYMBOL(scsi_remove_host); +EXPORT_SYMBOL(scsi_host_get); +EXPORT_SYMBOL(scsi_host_put); +EXPORT_SYMBOL(scsi_host_lookup); EXPORT_SYMBOL(scsi_register); EXPORT_SYMBOL(scsi_unregister); EXPORT_SYMBOL(scsicam_bios_param); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index ae390414c19..ea6949f890c 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -487,7 +487,7 @@ int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, } EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute); -void scsi_sysfs_release_attributes(struct SHT *hostt) +void scsi_sysfs_release_attributes(struct scsi_host_template *hostt) { if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs) kfree(hostt->sdev_attrs); diff --git a/drivers/scsi/scsi_typedefs.h b/drivers/scsi/scsi_typedefs.h new file mode 100644 index 00000000000..6c431323581 --- /dev/null +++ b/drivers/scsi/scsi_typedefs.h @@ -0,0 +1,6 @@ + +typedef struct scsi_host_template Scsi_Host_Template; +typedef struct scsi_device Scsi_Device; +typedef struct scsi_cmnd Scsi_Cmnd; +typedef struct scsi_request Scsi_Request; +typedef struct scsi_pointer Scsi_Pointer; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index cb572121f2b..60e26ebd374 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -76,6 +76,7 @@ struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; struct gendisk *disk; + unsigned int openers; /* protected by BKL for now, yuck */ sector_t capacity; /* size in 512-byte sectors */ u32 index; u8 media_present; @@ -87,7 +88,7 @@ struct scsi_disk { static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; -static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk); +static int sd_revalidate_disk(struct gendisk *disk); static void sd_rw_intr(struct scsi_cmnd * SCpnt); static int sd_probe(struct device *); @@ -95,7 +96,6 @@ static int sd_remove(struct device *); static void sd_shutdown(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); -static int sd_synchronize_cache(struct scsi_disk *, int); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); @@ -396,9 +396,10 @@ static int sd_open(struct inode *inode, struct file *filp) if (!sdev->online) goto error_out; - if (sdev->removable && sdev->access_count == 1) + if (!sdkp->openers++ && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); + } return 0; @@ -421,13 +422,15 @@ error_out: static int sd_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct scsi_device *sdev = scsi_disk(disk)->device; + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdev = sdkp->device; SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name)); - if (sdev->removable && sdev->access_count == 1) + if (!--sdkp->openers && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); + } /* * XXX and what if there are packets in flight and this close() @@ -566,7 +569,7 @@ static int sd_media_changed(struct gendisk *disk) * UNIT ATTENTION, or with same cartridge - GOOD STATUS. * * Drives that auto spin down. eg iomega jaz 1G, will be started - * by sd_spinup_disk() from sd_init_onedisk(), which happens whenever + * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever * sd_revalidate() is called. */ retval = -ENODEV; @@ -632,15 +635,6 @@ static void sd_rescan(struct device *dev) kfree(buffer); } -static int sd_revalidate_disk(struct gendisk *disk) -{ - struct scsi_disk *sdkp = scsi_disk(disk); - - sd_init_onedisk(sdkp, disk); - set_capacity(disk, sdkp->capacity); - return 0; -} - static struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, @@ -772,7 +766,7 @@ static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) } /* - * spinup disk - called only in sd_init_onedisk() + * spinup disk - called only in sd_revalidate_disk() */ static void sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, @@ -856,7 +850,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; - SRpnt->sr_data_direction = SCSI_DATA_READ; + SRpnt->sr_data_direction = SCSI_DATA_NONE; scsi_wait_req(SRpnt, (void *)cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); @@ -892,7 +886,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, } /* - * read disk capacity - called only in sd_init_onedisk() + * read disk capacity */ static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, @@ -1105,7 +1099,7 @@ sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, } /* - * read write protect setting, if possible - called only in sd_init_onedisk() + * read write protect setting, if possible - called only in sd_revalidate_disk() * called with buffer of length 512 */ static void @@ -1147,7 +1141,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, } /* - * sd_read_cache_type - called only from sd_init_onedisk() + * sd_read_cache_type - called only from sd_revalidate_disk() * called with buffer of length 512 */ static void @@ -1206,71 +1200,69 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, } /** - * sd_init_onedisk - called the first time a new disk is seen, + * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. - * @sdkp: pointer to associated struct scsi_disk object - * @dsk_nr: disk number within this driver (e.g. 0->/dev/sda, - * 1->/dev/sdb, etc) - * - * Note: this function is local to this driver. + * @disk: struct gendisk we care about **/ -static void -sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) +static int sd_revalidate_disk(struct gendisk *disk) { + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdp = sdkp->device; + struct scsi_request *sreq; unsigned char *buffer; - struct scsi_device *sdp; - struct scsi_request *SRpnt; - SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: disk=%s\n", disk->disk_name)); + SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); /* * If the device is offline, don't try and read capacity or any * of the other niceties. */ - sdp = sdkp->device; - if (sdp->online == FALSE) - return; + if (!sdp->online) + goto out; - SRpnt = scsi_allocate_request(sdp); - if (!SRpnt) { - printk(KERN_WARNING "(sd_init_onedisk:) Request allocation " + sreq = scsi_allocate_request(sdp); + if (!sreq) { + printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation " "failure.\n"); - return; + goto out; } - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); if (!buffer) { - printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation " + printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " "failure.\n"); - goto leave; + goto out_release_request; } /* defaults, until the device tells us otherwise */ + sdp->sector_size = 512; sdkp->capacity = 0; - sdkp->device->sector_size = 512; sdkp->media_present = 1; sdkp->write_prot = 0; sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp, disk->disk_name, SRpnt, buffer); + sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer); - if (sdkp->media_present) - sd_read_capacity(sdkp, disk->disk_name, SRpnt, buffer); - - if (sdp->removable && sdkp->media_present) - sd_read_write_protect_flag(sdkp, disk->disk_name, SRpnt, buffer); - /* without media there is no reason to ask; - moreover, some devices react badly if we do */ - if (sdkp->media_present) - sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer); + /* + * Without media there is no reason to ask; moreover, some devices + * react badly if we do. + */ + if (sdkp->media_present) { + sd_read_capacity(sdkp, disk->disk_name, sreq, buffer); + if (sdp->removable) + sd_read_write_protect_flag(sdkp, disk->disk_name, + sreq, buffer); + sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer); + } - SRpnt->sr_device->remap = 1; - - leave: - scsi_release_request(SRpnt); - + set_capacity(disk, sdkp->capacity); kfree(buffer); + + out_release_request: + scsi_release_request(sreq); + out: + return 0; } /** @@ -1329,6 +1321,7 @@ static int sd_probe(struct device *dev) sdkp->driver = &sd_template; sdkp->disk = gd; sdkp->index = index; + sdkp->openers = 0; gd->major = sd_major(index >> 4); gd->first_minor = (index & 15) << 4; @@ -1344,16 +1337,16 @@ static int sd_probe(struct device *dev) strcpy(gd->devfs_name, sdp->devfs_name); - sd_init_onedisk(sdkp, gd); + gd->private_data = &sdkp->driver; + + sd_revalidate_disk(gd); gd->driverfs_dev = &sdp->sdev_driverfs_dev; gd->flags = GENHD_FL_DRIVERFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; - gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; - set_capacity(gd, sdkp->capacity); dev_set_drvdata(dev, sdkp); add_disk(gd); @@ -1400,16 +1393,57 @@ static int sd_remove(struct device *dev) return 0; } +/* + * Send a SYNCHRONIZE CACHE instruction down to the device through + * the normal SCSI command structure. Wait for the command to + * complete. + */ static void sd_shutdown(struct device *dev) { + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); + struct scsi_request *sreq; + int retries, res; - if (sdkp->WCE) { - printk(KERN_NOTICE "Synchronizing SCSI cache: "); - sd_synchronize_cache(sdkp, 1); - printk("\n"); + if (!sdp->online || !sdkp->WCE) + return; + + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ", + sdkp->disk->disk_name); + + sreq = scsi_allocate_request(sdp); + if (!sreq) { + printk("FAILED\n No memory for request\n"); + return; } -} + + sreq->sr_data_direction = SCSI_DATA_NONE; + for (retries = 3; retries > 0; --retries) { + unsigned char cmd[10] = { 0 }; + + cmd[0] = SYNCHRONIZE_CACHE; + /* + * Leave the rest of the command zero to indicate + * flush everything. + */ + scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); + if (sreq->sr_result == 0) + break; + } + + res = sreq->sr_result; + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + print_req_sense("sd", sreq); + } + + scsi_release_request(sreq); + printk("\n"); +} /** * init_sd - entry point for this driver (both when built in or when @@ -1449,60 +1483,6 @@ static void __exit exit_sd(void) unregister_blkdev(sd_major(i), "sd"); } -/* send a SYNCHRONIZE CACHE instruction down to the device through the - * normal SCSI command structure. Wait for the command to complete (must - * have user context) */ -static int sd_synchronize_cache(struct scsi_disk *sdkp, int verbose) -{ - struct scsi_request *SRpnt; - struct scsi_device *SDpnt = sdkp->device; - int retries, the_result; - - if (!SDpnt->online) - return 0; - - if (verbose) - printk("%s ", sdkp->disk->disk_name); - - SRpnt = scsi_allocate_request(SDpnt); - if(!SRpnt) { - if(verbose) - printk("FAILED\n No memory for request\n"); - return 0; - } - - SRpnt->sr_data_direction = SCSI_DATA_NONE; - - for(retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* leave the rest of the command zero to indicate - * flush everything */ - scsi_wait_req(SRpnt, (void *)cmd, NULL, 0, - SD_TIMEOUT, SD_MAX_RETRIES); - - if(SRpnt->sr_result == 0) - break; - } - - the_result = SRpnt->sr_result; - if(verbose) { - if(the_result != 0) { - printk("FAILED\n status = %x, message = %02x, host = %d, driver = %02x\n ", - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result)); - if (driver_byte(the_result) & DRIVER_SENSE) - print_req_sense("sd", SRpnt); - - } - } - scsi_release_request(SRpnt); - return (the_result == 0); -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Eric Youngdale"); MODULE_DESCRIPTION("SCSI disk (sd) driver"); diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index dc9ed0b9877..ba64efe108e 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -729,13 +729,6 @@ static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmn return 0; } -static int seagate_st0x_command(Scsi_Cmnd * SCpnt) -{ - return internal_command (SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd, - SCpnt->request_buffer, SCpnt->request_bufflen, - (int) NO_RECONNECT); -} - static int internal_command (unsigned char target, unsigned char lun, const void *cmnd, void *buff, int bufflen, int reselect) { @@ -1704,7 +1697,6 @@ static Scsi_Host_Template driver_template = { .detect = seagate_st0x_detect, .release = seagate_st0x_release, .info = seagate_st0x_info, - .command = seagate_st0x_command, .queuecommand = seagate_st0x_queue_command, .eh_abort_handler = seagate_st0x_abort, .eh_bus_reset_handler = seagate_st0x_bus_reset, diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index 0614b041ddb..9eea1210daa 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -121,6 +121,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, hostdata->differential = differential; hostdata->clock = clock; hostdata->chip710 = 1; + NCR_700_set_io_mapped(hostdata); /* and register the chip */ if((host = NCR_700_detect(&sim710_driver_template, hostdata)) == NULL) { @@ -143,7 +144,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, return 0; out_unregister: - scsi_unregister(host); + scsi_host_put(host); out_release: release_region(host->base, 64); out_free: @@ -294,12 +295,17 @@ sim710_eisa_probe(struct device *dev) unsigned char irq, differential = 0, scsi_id = 7; if(strcmp(edev->id.sig, "HWP0C80") == 0) { + __u8 val; eisa_irqs = eisa_hwp_irqs; irq_index = (inb(io_addr + 0xc85) & 0x7) - 1; -#if 0 - /* this doesn't seem to work at the moment */ - scsi_id = ffs(inb(io_addr + 0x4)); -#endif + + val = inb(io_addr + 0x4); + scsi_id = ffs(val) - 1; + + if(scsi_id > 7 || (val & ~(1<name); + scsi_id = 7; + } } else { eisa_irqs = eisa_cpq_irqs; irq_index = inb(io_addr + 0xc88) & 0x07; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index c2c682a1481..df7e1b4964c 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -524,7 +524,6 @@ static int sr_probe(struct device *dev) sprintf(cd->cdi.name, "sr%d", minor); sdev->sector_size = 2048; /* A guess, just in case */ - sdev->remap = 1; /* FIXME: need to handle a get_capabilities failure properly ?? */ get_capabilities(cd); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index f6e1e006796..a8010099008 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -12,13 +12,12 @@ Copyright 1992 - 2003 Kai Makisara email Kai.Makisara@kolumbus.fi - Last modified: Sun Apr 13 10:17:18 2003 by makisara Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20030413"; +static char *verstr = "20030622"; #include @@ -1555,6 +1554,7 @@ static ssize_t } } else { filp->f_pos -= do_count; + count += do_count; STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); } @@ -3674,22 +3674,6 @@ __setup("st=", st_setup); #endif -/* Driverfs file support */ -static ssize_t st_device_kdev_read(struct device *dev, char *page) -{ - kdev_t kdev; - kdev.value=(unsigned long)dev->driver_data; - return sprintf(page, "%x\n",kdev.value); -} -static DEVICE_ATTR(kdev,S_IRUGO,st_device_kdev_read,NULL); - -static ssize_t st_device_type_read(struct device *ev, char * page) -{ - return sprintf (page, "CHR\n"); -} -static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL); - - static struct file_operations st_fops = { .owner = THIS_MODULE, diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 7c44fc01f78..b6320e655f1 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -413,7 +413,6 @@ static Scsi_Host_Template driver_template = { .slave_alloc = esp_slave_alloc, .slave_destroy = esp_slave_destroy, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index b2b47b00ec9..e7d971c5218 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -787,20 +787,6 @@ int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) return 0; } -static void internal_done(Scsi_Cmnd *SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int sym53c416_command(Scsi_Cmnd *SCpnt) -{ - sym53c416_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while(!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - static int sym53c416_abort(Scsi_Cmnd *SCpnt) { return FAILED; @@ -880,7 +866,6 @@ static Scsi_Host_Template driver_template = { .name = "Symbios Logic 53c416", .detect = sym53c416_detect, .info = sym53c416_info, - .command = sym53c416_command, .queuecommand = sym53c416_queuecommand, .eh_abort_handler = sym53c416_abort, .eh_host_reset_handler =sym53c416_host_reset, diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index 3e6c05a08d5..ff5542ed390 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -280,6 +280,16 @@ int __init t128_detect(Scsi_Host_Template * tpnt){ return count; } +static int t128_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) * @@ -403,6 +413,7 @@ MODULE_LICENSE("GPL"); static Scsi_Host_Template driver_template = { .name = "Trantor T128/T128F/T228", .detect = t128_detect, + .release = t128_release, .queuecommand = t128_queue_command, .eh_abort_handler = t128_abort, .eh_bus_reset_handler = t128_bus_reset, diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 0998f4950cc..868e50a5cf5 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1,6 +1,36 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 + * + Update for new IRQ API. + * + Use "goto" when appropriate. + * + Drop u14-34f.h. + * + Update for new module_param API. + * + Module parameters can now be specified only in the + * same format as the kernel boot options. + * + * boot option old module param + * ----------- ------------------ + * addr,... io_port=addr,... + * lc:[y|n] linked_comm=[1|0] + * mq:xx max_queue_depth=xx + * tm:[0|1|2] tag_mode=[0|1|2] + * et:[y|n] ext_tran=[1|0] + * of:[y|n] have_old_firmware=[1|0] + * + * A valid example using the new parameter format is: + * modprobe u14-34f "u14-34f=0x340,0x330,lc:y,tm:0,mq:4" + * + * which is equivalent to the old format: + * modprobe u14-34f io_port=0x340,0x330 linked_comm=1 tag_mode=0 \ + * max_queue_depth=4 + * + * With actual module code, u14-34f and u14_34f are equivalent + * as module parameter names. + * + * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 + * + Release irq before calling scsi_register. + * * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 * + Release driver_lock before calling scsi_register. * @@ -221,7 +251,7 @@ * * Multiple U14F and/or U34F host adapters are supported. * - * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -375,31 +405,8 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#include - -#ifndef LinuxVersionCode -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#endif - -#define MAX_INT_PARAM 10 - -#if defined(MODULE) -#include - -MODULE_PARM(boot_options, "s"); -MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); -MODULE_PARM(linked_comm, "i"); -MODULE_PARM(have_old_firmware, "i"); -MODULE_PARM(link_statistics, "i"); -MODULE_PARM(max_queue_depth, "i"); -MODULE_PARM(tag_mode, "i"); -MODULE_PARM(ext_tran, "i"); -MODULE_AUTHOR("Dario Ballabio"); - -#endif - +#include #include -#include #include #include #include @@ -408,20 +415,42 @@ MODULE_AUTHOR("Dario Ballabio"); #include #include #include +#include #include -#include #include #include #include #include #include - +#include "scsi.h" +#include "hosts.h" #include #include -#include "scsi.h" -#include "hosts.h" -#include "u14-34f.h" +static int u14_34f_detect(Scsi_Host_Template *); +static int u14_34f_release(struct Scsi_Host *); +static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int u14_34f_eh_abort(Scsi_Cmnd *); +static int u14_34f_eh_host_reset(Scsi_Cmnd *); +static int u14_34f_bios_param(struct scsi_device *, struct block_device *, + sector_t, int *); +static int u14_34f_slave_configure(Scsi_Device *); + +static Scsi_Host_Template driver_template = { + .name = "UltraStor 14F/34F rev. 8.10.00 ", + .detect = u14_34f_detect, + .release = u14_34f_release, + .queuecommand = u14_34f_queuecommand, + .eh_abort_handler = u14_34f_eh_abort, + .eh_device_reset_handler = NULL, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = u14_34f_eh_host_reset, + .bios_param = u14_34f_bios_param, + .slave_configure = u14_34f_slave_configure, + .this_id = 7, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING + }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" @@ -610,7 +639,6 @@ static int do_trace = FALSE; static int setup_done = FALSE; static int link_statistics; static int ext_tran = FALSE; -static char *boot_options; #if defined(HAVE_OLD_UX4F_FIRMWARE) static int have_old_firmware = TRUE; @@ -636,6 +664,24 @@ static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS; static int max_queue_depth = MAX_CMD_PER_LUN; #endif +#define MAX_INT_PARAM 10 +#define MAX_BOOT_OPTIONS_SIZE 256 +static char boot_options[MAX_BOOT_OPTIONS_SIZE]; + +#if defined(MODULE) +#include +#include + +module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); +MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \ +"option." \ +" Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\""); +MODULE_AUTHOR("Dario Ballabio"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver"); + +#endif + static int u14_34f_slave_configure(Scsi_Device *dev) { int j, tqd, utqd; char *tag_suffix, *link_suffix; @@ -802,24 +848,20 @@ static int port_detect \ sprintf(name, "%s%d", driver_name, j); - if(!request_region(port_base, REGION_SIZE, driver_name)) { + if (!request_region(port_base, REGION_SIZE, driver_name)) { #if defined(DEBUG_DETECT) printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); #endif - return FALSE; + goto fail; } - if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) { - release_region(port_base, REGION_SIZE); - return FALSE; - } + spin_lock_irq(&driver_lock); + + if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) goto freelock; in_byte = inb(port_base + REG_PRODUCT_ID2); - if ((in_byte & 0xf0) != PRODUCT_ID2) { - release_region(port_base, REGION_SIZE); - return FALSE; - } + if ((in_byte & 0xf0) != PRODUCT_ID2) goto freelock; *(char *)&config_1 = inb(port_base + REG_CONFIG1); *(char *)&config_2 = inb(port_base + REG_CONFIG2); @@ -833,16 +875,13 @@ static int port_detect \ SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), driver_name, (void *) &sha[j])) { printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (subversion == ISA && request_dma(dma_channel, driver_name)) { printk("%s: unable to allocate DMA channel %u, detaching.\n", name, dma_channel); - free_irq(irq, &sha[j]); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freeirq; } if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING; @@ -853,13 +892,7 @@ static int port_detect \ if (sh[j] == NULL) { printk("%s: unable to register host, detaching.\n", name); - - free_irq(irq, &sha[j]); - - if (subversion == ISA) free_dma(dma_channel); - - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } sh[j]->io_port = port_base; @@ -938,6 +971,8 @@ static int port_detect \ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); else sprintf(dma_name, "DMA %u", dma_channel); + spin_unlock_irq(&driver_lock); + for (i = 0; i < sh[j]->can_queue; i++) HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); @@ -947,8 +982,7 @@ static int port_detect \ sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - u14_34f_release(sh[j]); - return FALSE; + goto release; } if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) @@ -960,7 +994,7 @@ static int port_detect \ tag_mode = TAG_ORDERED; if (j == 0) { - printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n"); + printk("UltraStor 14F/34F: Copyright (C) 1994-2003 Dario Ballabio.\n"); printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n", driver_name, YESNO(have_old_firmware), tag_mode, YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); @@ -979,6 +1013,20 @@ static int port_detect \ BN(j), i, sh[j]->this_id); return TRUE; + +freedma: + if (subversion == ISA) free_dma(dma_channel); +freeirq: + free_irq(irq, &sha[j]); +freelock: + spin_unlock_irq(&driver_lock); + release_region(port_base, REGION_SIZE); +fail: + return FALSE; + +release: + u14_34f_release(sh[j]); + return FALSE; } static void internal_setup(char *str, int *ints) { @@ -1034,13 +1082,10 @@ static int option_setup(char *str) { static int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; - unsigned long spin_flags; - - spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "u14-34f"; - if(boot_options) option_setup(boot_options); + if(strlen(boot_options)) option_setup(boot_options); #if defined(MODULE) /* io_port could have been modified when loading as a module */ @@ -1060,7 +1105,6 @@ static int u14_34f_detect(Scsi_Host_Template *tpnt) { } num_boards = j; - spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -1680,7 +1724,7 @@ static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j, } -static void ihdlr(int irq, unsigned int j) { +static irqreturn_t ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg, ret; struct mscp *spp, *cpp; @@ -1689,7 +1733,7 @@ static void ihdlr(int irq, unsigned int j) { panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq); /* Check if this board need to be serviced */ - if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return; + if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none; HD(j)->iocount++; @@ -1701,7 +1745,7 @@ static void ihdlr(int irq, unsigned int j) { outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); - return; + goto none; } ret = inl(sh[j]->io_port + REG_ICM); @@ -1721,23 +1765,23 @@ static void ihdlr(int irq, unsigned int j) { spp = cpp; #if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; #endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; - return; + goto handled; } else if (HD(j)->cp_stat[i] == LOCKED) { HD(j)->cp_stat[i] = FREE; printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == FREE) { printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == IN_RESET) printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); @@ -1887,23 +1931,25 @@ static void ihdlr(int irq, unsigned int j) { if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, HD(j)->iocount); - return; +handled: + return IRQ_HANDLED; +none: + return IRQ_NONE; } static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) -{ + struct pt_regs *regs) { unsigned int j; unsigned long spin_flags; + irqreturn_t ret; /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; + if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ihdlr(irq, j); + ret = ihdlr(irq, j); spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return IRQ_HANDLED; + return ret; } static int u14_34f_release(struct Scsi_Host *shpnt) { @@ -1930,22 +1976,8 @@ static int u14_34f_release(struct Scsi_Host *shpnt) { return FALSE; } -static Scsi_Host_Template driver_template = { - .name = "UltraStor 14F/34F rev. " U14_34F_VERSION " ", - .detect = u14_34f_detect, - .release = u14_34f_release, - .queuecommand = u14_34f_queuecommand, - .eh_abort_handler = u14_34f_eh_abort, - .eh_host_reset_handler = u14_34f_eh_host_reset, - .bios_param = u14_34f_bios_param, - .slave_configure = u14_34f_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; #include "scsi_module.c" #ifndef MODULE __setup("u14-34f=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h deleted file mode 100644 index 9b57ef38f5e..00000000000 --- a/drivers/scsi/u14-34f.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * u14-34f.h - used by the low-level driver for UltraStor 14F/34F - */ - -static int u14_34f_detect(Scsi_Host_Template *); -static int u14_34f_release(struct Scsi_Host *); -static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int u14_34f_eh_abort(Scsi_Cmnd *); -static int u14_34f_eh_host_reset(Scsi_Cmnd *); -static int u14_34f_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int u14_34f_slave_configure(Scsi_Device *); - -#define U14_34F_VERSION "8.03.00" diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 97819e63383..5e18bef93cd 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -643,6 +643,18 @@ static int ultrastor_detect(Scsi_Host_Template * tpnt) return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt); } +static int ultrastor_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static const char *ultrastor_info(struct Scsi_Host * shpnt) { static char buf[64]; @@ -1177,6 +1189,7 @@ MODULE_LICENSE("GPL"); static Scsi_Host_Template driver_template = { .name = "UltraStor 14F/24F/34F", .detect = ultrastor_detect, + .release = ultrastor_release, .info = ultrastor_info, .queuecommand = ultrastor_queuecommand, .eh_abort_handler = ultrastor_abort, diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 8e3b4725364..591d397ac96 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1031,14 +1031,6 @@ static int make_code(unsigned hosterr, unsigned scsierr) return (scsierr | (hosterr << 16)); } - -static void wd7000_scsi_done(Scsi_Cmnd * SCpnt) -{ - dprintk("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt); - SCpnt->SCp.phase = 0; -} - - #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs) @@ -1188,20 +1180,6 @@ static int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) return 0; } - -static int wd7000_command(Scsi_Cmnd * SCpnt) -{ - wd7000_queuecommand(SCpnt, wd7000_scsi_done); - - while (SCpnt->SCp.phase > 0) { - cpu_relax(); - barrier(); /* phase counts scbs down to 0 */ - } - - return (SCpnt->result); -} - - static int wd7000_diagnostics(Adapter * host, int code) { static IcbDiag icb = { ICB_OP_DIAGNOSTICS }; @@ -1616,6 +1594,15 @@ static int wd7000_detect(Scsi_Host_Template * tpnt) return (present); } +static int wd7000_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} /* * I have absolutely NO idea how to do an abort with the WD7000... @@ -1722,7 +1709,7 @@ static Scsi_Host_Template driver_template = { .proc_info = wd7000_proc_info, .name = "Western Digital WD-7000", .detect = wd7000_detect, - .command = wd7000_command, + .release = wd7000_release, .queuecommand = wd7000_queuecommand, .eh_bus_reset_handler = wd7000_bus_reset, .eh_device_reset_handler = wd7000_device_reset, diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index f44dba00d35..d21396e514e 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -315,19 +315,6 @@ static const struct pnp_device_id pnp_dev_table[] = { MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -static inline void avoid_irq_share(struct pnp_dev *dev) -{ - unsigned int map = 0x1FF8; - struct pnp_irq *irq; - struct pnp_resources *res = dev->possible; - - serial8250_get_irq_map(&map); - - for ( ; res; res = res->dep) - for (irq = res->irq; irq; irq = irq->next) - irq->map = map; -} - static char *modem_names[] __devinitdata = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", @@ -346,6 +333,29 @@ static int __devinit check_name(char *name) return 0; } +static int __devinit check_resources(struct pnp_option *option) +{ + struct pnp_option *tmp; + if (!option) + return 0; + + for (tmp = option; tmp; tmp = tmp->next) { + struct pnp_port *port; + for (port = tmp->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || +#ifdef CONFIG_X86_PC9800 + (port->min == 0x8b0) || +#endif + (port->min == 0x3e8))) + return 1; + } + + return 0; +} + /* * Given a complete unknown PnP device, try to use some heuristics to * detect modems. Currently use such heuristic set: @@ -357,30 +367,16 @@ static int __devinit check_name(char *name) * PnP modems, alternatively we must hardcode all modems in pnp_devices[] * table. */ -static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags) +static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) { - struct pnp_resources *res = dev->possible; - struct pnp_resources *resa; - if (!(check_name(dev->dev.name) || (dev->card && check_name(dev->card->dev.name)))) return -ENODEV; - if (!res) - return -ENODEV; + if (check_resources(dev->independent)) + return 0; - for (resa = res->dep; resa; resa = resa->dep) { - struct pnp_port *port; - for (port = res->port; port; port = port->next) - if ((port->size == 8) && - ((port->min == 0x2f8) || - (port->min == 0x3f8) || - (port->min == 0x2e8) || -#ifdef CONFIG_X86_PC9800 - (port->min == 0x8b0) || -#endif - (port->min == 0x3e8))) - return 0; - } + if (check_resources(dev->dependent)) + return 0; return -ENODEV; } @@ -395,8 +391,6 @@ serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) if (ret < 0) return ret; } - if (flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); memset(&serial_req, 0, sizeof(serial_req)); serial_req.irq = pnp_irq(dev,0); serial_req.port = pnp_port_start(dev, 0); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e7cdf7141ab..02dc9df44ba 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -77,7 +77,15 @@ config SERIAL_8250_CS a module, say M here and read . If unsure, say N. -config SERIAL_HCDP +config SERIAL_8250_ACPI + bool "8250/16550 device discovery via ACPI namespace" + default y if IA64 + depends on ACPI_BUS + ---help--- + If you wish to enable serial port discovery via the ACPI + namespace, say Y here. If unsure, say N. + +config SERIAL_8250_HCDP bool "8250/16550 device discovery support via EFI HCDP table" depends on IA64 ---help--- diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 11927fe76bb..e65afa7a8f7 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -8,7 +8,8 @@ serial-8250-y := serial-8250-$(CONFIG_GSC) += 8250_gsc.o serial-8250-$(CONFIG_PCI) += 8250_pci.o serial-8250-$(CONFIG_PNP) += 8250_pnp.o -serial-8250-$(CONFIG_SERIAL_HCDP) += 8250_hcdp.o +serial-8250-$(CONFIG_SERIAL_8250_HCDP) += 8250_hcdp.o +serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o obj-$(CONFIG_SERIAL_CORE) += core.o obj-$(CONFIG_SERIAL_21285) += 21285.o diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index fe9c12cc0b3..74d68c51b95 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -7247,8 +7247,8 @@ static int ixj_get_status_proc(char *buf) len += sprintf(buf + len, "\n%s", ixj_h_rcsid); len += sprintf(buf + len, "\n%s", ixjuser_h_rcsid); len += sprintf(buf + len, "\nDriver version %i.%i.%i", IXJ_VER_MAJOR, IXJ_VER_MINOR, IXJ_BLD_VER); - len += sprintf(buf + len, "\nsizeof IXJ struct %d bytes", sizeof(IXJ)); - len += sprintf(buf + len, "\nsizeof DAA struct %d bytes", sizeof(DAA_REGS)); + len += sprintf(buf + len, "\nsizeof IXJ struct %Zd bytes", sizeof(IXJ)); + len += sprintf(buf + len, "\nsizeof DAA struct %Zd bytes", sizeof(DAA_REGS)); len += sprintf(buf + len, "\nUsing old telephony API"); len += sprintf(buf + len, "\nDebug Level %d\n", ixjdebug); diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h index 44ebbce3443..6d46a4e848d 100644 --- a/drivers/telephony/ixj.h +++ b/drivers/telephony/ixj.h @@ -1213,7 +1213,7 @@ typedef struct { #endif char *read_buffer, *read_buffer_end; char *read_convert_buffer; - unsigned int read_buffer_size; + size_t read_buffer_size; unsigned int read_buffer_ready; #if LINUX_VERSION_CODE < 0x020400 struct wait_queue *write_q; @@ -1222,7 +1222,7 @@ typedef struct { #endif char *write_buffer, *write_buffer_end; char *write_convert_buffer; - unsigned int write_buffer_size; + size_t write_buffer_size; unsigned int write_buffers_empty; unsigned long drybuffer; char *write_buffer_rp, *write_buffer_wp; @@ -1281,7 +1281,7 @@ typedef struct { unsigned char fskcnt; unsigned int cidsize; unsigned int cidcnt; - unsigned pstn_cid_received; + unsigned long pstn_cid_received; PHONE_CID cid; PHONE_CID cid_send; unsigned long pstn_ring_int; diff --git a/drivers/usb/Makefile.lib b/drivers/usb/Makefile.lib index 78bfdd1ad89..26e36d9c653 100644 --- a/drivers/usb/Makefile.lib +++ b/drivers/usb/Makefile.lib @@ -1,3 +1,4 @@ +obj-$(CONFIG_USB_AX8817X) += crc32.o obj-$(CONFIG_USB_CATC) += crc32.o obj-$(CONFIG_USB_SPEEDTOUCH) += crc32.o obj-$(CONFIG_USB_USBNET) += crc32.o diff --git a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c index b59a67471af..da94bc8a931 100644 --- a/drivers/usb/class/audio.c +++ b/drivers/usb/class/audio.c @@ -541,7 +541,7 @@ static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int si pgrem = rem; memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->wrptr += pgrem; if (db->wrptr >= db->dmasize) db->wrptr = 0; @@ -564,14 +564,14 @@ static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size) pgrem = rem; memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->rdptr += pgrem; if (db->rdptr >= db->dmasize) db->rdptr = 0; } } -static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size) +static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size) { unsigned int pgrem, rem; @@ -589,14 +589,14 @@ static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *b if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; } } -static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size) +static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size) { unsigned int pgrem, rem; @@ -614,7 +614,7 @@ static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; @@ -2010,7 +2010,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); info.modify_counter = ms->modcnt; - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return 0; } @@ -2018,7 +2018,7 @@ static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsign _old_mixer_info info; strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return 0; } @@ -2140,7 +2140,7 @@ static int drain_out(struct usb_audiodev *as, int nonblock) /* --------------------------------------------------------------------- */ -static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -2208,7 +2208,7 @@ static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, lof return ret; } -static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -2507,7 +2507,7 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int abinfo.fragstotal = as->usbout.dma.numfrag; abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift; spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) @@ -2520,7 +2520,7 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int abinfo.fragstotal = as->usbin.dma.numfrag; abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift; spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; @@ -2544,7 +2544,7 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int if (as->usbin.dma.mapped) as->usbin.dma.count &= as->usbin.dma.fragsize-1; spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) + if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -2558,7 +2558,7 @@ static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int if (as->usbout.dma.mapped) as->usbout.dma.count &= as->usbout.dma.fragsize-1; spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) + if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c index 84692c9a115..9fc03736202 100644 --- a/drivers/usb/class/bluetty.c +++ b/drivers/usb/class/bluetty.c @@ -484,7 +484,7 @@ static int bluetooth_write (struct tty_struct * tty, int from_user, const unsign retval = -ENOMEM; goto exit; } - if (copy_from_user (temp_buffer, buf, count)) { + if (copy_from_user (temp_buffer, (void __user *)buf, count)) { retval = -EFAULT; goto exit; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 4e9ee0d0078..8c0c35eb041 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -388,7 +388,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c count = (count > acm->writesize) ? acm->writesize : count; if (from_user) { - if (copy_from_user(acm->writeurb->transfer_buffer, buf, count)) + if (copy_from_user(acm->writeurb->transfer_buffer, (void __user *)buf, count)) return -EFAULT; } else memcpy(acm->writeurb->transfer_buffer, buf, count); @@ -548,7 +548,7 @@ static int acm_probe (struct usb_interface *intf, struct usb_host_config *cfacm; struct usb_host_interface *ifcom, *ifdata; struct usb_endpoint_descriptor *epctrl, *epread, *epwrite; - int readsize, ctrlsize, minor, i; + int readsize, ctrlsize, minor, i, j; unsigned char *buf; dev = interface_to_usbdev (intf); @@ -558,120 +558,123 @@ static int acm_probe (struct usb_interface *intf, dbg("probing config %d", cfacm->desc.bConfigurationValue); - if (cfacm->desc.bNumInterfaces != 2 || - usb_interface_claimed(cfacm->interface + 0) || - usb_interface_claimed(cfacm->interface + 1)) + for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) { + + if (usb_interface_claimed(cfacm->interface + j) || + usb_interface_claimed(cfacm->interface + j + 1)) continue; - ifcom = cfacm->interface[0].altsetting + 0; - ifdata = cfacm->interface[1].altsetting + 0; + ifcom = cfacm->interface[j].altsetting + 0; + ifdata = cfacm->interface[j + 1].altsetting + 0; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) { - ifcom = cfacm->interface[1].altsetting + 0; - ifdata = cfacm->interface[0].altsetting + 0; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) - continue; - } + if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) { + ifcom = cfacm->interface[j + 1].altsetting + 0; + ifdata = cfacm->interface[j].altsetting + 0; + if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) + continue; + } - if (ifcom->desc.bInterfaceClass != 2 || ifcom->desc.bInterfaceSubClass != 2 || - ifcom->desc.bInterfaceProtocol != 1 || ifcom->desc.bNumEndpoints < 1) - continue; + if (ifcom->desc.bInterfaceClass != 2 || ifcom->desc.bInterfaceSubClass != 2 || + ifcom->desc.bInterfaceProtocol < 1 || ifcom->desc.bInterfaceProtocol > 6 || + ifcom->desc.bNumEndpoints < 1) + continue; - epctrl = &ifcom->endpoint[0].desc; - epread = &ifdata->endpoint[0].desc; - epwrite = &ifdata->endpoint[1].desc; + epctrl = &ifcom->endpoint[0].desc; + epread = &ifdata->endpoint[0].desc; + epwrite = &ifdata->endpoint[1].desc; - if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || - (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || - ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) - continue; + if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || + (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || + ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) + continue; - if ((epread->bEndpointAddress & 0x80) != 0x80) { - epread = &ifdata->endpoint[1].desc; - epwrite = &ifdata->endpoint[0].desc; - } + if ((epread->bEndpointAddress & 0x80) != 0x80) { + epread = &ifdata->endpoint[1].desc; + epwrite = &ifdata->endpoint[0].desc; + } - usb_set_configuration(dev, cfacm->desc.bConfigurationValue); + usb_set_configuration(dev, cfacm->desc.bConfigurationValue); - for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); - if (acm_table[minor]) { - err("no more free acm devices"); - return -ENODEV; - } + for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); + if (acm_table[minor]) { + err("no more free acm devices"); + return -ENODEV; + } - if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { - err("out of memory"); - return -ENOMEM; - } - memset(acm, 0, sizeof(struct acm)); + if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { + err("out of memory"); + return -ENOMEM; + } + memset(acm, 0, sizeof(struct acm)); - ctrlsize = epctrl->wMaxPacketSize; - readsize = epread->wMaxPacketSize; - acm->writesize = epwrite->wMaxPacketSize; - acm->iface = cfacm->interface; - acm->minor = minor; - acm->dev = dev; + ctrlsize = epctrl->wMaxPacketSize; + readsize = epread->wMaxPacketSize; + acm->writesize = epwrite->wMaxPacketSize; + acm->iface = cfacm->interface + j; + acm->minor = minor; + acm->dev = dev; - INIT_WORK(&acm->work, acm_softint, acm); + INIT_WORK(&acm->work, acm_softint, acm); - if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { - err("out of memory"); - kfree(acm); - return -ENOMEM; - } + if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { + err("out of memory"); + kfree(acm); + return -ENOMEM; + } - acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->ctrlurb) { - err("out of memory"); - kfree(acm); - kfree(buf); - return -ENOMEM; - } - acm->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->readurb) { - err("out of memory"); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; - } - acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->writeurb) { - err("out of memory"); - usb_free_urb(acm->readurb); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; - } + acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->ctrlurb) { + err("out of memory"); + kfree(acm); + kfree(buf); + return -ENOMEM; + } + acm->readurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->readurb) { + err("out of memory"); + usb_free_urb(acm->ctrlurb); + kfree(acm); + kfree(buf); + return -ENOMEM; + } + acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->writeurb) { + err("out of memory"); + usb_free_urb(acm->readurb); + usb_free_urb(acm->ctrlurb); + kfree(acm); + kfree(buf); + return -ENOMEM; + } - usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), - buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), + buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); - usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf += ctrlsize, readsize, acm_read_bulk, acm); - acm->readurb->transfer_flags |= URB_NO_FSBR; + usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), + buf += ctrlsize, readsize, acm_read_bulk, acm); + acm->readurb->transfer_flags |= URB_NO_FSBR; - usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf += readsize, acm->writesize, acm_write_bulk, acm); - acm->writeurb->transfer_flags |= URB_NO_FSBR; + usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), + buf += readsize, acm->writesize, acm_write_bulk, acm); + acm->writeurb->transfer_flags |= URB_NO_FSBR; - info("ttyACM%d: USB ACM device", minor); + info("ttyACM%d: USB ACM device", minor); - acm_set_control(acm, acm->ctrlout); + acm_set_control(acm, acm->ctrlout); - acm->line.speed = cpu_to_le32(9600); - acm->line.databits = 8; - acm_set_line(acm, &acm->line); + acm->line.speed = cpu_to_le32(9600); + acm->line.databits = 8; + acm_set_line(acm, &acm->line); - usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm); - usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm); + usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm); + usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm); - tty_register_device(acm_tty_driver, minor, &intf->dev); + tty_register_device(acm_tty_driver, minor, &intf->dev); - acm_table[minor] = acm; - usb_set_intfdata (intf, acm); - return 0; + acm_table[minor] = acm; + usb_set_intfdata (intf, acm); + return 0; + } } return -EIO; diff --git a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c index b8e9a588575..29ce4d9f800 100644 --- a/drivers/usb/class/usb-midi.c +++ b/drivers/usb/class/usb-midi.c @@ -642,7 +642,7 @@ static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin) * **/ -static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usb_mididev *m = (struct usb_mididev *)file->private_data; struct midi_in_endpoint *ep = m->min.ep; @@ -725,7 +725,7 @@ static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff * **/ -static ssize_t usb_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usb_mididev *m = (struct usb_mididev *)file->private_data; ssize_t ret; diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 3adb70bcc60..4d607d53e25 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -296,13 +296,13 @@ static int usblp_check_status(struct usblp *usblp, int err) } status = *usblp->statusbuf; - if (~status & LP_PERRORP) { + + if (~status & LP_PERRORP) newerr = 3; - if (status & LP_POUTPA) - newerr = 1; - if (~status & LP_PSELECD) - newerr = 2; - } + if (status & LP_POUTPA) + newerr = 1; + if (~status & LP_PSELECD) + newerr = 2; if (newerr != err) info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); @@ -426,7 +426,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { struct usblp *usblp = file->private_data; int length, err, i; - unsigned char lpstatus, newChannel; + unsigned char newChannel; int status; int twoints[2]; int retval = 0; @@ -455,7 +455,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ - if (copy_to_user((unsigned char *) arg, + if (copy_to_user((void __user *) arg, usblp->device_id_string, (unsigned long) length)) { retval = -EFAULT; @@ -479,7 +479,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, twoints[1] |= (1<dev->bus->busnum; twoints[1] = usblp->dev->devnum; - if (copy_to_user((unsigned char *)arg, + if (copy_to_user((void __user *)arg, (unsigned char *)twoints, sizeof(twoints))) { retval = -EFAULT; @@ -560,7 +560,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, twoints[0] = usblp->dev->descriptor.idVendor; twoints[1] = usblp->dev->descriptor.idProduct; - if (copy_to_user((unsigned char *)arg, + if (copy_to_user((void __user *)arg, (unsigned char *)twoints, sizeof(twoints))) { retval = -EFAULT; @@ -578,13 +578,13 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, switch (cmd) { case LPGETSTATUS: - if (usblp_read_status(usblp, &lpstatus)) { + if (usblp_read_status(usblp, usblp->statusbuf)) { err("usblp%d: failed reading printer status", usblp->minor); retval = -EIO; goto done; } - status = lpstatus; - if (copy_to_user ((int *)arg, &status, sizeof(int))) + status = *usblp->statusbuf; + if (copy_to_user ((void __user *)arg, &status, sizeof(int))) retval = -EFAULT; break; @@ -597,7 +597,7 @@ done: return retval; } -static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); struct usblp *usblp = file->private_data; @@ -682,7 +682,7 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, return count; } -static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -858,8 +858,8 @@ static int usblp_probe(struct usb_interface *intf, } usblp->writebuf = usblp->readbuf = NULL; - usblp->writeurb->transfer_flags = URB_NO_DMA_MAP; - usblp->readurb->transfer_flags = URB_NO_DMA_MAP; + usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; /* Malloc write & read buffers. We somewhat wastefully * malloc both regardless of bidirectionality, because the * alternate setting can be changed later via an ioctl. */ diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 07f1c152116..63cfaf5789e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -459,7 +459,8 @@ static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) /* rh_timer protected by hcd_data_lock */ if (hcd->rh_timer.data || urb->status != -EINPROGRESS - || urb->transfer_buffer_length < len) { + || urb->transfer_buffer_length < len + || !HCD_IS_RUNNING (hcd->state)) { dev_dbg (hcd->controller, "not queuing rh status urb, stat %d\n", urb->status); @@ -489,11 +490,10 @@ static void rh_report_status (unsigned long ptr) local_irq_save (flags); spin_lock (&urb->lock); - /* do nothing if the hc is gone or the urb's been unlinked */ + /* do nothing if the urb's been unlinked */ if (!urb->dev || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == 0 - || !HCD_IS_RUNNING (hcd->state)) { + || (hcd = urb->dev->bus->hcpriv) == 0) { spin_unlock (&urb->lock); local_irq_restore (flags); return; @@ -1027,7 +1027,8 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) * valid and usb_buffer_{sync,unmap}() not be needed, since * they could clobber root hub response data. */ - urb->transfer_flags |= URB_NO_DMA_MAP; + urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); status = rh_urb_enqueue (hcd, urb); goto done; } @@ -1035,15 +1036,16 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) /* lower level hcd code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP) - && hcd->controller->dma_mask) { - if (usb_pipecontrol (urb->pipe)) + if (hcd->controller->dma_mask) { + if (usb_pipecontrol (urb->pipe) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->controller, urb->setup_packet, sizeof (struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0) + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) urb->transfer_dma = dma_map_single ( hcd->controller, urb->transfer_buffer, @@ -1410,12 +1412,14 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs // It would catch exit/unlink paths for all urbs. /* lower level hcd code should use *_dma exclusively */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { - if (usb_pipecontrol (urb->pipe)) + if (hcd->controller->dma_mask) { + if (usb_pipecontrol (urb->pipe) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) pci_unmap_single (hcd->pdev, urb->setup_dma, sizeof (struct usb_ctrlrequest), PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) pci_unmap_single (hcd->pdev, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3798e417b01..f844f0efddd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -461,7 +461,7 @@ static int hub_configure(struct usb_hub *hub, usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); hub->urb->transfer_dma = hub->buffer_dma; - hub->urb->transfer_flags |= URB_NO_DMA_MAP; + hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ret = usb_submit_urb(hub->urb, GFP_KERNEL); if (ret) { message = "couldn't submit status urb"; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 40ef07674dd..c89dbf4ec12 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -344,7 +344,8 @@ int usb_sg_init ( if (!io->urbs) goto nomem; - urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT; + urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP + | URB_NO_INTERRUPT; if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index b130401bdc8..7d63550ab39 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -297,7 +297,7 @@ int usb_submit_urb(struct urb *urb, int mem_flags) /* enforce simple/standard policy */ allowed = URB_ASYNC_UNLINK; // affects later unlinks - allowed |= URB_NO_DMA_MAP; + allowed |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); allowed |= URB_NO_INTERRUPT; switch (temp) { case PIPE_BULK: diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f440773501c..45602065a20 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1234,7 +1234,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent) } /** - * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP + * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP * @dev: device the buffer will be used with * @size: requested buffer size * @mem_flags: affect whether allocation may block @@ -1245,9 +1245,9 @@ int usb_new_device(struct usb_device *dev, struct device *parent) * specified device. Such cpu-space buffers are returned along with the DMA * address (through the pointer provided). * - * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to - * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping - * hardware for long idle periods. The implementation varies between + * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags + * to avoid behaviors like using "DMA bounce buffers", or tying down I/O + * mapping hardware for long idle periods. The implementation varies between * platforms, depending on details of how DMA will work to this device. * Using these buffers also helps prevent cacheline sharing problems on * architectures where CPU caches are not DMA-coherent. @@ -1291,17 +1291,17 @@ void usb_buffer_free ( /** * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be mapped + * @urb: urb whose transfer_buffer/setup_packet will be mapped * * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the - * operation succeeds. If the device is connected to this system through - * a non-DMA controller, this operation always succeeds. + * the parameter. URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are + * added to urb->transfer_flags if the operation succeeds. If the device + * is connected to this system through a non-DMA controller, this operation + * always succeeds. * * This call would normally be used for an urb which is reused, perhaps * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. It may not be used for - * control requests. + * calls to synchronize memory and dma state. * * Reverse the effect of this call with usb_buffer_unmap(). */ @@ -1311,7 +1311,6 @@ struct urb *usb_buffer_map (struct urb *urb) struct device *controller; if (!urb - || usb_pipecontrol (urb->pipe) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) @@ -1322,17 +1321,23 @@ struct urb *usb_buffer_map (struct urb *urb) urb->transfer_buffer, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + if (usb_pipecontrol (urb->pipe)) + urb->setup_dma = dma_map_single (controller, + urb->setup_packet, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); // FIXME generic api broken like pci, can't report errors // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; } else urb->transfer_dma = ~0; - urb->transfer_flags |= URB_NO_DMA_MAP; + urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); return urb; } /** * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer will be synchronized + * @urb: urb whose transfer_buffer/setup_packet will be synchronized */ void usb_buffer_dmasync (struct urb *urb) { @@ -1340,17 +1345,23 @@ void usb_buffer_dmasync (struct urb *urb) struct device *controller; if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) return; - if (controller->dma_mask) + if (controller->dma_mask) { dma_sync_single (controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + if (usb_pipecontrol (urb->pipe)) + dma_sync_single (controller, + urb->setup_dma, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + } } /** @@ -1365,18 +1376,25 @@ void usb_buffer_unmap (struct urb *urb) struct device *controller; if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) return; - if (controller->dma_mask) + if (controller->dma_mask) { dma_unmap_single (controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - urb->transfer_flags &= ~URB_NO_DMA_MAP; + if (usb_pipecontrol (urb->pipe)) + dma_unmap_single (controller, + urb->setup_dma, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + } + urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); } /** @@ -1391,7 +1409,7 @@ void usb_buffer_unmap (struct urb *urb) * * The caller is responsible for placing the resulting DMA addresses from * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_DMA_MAP transfer flag in each of those URBs. + * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. * * Top I/O rates come from queuing URBs, instead of waiting for each one * to complete before starting the next I/O. This is particularly easy diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index b41f47ef470..15142a16cbb 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -2222,7 +2222,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wIndex != 0 /* HALT feature */ + if (u.r.wValue != 0 /* HALT feature */ || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) @@ -2239,7 +2239,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wIndex != 0 /* HALT feature */ + if (u.r.wValue != 0 /* HALT feature */ || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 32478229d4c..b30da316351 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -115,19 +115,28 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} #ifdef DEBUG static void __attribute__((__unused__)) +dbg_qtd (char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) +{ + ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, + cpu_to_le32p (&qtd->hw_next), + cpu_to_le32p (&qtd->hw_alt_next), + cpu_to_le32p (&qtd->hw_token), + cpu_to_le32p (&qtd->hw_buf [0])); + if (qtd->hw_buf [1]) + ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n", + cpu_to_le32p (&qtd->hw_buf [1]), + cpu_to_le32p (&qtd->hw_buf [2]), + cpu_to_le32p (&qtd->hw_buf [3]), + cpu_to_le32p (&qtd->hw_buf [4])); +} + +static void __attribute__((__unused__)) dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) { - dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label, + ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, qh, qh->hw_next, qh->hw_info1, qh->hw_info2, - qh->hw_current, qh->hw_qtd_next); - dbg (" alt+nak+t= %x, token= %x, page0= %x, page1= %x", - qh->hw_alt_next, qh->hw_token, - qh->hw_buf [0], qh->hw_buf [1]); - if (qh->hw_buf [2]) { - dbg (" page2= %x, page3= %x, page4= %x", - qh->hw_buf [2], qh->hw_buf [3], - qh->hw_buf [4]); - } + qh->hw_current); + dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next); } static int __attribute__((__unused__)) @@ -284,8 +293,7 @@ static inline char token_mark (u32 token) return '*'; if (token & QTD_STS_HALT) return '-'; - if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */ - || QTD_LENGTH (token) == 0) + if (!IS_SHORT_READ (token)) return ' '; /* tries to advance through hw_alt_next */ return '/'; @@ -307,11 +315,14 @@ static void qh_lines ( char *next = *nextp; char mark; - mark = token_mark (qh->hw_token); + if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */ + mark = '@'; + else + mark = token_mark (qh->hw_token); if (mark == '/') { /* qh_alt_next controls qh advance? */ if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) mark = '#'; /* blocked */ - else if (qh->hw_alt_next & cpu_to_le32 (0x01)) + else if (qh->hw_alt_next == EHCI_LIST_END) mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } @@ -324,7 +335,7 @@ static void qh_lines ( (scratch >> 8) & 0x000f, scratch, cpu_to_le32p (&qh->hw_info2), cpu_to_le32p (&qh->hw_token), mark, - (cpu_to_le32 (0x8000000) & qh->hw_token) + (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) ? "data0" : "data1", (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; @@ -390,6 +401,8 @@ show_async (struct device *dev, char *buf) char *next; struct ehci_qh *qh; + *buf = 0; + pdev = container_of (dev, struct pci_dev, dev); ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd); next = buf; @@ -412,7 +425,7 @@ show_async (struct device *dev, char *buf) } spin_unlock_irqrestore (&ehci->lock, flags); - return PAGE_SIZE - size; + return strlen (buf); } static DEVICE_ATTR (async, S_IRUGO, show_async, NULL); @@ -548,7 +561,8 @@ show_registers (struct device *dev, char *buf) /* Capability Registers */ i = readw (&ehci->caps->hci_version); temp = snprintf (next, size, - "EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n", + "%s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", + pdev->dev.name, i >> 8, i & 0x0ff, ehci->hcd.state); size -= temp; next += temp; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e6b069559ba..dbfe5c8dcf2 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -39,13 +39,10 @@ #include #include #include +#include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32) -#include "../hcd.h" -#else #include "../core/hcd.h" -#endif #include #include @@ -94,11 +91,11 @@ * 2001-June Works with usb-storage and NEC EHCI on 2.4 */ -#define DRIVER_VERSION "2003-Jan-22" +#define DRIVER_VERSION "2003-Jun-13" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" -static const char hcd_name [] = "ehci-hcd"; +static const char hcd_name [] = "ehci_hcd"; // #define EHCI_VERBOSE_DEBUG @@ -123,7 +120,7 @@ static const char hcd_name [] = "ehci-hcd"; /* Initial IRQ latency: lower than default */ static int log2_irq_thresh = 0; // 0 to 6 -MODULE_PARM (log2_irq_thresh, "i"); +module_param (log2_irq_thresh, int, S_IRUGO); MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); #define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) @@ -434,7 +431,7 @@ static int ehci_start (struct usb_hcd *hcd) pci_set_mwi (ehci->hcd.pdev); /* clear interrupt enables, set irq latency */ - temp = readl (&ehci->regs->command) & 0xff; + temp = readl (&ehci->regs->command) & 0x0fff; if (log2_irq_thresh < 0 || log2_irq_thresh > 6) log2_irq_thresh = 0; temp |= 1 << (16 + log2_irq_thresh); @@ -1020,7 +1017,8 @@ static int __init init (void) if (usb_disabled()) return -ENODEV; - dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", + pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index b6aa6ec5b1a..abf3a8d89e4 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -88,7 +88,6 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, static inline void qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) { - qh->hw_current = 0; qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END; @@ -99,8 +98,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) /*-------------------------------------------------------------------------*/ -#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) - static void qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, @@ -279,16 +276,15 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) /* hardware copies qtd out of qh overlay */ rmb (); token = le32_to_cpu (qtd->hw_token); - stopped = stopped - || (HALT_BIT & qh->hw_token) != 0 - || (ehci->hcd.state == USB_STATE_HALT); /* always clean up qtds the hc de-activated */ if ((token & QTD_STS_ACTIVE) == 0) { - /* magic dummy for short reads; won't advance */ - if (IS_SHORT_READ (token) - && !(token & QTD_STS_HALT) + if ((token & QTD_STS_HALT) != 0) { + stopped = 1; + + /* magic dummy for some short reads; qh won't advance */ + } else if (IS_SHORT_READ (token) && (qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) { stopped = 1; @@ -296,10 +292,13 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) } /* stop scanning when we reach qtds the hc is using */ - } else if (likely (!stopped)) { + } else if (likely (!stopped + && HCD_IS_RUNNING (ehci->hcd.state))) { break; } else { + stopped = 1; + /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. @@ -358,12 +357,20 @@ halt: qh->qh_state = state; /* update qh after fault cleanup */ - if (unlikely ((HALT_BIT & qh->hw_token) != 0)) { - qh_update (ehci, qh, - list_empty (&qh->qtd_list) - ? qh->dummy - : list_entry (qh->qtd_list.next, - struct ehci_qtd, qtd_list)); + if (unlikely (stopped != 0) + /* some EHCI 0.95 impls will overlay dummy qtds */ + || qh->hw_qtd_next == EHCI_LIST_END) { + if (list_empty (&qh->qtd_list)) + end = qh->dummy; + else { + end = list_entry (qh->qtd_list.next, + struct ehci_qtd, qtd_list); + /* first qtd may already be partially processed */ + if (cpu_to_le32 (end->qtd_dma) == qh->hw_current) + end = 0; + } + if (end) + qh_update (ehci, qh, end); } return count; @@ -683,12 +690,11 @@ done: /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ - /* init as halted, toggle clear, advance to dummy */ + /* init as live, toggle clear, advance to dummy */ qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_le32 (info1); qh->hw_info2 = cpu_to_le32 (info2); qh_update (ehci, qh, qh->dummy); - qh->hw_token = cpu_to_le32 (QTD_STS_HALT); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); return qh; } @@ -788,11 +794,6 @@ static struct ehci_qh *qh_append_tds ( } } - /* FIXME: changing config or interface setting is not - * supported yet. preferred fix is for usbcore to tell - * us to clear out each endpoint's state, but... - */ - /* usb_clear_halt() means qh data toggle gets reset */ if (unlikely (!usb_gettoggle (urb->dev, (epnum & 0x0f), !(epnum & 0x10))) diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index c730b7ea5a2..ed23010d21a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -290,7 +290,10 @@ struct ehci_qtd { size_t length; /* length of buffer */ } __attribute__ ((aligned (32))); -#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */ +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK __constant_cpu_to_le32 (~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c index f98f1be253c..cb64dae5059 100644 --- a/drivers/usb/image/hpusbscsi.c +++ b/drivers/usb/image/hpusbscsi.c @@ -104,7 +104,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf, goto out_free_controlurb; /* In host->hostdata we store a pointer to desc */ - new->host = scsi_register(&hpusbscsi_scsi_host_template, sizeof(new)); + new->host = scsi_host_alloc(&hpusbscsi_scsi_host_template, sizeof(new)); if (!new->host) goto out_unlink_controlurb; @@ -137,7 +137,7 @@ hpusbscsi_usb_disconnect(struct usb_interface *intf) scsi_remove_host(desc->host); usb_unlink_urb(desc->controlurb); - scsi_unregister(desc->host); + scsi_host_put(desc->host); usb_free_urb(desc->controlurb); usb_free_urb(desc->dataurb); diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 76f28284e6f..6b0b070f73a 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -811,7 +811,7 @@ static int mts_usb_probe(struct usb_interface *intf, MTS_WARNING( "will this work? Image data EP is not usually %d\n", (int)new_desc->ep_image ); - new_desc->host = scsi_register(&mts_scsi_host_template, + new_desc->host = scsi_host_alloc(&mts_scsi_host_template, sizeof(new_desc)); if (!new_desc->host) goto out_free_urb; @@ -838,7 +838,7 @@ static void mts_usb_disconnect (struct usb_interface *intf) scsi_remove_host(desc->host); usb_unlink_urb(desc->urb); - scsi_unregister(desc->host); + scsi_host_put(desc->host); usb_free_urb(desc->urb); kfree(desc); diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index a368fba05b3..8cacde91561 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -330,7 +330,7 @@ aiptek_probe(struct usb_interface *intf, aiptek->data, aiptek->features->pktlen, aiptek->features->irq, aiptek, endpoint->bInterval); aiptek->irq->transfer_dma = aiptek->data_dma; - aiptek->irq->transfer_flags |= URB_NO_DMA_MAP; + aiptek->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&aiptek->dev); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 67bb831dd0e..80822ed23a6 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -215,7 +215,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign return -1; } - if (parser->global.logical_maximum <= parser->global.logical_minimum) { + if (parser->global.logical_maximum < parser->global.logical_minimum) { dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); return -1; } @@ -674,7 +674,6 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); - kfree(device->rdesc); kfree(device->collection); hid_free_device(device); kfree(parser); @@ -684,7 +683,6 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (dispatch_type[item.type](parser, &item)) { dbg("item %u %u %u %u parsing failed\n", item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - kfree(device->rdesc); kfree(device->collection); hid_free_device(device); kfree(parser); @@ -694,7 +692,6 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (start == end) { if (parser->collection_stack_ptr) { dbg("unbalanced collection at end of report description"); - kfree(device->rdesc); kfree(device->collection); hid_free_device(device); kfree(parser); @@ -702,7 +699,6 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) } if (parser->local.delimiter_depth) { dbg("unbalanced delimiter at end of report description"); - kfree(device->rdesc); kfree(device->collection); hid_free_device(device); kfree(parser); @@ -714,7 +710,6 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) } dbg("item fetching failed at offset %d\n", (int)(end - start)); - kfree(device->rdesc); kfree(device->collection); hid_free_device(device); kfree(parser); @@ -1518,7 +1513,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_DMA_MAP; + hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { if (hid->urbout) continue; @@ -1528,7 +1523,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_bulk_urb(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_DMA_MAP; + hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } @@ -1577,7 +1572,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= URB_NO_DMA_MAP; + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); return hid; diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index 5798b4eb36b..d1e9ba6801d 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c @@ -181,7 +181,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i kbtab->data, 8, kbtab_irq, kbtab, endpoint->bInterval); kbtab->irq->transfer_dma = kbtab->data_dma; - kbtab->irq->transfer_flags |= URB_NO_DMA_MAP; + kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&kbtab->dev); diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 396230a22a2..10a5889d643 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -180,7 +180,7 @@ static void powermate_sync_state(struct powermate_device *pm) (void *) pm->configcr, 0, 0, powermate_config_complete, pm); pm->config->setup_dma = pm->configcr_dma; - pm->config->transfer_flags |= URB_NO_DMA_MAP; + pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP; if (usb_submit_urb(pm->config, GFP_ATOMIC)) printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); @@ -355,7 +355,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval); pm->irq->transfer_dma = pm->data_dma; - pm->irq->transfer_flags |= URB_NO_DMA_MAP; + pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* register our interrupt URB with the USB system */ if (usb_submit_urb(pm->irq, GFP_KERNEL)) { diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 0e5a7dce38c..9bbacdf2de2 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -282,7 +282,7 @@ static int usb_kbd_probe(struct usb_interface *iface, kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval); kbd->irq->transfer_dma = kbd->new_dma; - kbd->irq->transfer_flags |= URB_NO_DMA_MAP; + kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->cr->bRequest = 0x09; @@ -325,7 +325,8 @@ static int usb_kbd_probe(struct usb_interface *iface, usb_kbd_led, kbd); kbd->led->setup_dma = kbd->cr_dma; kbd->led->transfer_dma = kbd->leds_dma; - kbd->led->transfer_flags |= URB_NO_DMA_MAP; + kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); input_register_device(&kbd->dev); diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index de6092ce712..9eb5c201813 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -207,7 +207,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_ (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval); mouse->irq->transfer_dma = mouse->data_dma; - mouse->irq->transfer_flags |= URB_NO_DMA_MAP; + mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&mouse->dev); printk(KERN_INFO "input: %s on %s\n", mouse->name, path); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index 0ed7cd17f44..1d50ba9936f 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -590,7 +590,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; - wacom->irq->transfer_flags |= URB_NO_DMA_MAP; + wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&wacom->dev); diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index ec55c4b5528..55ccc8339b4 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -259,7 +259,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; - xpad->irq_in->transfer_flags |= URB_NO_DMA_MAP; + xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; xpad->udev = udev; diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 2b83c44a8c2..00adf9b9f2c 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -149,8 +149,8 @@ do { \ /* External data structures / Interface */ typedef struct { - char *buf; /* return buffer for string contents */ - unsigned int bsize; /* size of return buffer */ + char __user *buf; /* return buffer for string contents */ + unsigned int bsize; /* size of return buffer */ } audevinfo_t,*paudevinfo_t; /* IO controls */ @@ -1548,7 +1548,7 @@ static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int /* get a string descriptor for the device */ case IOCTL_AU_DEVINFO: dbg ("IOCTL_AU_DEVINFO"); - if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) { + if (copy_from_user (&devinfo, (void __user *) arg, sizeof (audevinfo_t))) { ret = -EFAULT; break; } @@ -1578,7 +1578,7 @@ static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int } /* Read data from the device */ -static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos) +static ssize_t auerchar_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) { unsigned long flags; pauerchar_t ccp = (pauerchar_t) file->private_data; @@ -1708,7 +1708,7 @@ doreadlist: /* Write a data block into the right service channel of the device */ -static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos) +static ssize_t auerchar_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) { pauerchar_t ccp = (pauerchar_t) file->private_data; pauerswald_t cp = NULL; diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c index 834058de2dd..46b790ce857 100644 --- a/drivers/usb/misc/brlvger.c +++ b/drivers/usb/misc/brlvger.c @@ -109,9 +109,9 @@ static int brlvger_probe (struct usb_interface *intf, static void brlvger_disconnect(struct usb_interface *intf); static int brlvger_open(struct inode *inode, struct file *file); static int brlvger_release(struct inode *inode, struct file *file); -static ssize_t brlvger_write(struct file *file, const char *buffer, +static ssize_t brlvger_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos); -static ssize_t brlvger_read(struct file *file, char *buffer, +static ssize_t brlvger_read(struct file *file, char __user *buffer, size_t count, loff_t *unused_pos); static int brlvger_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg); @@ -546,7 +546,7 @@ brlvger_release(struct inode *inode, struct file *file) } static ssize_t -brlvger_write(struct file *file, const char *buffer, +brlvger_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { struct brlvger_priv *priv = file->private_data; @@ -655,7 +655,7 @@ read_index(struct brlvger_priv *priv) } static ssize_t -brlvger_read(struct file *file, char *buffer, +brlvger_read(struct file *file, char __user *buffer, size_t count, loff_t *unused_pos) { struct brlvger_priv *priv = file->private_data; @@ -719,7 +719,7 @@ brlvger_ioctl(struct inode *inode, struct file *file, memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE); memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE); - if(copy_to_user((void *)arg, &vi, sizeof(vi))) + if(copy_to_user((void __user *)arg, &vi, sizeof(vi))) return -EFAULT; return 0; } diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index ba75c959b28..8c1f86f35f0 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -111,7 +111,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, { struct RioCommand rio_cmd; struct rio_usb_data *rio = &rio_instance; - void *data; + void __user *data; unsigned char *buffer; int result, requesttype; int retries; @@ -129,7 +129,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, switch (cmd) { case RIO_RECV_COMMAND: - data = (void *) arg; + data = (void __user *) arg; if (data == NULL) break; if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { @@ -199,7 +199,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, break; case RIO_SEND_COMMAND: - data = (void *) arg; + data = (void __user *) arg; if (data == NULL) break; if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { @@ -266,7 +266,7 @@ err_out: } static ssize_t -write_rio(struct file *file, const char *buffer, +write_rio(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) { struct rio_usb_data *rio = &rio_instance; @@ -352,7 +352,7 @@ error: } static ssize_t -read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos) +read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { struct rio_usb_data *rio = &rio_instance; ssize_t read_count; diff --git a/drivers/usb/misc/rio500_usb.h b/drivers/usb/misc/rio500_usb.h index 9fc712f3d29..359abc98e70 100644 --- a/drivers/usb/misc/rio500_usb.h +++ b/drivers/usb/misc/rio500_usb.h @@ -32,6 +32,6 @@ struct RioCommand { int requesttype; int value; int index; - void *buffer; + void __user *buffer; int timeout; }; diff --git a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c index c4925ad5b69..131bc1f2b96 100644 --- a/drivers/usb/misc/speedtch.c +++ b/drivers/usb/misc/speedtch.c @@ -61,6 +61,7 @@ #include #include +#include #include #include #include @@ -102,12 +103,43 @@ static const char udsl_driver_name [] = "speedtch"; #define SPEEDTOUCH_VENDORID 0x06b9 #define SPEEDTOUCH_PRODUCTID 0x4061 -#define UDSL_NUM_RCV_URBS 1 -#define UDSL_NUM_SND_URBS 1 -#define UDSL_NUM_RCV_BUFS (2*UDSL_NUM_RCV_URBS) -#define UDSL_NUM_SND_BUFS (2*UDSL_NUM_SND_URBS) -#define UDSL_RCV_BUF_SIZE 32 /* ATM cells */ -#define UDSL_SND_BUF_SIZE 64 /* ATM cells */ +#define UDSL_MAX_RCV_URBS 4 +#define UDSL_MAX_SND_URBS 4 +#define UDSL_MAX_RCV_BUFS 8 +#define UDSL_MAX_SND_BUFS 8 +#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_DEFAULT_RCV_URBS 1 +#define UDSL_DEFAULT_SND_URBS 1 +#define UDSL_DEFAULT_RCV_BUFS 2 +#define UDSL_DEFAULT_SND_BUFS 2 +#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */ +#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */ + +static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS; +static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS; +static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS; +static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS; +static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE; +static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE; + +module_param (num_rcv_urbs, uint, 0444); +MODULE_PARM_DESC (num_rcv_urbs, "Number of urbs used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_URBS) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_URBS) ")"); + +module_param (num_snd_urbs, uint, 0444); +MODULE_PARM_DESC (num_snd_urbs, "Number of urbs used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_URBS) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_URBS) ")"); + +module_param (num_rcv_bufs, uint, 0444); +MODULE_PARM_DESC (num_rcv_bufs, "Number of buffers used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_BUFS) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_BUFS) ")"); + +module_param (num_snd_bufs, uint, 0444); +MODULE_PARM_DESC (num_snd_bufs, "Number of buffers used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_BUFS) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_BUFS) ")"); + +module_param (rcv_buf_size, uint, 0444); +MODULE_PARM_DESC (rcv_buf_size, "Size of the buffers used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_BUF_SIZE) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_BUF_SIZE) ")"); + +module_param (snd_buf_size, uint, 0444); +MODULE_PARM_DESC (snd_buf_size, "Size of the buffers used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_BUF_SIZE) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_BUF_SIZE) ")"); #define UDSL_IOCTL_LINE_UP 1 #define UDSL_IOCTL_LINE_DOWN 2 @@ -196,8 +228,8 @@ struct udsl_instance_data { struct list_head vcc_list; /* receive */ - struct udsl_receiver receivers [UDSL_NUM_RCV_URBS]; - struct udsl_receive_buffer receive_buffers [UDSL_NUM_RCV_BUFS]; + struct udsl_receiver receivers [UDSL_MAX_RCV_URBS]; + struct udsl_receive_buffer receive_buffers [UDSL_MAX_RCV_BUFS]; spinlock_t receive_lock; struct list_head spare_receivers; @@ -207,8 +239,8 @@ struct udsl_instance_data { struct list_head spare_receive_buffers; /* send */ - struct udsl_sender senders [UDSL_NUM_SND_URBS]; - struct udsl_send_buffer send_buffers [UDSL_NUM_SND_BUFS]; + struct udsl_sender senders [UDSL_MAX_SND_URBS]; + struct udsl_send_buffer send_buffers [UDSL_MAX_SND_BUFS]; struct sk_buff_head sndqueue; @@ -503,7 +535,7 @@ static void udsl_complete_receive (struct urb *urb, struct pt_regs *regs) vdbg ("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf); - BUG_ON (buf->filled_cells > UDSL_RCV_BUF_SIZE); + BUG_ON (buf->filled_cells > rcv_buf_size); /* may not be in_interrupt() */ spin_lock_irqsave (&instance->receive_lock, flags); @@ -541,7 +573,7 @@ made_progress: instance->usb_dev, usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN), buf->base, - UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE, + rcv_buf_size * ATM_CELL_SIZE, udsl_complete_receive, rcv); @@ -626,11 +658,11 @@ made_progress: instance->usb_dev, usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), buf->base, - (UDSL_SND_BUF_SIZE - buf->free_cells) * ATM_CELL_SIZE, + (snd_buf_size - buf->free_cells) * ATM_CELL_SIZE, udsl_complete_send, snd); - vdbg ("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", snd->urb, UDSL_SND_BUF_SIZE - buf->free_cells, snd, buf); + vdbg ("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", snd->urb, snd_buf_size - buf->free_cells, snd, buf); if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) { dbg ("udsl_process_send: urb submission failed (%d)!", err); @@ -662,7 +694,7 @@ made_progress: spin_unlock_irq (&instance->send_lock); buf->free_start = buf->base; - buf->free_cells = UDSL_SND_BUF_SIZE; + buf->free_cells = snd_buf_size; instance->current_buffer = buf; } @@ -676,7 +708,7 @@ made_progress: instance->current_buffer = NULL; } - vdbg ("udsl_process_send: buffer contains %d cells, %d left", UDSL_SND_BUF_SIZE - buf->free_cells, buf->free_cells); + vdbg ("udsl_process_send: buffer contains %d cells, %d left", snd_buf_size - buf->free_cells, buf->free_cells); if (!UDSL_SKB (skb)->num_cells) { struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc; @@ -1039,7 +1071,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i INIT_LIST_HEAD (&instance->filled_send_buffers); /* receive init */ - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) { + for (i = 0; i < num_rcv_urbs; i++) { struct udsl_receiver *rcv = &(instance->receivers [i]); if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) { @@ -1052,10 +1084,10 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i list_add (&rcv->list, &instance->spare_receivers); } - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) { + for (i = 0; i < num_rcv_bufs; i++) { struct udsl_receive_buffer *buf = &(instance->receive_buffers [i]); - if (!(buf->base = kmalloc (UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) { + if (!(buf->base = kmalloc (rcv_buf_size * ATM_CELL_SIZE, GFP_KERNEL))) { dbg ("udsl_usb_probe: no memory for receive buffer %d!", i); goto fail; } @@ -1064,7 +1096,7 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i } /* send init */ - for (i = 0; i < UDSL_NUM_SND_URBS; i++) { + for (i = 0; i < num_snd_urbs; i++) { struct udsl_sender *snd = &(instance->senders [i]); if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) { @@ -1077,10 +1109,10 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i list_add (&snd->list, &instance->spare_senders); } - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) { + for (i = 0; i < num_snd_bufs; i++) { struct udsl_send_buffer *buf = &(instance->send_buffers [i]); - if (!(buf->base = kmalloc (UDSL_SND_BUF_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) { + if (!(buf->base = kmalloc (snd_buf_size * ATM_CELL_SIZE, GFP_KERNEL))) { dbg ("udsl_usb_probe: no memory for send buffer %d!", i); goto fail; } @@ -1139,16 +1171,16 @@ finish: return 0; fail: - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) + for (i = 0; i < num_snd_bufs; i++) kfree (instance->send_buffers [i].base); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) usb_free_urb (instance->senders [i].urb); - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) + for (i = 0; i < num_rcv_bufs; i++) kfree (instance->receive_buffers [i].base); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) usb_free_urb (instance->receivers [i].urb); kfree (instance); @@ -1175,7 +1207,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf) /* receive finalize */ tasklet_disable (&instance->receive_tasklet); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) if ((result = usb_unlink_urb (instance->receivers [i].urb)) < 0) dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d", i, result); @@ -1184,13 +1216,13 @@ static void udsl_usb_disconnect (struct usb_interface *intf) count = 0; spin_lock_irq (&instance->receive_lock); list_for_each (pos, &instance->spare_receivers) - if (++count > UDSL_NUM_RCV_URBS) + if (++count > num_rcv_urbs) panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__); spin_unlock_irq (&instance->receive_lock); dbg ("udsl_usb_disconnect: found %u spare receivers", count); - if (count == UDSL_NUM_RCV_URBS) + if (count == num_rcv_urbs) break; set_current_state (TASK_RUNNING); @@ -1203,16 +1235,16 @@ static void udsl_usb_disconnect (struct usb_interface *intf) tasklet_enable (&instance->receive_tasklet); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) usb_free_urb (instance->receivers [i].urb); - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) + for (i = 0; i < num_rcv_bufs; i++) kfree (instance->receive_buffers [i].base); /* send finalize */ tasklet_disable (&instance->send_tasklet); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) if ((result = usb_unlink_urb (instance->senders [i].urb)) < 0) dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d", i, result); @@ -1221,13 +1253,13 @@ static void udsl_usb_disconnect (struct usb_interface *intf) count = 0; spin_lock_irq (&instance->send_lock); list_for_each (pos, &instance->spare_senders) - if (++count > UDSL_NUM_SND_URBS) + if (++count > num_snd_urbs) panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__); spin_unlock_irq (&instance->send_lock); dbg ("udsl_usb_disconnect: found %u spare senders", count); - if (count == UDSL_NUM_SND_URBS) + if (count == num_snd_urbs) break; set_current_state (TASK_RUNNING); @@ -1241,10 +1273,10 @@ static void udsl_usb_disconnect (struct usb_interface *intf) tasklet_enable (&instance->send_tasklet); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) usb_free_urb (instance->senders [i].urb); - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) + for (i = 0; i < num_snd_bufs; i++) kfree (instance->send_buffers [i].base); wmb (); @@ -1270,6 +1302,11 @@ static int __init udsl_usb_init (void) return -EIO; } + if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) || (num_snd_urbs > UDSL_MAX_SND_URBS) || + (num_rcv_bufs > UDSL_MAX_RCV_BUFS) || (num_snd_bufs > UDSL_MAX_SND_BUFS) || + (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE)) + return -EINVAL; + return usb_register (&udsl_usb_driver); } diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c index 7fff7d0740c..135b7de92b9 100644 --- a/drivers/usb/misc/tiglusb.c +++ b/drivers/usb/misc/tiglusb.c @@ -155,7 +155,7 @@ tiglusb_release (struct inode *inode, struct file *filp) } static ssize_t -tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos) +tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos) { ptiglusb_t s = (ptiglusb_t) filp->private_data; ssize_t ret = 0; @@ -208,7 +208,7 @@ tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos) } static ssize_t -tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos) +tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * f_pos) { ptiglusb_t s = (ptiglusb_t) filp->private_data; ssize_t ret = 0; diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 6f777477f1d..6324d7eb9e2 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -88,12 +88,12 @@ ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd, i = (lcd->lcd_dev)->descriptor.bcdDevice; sprintf(buf,"%1d%1d.%1d%1d",(i & 0xF000)>>12,(i & 0xF00)>>8, (i & 0xF0)>>4,(i & 0xF)); - if (copy_to_user((void *)arg,buf,strlen(buf))!=0) + if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) return -EFAULT; break; case IOCTL_GET_DRV_VERSION: sprintf(buf,DRIVER_VERSION); - if (copy_to_user((void *)arg,buf,strlen(buf))!=0) + if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) return -EFAULT; break; default: @@ -105,7 +105,7 @@ ioctl_lcd(struct inode *inode, struct file *file, unsigned int cmd, } static ssize_t -write_lcd(struct file *file, const char *buffer, +write_lcd(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) { struct lcd_usb_data *lcd = &lcd_instance; @@ -171,7 +171,7 @@ write_lcd(struct file *file, const char *buffer, } static ssize_t -read_lcd(struct file *file, char *buffer, size_t count, loff_t * ppos) +read_lcd(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { struct lcd_usb_data *lcd = &lcd_instance; ssize_t read_count; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index f73c657839f..4d7f9a9158e 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -107,7 +107,7 @@ static struct urb *simple_alloc_urb ( urb->interval = (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE; - urb->transfer_flags = URB_NO_DMA_MAP; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 4ce51c46976..6711a836452 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -7,6 +7,27 @@ comment "USB Network adaptors" comment "Networking support is needed for USB Networking device support" depends on USB && !NET +config USB_AX8817X + tristate "USB ASIX AX8817X Ethernet device support (EXPERIMENTAL)" + depends on USB && NET && EXPERIMENTAL + ---help--- + Say Y if you want to use one of the following 10/100Mps USB + Ethernet devices based on the ASIX AX88172 chip. Supported + devices are: + ASIX AX88172 + D-Link DUB-E100 + Hawking UF200 + Netgear FA120 + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ax8817x.o. If you want to compile it as a + module, say M here and read . + config USB_CATC tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" depends on USB && NET && EXPERIMENTAL @@ -191,7 +212,8 @@ config USB_ARMLINUX help Choose this option to support the "usb-eth" networking driver used by most of the ARM Linux community with device controllers - such as the SA-11x0 and PXA-25x UDCs. + such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities + in some PXA versions of the "blob" boot loader. Although the ROMs shipped with Sharp Zaurus products use a different link level framing protocol, you can have them use diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 5eec1ed7e40..dde3b3e8cfd 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -2,6 +2,7 @@ # Makefile for USB Network drivers # +obj-$(CONFIG_USB_AX8817X) += ax8817x.o obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o diff --git a/drivers/usb/net/Makefile.mii b/drivers/usb/net/Makefile.mii index 5fa1204701a..30885e3f463 100644 --- a/drivers/usb/net/Makefile.mii +++ b/drivers/usb/net/Makefile.mii @@ -2,4 +2,5 @@ # Makefile for USB Network drivers which require generic MII code. # +obj-$(CONFIG_USB_AX8817X) += mii.o obj-$(CONFIG_USB_PEGASUS) += mii.o diff --git a/drivers/usb/net/ax8817x.c b/drivers/usb/net/ax8817x.c new file mode 100644 index 00000000000..574fca3d3c0 --- /dev/null +++ b/drivers/usb/net/ax8817x.c @@ -0,0 +1,1341 @@ +/* + * ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver + * + * $Id: ax8817x.c,v 1.11 2003/06/15 19:00:02 dhollis Exp $ + * + * Copyright (c) 2002-2003 TiVo Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * History + * + * 2003-06-15 - Dave Hollis 2.0.0 + * * Remove crc32 inline function, use core kernel instead + * * Set sane defaults for rx_buffers + * * Fix ethtool GETDRVINFO bits - use strlcpy and + * usb_make_path + * + * 2003-06-05 - Dave Hollis 0.10.0 + * * Port to 2.5 series kernels + * * Remove #if 0 blocks that are confirmed + * unnecessary + * * Re-did tx routines based off pegasus driver. + * This resolved hard crashes and greatly simplified + * things. + * * Redo mii/ethtool routines + * + * 2003-05-31 - Dave Hollis 0.9.8 + * * Don't stop/start the queue in start_xmit + * * Swallow URB status upon hard removal + * * Cleanup remaining comments (kill // style) + * + * 2003-05-29 - Dave Hollis 0.9.7 + * * Set module owner + * * Follow-up on suggestions from David Brownell & + * Oliver Neukum which should help with robustness + * * Use ether_crc from stock kernel if available + * + * 2003-05-28 - Dave Hollis 0.9.6 + * * Added basic ethtool & mii support + * + * 2003-05-28 - Dave Hollis 0.9.5 + * * Workout devrequest change to usb_ctrlrequest structure + * * Replace FILL_BULK_URB macros to non-deprecated + * usb_fill_bulk_urb macros + * * Replace printks with equivalent macros + * * Use defines for module description, version, author to + * simplify future changes + * + * Known Issues + * + * Todo + * Fix mii/ethtool output +*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version Information */ +#define DRIVER_VERSION "v2.0.0" +#define DRIVER_AUTHOR "TiVo, Inc." +#define DRIVER_DESC "ASIX AX8817x USB Ethernet driver" +#define DRIVER_NAME "ax8817x" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +#define AX_REQ_READ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) +#define AX_REQ_WRITE ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) + +#define AX_CMD_SET_SW_MII 0x06 +#define AX_CMD_READ_MII_REG 0x07 +#define AX_CMD_WRITE_MII_REG 0x08 +#define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX_CMD_READ_NODE_ID 0x17 +#define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_WRITE_GPIOS 0x1f + +#define AX_RX_MAX ETH_FRAME_LEN +#define AX_TIMEOUT_CMD ( HZ / 10 ) +#define AX_TIMEOUT_TX ( HZ * 2 ) +#define AX_MAX_MCAST 64 + +#define AX_DRV_STATE_INITIALIZING 0x00 +#define AX_DRV_STATE_RUNNING 0x01 +#define AX_DRV_STATE_EXITING 0x02 + +#define AX_PHY_STATE_INITIALIZING 0x00 +#define AX_PHY_STATE_NO_LINK 0x01 +#define AX_PHY_STATE_POLLING_1 0x02 +#define AX_PHY_STATE_POLLING_2 0x03 +#define AX_PHY_STATE_POLLING_3 0x04 +#define AX_PHY_STATE_POLLING_4 0x05 +#define AX_PHY_STATE_SETTING_MAC 0x06 +#define AX_PHY_STATE_LINK 0x07 +#define AX_PHY_STATE_ABORT_POLL 0x08 +#define AX_PHY_STATE_ABORTING 0x09 + +#define AX_MAX_PHY_RETRY 50 + +#define AX_RX_URBS_DEFAULT 2 + +static int n_rx_urbs = AX_RX_URBS_DEFAULT; + +MODULE_PARM(n_rx_urbs, "i"); +MODULE_PARM_DESC(n_rx_urbs, + "Number of rx buffers to queue at once (def 2)"); + +struct ax8817x_info; +struct ax_cmd_req; +typedef int (*ax_cmd_callback_t) (struct ax8817x_info *, + struct ax_cmd_req *); + +struct ax_cmd_req { + struct list_head list; + ax_cmd_callback_t cmd_callback; + void *priv; + int status; + void *data; + int data_size; + int timeout; + struct usb_ctrlrequest devreq; +}; + +struct ax8817x_info { + struct usb_device *usb; + struct net_device *net; + struct net_device_stats stats; + struct mii_if_info mii; + struct urb **rx_urbs; + struct urb *int_urb; + struct urb *tx_urb; + u8 *int_buf; + struct urb *ctl_urb; + struct list_head ctl_queue; + spinlock_t ctl_lock; + atomic_t rx_refill_cnt; + struct ax_cmd_req phy_req; + u8 phy_id; + u8 phy_state; + u8 drv_state; +}; + + +const struct usb_device_id ax8817x_id_table[] __devinitdata = { + /* Linksys USB200M */ + {USB_DEVICE(0x077b, 0x2226), driver_info:0x00130103}, + /* Hawking UF200, TRENDnet TU2-ET100 */ + {USB_DEVICE(0x07b8, 0x420a), driver_info:0x001f1d1f}, + /* NETGEAR FA120 */ + {USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103}, + /* D-Link DUB-E100 */ + {USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f}, + + {} +}; + +MODULE_DEVICE_TABLE(usb, ax8817x_id_table); + + +static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *, + int); +static void ax_rx_callback(struct urb *, struct pt_regs *); + +static void ax_ctl_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = + (struct ax8817x_info *) urb->context; + + ax_run_ctl_queue(ax_info, NULL, + urb->status ? urb->status : urb->actual_length); +} + +/* + * Queue a new ctl request, or dequeue the first in the list +*/ +static void ax_run_ctl_queue(struct ax8817x_info *ax_info, + struct ax_cmd_req *req, int status) +{ + struct ax_cmd_req *next_req = NULL; + struct ax_cmd_req *last_req = NULL; + unsigned long flags; + + /* Need to lock around queue list manipulation */ + spin_lock_irqsave(&ax_info->ctl_lock, flags); + + if (req == NULL) { + last_req = + list_entry(ax_info->ctl_queue.next, struct ax_cmd_req, + list); + } else { + if (list_empty(&ax_info->ctl_queue)) { + next_req = req; + } + + req->status = -EINPROGRESS; + list_add_tail(&req->list, &ax_info->ctl_queue); + } + + while (1) { + if (last_req != NULL) { + /* dequeue completed entry */ + list_del(&last_req->list); + + last_req->status = status; + if (last_req->cmd_callback(ax_info, last_req)) { + /* requeue if told to do so */ + last_req->status = -EINPROGRESS; + list_add_tail(&last_req->list, + &ax_info->ctl_queue); + } + + if (list_empty(&ax_info->ctl_queue)) { + next_req = NULL; + } else { + next_req = + list_entry(ax_info->ctl_queue.next, + struct ax_cmd_req, list); + } + } + + spin_unlock_irqrestore(&ax_info->ctl_lock, flags); + + if (next_req == NULL) { + break; + } + + /* XXX: do something with timeout */ + usb_fill_control_urb(ax_info->ctl_urb, ax_info->usb, + next_req->devreq. + bRequestType & USB_DIR_IN ? + usb_rcvctrlpipe(ax_info->usb, + 0) : + usb_sndctrlpipe(ax_info->usb, 0), + (void *) &next_req->devreq, + next_req->data, next_req->data_size, + ax_ctl_callback, ax_info); + + status = usb_submit_urb(ax_info->ctl_urb, GFP_ATOMIC); + if (status >= 0) { + break; + } + + last_req = next_req; + + spin_lock_irqsave(&ax_info->ctl_lock, flags); + } +} + +static int ax_sync_cmd_callback(struct ax8817x_info *unused, + struct ax_cmd_req *req) +{ + wait_queue_head_t *wq = (wait_queue_head_t *) req->priv; + + wake_up(wq); + + return 0; +} + +static int ax_async_cmd_callback(struct ax8817x_info *unused, + struct ax_cmd_req *req) +{ + if (req->status < 0) { + err("%s: Async command %d failed: %d\n", __FUNCTION__, + req->devreq.bRequest, req->status); + } + + /* Nothing else to do here, just need to free the request (and its + allocated data) */ + if (req->data != NULL) { + kfree(req->data); + } + kfree(req); + + return 0; +} + +/* + * This is mostly the same as usb_control_msg(), except that it is able + * to queue control messages +*/ +static int ax_control_msg(struct ax8817x_info *ax_info, u8 requesttype, + u8 request, u16 value, u16 index, void *data, + u16 size, int timeout) +{ + struct ax_cmd_req *req; + DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAITQUEUE(wait, current); + int ret; + + req = kmalloc(sizeof(struct ax_cmd_req), GFP_KERNEL); + if (req == NULL) { + return -ENOMEM; + } + + req->devreq.bRequestType = requesttype; + req->devreq.bRequest = request; + req->devreq.wValue = cpu_to_le16(value); + req->devreq.wIndex = cpu_to_le16(index); + req->devreq.wLength = cpu_to_le16(size); + req->data = data; + req->data_size = size; + req->timeout = timeout; + + req->priv = &wq; + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&wq, &wait); + + req->cmd_callback = ax_sync_cmd_callback; + + ax_run_ctl_queue(ax_info, req, 0); + schedule(); + + ret = req->status; + + kfree(req); + + return ret; +} + +/* + * Same, but can be used asynchronously, may fail, and returns no exit + * status +*/ +static void ax_control_msg_async(struct ax8817x_info *ax_info, + u8 requesttype, u8 request, u16 value, + u16 index, void *data, u16 size, + int timeout) +{ + struct ax_cmd_req *req; + + req = kmalloc(sizeof(struct ax_cmd_req), GFP_ATOMIC); + if (req == NULL) { + /* There's not much else we can do here... */ + err("%s: Failed alloc\n", __FUNCTION__); + return; + } + + req->devreq.bRequestType = requesttype; + req->devreq.bRequest = request; + req->devreq.wValue = cpu_to_le16(value); + req->devreq.wIndex = cpu_to_le16(index); + req->devreq.wLength = cpu_to_le16(size); + req->data = data; + req->data_size = size; + req->timeout = timeout; + + req->cmd_callback = ax_async_cmd_callback; + + ax_run_ctl_queue(ax_info, req, 0); +} + +static inline int ax_read_cmd(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, void *data) +{ + return ax_control_msg(ax_info, AX_REQ_READ, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static inline int ax_write_cmd(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, void *data) +{ + return ax_control_msg(ax_info, AX_REQ_WRITE, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static inline void ax_write_cmd_async(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, + void *data) +{ + ax_control_msg_async(ax_info, AX_REQ_WRITE, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static int ax_refill_rx_urb(struct ax8817x_info *ax_info, struct urb *urb) +{ + struct sk_buff *skb; + int ret; + + skb = dev_alloc_skb(AX_RX_MAX + 2); + if (skb != NULL) { + skb_reserve(skb, 2); /* for IP header alignment */ + skb->dev = ax_info->net; + + usb_fill_bulk_urb(urb, ax_info->usb, + usb_rcvbulkpipe(ax_info->usb, 3), + skb->data, AX_RX_MAX, ax_rx_callback, + skb); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + err("Failed submit rx URB (%d)\n", ret); + dev_kfree_skb_irq(skb); + urb->context = NULL; + } else { + ret = 0; + } + } else { + /* this just means we're low on memory at the moment. Try to + handle it gracefully. */ + urb->context = NULL; + ret = 1; + } + + return ret; +} + +static int ax_phy_cmd_callback(struct ax8817x_info *ax_info, + struct ax_cmd_req *req) +{ + int full_duplex; + int flow_control; + u16 mii_data_le; + + if (req->status < 0) { + err("%s: Failed at state %d: %d\n", __FUNCTION__, + ax_info->phy_state, req->status); + /* Not sure what else we can do, so just bail */ + ax_info->phy_state = AX_PHY_STATE_ABORTING; + } + + switch (ax_info->phy_state) { + /* Now that we're in software MII mode, read the BMSR */ + case AX_PHY_STATE_POLLING_1: + ax_info->phy_state = AX_PHY_STATE_POLLING_2; + req->devreq.bRequestType = AX_REQ_READ; + req->devreq.bRequest = AX_CMD_READ_MII_REG; + req->devreq.wValue = cpu_to_le16(ax_info->phy_id); + req->devreq.wIndex = cpu_to_le16(MII_BMSR); + req->devreq.wLength = cpu_to_le16(2); + req->data_size = 2; + req->priv = 0; /* This is the retry count */ + return 1; + + /* Done reading BMSR */ + case AX_PHY_STATE_POLLING_2: + mii_data_le = *(u16 *) req->data; + if ((mii_data_le & + cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) + == cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) { + if (mii_data_le & cpu_to_le16(BMSR_ANEGCOMPLETE)) { + /* Autonegotiation done, go on to read LPA */ + ax_info->phy_state = + AX_PHY_STATE_POLLING_3; + req->devreq.wIndex = cpu_to_le16(MII_LPA); + return 1; + } else if ((long) req->priv++ < AX_MAX_PHY_RETRY) { + /* Reread BMSR if it's still autonegotiating. This is + probably unnecessary logic, I've never seen it take + more than 1 try... */ + return 1; + } + /* else fall through to abort */ + } + /* XXX: should probably handle auto-neg failure better, + by reverting to manual setting of something safe. (?) */ + + ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; + /* and then fall through to set hw MII */ + + /* Got what we needed from PHY, set back to hardware MII mode + (Do same for abort in mid-poll) */ + case AX_PHY_STATE_POLLING_3: + case AX_PHY_STATE_ABORT_POLL: + ax_info->phy_state += 1; + req->devreq.bRequestType = AX_REQ_WRITE; + req->devreq.bRequest = AX_CMD_SET_HW_MII; + req->devreq.wValue = cpu_to_le16(0); + req->devreq.wIndex = cpu_to_le16(0); + req->devreq.wLength = cpu_to_le16(0); + req->data_size = 0; + return 1; + + /* The end result, set the right duplex and flow control mode in the + MAC (based on the PHY's LPA reg, which should still be in the data + buffer) */ + case AX_PHY_STATE_POLLING_4: + mii_data_le = *(u16 *) req->data; + ax_info->phy_state = AX_PHY_STATE_SETTING_MAC; + req->devreq.bRequest = AX_CMD_WRITE_MEDIUM_MODE; + full_duplex = mii_data_le & cpu_to_le16(LPA_DUPLEX); + flow_control = full_duplex && + (mii_data_le & cpu_to_le16(0x0400)); + req->devreq.wValue = cpu_to_le16(0x04) | + (full_duplex ? cpu_to_le16(0x02) : 0) | + (flow_control ? cpu_to_le16(0x10) : 0); + info("%s: Link established, %s duplex, flow control %sabled\n", ax_info->net->name, full_duplex ? "full" : "half", flow_control ? "en" : "dis"); + return 1; + + /* All done */ + case AX_PHY_STATE_SETTING_MAC: + ax_info->phy_state = AX_PHY_STATE_LINK; + netif_carrier_on(ax_info->net); + return 0; + + default: + err("%s: Unknown state %d\n", __FUNCTION__, + ax_info->phy_state); + /* fall through */ + case AX_PHY_STATE_ABORTING: + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + return 0; + } +} + +static void ax_int_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = + (struct ax8817x_info *) urb->context; + u8 phy_link; + + if (ax_info->drv_state == AX_DRV_STATE_EXITING || + urb->actual_length < 3) { + return; + } + + /* Ignore the first PHY link report, it will sometimes be reported as + link active, even though we just told the PHY to reset. If it + really has link, we'll pick it up next int callback. + */ + if (ax_info->phy_state == AX_PHY_STATE_INITIALIZING) { + netif_carrier_off(ax_info->net); + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + return; + } + + /* Assume we're only interested in the primary PHY for now. */ + phy_link = ax_info->int_buf[2] & 1; + + if (phy_link == + (ax_info->phy_state == AX_PHY_STATE_NO_LINK) ? 0 : 1) { + /* Common case, no change */ + return; + } + + if (phy_link == 0) { + netif_carrier_off(ax_info->net); + /* Abort an in-progress poll of the PHY if necessary */ + switch (ax_info->phy_state) { + case AX_PHY_STATE_POLLING_1: + case AX_PHY_STATE_POLLING_2: + case AX_PHY_STATE_POLLING_3: + ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; + break; + + case AX_PHY_STATE_POLLING_4: + case AX_PHY_STATE_SETTING_MAC: + ax_info->phy_state = AX_PHY_STATE_ABORTING; + break; + + case AX_PHY_STATE_LINK: + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + break; + + default: + /* If we're already aborting, continue aborting */ + break; + } + } else { + /* Note that we only fall into this case if previous phy_state was + AX_PHY_STATE_NO_LINK. When the link is reported active while + we're still polling, or when we're aborting, the logic above + will just return, and we'll check again next int callback. */ + + ax_info->phy_state = AX_PHY_STATE_POLLING_1; + ax_info->phy_req.devreq.bRequestType = AX_REQ_WRITE; + ax_info->phy_req.devreq.bRequest = AX_CMD_SET_SW_MII; + ax_info->phy_req.devreq.wValue = cpu_to_le16(0); + ax_info->phy_req.devreq.wIndex = cpu_to_le16(0); + ax_info->phy_req.devreq.wLength = cpu_to_le16(0); + ax_info->phy_req.data_size = 0; + ax_info->phy_req.timeout = AX_TIMEOUT_CMD; + ax_info->phy_req.cmd_callback = ax_phy_cmd_callback; + + ax_run_ctl_queue(ax_info, &ax_info->phy_req, 0); + } +} + +static void ax_rx_callback(struct urb *urb, struct pt_regs *regs) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct net_device *net = skb->dev; + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + int ret, len, refill; + + switch (urb->status) { + case 0: + break; + + default: + err("%s: URB status %d\n", __FUNCTION__, urb->status); + /* It's not clear that we can do much in this case, the rx pipe + doesn't ever seem to stall, so if we got -ETIMEDOUT, that + usually means the device was unplugged, and we just haven't + noticed yet. + Just fall through and free skb without resubmitting urb. */ + case -ENOENT: /* */ + case -ECONNRESET: /* Async unlink */ + case -ESHUTDOWN: /* Hardware gone */ + case -EILSEQ: /* Get this when you yank it out on UHCI */ + case -ETIMEDOUT: /* OHCI */ + case -EPROTO: /* EHCI */ + case -EPIPE: + dev_kfree_skb_any(skb); + urb->context = NULL; + return; + } + + if (ax_info->drv_state == AX_DRV_STATE_INITIALIZING) { + /* Not really expecting this to ever happen, since we haven't yet + enabled receive in the rx_ctl register, but ya never know... */ + goto refill_same; + } else if (ax_info->drv_state == AX_DRV_STATE_EXITING) { + dev_kfree_skb_any(skb); + urb->context = NULL; + return; + } + + len = urb->actual_length; + if (len == 0) { + /* this shouldn't happen... */ + goto refill_same; + } + + refill = ax_refill_rx_urb(ax_info, urb); + + if (refill == 0 + || atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { + /* Send the receive buffer up the network stack */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, net); + net->last_rx = jiffies; + ax_info->stats.rx_packets++; + ax_info->stats.rx_bytes += len; + + netif_rx(skb); + + if (refill == 0) { + int i; + + /* This is the common case. This URB got refilled OK, and + no other URBs need to be refilled. */ + if (atomic_read(&ax_info->rx_refill_cnt) == 0) { + return; + } + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb->context == NULL) { + if (ax_refill_rx_urb(ax_info, urb) + == 0) { + atomic_dec(&ax_info-> + rx_refill_cnt); + } else { + break; + } + } + } + } else { + /* remember to refill this one later */ + atomic_inc(&ax_info->rx_refill_cnt); + } + + return; + } else { + ax_info->stats.rx_dropped++; + if (refill < 0) { + /* the error code was already printk'ed in ax_refill_rx_urb() + so just note the consequences here: */ + warn("Halting rx due to error\n"); + return; + } + + /* fall through to resubmit this URB with the existing skb + will try to reallocate skb's on next rx callback */ + } + +refill_same: + usb_fill_bulk_urb(urb, ax_info->usb, + usb_rcvbulkpipe(ax_info->usb, 3), skb->data, + AX_RX_MAX, ax_rx_callback, skb); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + err("Failed submit rx URB (%d)\n", ret); + } +} + +static int ax8817x_open(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[4]; + int i, ret; + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0) { + return ret; + } + + ret = 0; + + ax_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->tx_urb == NULL) { + err("Error allocating tx_urb!"); + ret = -ENOMEM; + } + + atomic_set(&ax_info->rx_refill_cnt, 0); + + for (i = 0; i < n_rx_urbs && ret == 0; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb == NULL) { + urb = ax_info->rx_urbs[i] = + usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { + ret = -ENOMEM; + break; + } + if (n_rx_urbs > 1) { + urb->transfer_flags |= URB_NO_INTERRUPT; /* FIXME: Was USB_QUEUE_BULK */ + } + } + ret = ax_refill_rx_urb(ax_info, urb); + if (ret == 1) { + atomic_inc(&ax_info->rx_refill_cnt); + ret = 0; + } + } + + /* XXX: should handle the case where we couldn't allocate any skb's + better. They get allocated with GFP_ATOMIC, so they may all fail... */ + if (ret == 0 && atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { + netif_start_queue(net); + } else { + /* Error: clean up anything we allocated and bail. */ + usb_free_urb(ax_info->tx_urb); + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb != NULL) { + /* skb gets freed in the URB callback */ + usb_unlink_urb(urb); + usb_free_urb(urb); + } + } + + err("%s: Failed start rx queue (%d)\n", __FUNCTION__, ret); + } + return ret; +} + +static int ax8817x_stop(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[4]; + int i, ret; + + netif_stop_queue(net); + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0 && ax_info->drv_state != AX_DRV_STATE_EXITING) { + err("%s: Failed cmd (%d)\n", __FUNCTION__, ret); + } + if (ax_info->tx_urb != NULL) { + usb_unlink_urb(ax_info->tx_urb); + usb_free_urb(ax_info->tx_urb); + ax_info->tx_urb = NULL; + } + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + if (urb != NULL) { + /* skb gets freed in the URB callback */ + usb_unlink_urb(urb); + usb_free_urb(urb); + ax_info->rx_urbs[i] = NULL; + } + } + + return 0; +} + +static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = urb->context; + + if (!ax_info || (ax_info->drv_state == AX_DRV_STATE_EXITING)) + return; + + if (!netif_device_present(ax_info->net)) + return; + + if (urb->status) + info("%s: TX status %d", ax_info->net->name, urb->status); + + ax_info->net->trans_start = jiffies; + netif_wake_queue(ax_info->net); +} + +static int ax8817x_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + struct ax8817x_info *ax_info = net->priv; + int res; + + netif_stop_queue(net); + + ax_info->tx_urb->transfer_flags |= URB_ZERO_PACKET; + usb_fill_bulk_urb(ax_info->tx_urb, ax_info->usb, + usb_sndbulkpipe(ax_info->usb, 2), + skb->data, skb->len, write_bulk_callback, + ax_info); + if ((res = usb_submit_urb(ax_info->tx_urb, GFP_ATOMIC))) { + warn("Failed tx_urb %d", res); + ax_info->stats.tx_errors++; + netif_start_queue(net); + } else { + ax_info->stats.tx_packets++; + ax_info->stats.tx_bytes += skb->len; + net->trans_start = jiffies; + } + dev_kfree_skb(skb); + + return 0; +} + +static void ax8817x_tx_timeout(struct net_device *net) +{ + struct ax8817x_info *ax_info = net->priv; + + if (!ax_info) + return; + + warn("%s: Tx timed out.", net->name); + ax_info->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; + usb_unlink_urb(ax_info->tx_urb); + ax_info->stats.tx_errors++; +} + +static struct net_device_stats *ax8817x_stats(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + + return &ax_info->stats; +} + +static void ax8817x_set_multicast(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 rx_ctl = 0x8c; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x01; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > AX_MAX_MCAST) { + rx_ctl |= 0x02; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + struct dev_mc_list *mc_list = net->mc_list; + u8 *multi_filter; + u32 crc_bits; + int i; + + multi_filter = kmalloc(8, GFP_ATOMIC); + if (multi_filter == NULL) { + /* Oops, couldn't allocate a DMA buffer for setting the multicast + filter. Try all multi mode, although the ax_write_cmd_async + will almost certainly fail, too... (but it will printk). */ + rx_ctl |= 0x02; + } else { + memset(multi_filter, 0, 8); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + ax_write_cmd_async(ax_info, + AX_CMD_WRITE_MULTI_FILTER, 0, 0, + 8, multi_filter); + + rx_ctl |= 0x10; + } + } + + ax_write_cmd_async(ax_info, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, + NULL); +} + +static int read_mii_word(struct ax8817x_info *ax_info, __u8 phy, __u8 indx, + __u16 * regd) +{ + int ret; + + ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); + ret = + ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, phy, indx, 2, regd); + ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); + + return 0; +} + +static int write_mii_word(struct ax8817x_info *ax_info, __u8 phy, + __u8 indx, __u16 regd) +{ + warn("write_mii_word - not implemented!"); + return 0; +} + +static int mdio_read(struct net_device *dev, int phy_id, int loc) +{ + struct ax8817x_info *ax_info = dev->priv; + int res; + + read_mii_word(ax_info, phy_id, loc, (u16 *) & res); + return res & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int loc, + int val) +{ + struct ax8817x_info *ax_info = dev->priv; + + write_mii_word(ax_info, phy_id, loc, val); +} + +static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) +{ + struct ax8817x_info *ax_info; + int cmd; + + ax_info = net->priv; + if (get_user(cmd, (int *) uaddr)) + return -EFAULT; + + switch (cmd) { + case ETHTOOL_GDRVINFO:{ + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + + strlcpy(info.driver, DRIVER_NAME, + ETHTOOL_BUSINFO_LEN); + strlcpy(info.version, DRIVER_VERSION, + ETHTOOL_BUSINFO_LEN); + usb_make_path(ax_info->usb, info.bus_info,sizeof info.bus_info); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case ETHTOOL_GSET:{ + struct ethtool_cmd ecmd; + + mii_ethtool_gset(&ax_info->mii, &ecmd); + if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET:{ + int r; + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, uaddr, sizeof(ecmd))) + return -EFAULT; + r = mii_ethtool_sset(&ax_info->mii, &ecmd); + return r; + } + case ETHTOOL_NWAY_RST:{ + return mii_nway_restart(&ax_info->mii); + } + case ETHTOOL_GLINK:{ + struct ethtool_value edata = { ETHTOOL_GLINK }; + + edata.data = + ax_info->phy_state == AX_PHY_STATE_LINK; + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_GMSGLVL:{ + struct ethtool_value edata = { ETHTOOL_GMSGLVL }; + /* edata.data = ax_info->msg_enable; FIXME */ + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SMSGLVL:{ + struct ethtool_value edata; + + if (copy_from_user(&edata, uaddr, sizeof(edata))) + return -EFAULT; + /* sp->msg_enable = edata.data; FIXME */ + return 0; + } + } + return -EOPNOTSUPP; +} + +static int ax8817x_mii_ioctl(struct net_device *net, struct ifreq *ifr, + int cmd) +{ + struct ax8817x_info *ax_info; + struct mii_ioctl_data *data_ptr = + (struct mii_ioctl_data *) &(ifr->ifr_data); + + ax_info = net->priv; + + switch (cmd) { + case SIOCGMIIPHY: + data_ptr->phy_id = ax_info->phy_id; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, 0, + data_ptr->reg_num & 0x1f, 2, + &(data_ptr->val_out)); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr, + int cmd) +{ + struct ax8817x_info *ax_info; + int res; + + ax_info = net->priv; + res = 0; + + switch (cmd) { + case SIOCETHTOOL: + res = ax8817x_ethtool_ioctl(net, (void __user *)ifr->ifr_data); + break; + case SIOCGMIIPHY: /* Get address of PHY in use */ + case SIOCGMIIREG: /* Read from MII PHY register */ + case SIOCSMIIREG: /* Write to MII PHY register */ + return ax8817x_mii_ioctl(net, ifr, cmd); + default: + res = -EOPNOTSUPP; + } + + return res; +} + +static int ax8817x_net_init(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[6]; + u16 *buf16 = (u16 *) buf; + int ret; + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0) { + return ret; + } + + memset(buf, 0, 6); + + /* Get the MAC address */ + ret = ax_read_cmd(ax_info, AX_CMD_READ_NODE_ID, 0, 0, 6, buf); + if (ret < 0) { + return ret; + } + + memcpy(net->dev_addr, buf, 6); + + /* Get the PHY id */ + ret = ax_read_cmd(ax_info, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); + if (ret < 0) { + return ret; + } else if (ret < 2) { + /* this should always return 2 bytes */ + return -EIO; + } + + /* Reset the PHY, and drop it into auto-negotiation mode */ + ax_info->phy_id = buf[1]; + ax_info->phy_state = AX_PHY_STATE_INITIALIZING; + + ret = ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + if (ret < 0) { + return ret; + } + + *buf16 = cpu_to_le16(BMCR_RESET); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_BMCR, 2, buf16); + if (ret < 0) { + return ret; + } + + /* Advertise that we can do full-duplex pause */ + *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_ADVERTISE, 2, buf16); + if (ret < 0) { + return ret; + } + + *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_BMCR, 2, buf16); + if (ret < 0) { + return ret; + } + + ret = ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + if (ret < 0) { + return ret; + } + + net->open = ax8817x_open; + net->stop = ax8817x_stop; + net->hard_start_xmit = ax8817x_start_xmit; + net->tx_timeout = ax8817x_tx_timeout; + net->watchdog_timeo = AX_TIMEOUT_TX; + net->get_stats = ax8817x_stats; + net->do_ioctl = ax8817x_ioctl; + net->set_multicast_list = ax8817x_set_multicast; + + return 0; +} + +static int ax8817x_bind(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *usb = interface_to_usbdev(intf); + struct ax8817x_info *ax_info; + struct net_device *net; + int i, ret; + unsigned long gpio_bits = id->driver_info; + u8 buf[2]; + + /* Allocate the URB lists along with the device info struct */ + ax_info = kmalloc(sizeof(struct ax8817x_info) + + n_rx_urbs * sizeof(struct urb *), GFP_KERNEL); + if (ax_info == NULL) { + err("%s: Failed ax alloc\n", __FUNCTION__); + goto exit_err; + } + + memset(ax_info, 0, sizeof(struct ax8817x_info) + + n_rx_urbs * sizeof(struct urb *)); + + ax_info->drv_state = AX_DRV_STATE_INITIALIZING; + ax_info->rx_urbs = (struct urb **) (ax_info + 1); + ax_info->usb = usb; + + /* Set up the control URB queue */ + + INIT_LIST_HEAD(&ax_info->ctl_queue); + spin_lock_init(&ax_info->ctl_lock); + ax_info->ctl_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->ctl_urb == NULL) { + goto exit_err_free_ax; + } + + /* Toggle the GPIOs in a manufacturer/model specific way */ + + for (i = 2; i >= 0; i--) { + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_GPIOS, + (gpio_bits >> (i * 8)) & 0xff, 0, 0, + buf); + if (ret < 0) { + goto exit_err_free_ax; + } + wait_ms(5); + } + + /* Set up the net device */ + + net = alloc_etherdev(0); + if (net == NULL) { + err("%s: Failed net alloc\n", __FUNCTION__); + goto exit_err_free_ax; + } + + ax_info->net = net; + + SET_MODULE_OWNER(net); + net->init = ax8817x_net_init; + net->priv = ax_info; + + ret = register_netdev(net); + if (ret < 0) { + err("%s: Failed net init (%d)\n", __FUNCTION__, ret); + goto exit_err_free_net; + } + + /* Setup mii structure */ + ax_info->mii.dev = net; + ax_info->mii.mdio_read = mdio_read; + ax_info->mii.mdio_write = mdio_write; + ax_info->mii.phy_id_mask = 0x1f; + ax_info->mii.reg_num_mask = 0x1f; + + /* Set up the interrupt URB, and start PHY state monitoring */ + + ax_info->int_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->int_urb == NULL) { + goto exit_err_unregister_net; + } + ax_info->int_buf = kmalloc(8, GFP_KERNEL); + if (ax_info->int_buf == NULL) { + goto exit_err_free_int_urb; + } + ax_info->phy_req.data = kmalloc(2, GFP_KERNEL); + if (ax_info->phy_req.data == NULL) { + goto exit_err_free_int_buf; + } + + usb_fill_int_urb(ax_info->int_urb, usb, usb_rcvintpipe(usb, 1), + ax_info->int_buf, 8, ax_int_callback, ax_info, + 100); + + ret = usb_submit_urb(ax_info->int_urb, GFP_ATOMIC); + if (ret < 0) { + err("%s: Failed int URB submit (%d)\n", __FUNCTION__, ret); + goto exit_err_free_phy_buf; + } + + ax_info->drv_state = AX_DRV_STATE_RUNNING; + usb_set_intfdata(intf, ax_info); + + return 0; + + exit_err_free_phy_buf: + kfree(ax_info->phy_req.data); + + exit_err_free_int_buf: + kfree(ax_info->int_buf); + + exit_err_free_int_urb: + usb_free_urb(ax_info->int_urb); + + exit_err_unregister_net: + ax_info->drv_state = AX_DRV_STATE_EXITING; + unregister_netdev(net); + + exit_err_free_net: + kfree(net); + + exit_err_free_ax: + if (ax_info->ctl_urb != NULL) { + /* no need to unlink, since there should not be any ctl URBs + pending at this point */ + usb_free_urb(ax_info->ctl_urb); + } + + kfree(ax_info); + +exit_err: + err("%s: Failed to initialize\n", __FUNCTION__); + return -EIO; +} + +static void ax8817x_disconnect(struct usb_interface *intf) +{ + struct ax8817x_info *ax_info = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + if (ax_info) { + ax_info->drv_state = AX_DRV_STATE_EXITING; + + if (ax_info->int_urb != NULL) { + usb_unlink_urb(ax_info->int_urb); + usb_free_urb(ax_info->int_urb); + kfree(ax_info->int_buf); + } + + unregister_netdev(ax_info->net); + + /* XXX: hmmm... need to go through and clear out the ctl queue, too... */ + if (ax_info->ctl_urb != NULL) { + usb_unlink_urb(ax_info->ctl_urb); + usb_free_urb(ax_info->ctl_urb); + } + + kfree(ax_info); + } +} + +static struct usb_driver ax8817x_driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .probe = ax8817x_bind, + .disconnect = ax8817x_disconnect, + .id_table = ax8817x_id_table, +}; + +static int __init ax8817x_init(void) +{ + int ret; + + if (n_rx_urbs < 1) + n_rx_urbs = AX_RX_URBS_DEFAULT; + + ret = usb_register(&ax8817x_driver); + if (ret < 0) { + err("%s: Failed to register\n", __FUNCTION__); + } else { + info(DRIVER_DESC " " DRIVER_VERSION); + } + + return ret; +} + +static void __exit ax8817x_exit(void) +{ + usb_deregister(&ax8817x_driver); +} + +module_init(ax8817x_init); +module_exit(ax8817x_exit); diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index d8018a98743..d84208ebd1a 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -667,7 +667,7 @@ static void catc_set_multicast_list(struct net_device *netdev) /* * ioctl's */ -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct catc *catc = dev->priv; u32 cmd; @@ -726,7 +726,7 @@ static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { switch(cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(dev, (void __user *)rq->ifr_data); default: return -EOPNOTSUPP; } diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index effc6f16eea..4e1d82271f2 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -225,13 +225,17 @@ struct kaweth_device struct urb *rx_urb; struct urb *tx_urb; struct urb *irq_urb; + + dma_addr_t intbufferhandle; + __u8 *intbuffer; + dma_addr_t rxbufferhandle; + __u8 *rx_buf; + struct sk_buff *tx_skb; __u8 *firmware_buf; __u8 scratch[KAWETH_SCRATCH_SIZE]; - __u8 rx_buf[KAWETH_BUF_SIZE]; - __u8 intbuffer[INTBUFFERSIZE]; __u16 packet_filter_bitmap; struct kaweth_ethernet_configuration configuration; @@ -524,6 +528,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, KAWETH_BUF_SIZE, kaweth_usb_receive, kaweth); + kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { if (result == -ENOMEM) @@ -532,7 +538,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, } else { kaweth->suspend_lowmem = 0; } - + return result; } @@ -630,6 +636,8 @@ static int kaweth_open(struct net_device *net) int_callback, kaweth, HZ/4); + kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; + kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { @@ -662,13 +670,13 @@ static int kaweth_close(struct net_device *net) return 0; } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; - + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; - + switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; @@ -678,7 +686,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) return 0; } } - + return -EOPNOTSUPP; } @@ -689,7 +697,7 @@ static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { switch (cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(net, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(net, (void __user *)rq->ifr_data); } return -EOPNOTSUPP; } @@ -1033,6 +1041,19 @@ static int kaweth_probe( if (!kaweth->irq_urb) goto err_tx_and_rx; + kaweth->intbuffer = usb_buffer_alloc( kaweth->dev, + INTBUFFERSIZE, + GFP_KERNEL, + &kaweth->intbufferhandle); + if (!kaweth->intbuffer) + goto err_tx_and_rx_and_irq; + kaweth->rx_buf = usb_buffer_alloc( kaweth->dev, + KAWETH_BUF_SIZE, + GFP_KERNEL, + &kaweth->rxbufferhandle); + if (!kaweth->rx_buf) + goto err_all_but_rxbuf; + kaweth->net = netdev; memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr)); memcpy(kaweth->net->dev_addr, @@ -1053,7 +1074,7 @@ static int kaweth_probe( kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size); memset(&kaweth->stats, 0, sizeof(kaweth->stats)); - + SET_MODULE_OWNER(netdev); usb_set_intfdata(intf, kaweth); @@ -1071,6 +1092,12 @@ static int kaweth_probe( err_intfdata: usb_set_intfdata(intf, NULL); +err_all: + usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); +err_all_but_rxbuf: + usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); +err_tx_and_rx_and_irq: + usb_free_urb(kaweth->irq_urb); err_tx_and_rx: usb_free_urb(kaweth->rx_urb); err_only_tx: @@ -1123,6 +1150,11 @@ static void kaweth_disconnect(struct usb_interface *intf) usb_free_urb(kaweth->rx_urb); usb_free_urb(kaweth->tx_urb); + usb_free_urb(kaweth->irq_urb); + + + usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); + usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); kfree(kaweth); } diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 51004ee4483..562edd19784 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -945,7 +945,7 @@ static int pegasus_close(struct net_device *net) return 0; } #ifdef CONFIG_MII -static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int pegasus_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; @@ -1024,7 +1024,7 @@ static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr) } #else -static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) +static int pegasus_ethtool_ioctl(struct net_device *net, void __user *uaddr) { pegasus_t *pegasus; int cmd; @@ -1113,7 +1113,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) switch (cmd) { case SIOCETHTOOL: - res = pegasus_ethtool_ioctl(net, rq->ifr_data); + res = pegasus_ethtool_ioctl(net, (void __user *)rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = pegasus->phy; diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 13437d616fc..5ee56eb529c 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -673,7 +673,7 @@ static int rtl8150_close(struct net_device *netdev) return res; } -static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) +static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr) { rtl8150_t *dev; int cmd; @@ -758,7 +758,7 @@ static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) switch (cmd) { case SIOCETHTOOL: - res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); + res = rtl8150_ethtool_ioctl(netdev, (void __user *)rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = dev->phy; diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 596fb46284c..314d02187cf 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1622,6 +1622,11 @@ static const struct driver_info yopy_info = { .check_connect = always_connected, }; +static const struct driver_info blob_info = { + .description = "Boot Loader OBject", + .check_connect = always_connected, +}; + #endif /* CONFIG_USB_ARMLINUX */ @@ -2097,7 +2102,7 @@ done: /*-------------------------------------------------------------------------*/ static inline int -usbnet_ethtool_ioctl (struct net_device *net, void *useraddr) +usbnet_ethtool_ioctl (struct net_device *net, void __user *useraddr) { struct usbnet *dev = (struct usbnet *) net->priv; u32 cmd; @@ -2161,7 +2166,7 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { switch (cmd) { case SIOCETHTOOL: - return usbnet_ethtool_ioctl (net, (void *)rq->ifr_data); + return usbnet_ethtool_ioctl (net, (void __user *)rq->ifr_data); default: return -EOPNOTSUPP; } @@ -2707,6 +2712,9 @@ static const struct usb_device_id products [] = { }, { USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" .driver_info = (unsigned long) &yopy_info, +}, { + USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader + .driver_info = (unsigned long) &blob_info, }, #endif diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 5cba0713844..3c6e0eb4901 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -548,10 +548,9 @@ void isd200_invoke_transport( struct us_data *us, /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("-- transport indicates command was aborted\n"); - srb->result = DID_ABORT << 16; - return; + if (us->sm_state == US_STATE_ABORTING) { + US_DEBUGP("-- command was aborted\n"); + goto Handle_Abort; } switch (transferStatus) { @@ -561,6 +560,11 @@ void isd200_invoke_transport( struct us_data *us, srb->result = SAM_STAT_GOOD; break; + case USB_STOR_TRANSPORT_NO_SENSE: + US_DEBUGP("-- transport indicates protocol failure\n"); + srb->result = SAM_STAT_CHECK_CONDITION; + return; + case USB_STOR_TRANSPORT_FAILED: US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; @@ -591,10 +595,9 @@ void isd200_invoke_transport( struct us_data *us, if (need_auto_sense) { result = isd200_read_regs(us); - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- auto-sense aborted\n"); - srb->result = DID_ABORT << 16; - return; + goto Handle_Abort; } if (result == ISD200_GOOD) { isd200_build_sense(us, srb); @@ -603,8 +606,10 @@ void isd200_invoke_transport( struct us_data *us, /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = SAM_STAT_GOOD; - } else + } else { srb->result = DID_ERROR << 16; + /* Need reset here */ + } } /* Regardless of auto-sense, if we _know_ we have an error @@ -612,6 +617,16 @@ void isd200_invoke_transport( struct us_data *us, */ if (transferStatus == USB_STOR_TRANSPORT_FAILED) srb->result = SAM_STAT_CHECK_CONDITION; + return; + + /* abort processing: the bulk-only transport requires a reset + * following an abort */ + Handle_Abort: + srb->result = DID_ABORT << 16; + + /* permit the reset transfer to take place */ + clear_bit(US_FLIDX_ABORTING, &us->flags); + /* Need reset here */ } #ifdef CONFIG_USB_STORAGE_DEBUG diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 9dc830cf2f0..97476a3789b 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -82,6 +82,10 @@ static void fix_inquiry_data(Scsi_Cmnd *srb) if (srb->cmnd[0] != INQUIRY) return; + /* oddly short buffer -- bail out */ + if (srb->request_bufflen < 3) + return; + data_ptr = find_data_location(srb); if ((data_ptr[2] & 7) == 2) diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h index 32b29498c77..2868ae4e485 100644 --- a/drivers/usb/storage/protocol.h +++ b/drivers/usb/storage/protocol.h @@ -57,6 +57,8 @@ #define US_SC_MIN US_SC_RBC #define US_SC_MAX US_SC_ISD200 +#define US_SC_DEVICE 0xff /* Use device's value */ + extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 06e66f8874b..cd64dc35b25 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -57,100 +57,36 @@ * Host functions ***********************************************************************/ -static const char* usb_storage_info(struct Scsi_Host *host) +static const char* host_info(struct Scsi_Host *host) { return "SCSI emulation for USB Mass Storage devices"; } -#if 0 -/* detect a virtual adapter (always works) - * Synchronization: 2.4: with the io_request_lock - * 2.5: no locks. - * fortunately we don't care. - * */ -static int usb_storage_detect(struct SHT *sht) +static int slave_configure (struct scsi_device *sdev) { - struct us_data *us; - char local_name[32]; - - /* This is not nice at all, but how else are we to get the - * data here? */ - us = (struct us_data *)sht->proc_dir; - - /* set up the name of our subdirectory under /proc/scsi/ */ - sprintf(local_name, "usb-storage-%d", us->host_number); - sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); - if (!sht->proc_name) - return 0; - strcpy(sht->proc_name, local_name); - - /* we start with no /proc directory entry */ - sht->proc_dir = NULL; - - /* register the host */ - us->host = scsi_register(sht, sizeof(us)); - if (us->host) { - struct usb_interface *iface; - us->host->hostdata[0] = (unsigned long)us; - us->host_no = us->host->host_no; - iface = usb_ifnum_to_if(us->pusb_dev, us->ifnum); - if (iface) - scsi_set_device(us->host, &iface->dev); - return 1; - } + /* set device to use 10-byte commands where possible */ + sdev->use_10_for_ms = 1; + sdev->use_10_for_rw = 1; - /* odd... didn't register properly. Abort and free pointers */ - kfree(sht->proc_name); - sht->proc_name = NULL; + /* this is to satisify the compiler, tho I don't think the + * return code is ever checked anywhere. */ return 0; } -/* Release all resources used by the virtual host - * - * NOTE: There is no contention here, because we're already deregistered - * the driver and we're doing each virtual host in turn, not in parallel - * Synchronization: BKL, no spinlock. - */ -static int usb_storage_release(struct Scsi_Host *psh) -{ - struct us_data *us = (struct us_data *)psh->hostdata[0]; - - US_DEBUGP("release() called for host %s\n", us->htmplt.name); - - /* Kill the control threads - * - * Enqueue the command, wake up the thread, and wait for - * notification that it has exited. - */ - US_DEBUGP("-- sending exit command to thread\n"); - BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); - us->srb = NULL; - up(&(us->sema)); - wait_for_completion(&(us->notify)); - - /* remove the pointer to the data structure we were using */ - (struct us_data*)psh->hostdata[0] = NULL; - - /* we always have a successful release */ - return 0; -} -#endif - /* queue a command */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); - US_DEBUGP("queuecommand() called\n"); + US_DEBUGP("%s called\n", __FUNCTION__); srb->host_scribble = (unsigned char *)us; /* enqueue the command */ - if (state != US_STATE_IDLE || us->srb != NULL) { + if (us->sm_state != US_STATE_IDLE || us->srb != NULL) { printk(KERN_ERR USB_STORAGE "Error in %s: " "state = %d, us->srb = %p\n", - __FUNCTION__, state, us->srb); + __FUNCTION__, us->sm_state, us->srb); return SCSI_MLQUEUE_HOST_BUSY; } @@ -169,11 +105,10 @@ static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) /* Command abort */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_command_abort( Scsi_Cmnd *srb ) +static int command_abort( Scsi_Cmnd *srb ) { struct Scsi_Host *host = srb->device->host; struct us_data *us = (struct us_data *) host->hostdata[0]; - int state = atomic_read(&us->sm_state); US_DEBUGP("%s called\n", __FUNCTION__); @@ -186,20 +121,20 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb ) /* Normally the current state is RUNNING. If the control thread * hasn't even started processing this command, the state will be * IDLE. Anything else is a bug. */ - if (state != US_STATE_RUNNING && state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_RUNNING + && us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* Set state to ABORTING, set the ABORTING bit, and release the lock */ - atomic_set(&us->sm_state, US_STATE_ABORTING); + us->sm_state = US_STATE_ABORTING; set_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(host); - /* If the state was RUNNING, stop an ongoing USB transfer */ - if (state == US_STATE_RUNNING) - usb_stor_stop_transport(us); + /* Stop an ongoing USB transfer */ + usb_stor_stop_transport(us); /* Wait for the aborted command to finish */ wait_for_completion(&us->notify); @@ -213,35 +148,30 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb ) /* This invokes the transport reset mechanism to reset the state of the * device */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_device_reset( Scsi_Cmnd *srb ) +static int device_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); int result; US_DEBUGP("%s called\n", __FUNCTION__); - if (state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RESETTING); + us->sm_state = US_STATE_RESETTING; scsi_unlock(srb->device->host); - /* lock the device pointers */ + /* lock the device pointers and do the reset */ down(&(us->dev_semaphore)); - - /* do the reset */ result = us->transport_reset(us); - - /* unlock */ up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(srb->device->host); - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; return result; } @@ -249,45 +179,42 @@ static int usb_storage_device_reset( Scsi_Cmnd *srb ) /* It refuses to work if there's more than one interface in * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_bus_reset( Scsi_Cmnd *srb ) +static int bus_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); int result; US_DEBUGP("%s called\n", __FUNCTION__); - if (state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RESETTING); + us->sm_state = US_STATE_RESETTING; scsi_unlock(srb->device->host); /* The USB subsystem doesn't handle synchronisation between - a device's several drivers. Therefore we reset only devices - with just one interface, which we of course own. - */ - - //FIXME: needs locking against config changes - - if (us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + * a device's several drivers. Therefore we reset only devices + * with just one interface, which we of course own. */ - /* lock the device and attempt to reset the port */ - down(&(us->dev_semaphore)); - result = usb_reset_device(us->pusb_dev); - up(&(us->dev_semaphore)); - US_DEBUGP("usb_reset_device returns %d\n", result); - } else { + down(&(us->dev_semaphore)); + if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + result = -EIO; + US_DEBUGP("Attempt to reset during disconnect\n"); + } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { result = -EBUSY; US_DEBUGP("Refusing to reset a multi-interface device\n"); + } else { + result = usb_reset_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); } + up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(srb->device->host); - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; return result < 0 ? FAILED : SUCCESS; } @@ -300,7 +227,7 @@ static int usb_storage_bus_reset( Scsi_Cmnd *srb ) #define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) -static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, +static int proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, int length, int inout) { struct us_data *us; @@ -333,8 +260,6 @@ static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char #define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) DO_FLAG(SINGLE_LUN); DO_FLAG(MODE_XLATE); - DO_FLAG(START_STOP); - DO_FLAG(IGNORE_SER); DO_FLAG(SCM_MULT_TARG); DO_FLAG(FIX_INQUIRY); DO_FLAG(FIX_CAPACITY); @@ -360,29 +285,20 @@ static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char * this defines our host template, with which we'll allocate hosts */ -struct SHT usb_stor_host_template = { +struct scsi_host_template usb_stor_host_template = { /* basic userland interface stuff */ .name = "usb-storage", .proc_name = "usb-storage", - .proc_info = usb_storage_proc_info, - .proc_dir = NULL, - .info = usb_storage_info, - .ioctl = NULL, - - /* old-style detect and release */ - .detect = NULL, - .release = NULL, + .proc_info = proc_info, + .info = host_info, /* command interface -- queued only */ - .command = NULL, - .queuecommand = usb_storage_queuecommand, + .queuecommand = queuecommand, /* error and abort handlers */ - .eh_abort_handler = usb_storage_command_abort, - .eh_device_reset_handler = usb_storage_device_reset, - .eh_bus_reset_handler = usb_storage_bus_reset, - .eh_host_reset_handler = NULL, - .eh_strategy_handler = NULL, + .eh_abort_handler = command_abort, + .eh_device_reset_handler = device_reset, + .eh_bus_reset_handler = bus_reset, /* queue commands only, only one command per LUN */ .can_queue = 1, @@ -391,21 +307,11 @@ struct SHT usb_stor_host_template = { /* unknown initiator id */ .this_id = -1, - /* no limit on commands */ - .max_sectors = 0, - - /* pre- and post- device scan functions */ - .slave_alloc = NULL, - .slave_configure = NULL, - .slave_destroy = NULL, + .slave_configure = slave_configure, /* lots of sg segments can be handled */ .sg_tablesize = SG_ALL, - /* use 32-bit address space for DMA */ - .unchecked_isa_dma = FALSE, - .highmem_io = FALSE, - /* merge commands... this seems to help performance, but * periodically someone should test to see which setting is more * optimal. @@ -415,9 +321,6 @@ struct SHT usb_stor_host_template = { /* emulated HBA */ .emulated = TRUE, - /* sorry, no BIOS to help us */ - .bios_param = NULL, - /* module management */ .module = THIS_MODULE }; diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h index 35f4cb7e4bf..4d604c23974 100644 --- a/drivers/usb/storage/scsiglue.h +++ b/drivers/usb/storage/scsiglue.h @@ -47,7 +47,7 @@ extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_invalidCDB[18]; -extern struct SHT usb_stor_host_template; +extern struct scsi_host_template usb_stor_host_template; extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index f7fd0de14c3..1acd6079f98 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -136,9 +136,9 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) struct timer_list to_timer; int status; - /* don't submit URBS during abort/disconnect processing */ + /* don't submit URBs during abort/disconnect processing */ if (us->flags & DONT_SUBMIT) - return -ECONNRESET; + return -EIO; /* set up data structures for the wakeup system */ init_completion(&urb_done); @@ -299,17 +299,17 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; - /* NAK - that means we've retried this a few times already */ + /* timeout or excessively long NAK */ case -ETIMEDOUT: - US_DEBUGP("-- device NAKed\n"); + US_DEBUGP("-- timeout or NAK\n"); return USB_STOR_XFER_ERROR; /* babble - the device tried to send more than we wanted to read */ case -EOVERFLOW: - US_DEBUGP("-- Babble\n"); + US_DEBUGP("-- babble\n"); return USB_STOR_XFER_LONG; - /* the transfer was cancelled, presumably by an abort */ + /* the transfer was cancelled by abort, disconnect, or timeout */ case -ECONNRESET: US_DEBUGP("-- transfer cancelled\n"); return USB_STOR_XFER_ERROR; @@ -319,6 +319,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, US_DEBUGP("-- short read transfer\n"); return USB_STOR_XFER_SHORT; + /* abort or disconnect in progress */ + case -EIO: + US_DEBUGP("-- abort or disconnect in progress\n"); + return USB_STOR_XFER_ERROR; + /* the catch-all error case */ default: US_DEBUGP("-- unknown error\n"); @@ -430,7 +435,7 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, /* initialize the scatter-gather request block */ US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__, length, num_sg); - result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0, + result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, sg, num_sg, length, SLAB_NOIO); if (result) { US_DEBUGP("usb_sg_init returned %d\n", result); @@ -447,19 +452,19 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, /* cancel the request, if it hasn't been cancelled already */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(us->current_sg); + usb_sg_cancel(&us->current_sg); } } /* wait for the completion of the transfer */ - usb_sg_wait(us->current_sg); + usb_sg_wait(&us->current_sg); clear_bit(US_FLIDX_SG_ACTIVE, &us->flags); - result = us->current_sg->status; + result = us->current_sg.status; if (act_len) - *act_len = us->current_sg->bytes; + *act_len = us->current_sg.bytes; return interpret_urb_result(us, pipe, length, result, - us->current_sg->bytes); + us->current_sg.bytes); } /* @@ -518,7 +523,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- command was aborted\n"); goto Handle_Abort; } @@ -650,7 +655,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) srb->cmd_len = old_cmd_len; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- auto-sense aborted\n"); goto Handle_Abort; } @@ -734,7 +739,7 @@ void usb_stor_stop_transport(struct us_data *us) /* If we are waiting for a scatter-gather operation, cancel it. */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(us->current_sg); + usb_sg_cancel(&us->current_sg); } } diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index dd59c7bb40e..44ce6fd88be 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -63,17 +63,19 @@ #define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ #ifdef CONFIG_USB_STORAGE_FREECOM -#define US_PR_FREECOM 0xf1 /* Freecom */ +#define US_PR_FREECOM 0xf1 /* Freecom */ #endif #ifdef CONFIG_USB_STORAGE_DATAFAB -#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ +#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ #endif #ifdef CONFIG_USB_STORAGE_JUMPSHOT -#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ +#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ #endif +#define US_PR_DEVICE 0xff /* Use device's value */ + /* * Bulk only data structures */ diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 05874cdf9b7..9d0c5e7e662 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -75,28 +75,26 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, /* Deduced by Jonathan Woithe * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message - * always fails and confuses drive; without US_FL_START_STOP, drive accesses - * (read or write) all fail. + * always fails and confuses drive. */ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, "Buffalo", "DUB-P40G HDD", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY | US_FL_START_STOP), + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY ), #ifdef CONFIG_USB_STORAGE_DPCM UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), + US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), #endif /* Made with the help of Edd Dumbill */ UNUSUAL_DEV( 0x0451, 0x5409, 0x0001, 0x0001, "Frontier Labs", "Nex II Digital", - US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), + US_SC_SCSI, US_PR_BULK, NULL, 0), /* Patch submitted by Philipp Friedrich */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, @@ -124,15 +122,6 @@ UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, "785EPX Storage", US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN), -/* Reported by Jan Willamowius - * The device needs the flags only. - */ -UNUSUAL_DEV( 0x04c8, 0x0723, 0x0000, 0x9999, - "Konica", - "KD-200Z", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP), - UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, "Fujifilm", "FinePix 1400Zoom", @@ -144,7 +133,7 @@ UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, "ScanLogic", "SL11R-IDE", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), /* Reported by Kriston Fincher @@ -183,14 +172,14 @@ UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999, "Sandisk", "ImageMate SDDR09", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* This entry is from Andries.Brouwer@cwi.nl */ UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, "SCM Microsystems", "eUSB SmartMedia / CompactFlash Adapter", US_SC_SCSI, US_PR_DPCM_USB, sddr09_init, - US_FL_START_STOP), + 0), #endif UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0205, @@ -247,40 +236,40 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, "Iomega", "USB Clik! 40", US_SC_8070, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY | US_FL_START_STOP ), + US_FL_FIX_INQUIRY ), /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, "Sony", "DSC-S30/S70/S75/505V/F505/F707/F717/P8", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), + US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), /* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", "Memorystick NW-MS7", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, "Sony", "Memorystick MSAC-US1", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* Submitted by Klaus Mueller */ UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310, "Sony", "Handycam", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE), + US_FL_SINGLE_LUN | US_FL_MODE_XLATE), UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, "Sony", "Memorystick MSC-U01N", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* Submitted by Nathan Babb */ UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, @@ -316,7 +305,7 @@ UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, "Pentax", "Optio 2/3/400", - US_SC_8070, US_PR_CBI, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Submitted by Per Winkvist */ @@ -380,7 +369,7 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, "SIIG", "CompactFlash Card Reader", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Reported by Peter Marks @@ -393,7 +382,7 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001, "EagleTec", "External Hard Disk", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0x9999, @@ -402,6 +391,14 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0x9999, US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), +/* Reported by Hanno Boeck + * Taken from the Lycoris Kernel */ +UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, + "Vivitar", + "Vivicam 35Xx", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -412,25 +409,9 @@ UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, "Olympus", "Camedia MAUSB-2", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), #endif -/* Submitted by kedar@centillium - * Needed for START_STOP flag, but that is unconfirmed */ -UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - -/* Submitted by f.brugmans@hccnet.nl - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", "FlashGate SmartMedia", @@ -445,13 +426,12 @@ UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk", "ImageMate SDDR-05a", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP), + US_FL_SINGLE_LUN ), UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk", "ImageMate SDDR-31", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_IGNORE_SER), + US_SC_SCSI, US_PR_BULK, NULL, 0 ), UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -464,7 +444,7 @@ UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999, "Sandisk", "ImageMate SDDR-09", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), #endif #ifdef CONFIG_USB_STORAGE_FREECOM @@ -490,8 +470,7 @@ UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, "Microtech", "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), + US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), #endif #ifdef CONFIG_USB_STORAGE_DATAFAB @@ -568,7 +547,7 @@ UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999, UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, "Datafab", "KECF-USB", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant @@ -629,20 +608,7 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, "Global Channel Solutions", "EasyDisk EDxxxx", US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), - -/* Submitted by Brian Hall - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, - "JMTek", - "USBDrive", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), -UNUSUAL_DEV( 0x0c76, 0x0005, 0x0100, 0x0100, - "JMTek", - "USBDrive", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), + US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ), /* Reported by Dan Pilone * The device needs the flags only. @@ -652,8 +618,8 @@ UNUSUAL_DEV( 0x0c76, 0x0005, 0x0100, 0x0100, UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, "CCYU TECHNOLOGY", "EasyDisk Portable Device", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP), + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MODE_XLATE ), #ifdef CONFIG_USB_STORAGE_SDDR55 UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999, @@ -670,5 +636,5 @@ UNUSUAL_DEV( 0x08ca, 0x2011, 0x0000, 0x9999, "AIPTEK", "PocketCAM 3Mega", US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP), + US_FL_MODE_XLATE ), diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index e5606b237c2..dfe2a8d870d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -102,8 +102,6 @@ static void storage_disconnect(struct usb_interface *iface); /* The entries in this table, except for final ones here * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, * line for line with the entries of us_unsuaul_dev_list[]. - * For now, we duplicate idVendor and idProduct in us_unsual_dev_list, - * just to avoid alignment bugs. */ #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ @@ -328,13 +326,13 @@ static int usb_stor_control_thread(void * __us) scsi_lock(host); /* has the command been aborted *already* ? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { us->srb->result = DID_ABORT << 16; goto SkipForAbort; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RUNNING); + us->sm_state = US_STATE_RUNNING; scsi_unlock(host); /* lock the device pointers */ @@ -353,7 +351,7 @@ static int usb_stor_control_thread(void * __us) */ else if (us->srb->device->id && !(us->flags & US_FL_SCM_MULT_TARG)) { - US_DEBUGP("Bad target number (%d/%d)\n", + US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } @@ -404,12 +402,12 @@ static int usb_stor_control_thread(void * __us) * sm_state == US_STATE_ABORTING, not srb->result == DID_ABORT, * because an abort request might be received after all the * USB processing was complete. */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) + if (us->sm_state == US_STATE_ABORTING) complete(&(us->notify)); /* empty the queue, reset the state, and release the lock */ us->srb = NULL; - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; scsi_unlock(host); } /* for (;;) */ @@ -424,10 +422,13 @@ static int usb_stor_control_thread(void * __us) ***********************************************************************/ /* Get the unusual_devs entries and the string descriptors */ -static void get_device_info(struct us_data *us, - struct us_unusual_dev *unusual_dev) +static void get_device_info(struct us_data *us, int id_index) { struct usb_device *dev = us->pusb_dev; + struct usb_host_interface *altsetting = + &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting]; + struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; + struct usb_device_id *id = &storage_usb_ids[id_index]; if (unusual_dev->vendorName) US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); @@ -436,10 +437,40 @@ static void get_device_info(struct us_data *us, /* Store the entries */ us->unusual_dev = unusual_dev; - us->subclass = unusual_dev->useProtocol; - us->protocol = unusual_dev->useTransport; + us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? + altsetting->desc.bInterfaceSubClass : + unusual_dev->useProtocol; + us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ? + altsetting->desc.bInterfaceProtocol : + unusual_dev->useTransport; us->flags = unusual_dev->flags; + /* Log a message if a non-generic unusual_dev entry contains an + * unnecessary subclass or protocol override. This may stimulate + * reports from users that will help us remove unneeded entries + * from the unusual_devs.h table. + */ + if (id->idVendor || id->idProduct) { + static char *msgs[3] = { + "an unneeded SubClass entry", + "an unneeded Protocol entry", + "unneeded SubClass and Protocol entries"}; + int msg = -1; + + if (unusual_dev->useProtocol != US_SC_DEVICE && + us->subclass == altsetting->desc.bInterfaceSubClass) + msg += 1; + if (unusual_dev->useTransport != US_PR_DEVICE && + us->protocol == altsetting->desc.bInterfaceProtocol) + msg += 2; + if (msg >= 0) + printk(KERN_NOTICE USB_STORAGE "This device " + "(%04x,%04x) has %s in unusual_devs.h\n" + " Please send a copy of this message to " + "\n", + id->idVendor, id->idProduct, msgs[msg]); + } + /* Read the device's string descriptors */ if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, @@ -447,7 +478,7 @@ static void get_device_info(struct us_data *us, if (dev->descriptor.iProduct) usb_string(dev, dev->descriptor.iProduct, us->product, sizeof(us->product)); - if (dev->descriptor.iSerialNumber && !(us->flags & US_FL_IGNORE_SER)) + if (dev->descriptor.iSerialNumber) usb_string(dev, dev->descriptor.iSerialNumber, us->serial, sizeof(us->serial)); @@ -698,13 +729,6 @@ static int usb_stor_acquire_resources(struct us_data *us) return -ENOMEM; } - US_DEBUGP("Allocating scatter-gather request block\n"); - us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL); - if (!us->current_sg) { - US_DEBUGP("allocation failed\n"); - return -ENOMEM; - } - /* Lock the device while we carry out the next two operations */ down(&us->dev_semaphore); @@ -720,7 +744,7 @@ static int usb_stor_acquire_resources(struct us_data *us) up(&us->dev_semaphore); /* Start up our control thread */ - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); if (p < 0) { printk(KERN_WARNING USB_STORAGE @@ -736,7 +760,7 @@ static int usb_stor_acquire_resources(struct us_data *us) * Since this is a new device, we need to register a SCSI * host definition with the higher SCSI layers. */ - us->host = scsi_register(&usb_stor_host_template, sizeof(us)); + us->host = scsi_host_alloc(&usb_stor_host_template, sizeof(us)); if (!us->host) { printk(KERN_WARNING USB_STORAGE "Unable to register the scsi host\n"); @@ -772,7 +796,7 @@ void usb_stor_release_resources(struct us_data *us) /* Finish the SCSI host removal sequence */ if (us->host) { (struct us_data *) us->host->hostdata[0] = NULL; - scsi_unregister(us->host); + scsi_host_put(us->host); } /* Kill the control thread @@ -782,7 +806,7 @@ void usb_stor_release_resources(struct us_data *us) */ if (us->pid) { US_DEBUGP("-- sending exit command to thread\n"); - BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); + BUG_ON(us->sm_state != US_STATE_IDLE); us->srb = NULL; up(&(us->sema)); wait_for_completion(&(us->notify)); @@ -800,8 +824,6 @@ void usb_stor_release_resources(struct us_data *us) } /* Free the USB control blocks */ - if (us->current_sg) - kfree(us->current_sg); if (us->current_urb) usb_free_urb(us->current_urb); if (us->dr) @@ -852,7 +874,7 @@ static int storage_probe(struct usb_interface *intf, * of the match from the usb_device_id table, so we can find the * corresponding entry in the private table. */ - get_device_info(us, &us_unusual_dev_list[id_index]); + get_device_info(us, id_index); #ifdef CONFIG_USB_STORAGE_SDDR09 if (us->protocol == US_PR_EUSB_SDDR09 || diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index f0b9a231293..d287f4ee9b1 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -71,8 +71,6 @@ struct us_unusual_dev { #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for Win/MacOS compatibility */ -#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ @@ -139,7 +137,7 @@ struct us_data { /* thread information */ int pid; /* control thread */ - atomic_t sm_state; /* what we are doing */ + int sm_state; /* what we are doing */ /* interrupt communications data */ unsigned char irqdata[2]; /* data from USB IRQ */ @@ -147,7 +145,7 @@ struct us_data { /* control and bulk communications data */ struct urb *current_urb; /* non-int USB requests */ struct usb_ctrlrequest *dr; /* control requests */ - struct usb_sg_request *current_sg; /* scatter-gather USB */ + struct usb_sg_request current_sg; /* scatter-gather USB */ /* the semaphore for sleeping the control thread */ struct semaphore sema; /* to sleep thread on */ diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt new file mode 100644 index 00000000000..bd2ba8d2993 --- /dev/null +++ b/fs/Kconfig.binfmt @@ -0,0 +1,116 @@ +config BINFMT_ELF + tristate "Kernel support for ELF binaries" + depends on MMU + default y + ---help--- + ELF (Executable and Linkable Format) is a format for libraries and + executables used across different architectures and operating + systems. Saying Y here will enable your kernel to run ELF binaries + and enlarge it by about 13 KB. ELF support under Linux has now all + but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating systems + however) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. + + Information about ELF is contained in the ELF HOWTO available from + . + + If you find that after upgrading from Linux kernel 1.2 and saying Y + here, you still can't run any ELF binaries (they just crash), then + you'll have to install the newest ELF runtime libraries, including + ld.so (check the file for location and + latest version). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called binfmt_elf. Saying M or N here is dangerous because + some crucial programs on your system might be in ELF format. + +config BINFMT_FLAT + tristate "Kernel support for flat binaries" + depends on !MMU || SUPERH + help + Support uClinux FLAT format binaries. + +config BINFMT_ZFLAT + bool "Enable ZFLAT support" + depends on BINFMT_FLAT + help + Support FLAT format compressed binaries + +config BINFMT_AOUT + tristate "Kernel support for a.out and ECOFF binaries" + depends on X86 || ALPHA || ARM || M68K || SPARC + ---help--- + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used + the a.out formats QMAGIC and ZMAGIC until they were replaced + with the ELF format. + + The conversion to ELF started in 1995. This option is primarily + provided for historical interest and for the benefit of those + who need to run binaries from that era. + + Most people should answer N here. If you think you may have + occasional use for this format, enable module support above + and answer M here to compile this support as a module called + binfmt_aout. + + If any crucial components of your system (such as /sbin/init + or /lib/ld.so) are still in a.out format, you will have to + say Y here. + +config OSF4_COMPAT + bool "OSF/1 v4 readv/writev compatibility" + depends on ALPHA && BINFMT_AOUT + help + Say Y if you are using OSF/1 binaries (like Netscape and Acrobat) + with v4 shared libraries freely available from Compaq. If you're + going to use shared libraries from Tru64 version 5.0 or later, say N. + +config BINFMT_EM86 + tristate "Kernel support for Linux/Intel ELF binaries" + depends on ALPHA + ---help--- + Say Y here if you want to be able to execute Linux/Intel ELF + binaries just like native Alpha binaries on your Alpha machine. For + this to work, you need to have the emulator /usr/bin/em86 in place. + + You can get the same functionality by saying N here and saying Y to + "Kernel support for MISC binaries". + + You may answer M to compile the emulation support as a module and + later load the module when you want to use a Linux/Intel binary. The + module will be called binfmt_em86. If unsure, say Y. + +config BINFMT_SOM + tristate "Kernel support for SOM binaries" + depends on PARISC && HPUX + help + SOM is a binary executable format inherited from HP/UX. Say + Y here to be able to load and execute SOM binaries directly. + +config BINFMT_MISC + tristate "Kernel support for MISC binaries" + ---help--- + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + ). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. + + You can do other nice things, too. Read the file + to learn how to use this + feature, and for information about how + to include Java support. + + You may say M here for module support and later load the module when + you have use for it; the module is called binfmt_misc. If you + don't know what to answer at this point, say Y. diff --git a/fs/adfs/super.c b/fs/adfs/super.c index d5b8294a2fa..31591a9d6ea 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -189,7 +189,7 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data) return parse_options(sb, data); } -static int adfs_statfs(struct super_block *sb, struct statfs *buf) +static int adfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct adfs_sb_info *asb = ADFS_SB(sb); @@ -200,7 +200,7 @@ static int adfs_statfs(struct super_block *sb, struct statfs *buf) buf->f_files = asb->s_ids_per_zone * asb->s_map_size; buf->f_bavail = buf->f_bfree = adfs_map_free(sb); - buf->f_ffree = buf->f_bfree * buf->f_files / buf->f_blocks; + buf->f_ffree = (long)(buf->f_bfree * buf->f_files) / (long)buf->f_blocks; return 0; } diff --git a/fs/affs/super.c b/fs/affs/super.c index 61c71fe3f78..5a07bcd17f6 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -33,7 +33,7 @@ extern struct timezone sys_tz; -static int affs_statfs(struct super_block *sb, struct statfs *buf); +static int affs_statfs(struct super_block *sb, struct kstatfs *buf); static int affs_remount (struct super_block *sb, int *flags, char *data); static void @@ -524,7 +524,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) } static int -affs_statfs(struct super_block *sb, struct statfs *buf) +affs_statfs(struct super_block *sb, struct kstatfs *buf) { int free; diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 5295f9d97c8..4fb5a163e50 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -47,7 +47,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, char **out, int *out_len); static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); -static int befs_statfs(struct super_block *, struct statfs *); +static int befs_statfs(struct super_block *, struct kstatfs *); static int parse_options(char *, befs_mount_options *); static const struct super_operations befs_sops = { @@ -896,7 +896,7 @@ befs_remount(struct super_block *sb, int *flags, char *data) } static int -befs_statfs(struct super_block *sb, struct statfs *buf) +befs_statfs(struct super_block *sb, struct kstatfs *buf) { befs_debug(sb, "---> befs_statfs()"); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 7a28495b0a8..1cd9f94879a 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -191,7 +191,7 @@ static void bfs_put_super(struct super_block *s) s->s_fs_info = NULL; } -static int bfs_statfs(struct super_block *s, struct statfs *buf) +static int bfs_statfs(struct super_block *s, struct kstatfs *buf) { struct bfs_sb_info *info = BFS_SB(s); buf->f_type = BFS_MAGIC; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 21e8ea6d09d..910c65de26f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -697,7 +697,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += load_bias; - reloc_func_desc = load_addr; + reloc_func_desc = load_bias; } } k = elf_ppnt->p_vaddr; diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 0a02aa2bde5..03af9fb3514 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,17 @@ +Version 0.80 +----------- +Fix oops on stopping oplock thread when removing cifs when +built as module. + +Version 0.79 +------------ +Fix mount options for ro (readonly), uid, gid and file and directory mode. + +Version 0.78 +------------ +Fix errors displayed on failed mounts to be more understandable. +Fixed various incorrect or misleading smb to posix error code mappings. + Version 0.77 ------------ Fix display of NTFS DFS junctions to display as symlinks. diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index b6af49330e4..a59742e0474 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -432,7 +432,7 @@ static int compare_oid(unsigned long *oid1, unsigned int oid1len, unsigned long *oid2, unsigned int oid2len) { - int i; + unsigned int i; if (oid1len != oid2len) return 0; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 8574b4d014a..8007c2e925f 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -24,5 +24,9 @@ struct cifs_sb_info { struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; + uid_t mnt_uid; + gid_t mnt_gid; + mode_t mnt_file_mode; + mode_t mnt_dir_mode; }; #endif /* _CIFS_FS_SB_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ea19ac025e5..1b3c43949f3 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -62,6 +62,9 @@ extern int cifs_umount(struct super_block *, struct cifs_sb_info *); void cifs_proc_init(void); void cifs_proc_clean(void); +static DECLARE_COMPLETION(cifs_oplock_exited); + + static int cifs_read_super(struct super_block *sb, void *data, const char *devname, int silent) @@ -143,7 +146,7 @@ cifs_put_super(struct super_block *sb) } int -cifs_statfs(struct super_block *sb, struct statfs *buf) +cifs_statfs(struct super_block *sb, struct kstatfs *buf) { int xid, rc; struct cifs_sb_info *cifs_sb; @@ -427,7 +430,8 @@ cifs_destroy_mids(void) "cifs_destroy_mids: error not all structures were freed\n"); if (kmem_cache_destroy(cifs_oplock_cachep)) printk(KERN_WARNING - "error not all oplock structures were freed\n");} + "error not all oplock structures were freed\n"); +} static int cifs_oplock_thread(void * dummyarg) { @@ -439,14 +443,13 @@ static int cifs_oplock_thread(void * dummyarg) int rc; daemonize("cifsoplockd"); - allow_signal(SIGKILL); + allow_signal(SIGTERM); oplockThread = current; - while (1) { + do { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100*HZ); /* BB add missing code */ - cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */ write_lock(&GlobalMid_Lock); list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) { oplock_item = list_entry(tmp, struct oplock_q_entry, @@ -466,11 +469,10 @@ static int cifs_oplock_thread(void * dummyarg) write_lock(&GlobalMid_Lock); } else break; - cFYI(1,("next time through list")); /* BB remove */ } write_unlock(&GlobalMid_Lock); - cFYI(1,("next time through while loop")); /* BB remove */ - } + } while(!signal_pending(current)); + complete_and_exit (&cifs_oplock_exited, 0); } static int __init @@ -532,8 +534,10 @@ exit_cifs(void) cifs_destroy_inodecache(); cifs_destroy_mids(); cifs_destroy_request_bufs(); - if(oplockThread) - send_sig(SIGKILL, oplockThread, 1); + if(oplockThread) { + send_sig(SIGTERM, oplockThread, 1); + wait_for_completion(&cifs_oplock_exited); + } } MODULE_AUTHOR("Steve French "); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0506717b6c5..e557442f61f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -49,7 +49,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); -extern int smbCalcSize(struct smb_hdr *ptr); +extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int map_smb_to_linux_error(struct smb_hdr *smb); @@ -137,7 +137,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, unsigned int *pnum_referrals, unsigned char ** preferrals); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct statfs *FSData, + struct kstatfs *FSData, const struct nls_table *nls_codepage); extern int CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 978f5cacd82..1d2d347e3ad 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1782,7 +1782,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, - struct statfs *FSData, const struct nls_table *nls_codepage) + struct kstatfs *FSData, const struct nls_table *nls_codepage) { /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; @@ -1846,8 +1846,9 @@ CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, FSData->f_bfree = FSData->f_bavail = le64_to_cpu(response_data->FreeAllocationUnits); cFYI(1, - ("Blocks: %ld Free: %ld Block size %ld", - FSData->f_blocks, FSData->f_bfree, + ("Blocks: %lld Free: %lld Block size %ld", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, FSData->f_bsize)); } } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b38669111dd..add558cc01a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -53,7 +53,7 @@ struct smb_vol { char *UNC; char *UNCip; uid_t linux_uid; - uid_t linux_gid; + gid_t linux_gid; mode_t file_mode; mode_t dir_mode; int rw; @@ -136,8 +136,8 @@ cifs_reconnect(struct TCP_Server_Info *server) int cifs_demultiplex_thread(struct TCP_Server_Info *server) { - int length, total_read; - unsigned int pdu_length; + int length; + unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; struct msghdr smb_msg; mm_segment_t temp_fs; @@ -351,6 +351,10 @@ parse_mount_options(char *options, const char *devname, struct smb_vol *vol) memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; + vol->dir_mode = S_IRWXUGO; + /* 2767 perms indicate mandatory locking support */ + vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + vol->rw = TRUE; if (!options) @@ -466,6 +470,8 @@ parse_mount_options(char *options, const char *devname, struct smb_vol *vol) /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; + } else if (strnicmp(data, "ro", 2) == 0) { + vol->rw = FALSE; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } @@ -929,8 +935,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->rsize = PAGE_CACHE_SIZE; cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); } - - + cifs_sb->mnt_uid = volume_info.linux_uid; + cifs_sb->mnt_gid = volume_info.linux_gid; + cifs_sb->mnt_file_mode = volume_info.file_mode; + cifs_sb->mnt_dir_mode = volume_info.dir_mode; + cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d4345e45c40..de7dd790889 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -123,8 +123,8 @@ cifs_open(struct inode *inode, struct file *file) to problems creating new read-only files */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, cifs_sb->local_nls); else {/* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -351,8 +351,8 @@ cifs_write(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { int rc = 0; - int bytes_written = 0; - int total_written; + unsigned int bytes_written = 0; + unsigned int total_written; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; @@ -633,9 +633,9 @@ cifs_read(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { int rc = -EACCES; - int bytes_read = 0; - int total_read; - int current_read_size; + unsigned int bytes_read = 0; + unsigned int total_read; + unsigned int current_read_size; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid; @@ -742,13 +742,13 @@ cifs_readpages(struct file *file, struct address_space *mapping, struct list_head *page_list, unsigned num_pages) { int rc = -EACCES; - int xid,i; + int xid; loff_t offset; struct page * page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int bytes_read = 0; - unsigned int read_size; + unsigned int read_size,i; char * smb_read_data = 0; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; @@ -877,6 +877,8 @@ fill_in_inode(struct inode *tmp_inode, FILE_DIRECTORY_INFO * pfindData, int *pobject_type) { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + pfindData->ExtFileAttributes = le32_to_cpu(pfindData->ExtFileAttributes); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); @@ -894,7 +896,13 @@ fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ - tmp_inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + tmp_inode->i_uid = cifs_sb->mnt_uid; + tmp_inode->i_gid = cifs_sb->mnt_gid; + /* set default mode. will override for dirs below */ + tmp_inode->i_mode = cifs_sb->mnt_file_mode; + cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", pfindData->ExtFileAttributes)); @@ -905,7 +913,7 @@ fill_in_inode(struct inode *tmp_inode, } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ - tmp_inode->i_mode = S_IRWXUGO; + tmp_inode->i_mode = cifs_sb->mnt_dir_mode; tmp_inode->i_mode |= S_IFDIR; } else { *pobject_type = DT_REG; @@ -1091,10 +1099,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) { int rc = 0; - int xid, i; + int xid; int Unicode = FALSE; int UnixSearch = FALSE; - unsigned int bufsize; + unsigned int bufsize, i; __u16 searchHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7091afc6bd2..19b4bd43dca 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -224,16 +224,19 @@ cifs_get_inode_info(struct inode **pinode, cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime)); - inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms indicate mandatory locking - will override for dirs later */ cFYI(0, (" Attributes came in as 0x%x ", findData.Attributes)); - if (findData.Attributes & ATTR_REPARSE) { - /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ + + /* set default mode. will override for dirs below */ + inode->i_mode = cifs_sb->mnt_file_mode; + + if (findData.Attributes & ATTR_REPARSE) { + /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ inode->i_mode |= S_IFLNK; } else if (findData.Attributes & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking on dirs */ - inode->i_mode = S_IRWXUGO; - inode->i_mode |= S_IFDIR; + /* override default perms since we do not do byte range locking on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only mode e.g. 555 */ @@ -250,8 +253,11 @@ cifs_get_inode_info(struct inode **pinode, (unsigned long) inode->i_size, inode->i_blocks)); inode->i_nlink = le32_to_cpu(findData.NumberOfLinks); - /* BB fill in uid and gid here? with help from winbind? */ - + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + if (S_ISREG(inode->i_mode)) { cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; @@ -389,8 +395,8 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) direntry->d_inode->i_nlink = 2; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, cifs_sb->local_nls); else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 921ba32734d..ee4e95a20b7 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -274,12 +274,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, ntohl(smb->smb_buf_length))); - if ((length < 2 + sizeof (struct smb_hdr)) + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || (4 + ntohl(smb->smb_buf_length) > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) { - if (length < 2 + sizeof (struct smb_hdr)) { + if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); - if ((length >= sizeof (struct smb_hdr) - 1) + if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) return 0; /* some error cases do not return wct and bcc */ @@ -298,7 +298,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) return 1; if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) - || (4 + ntohl(smb->smb_buf_length) != length)) { + || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { return 0; } else { cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f9801cdcfd4..77a23ab314d 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -791,7 +791,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) int map_smb_to_linux_error(struct smb_hdr *smb) { - int i; + unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ __u8 smberrclass; __u16 smberrcode; @@ -859,10 +859,10 @@ map_smb_to_linux_error(struct smb_hdr *smb) * calculate the size of the SMB message based on the fixed header * portion, the number of word parameters and the data portion of the message */ -int +unsigned int smbCalcSize(struct smb_hdr *ptr) { - return (sizeof (struct smb_hdr) + (int) (2 * ptr->WordCount) + + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + BCC(ptr)); } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index ccfe283a6f3..4705a16d9ef 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -186,7 +186,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, int *pbytes_returned, const int long_op) { int rc = 0; - int receive_len; + unsigned int receive_len; long timeout; struct mid_q_entry *midQ; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index b7a836f30cf..91087269e25 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -34,7 +34,7 @@ /* VFS super_block ops */ static void coda_clear_inode(struct inode *); static void coda_put_super(struct super_block *); -static int coda_statfs(struct super_block *sb, struct statfs *buf); +static int coda_statfs(struct super_block *sb, struct kstatfs *buf); static kmem_cache_t * coda_inode_cachep; @@ -273,7 +273,7 @@ struct inode_operations coda_file_inode_operations = { .setattr = coda_setattr, }; -static int coda_statfs(struct super_block *sb, struct statfs *buf) +static int coda_statfs(struct super_block *sb, struct kstatfs *buf) { int error; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 9a15dedc8d8..6ab4f181513 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -585,7 +585,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, return error; } -int venus_statfs(struct super_block *sb, struct statfs *sfs) +int venus_statfs(struct super_block *sb, struct kstatfs *sfs) { union inputArgs *inp; union outputArgs *outp; diff --git a/fs/compat.c b/fs/compat.c index d90231ba328..5c1cb73ff71 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -87,8 +87,15 @@ asmlinkage long compat_sys_newfstat(unsigned int fd, return error; } -static int put_compat_statfs(struct compat_statfs *ubuf, struct statfs *kbuf) +static int put_compat_statfs(struct compat_statfs *ubuf, struct kstatfs *kbuf) { + + if (sizeof ubuf->f_blocks == 4) { + if ((kbuf->f_blocks | kbuf->f_bfree | + kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) & + 0xffffffff00000000ULL) + return -EOVERFLOW; + } if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) || __put_user(kbuf->f_type, &ubuf->f_type) || __put_user(kbuf->f_bsize, &ubuf->f_bsize) || @@ -99,7 +106,8 @@ static int put_compat_statfs(struct compat_statfs *ubuf, struct statfs *kbuf) __put_user(kbuf->f_ffree, &ubuf->f_ffree) || __put_user(kbuf->f_namelen, &ubuf->f_namelen) || __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || - __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1])) + __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || + __put_user(kbuf->f_frsize, &ubuf->f_frsize)) return -EFAULT; return 0; } @@ -115,7 +123,7 @@ asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf) error = user_path_walk(path, &nd); if (!error) { - struct statfs tmp; + struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); if (!error && put_compat_statfs(buf, &tmp)) error = -EFAULT; @@ -127,7 +135,7 @@ asmlinkage long compat_sys_statfs(const char *path, struct compat_statfs *buf) asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs *buf) { struct file * file; - struct statfs tmp; + struct kstatfs tmp; int error; error = -EBADF; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 7e7f162fc0e..c6d6844796b 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -266,7 +266,7 @@ out: return -EINVAL; } -static int cramfs_statfs(struct super_block *sb, struct statfs *buf) +static int cramfs_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = CRAMFS_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; diff --git a/fs/efs/super.c b/fs/efs/super.c index f7276de1f6b..13ef5b5b781 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -278,7 +278,7 @@ out_no_fs: return -EINVAL; } -int efs_statfs(struct super_block *s, struct statfs *buf) { +int efs_statfs(struct super_block *s, struct kstatfs *buf) { struct efs_sb_info *sb = SUPER_INFO(s); buf->f_type = EFS_SUPER_MAGIC; /* efs magic number */ diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 48a3d099f9a..c4604187f18 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -34,7 +34,7 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es); static int ext2_remount (struct super_block * sb, int * flags, char * data); -static int ext2_statfs (struct super_block * sb, struct statfs * buf); +static int ext2_statfs (struct super_block * sb, struct kstatfs * buf); static char error_buf[1024]; @@ -939,7 +939,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) return 0; } -static int ext2_statfs (struct super_block * sb, struct statfs * buf) +static int ext2_statfs (struct super_block * sb, struct kstatfs * buf) { struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long overhead; diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index e2f1f475593..9313430093c 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -361,7 +361,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) error = -ENOMEM; if (!clone) goto cleanup; - + mode = inode->i_mode; error = posix_acl_create_masq(clone, &mode); if (error >= 0) { @@ -416,12 +416,14 @@ ext3_acl_chmod(struct inode *inode) handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); if (IS_ERR(handle)) { + error = PTR_ERR(handle); ext3_std_error(inode->i_sb, error); - return PTR_ERR(handle); + goto out; } error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); ext3_journal_stop(handle); } +out: posix_acl_release(clone); return error; } diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index e0a02e09404..9ce1003c13b 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -54,7 +54,7 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, return NULL; } - + group_desc = block_group / EXT3_DESC_PER_BLOCK(sb); desc = block_group % EXT3_DESC_PER_BLOCK(sb); if (!EXT3_SB(sb)->s_group_desc[group_desc]) { @@ -64,7 +64,7 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, block_group, group_desc, desc); return NULL; } - + gdp = (struct ext3_group_desc *) EXT3_SB(sb)->s_group_desc[group_desc]->b_data; if (bh) @@ -83,7 +83,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext3_group_desc * desc; struct buffer_head * bh = NULL; - + desc = ext3_get_group_desc (sb, block_group, NULL); if (!desc) goto error_out; @@ -110,6 +110,7 @@ void ext3_free_blocks (handle_t *handle, struct inode * inode, struct super_block * sb; struct ext3_group_desc * gdp; struct ext3_super_block * es; + struct ext3_sb_info *sbi; int err = 0, ret; int dquot_freed_blocks = 0; @@ -118,7 +119,7 @@ void ext3_free_blocks (handle_t *handle, struct inode * inode, printk ("ext3_free_blocks: nonexistent device"); return; } - lock_super (sb); + sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || @@ -170,30 +171,28 @@ do_more: */ /* @@@ check errors */ BUFFER_TRACE(bitmap_bh, "getting undo access"); - err = ext3_journal_get_undo_access(handle, bitmap_bh); + err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL); if (err) goto error_return; - + /* * We are about to modify some metadata. Call the journal APIs * to unshare ->b_data if a currently-committing transaction is * using it */ BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, gd_bh); + err = ext3_journal_get_write_access(handle, gd_bh); if (err) goto error_return; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (err) - goto error_return; + jbd_lock_bh_state(bitmap_bh); for (i = 0; i < count; i++) { /* * An HJ special. This is expensive... */ #ifdef CONFIG_JBD_DEBUG + jbd_unlock_bh_state(bitmap_bh); { struct buffer_head *debug_bh; debug_bh = sb_find_get_block(sb, block + i); @@ -206,20 +205,8 @@ do_more: __brelse(debug_bh); } } + jbd_lock_bh_state(bitmap_bh); #endif - BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) { - ext3_error (sb, __FUNCTION__, - "bit already cleared for block %lu", - block + i); - BUFFER_TRACE(bitmap_bh, "bit already cleared"); - } else { - dquot_freed_blocks++; - gdp->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); - es->s_free_blocks_count = - cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1); - } /* @@@ This prevents newly-allocated data from being * freed and then reallocated within the same * transaction. @@ -238,11 +225,36 @@ do_more: * activity on the buffer any more and so it is safe to * reallocate it. */ - BUFFER_TRACE(bitmap_bh, "clear in b_committed_data"); + BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data != NULL); - ext3_set_bit(bit + i, bh2jh(bitmap_bh)->b_committed_data); + ext3_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, + bh2jh(bitmap_bh)->b_committed_data); + + /* + * We clear the bit in the bitmap after setting the committed + * data bit, because this is the reverse order to that which + * the allocator uses. + */ + BUFFER_TRACE(bitmap_bh, "clear bit"); + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit + i, bitmap_bh->b_data)) { + ext3_error (sb, __FUNCTION__, + "bit already cleared for block %lu", + block + i); + BUFFER_TRACE(bitmap_bh, "bit already cleared"); + } else { + dquot_freed_blocks++; + } } + jbd_unlock_bh_state(bitmap_bh); + + spin_lock(sb_bgl_lock(sbi, block_group)); + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + + dquot_freed_blocks); + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_mod(&sbi->s_freeblocks_counter, count); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); @@ -253,11 +265,6 @@ do_more: ret = ext3_journal_dirty_metadata(handle, gd_bh); if (!err) err = ret; - /* And the superblock */ - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "dirtied superblock"); - ret = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!err) err = ret; - if (overflow && !err) { block += count; count = overflow; @@ -267,7 +274,6 @@ do_more: error_return: brelse(bitmap_bh); ext3_std_error(sb, err); - unlock_super(sb); if (dquot_freed_blocks) DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); return; @@ -288,11 +294,12 @@ error_return: * data-writes at some point, and disable it for metadata allocations or * sync-data inodes. */ -static int ext3_test_allocatable(int nr, struct buffer_head *bh) +static inline int ext3_test_allocatable(int nr, struct buffer_head *bh, + int have_access) { if (ext3_test_bit(nr, bh->b_data)) return 0; - if (!buffer_jbd(bh) || !bh2jh(bh)->b_committed_data) + if (!have_access || !buffer_jbd(bh) || !bh2jh(bh)->b_committed_data) return 1; return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data); } @@ -304,12 +311,12 @@ static int ext3_test_allocatable(int nr, struct buffer_head *bh) * the initial goal; then for a free byte somewhere in the bitmap; then * for any free bit in the bitmap. */ -static int find_next_usable_block(int start, - struct buffer_head *bh, int maxblocks) +static int find_next_usable_block(int start, struct buffer_head *bh, + int maxblocks, int have_access) { int here, next; char *p, *r; - + if (start > 0) { /* * The goal was occupied; search forward for a free @@ -321,17 +328,17 @@ static int find_next_usable_block(int start, */ int end_goal = (start + 63) & ~63; here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); - if (here < end_goal && ext3_test_allocatable(here, bh)) + if (here < end_goal && + ext3_test_allocatable(here, bh, have_access)) return here; - + ext3_debug ("Bit not found near goal\n"); - } - + here = start; if (here < 0) here = 0; - + /* * There has been no free block found in the near vicinity of * the goal: do a search forward through the block groups, @@ -343,10 +350,10 @@ static int find_next_usable_block(int start, p = ((char *) bh->b_data) + (here >> 3); r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *) bh->b_data)) << 3; - - if (next < maxblocks && ext3_test_allocatable(next, bh)) + + if (next < maxblocks && ext3_test_allocatable(next, bh, have_access)) return next; - + /* The bitmap search --- search forward alternately * through the actual bitmap and the last-committed copy * until we find a bit free in both. */ @@ -356,18 +363,116 @@ static int find_next_usable_block(int start, maxblocks, here); if (next >= maxblocks) return -1; - if (ext3_test_allocatable(next, bh)) + if (ext3_test_allocatable(next, bh, have_access)) return next; - J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data); - here = ext3_find_next_zero_bit - ((unsigned long *) bh2jh(bh)->b_committed_data, - maxblocks, next); + if (have_access) + here = ext3_find_next_zero_bit + ((unsigned long *) bh2jh(bh)->b_committed_data, + maxblocks, next); } return -1; } /* + * We think we can allocate this block in this bitmap. Try to set the bit. + * If that succeeds then check that nobody has allocated and then freed the + * block since we saw that is was not marked in b_committed_data. If it _was_ + * allocated and freed then clear the bit in the bitmap again and return + * zero (failure). + */ +static inline int +claim_block(spinlock_t *lock, int block, struct buffer_head *bh) +{ + if (ext3_set_bit_atomic(lock, block, bh->b_data)) + return 0; + if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data && + ext3_test_bit(block, bh2jh(bh)->b_committed_data)) { + ext3_clear_bit_atomic(lock, block, bh->b_data); + return 0; + } + return 1; +} + +/* + * If we failed to allocate the desired block then we may end up crossing to a + * new bitmap. In that case we must release write access to the old one via + * ext3_journal_release_buffer(), else we'll run out of credits. + */ +static int +ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, + struct buffer_head *bitmap_bh, int goal, int *errp) +{ + int i, fatal = 0; + int have_access = 0; + int credits = 0; + + *errp = 0; + + if (goal >= 0 && ext3_test_allocatable(goal, bitmap_bh, 0)) + goto got; + +repeat: + goal = find_next_usable_block(goal, bitmap_bh, + EXT3_BLOCKS_PER_GROUP(sb), have_access); + if (goal < 0) + goto fail; + + for (i = 0; + i < 7 && goal > 0 && + ext3_test_allocatable(goal - 1, bitmap_bh, have_access); + i++, goal--); + +got: + if (!have_access) { + /* + * Make sure we use undo access for the bitmap, because it is + * critical that we do the frozen_data COW on bitmap buffers in + * all cases even if the buffer is in BJ_Forget state in the + * committing transaction. + */ + BUFFER_TRACE(bitmap_bh, "get undo access for new block"); + fatal = ext3_journal_get_undo_access(handle, bitmap_bh, + &credits); + if (fatal) { + *errp = fatal; + goto fail; + } + jbd_lock_bh_state(bitmap_bh); + have_access = 1; + } + + if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) { + /* + * The block was allocated by another thread, or it was + * allocated and then freed by another thread + */ + goal++; + if (goal >= EXT3_BLOCKS_PER_GROUP(sb)) + goto fail; + goto repeat; + } + + BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); + jbd_unlock_bh_state(bitmap_bh); + fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + goto fail; + } + + return goal; +fail: + if (have_access) { + BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); + jbd_unlock_bh_state(bitmap_bh); + ext3_journal_release_buffer(handle, bitmap_bh, credits); + } + return -1; +} + + +/* * ext3_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block * is allocated. Otherwise a forward search is made for a free block; within @@ -383,13 +488,15 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, struct buffer_head *gdp_bh; /* bh2 */ int group_no; /* i */ int ret_block; /* j */ - int bit; /* k */ + int bgi; /* blockgroup iteration index */ int target_block; /* tmp */ int fatal = 0, err; int performed_allocation = 0; + int free_blocks, root_blocks; struct super_block *sb; struct ext3_group_desc *gdp; struct ext3_super_block *es; + struct ext3_sb_info *sbi; #ifdef EXT3FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif @@ -408,18 +515,19 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, return 0; } - lock_super(sb); + sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; - if (le32_to_cpu(es->s_free_blocks_count) <= - le32_to_cpu(es->s_r_blocks_count) && - ((EXT3_SB(sb)->s_resuid != current->fsuid) && - (EXT3_SB(sb)->s_resgid == 0 || - !in_group_p(EXT3_SB(sb)->s_resgid)) && - !capable(CAP_SYS_RESOURCE))) - goto out; - ext3_debug("goal=%lu.\n", goal); + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(es->s_r_blocks_count); + if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + *errp = -ENOSPC; + return 0; + } + /* * First, test whether the goal block is free. */ @@ -432,40 +540,26 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, if (!gdp) goto io_error; - if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (free_blocks > 0) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb)); -#ifdef EXT3FS_DEBUG - if (ret_block) - goal_attempts++; -#endif bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; - - ext3_debug("goal is at %d:%d.\n", group_no, ret_block); - - if (ext3_test_allocatable(ret_block, bitmap_bh)) { -#ifdef EXT3FS_DEBUG - goal_hits++; - ext3_debug("goal bit allocated.\n"); -#endif - goto got_block; - } - - ret_block = find_next_usable_block(ret_block, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); + ret_block = ext3_try_to_allocate(sb, handle, group_no, + bitmap_bh, ret_block, &fatal); + if (fatal) + goto out; if (ret_block >= 0) - goto search_back; + goto allocated; } - ext3_debug("Bit not found in block group %d.\n", group_no); - /* * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ - for (bit = 0; bit < EXT3_SB(sb)->s_groups_count; bit++) { + for (bgi = 0; bgi < EXT3_SB(sb)->s_groups_count; bgi++) { group_no++; if (group_no >= EXT3_SB(sb)->s_groups_count) group_no = 0; @@ -474,57 +568,36 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal, *errp = -EIO; goto out; } - if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - ret_block = find_next_usable_block(-1, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); - if (ret_block >= 0) - goto search_back; - } + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (free_blocks <= 0) + continue; + + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, group_no); + if (!bitmap_bh) + goto io_error; + ret_block = ext3_try_to_allocate(sb, handle, group_no, + bitmap_bh, -1, &fatal); + if (fatal) + goto out; + if (ret_block >= 0) + goto allocated; } /* No space left on the device */ + *errp = -ENOSPC; goto out; -search_back: - /* - * We have succeeded in finding a free byte in the block - * bitmap. Now search backwards up to 7 bits to find the - * start of this group of free blocks. - */ - for ( bit = 0; - bit < 7 && ret_block > 0 && - ext3_test_allocatable(ret_block - 1, bitmap_bh); - bit++, ret_block--) - ; - -got_block: +allocated: ext3_debug("using block group %d(%d)\n", group_no, gdp->bg_free_blocks_count); - /* Make sure we use undo access for the bitmap, because it is - critical that we do the frozen_data COW on bitmap buffers in - all cases even if the buffer is in BJ_Forget state in the - committing transaction. */ - BUFFER_TRACE(bitmap_bh, "get undo access for marking new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh); - if (fatal) - goto out; - BUFFER_TRACE(gdp_bh, "get_write_access"); fatal = ext3_journal_get_write_access(handle, gdp_bh); if (fatal) goto out; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (fatal) - goto out; - target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); @@ -536,11 +609,6 @@ got_block: "Allocating block in system zone - " "block = %u", target_block); - /* The superblock lock should guard against anybody else beating - * us to this point! */ - J_ASSERT_BH(bitmap_bh, !ext3_test_bit(ret_block, bitmap_bh->b_data)); - BUFFER_TRACE(bitmap_bh, "setting bitmap bit"); - ext3_set_bit(ret_block, bitmap_bh->b_data); performed_allocation = 1; #ifdef CONFIG_JBD_DEBUG @@ -555,21 +623,23 @@ got_block: brelse(debug_bh); } } -#endif - if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) - J_ASSERT_BH(bitmap_bh, - !ext3_test_bit(ret_block, - bh2jh(bitmap_bh)->b_committed_data)); + jbd_lock_bh_state(bitmap_bh); + spin_lock(sb_bgl_lock(sbi, group_no)); + if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { + if (ext3_test_bit(ret_block, + bh2jh(bitmap_bh)->b_committed_data)) { + printk("%s: block was unexpectedly set in " + "b_committed_data\n", __FUNCTION__); + } + } ext3_debug("found bit %d\n", ret_block); + spin_unlock(sb_bgl_lock(sbi, group_no)); + jbd_unlock_bh_state(bitmap_bh); +#endif /* ret_block was blockgroup-relative. Now it becomes fs-relative */ ret_block = target_block; - BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (!fatal) - fatal = err; - if (ret_block >= le32_to_cpu(es->s_blocks_count)) { ext3_error(sb, "ext3_new_block", "block(%d) >= blocks count(%d) - " @@ -586,31 +656,25 @@ got_block: ext3_debug("allocating block %d. Goal hits %d of %d.\n", ret_block, goal_hits, goal_attempts); + spin_lock(sb_bgl_lock(sbi, group_no)); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); - es->s_free_blocks_count = - cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); + spin_unlock(sb_bgl_lock(sbi, group_no)); + percpu_counter_mod(&sbi->s_freeblocks_counter, -1); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext3_journal_dirty_metadata(handle, gdp_bh); if (!fatal) fatal = err; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, - "journal_dirty_metadata for superblock"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!fatal) - fatal = err; - sb->s_dirt = 1; if (fatal) goto out; - unlock_super(sb); *errp = 0; brelse(bitmap_bh); return ret_block; - + io_error: *errp = -EIO; out: @@ -618,7 +682,6 @@ out: *errp = fatal; ext3_std_error(sb, fatal); } - unlock_super(sb); /* * Undo the block allocation */ @@ -626,18 +689,18 @@ out: DQUOT_FREE_BLOCK(inode, 1); brelse(bitmap_bh); return 0; - } unsigned long ext3_count_free_blocks(struct super_block *sb) { + unsigned long desc_count; + struct ext3_group_desc *gdp; + int i; #ifdef EXT3FS_DEBUG struct ext3_super_block *es; - unsigned long desc_count, bitmap_count, x; + unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - struct ext3_group_desc *gdp; - int i; - + lock_super(sb); es = EXT3_SB(sb)->s_es; desc_count = 0; @@ -652,7 +715,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) bitmap_bh = read_block_bitmap(sb, i); if (bitmap_bh == NULL) continue; - + x = ext3_count_free(bitmap_bh, sb->s_blocksize); printk("group %d: stored = %d, counted = %lu\n", i, le16_to_cpu(gdp->bg_free_blocks_count), x); @@ -664,7 +727,15 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) unlock_super(sb); return bitmap_count; #else - return le32_to_cpu(EXT3_SB(sb)->s_es->s_free_blocks_count); + desc_count = 0; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc(sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + } + + return desc_count; #endif } diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c index 381559e65f0..6c419b9ab0e 100644 --- a/fs/ext3/bitmap.c +++ b/fs/ext3/bitmap.c @@ -16,7 +16,7 @@ unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) { unsigned int i; unsigned long sum = 0; - + if (!map) return (0); for (i = 0; i < numchars; i++) diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index b00bec6fe0c..b9c64eb1d66 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -16,6 +16,9 @@ * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * Hash Tree Directory indexing (c) 2001 Daniel Phillips + * */ #include @@ -154,7 +157,7 @@ static int ext3_readdir(struct file * filp, brelse (bha[i]); } } - + revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid @@ -180,7 +183,7 @@ revalidate: | offset; filp->f_version = inode->i_version; } - + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); @@ -326,7 +329,7 @@ void ext3_htree_free_dir_info(struct dir_private_info *p) free_rb_tree_fname(&p->root); kfree(p); } - + /* * Given a directory entry, enter it into the fname rb tree. */ @@ -355,7 +358,7 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, new_fn->file_type = dirent->file_type; memcpy(new_fn->name, dirent->name, dirent->name_len); new_fn->name[dirent->name_len] = 0; - + while (*p) { parent = *p; fname = rb_entry(parent, struct fname, rb_hash); @@ -370,7 +373,7 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, fname->next = new_fn; return 0; } - + if (new_fn->hash < fname->hash) p = &(*p)->rb_left; else if (new_fn->hash > fname->hash) @@ -403,7 +406,7 @@ static int call_filldir(struct file * filp, void * dirent, int error; sb = inode->i_sb; - + if (!fname) { printk("call_filldir: called with null fname?!?\n"); return 0; diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 7a329a70a6f..94ac5cd2848 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -69,7 +69,7 @@ ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) */ if (ret <= 0) return ret; - + /* * If the inode is IS_SYNC, or is O_SYNC and we are doing data * journalling then we need to make sure that we force the transaction @@ -97,14 +97,14 @@ ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos) */ if (!IS_SYNC(inode)) return ret; - + /* * Open question #2 --- should we force data to disk here too? If we * don't, the only impact is that data=writeback filesystems won't * flush data to disk automatically on IS_SYNC, only metadata (but * historically, that is what ext2 has done.) */ - + force_commit: err = ext3_force_commit(inode->i_sb); if (err) diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c index d00d658b1cf..f3780279f5c 100644 --- a/fs/ext3/hash.c +++ b/fs/ext3/hash.c @@ -23,10 +23,10 @@ static void TEA_transform(__u32 buf[4], __u32 const in[]) __u32 a = in[0], b = in[1], c = in[2], d = in[3]; int n = 16; - do { - sum += DELTA; - b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); - b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); } while(--n); buf[0] += b0; @@ -107,7 +107,7 @@ static __u32 dx_hack_hash (const char *name, int len) __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; while (len--) { __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373)); - + if (hash & 0x80000000) hash -= 0x7fffffff; hash1 = hash0; hash0 = hash; @@ -178,7 +178,7 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) if (i < 4) memcpy(buf, hinfo->seed, sizeof(buf)); } - + switch (hinfo->hash_version) { case DX_HASH_LEGACY: hash = dx_hack_hash(name, len); diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 155c19c4ac9..7f0c2bfb81f 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -97,6 +97,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) unsigned long bit; struct ext3_group_desc * gdp; struct ext3_super_block * es; + struct ext3_sb_info *sbi = EXT3_SB(sb); int fatal = 0, err; if (atomic_read(&inode->i_count) > 1) { @@ -131,7 +132,6 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) /* Do this BEFORE marking the inode not in use or returning an error */ clear_inode (inode); - lock_super (sb); es = EXT3_SB(sb)->s_es; if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_free_inode", @@ -150,7 +150,8 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) goto error_return; /* Ok, now we can actually update the inode bitmaps.. */ - if (!ext3_clear_bit(bit, bitmap_bh->b_data)) + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit, bitmap_bh->b_data)) ext3_error (sb, "ext3_free_inode", "bit already cleared for inode %lu", ino); else { @@ -160,28 +161,22 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) fatal = ext3_journal_get_write_access(handle, bh2); if (fatal) goto error_return; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get write access"); - fatal = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (fatal) goto error_return; - if (gdp) { + spin_lock(sb_bgl_lock(sbi, block_group)); gdp->bg_free_inodes_count = cpu_to_le16( le16_to_cpu(gdp->bg_free_inodes_count) + 1); - if (is_directory) { + if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16( le16_to_cpu(gdp->bg_used_dirs_count) - 1); - EXT3_SB(sb)->s_dir_count--; - } + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_inc(&sbi->s_freeinodes_counter); + if (is_directory) + percpu_counter_dec(&sbi->s_dirs_counter); + } BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (!fatal) fatal = err; - es->s_free_inodes_count = - cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, - "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!fatal) fatal = err; } BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bitmap_bh); @@ -191,7 +186,6 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) error_return: brelse(bitmap_bh); ext3_std_error(sb, fatal); - unlock_super(sb); } /* @@ -206,13 +200,15 @@ error_return: */ static int find_group_dir(struct super_block *sb, struct inode *parent) { - struct ext3_super_block * es = EXT3_SB(sb)->s_es; int ngroups = EXT3_SB(sb)->s_groups_count; - int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; + int freei, avefreei; struct ext3_group_desc *desc, *best_desc = NULL; struct buffer_head *bh; int group, best_group = -1; + freei = percpu_counter_read_positive(&EXT3_SB(sb)->s_freeinodes_counter); + avefreei = freei / ngroups; + for (group = 0; group < ngroups; group++) { desc = ext3_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) @@ -264,15 +260,20 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) struct ext3_super_block *es = sbi->s_es; int ngroups = sbi->s_groups_count; int inodes_per_group = EXT3_INODES_PER_GROUP(sb); - int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; - int avefreeb = le32_to_cpu(es->s_free_blocks_count) / ngroups; - int blocks_per_dir; - int ndirs = sbi->s_dir_count; + int freei, avefreei; + int freeb, avefreeb; + int blocks_per_dir, ndirs; int max_debt, max_dirs, min_blocks, min_inodes; int group = -1, i; struct ext3_group_desc *desc; struct buffer_head *bh; + freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); + avefreei = freei / ngroups; + freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + avefreeb = freeb / ngroups; + ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); + if ((parent == sb->s_root->d_inode) || (parent->i_flags & EXT3_TOPDIR_FL)) { int best_ndir = inodes_per_group; @@ -299,8 +300,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) goto fallback; } - blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_free_blocks_count)) / ndirs; + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - freeb) / ndirs; max_dirs = ndirs / ngroups + inodes_per_group / 16; min_inodes = avefreei - inodes_per_group / 4; @@ -340,6 +340,15 @@ fallback: return group; } + if (avefreei) { + /* + * The free-inodes counter is approximate, and for really small + * filesystems the above test can fail to find any blockgroups + */ + avefreei = 0; + goto fallback; + } + return -1; } @@ -417,13 +426,15 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) struct buffer_head *bitmap_bh = NULL; struct buffer_head *bh2; int group; - unsigned long ino; + unsigned long ino = 0; struct inode * inode; - struct ext3_group_desc * gdp; + struct ext3_group_desc * gdp = NULL; struct ext3_super_block * es; struct ext3_inode_info *ei; + struct ext3_sb_info *sbi; int err = 0; struct inode *ret; + int i; /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) @@ -435,9 +446,8 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode) return ERR_PTR(-ENOMEM); ei = EXT3_I(inode); - lock_super (sb); es = EXT3_SB(sb)->s_es; -repeat: + sbi = EXT3_SB(sb); if (S_ISDIR(mode)) { if (test_opt (sb, OLDALLOC)) group = find_group_dir(sb, dir); @@ -450,48 +460,55 @@ repeat: if (group == -1) goto out; - err = -EIO; - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) - goto fail; - gdp = ext3_get_group_desc (sb, group, &bh2); - - if ((ino = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, - EXT3_INODES_PER_GROUP(sb))) < - EXT3_INODES_PER_GROUP(sb)) { - BUFFER_TRACE(bitmap_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bitmap_bh); - if (err) goto fail; - - if (ext3_set_bit(ino, bitmap_bh->b_data)) { - ext3_error (sb, "ext3_new_inode", - "bit already set for inode %lu", ino); - goto repeat; - } - BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (err) goto fail; - } else { - if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { - ext3_error (sb, "ext3_new_inode", - "Free inodes count corrupted in group %d", - group); - /* Is it really ENOSPC? */ - err = -ENOSPC; - if (sb->s_flags & MS_RDONLY) + for (i = 0; i < sbi->s_groups_count; i++) { + gdp = ext3_get_group_desc(sb, group, &bh2); + + err = -EIO; + brelse(bitmap_bh); + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) + goto fail; + + ino = ext3_find_first_zero_bit((unsigned long *) + bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb)); + if (ino < EXT3_INODES_PER_GROUP(sb)) { + int credits = 0; + + BUFFER_TRACE(bitmap_bh, "get_write_access"); + err = ext3_journal_get_write_access_credits(handle, + bitmap_bh, &credits); + if (err) goto fail; - BUFFER_TRACE(bh2, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh2); - if (err) goto fail; - gdp->bg_free_inodes_count = 0; - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); - if (err) goto fail; + if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group), + ino, bitmap_bh->b_data)) { + /* we won it */ + BUFFER_TRACE(bitmap_bh, + "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, + bitmap_bh); + if (err) + goto fail; + goto got; + } + /* we lost it */ + journal_release_buffer(handle, bitmap_bh, credits); } - goto repeat; + + /* + * This case is possible in concurrent environment. It is very + * rare. We cannot repeat the find_group_xxx() call because + * that will simply return the same blockgroup, because the + * group descriptor metadata has not yet been updated. + * So we just go onto the next blockgroup. + */ + if (++group == sbi->s_groups_count) + group = 0; } + err = -ENOSPC; + goto out; + +got: ino += group * EXT3_INODES_PER_GROUP(sb) + 1; if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", @@ -504,26 +521,22 @@ repeat: BUFFER_TRACE(bh2, "get_write_access"); err = ext3_journal_get_write_access(handle, bh2); if (err) goto fail; + spin_lock(sb_bgl_lock(sbi, group)); gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); if (S_ISDIR(mode)) { gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); - EXT3_SB(sb)->s_dir_count++; } + spin_unlock(sb_bgl_lock(sbi, group)); BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (err) goto fail; - - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (err) goto fail; - es->s_free_inodes_count = - cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + + percpu_counter_dec(&sbi->s_freeinodes_counter); + if (S_ISDIR(mode)) + percpu_counter_inc(&sbi->s_dirs_counter); sb->s_dirt = 1; - if (err) goto fail; inode->i_uid = current->fsuid; if (test_opt (sb, GRPID)) @@ -567,7 +580,7 @@ repeat: ei->i_prealloc_count = 0; #endif ei->i_block_group = group; - + ext3_set_inode_flags(inode); if (IS_DIRSYNC(inode)) handle->h_sync = 1; @@ -576,7 +589,6 @@ repeat: ei->i_state = EXT3_STATE_NEW; - unlock_super(sb); ret = inode; if(DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); @@ -600,7 +612,6 @@ repeat: fail: ext3_std_error(sb, err); out: - unlock_super(sb); iput(inode); ret = ERR_PTR(err); really_out: @@ -673,12 +684,13 @@ out: unsigned long ext3_count_free_inodes (struct super_block * sb) { + unsigned long desc_count; + struct ext3_group_desc *gdp; + int i; #ifdef EXT3FS_DEBUG struct ext3_super_block *es; - unsigned long desc_count, bitmap_count, x; - struct ext3_group_desc *gdp; + unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - int i; lock_super (sb); es = EXT3_SB(sb)->s_es; @@ -706,7 +718,14 @@ unsigned long ext3_count_free_inodes (struct super_block * sb) unlock_super(sb); return desc_count; #else - return le32_to_cpu(EXT3_SB(sb)->s_es->s_free_inodes_count); + desc_count = 0; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + } + return desc_count; #endif } diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 5ac6ce0f66c..190875df3a1 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -72,7 +72,7 @@ int ext3_forget(handle_t *handle, int is_metadata, "data mode %lx\n", bh, is_metadata, inode->i_mode, test_opt(inode->i_sb, DATA_FLAGS)); - + /* Never use the revoke function if we are doing full data * journaling: there is no need to, and a V1 superblock won't * support it. Otherwise, only skip the revoke on un-journaled @@ -107,7 +107,7 @@ int ext3_forget(handle_t *handle, int is_metadata, static unsigned long blocks_for_truncate(struct inode *inode) { unsigned long needed; - + needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); /* Give ourselves just enough room to cope with inodes in which @@ -126,7 +126,7 @@ static unsigned long blocks_for_truncate(struct inode *inode) return EXT3_DATA_TRANS_BLOCKS + needed; } - + /* * Truncate transactions can be complex and absolutely huge. So we need to * be able to restart the transaction at a conventient checkpoint to make @@ -141,11 +141,11 @@ static unsigned long blocks_for_truncate(struct inode *inode) static handle_t *start_transaction(struct inode *inode) { handle_t *result; - + result = ext3_journal_start(inode, blocks_for_truncate(inode)); if (!IS_ERR(result)) return result; - + ext3_std_error(inode->i_sb, PTR_ERR(result)); return result; } @@ -195,11 +195,10 @@ void ext3_put_inode(struct inode *inode) void ext3_delete_inode (struct inode * inode) { handle_t *handle; - + if (is_bad_inode(inode)) goto no_delete; - lock_kernel(); handle = start_transaction(inode); if (IS_ERR(handle)) { /* If we're going to skip the normal cleanup, we still @@ -208,10 +207,9 @@ void ext3_delete_inode (struct inode * inode) ext3_orphan_del(NULL, inode); ext3_std_error(inode->i_sb, PTR_ERR(handle)); - unlock_kernel(); goto no_delete; } - + if (IS_SYNC(inode)) handle->h_sync = 1; inode->i_size = 0; @@ -241,7 +239,6 @@ void ext3_delete_inode (struct inode * inode) else ext3_free_inode(handle, inode); ext3_journal_stop(handle); - unlock_kernel(); return; no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ @@ -251,7 +248,6 @@ void ext3_discard_prealloc (struct inode * inode) { #ifdef EXT3_PREALLOCATE struct ext3_inode_info *ei = EXT3_I(inode); - lock_kernel(); /* Writer: ->i_prealloc* */ if (ei->i_prealloc_count) { unsigned short total = ei->i_prealloc_count; @@ -261,7 +257,6 @@ void ext3_discard_prealloc (struct inode * inode) /* Writer: end */ ext3_free_blocks (inode, block, total); } - unlock_kernel(); #endif } @@ -598,7 +593,7 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, break; branch[n].key = cpu_to_le32(nr); keys = n+1; - + /* * Get buffer_head for parent block, zero it out * and set the pointer to new one, then send @@ -626,7 +621,7 @@ static int ext3_alloc_branch(handle_t *handle, struct inode *inode, err = ext3_journal_dirty_metadata(handle, bh); if (err) break; - + parent = nr; } } @@ -728,7 +723,7 @@ changed: */ jbd_debug(1, "the chain changed: try again\n"); err = -EAGAIN; - + err_out: for (i = 1; i < num; i++) { BUFFER_TRACE(where[i].bh, "call journal_forget"); @@ -781,7 +776,6 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, if (depth == 0) goto out; - lock_kernel(); reread: partial = ext3_get_branch(inode, depth, offsets, chain, &err); @@ -806,7 +800,6 @@ cleanup: partial--; } BUFFER_TRACE(bh_result, "returned"); - unlock_kernel(); out: return err; } @@ -894,7 +887,6 @@ ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock, handle_t *handle = journal_current_handle(); int ret = 0; - lock_kernel(); if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { /* * Getting low on buffer credits... @@ -911,7 +903,6 @@ ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock, bh_result, create, 0); if (ret == 0) bh_result->b_size = (1 << inode->i_blkbits); - unlock_kernel(); return ret; } @@ -924,7 +915,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode, { struct buffer_head dummy; int fatal = 0, err; - + J_ASSERT(handle != NULL || create == 0); dummy.b_state = 0; @@ -944,7 +935,6 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode, For now, regular file writes use ext3_get_block instead, so it's not a problem. */ - lock_kernel(); lock_buffer(bh); BUFFER_TRACE(bh, "call get_create_access"); fatal = ext3_journal_get_create_access(handle, bh); @@ -957,7 +947,6 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode * inode, BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh); if (!fatal) fatal = err; - unlock_kernel(); } else { BUFFER_TRACE(bh, "not a new buffer"); } @@ -1037,11 +1026,13 @@ static int walk_page_buffers( handle_t *handle, unsigned block_start, block_end; unsigned blocksize = head->b_size; int err, ret = 0; + struct buffer_head *next; for ( bh = head, block_start = 0; ret == 0 && (bh != head || !block_start); - block_start = block_end, bh = bh->b_this_page) + block_start = block_end, bh = next) { + next = bh->b_this_page; block_end = block_start + blocksize; if (block_end <= from || block_start >= to) { if (partial && !buffer_uptodate(bh)) @@ -1084,6 +1075,8 @@ static int walk_page_buffers( handle_t *handle, static int do_journal_get_write_access(handle_t *handle, struct buffer_head *bh) { + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; return ext3_journal_get_write_access(handle, bh); } @@ -1094,15 +1087,12 @@ static int ext3_prepare_write(struct file *file, struct page *page, int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; - lock_kernel(); handle = ext3_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } - unlock_kernel(); ret = block_prepare_write(page, from, to, ext3_get_block); - lock_kernel(); if (ret != 0) goto prepare_write_failed; @@ -1114,7 +1104,6 @@ prepare_write_failed: if (ret) ext3_journal_stop(handle); out: - unlock_kernel(); return ret; } @@ -1131,6 +1120,8 @@ ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) /* For commit_write() in data=journal mode */ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) { + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; set_buffer_uptodate(bh); return ext3_journal_dirty_metadata(handle, bh); } @@ -1143,56 +1134,81 @@ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) * buffers are managed internally. */ -static int ext3_commit_write(struct file *file, struct page *page, +static int ext3_ordered_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { handle_t *handle = ext3_journal_current_handle(); struct inode *inode = page->mapping->host; int ret = 0, ret2; - lock_kernel(); - if (ext3_should_journal_data(inode)) { + ret = walk_page_buffers(handle, page_buffers(page), + from, to, NULL, ext3_journal_dirty_data); + + if (ret == 0) { /* - * Here we duplicate the generic_commit_write() functionality + * generic_commit_write() will run mark_inode_dirty() if i_size + * changes. So let's piggyback the i_disksize mark_inode_dirty + * into that. */ - int partial = 0; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + loff_t new_i_size; - ret = walk_page_buffers(handle, page_buffers(page), - from, to, &partial, commit_write_fn); - if (!partial) - SetPageUptodate(page); - if (pos > inode->i_size) - inode->i_size = pos; - EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; - if (inode->i_size > EXT3_I(inode)->i_disksize) { - EXT3_I(inode)->i_disksize = inode->i_size; - ret2 = ext3_mark_inode_dirty(handle, inode); - if (!ret) - ret = ret2; - } - } else { - if (ext3_should_order_data(inode)) { - ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, ext3_journal_dirty_data); - } - /* Be careful here if generic_commit_write becomes a - * required invocation after block_prepare_write. */ - if (ret == 0) { - /* - * generic_commit_write() will run mark_inode_dirty() - * if i_size changes. So let's piggyback the - * i_disksize mark_inode_dirty into that. - */ - loff_t new_i_size = - ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - if (new_i_size > EXT3_I(inode)->i_disksize) - EXT3_I(inode)->i_disksize = new_i_size; - ret = generic_commit_write(file, page, from, to); - } + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + ret = generic_commit_write(file, page, from, to); + } + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_writeback_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + loff_t new_i_size; + + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + ret = generic_commit_write(file, page, from, to); + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_journalled_commit_write(struct file *file, + struct page *page, unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + int partial = 0; + loff_t pos; + + /* + * Here we duplicate the generic_commit_write() functionality + */ + pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + ret = walk_page_buffers(handle, page_buffers(page), from, + to, &partial, commit_write_fn); + if (!partial) + SetPageUptodate(page); + if (pos > inode->i_size) + inode->i_size = pos; + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + if (inode->i_size > EXT3_I(inode)->i_disksize) { + EXT3_I(inode)->i_disksize = inode->i_size; + ret2 = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; } ret2 = ext3_journal_stop(handle); - unlock_kernel(); if (!ret) ret = ret2; return ret; @@ -1217,7 +1233,7 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) struct inode *inode = mapping->host; journal_t *journal; int err; - + if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) { /* * This is a REALLY heavyweight approach, but the use of @@ -1236,17 +1252,17 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block) * hasn't yet been flushed to disk, they deserve * everything they get. */ - + EXT3_I(inode)->i_state &= ~EXT3_STATE_JDATA; journal = EXT3_JOURNAL(inode); journal_lock_updates(journal); err = journal_flush(journal); journal_unlock_updates(journal); - + if (err) return 0; } - + return generic_block_bmap(mapping,block,ext3_get_block); } @@ -1317,55 +1333,44 @@ static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) * We don't honour synchronous mounts for writepage(). That would be * disastrous. Any write() or metadata operation will sync the fs for * us. + * + * AKPM2: if all the page's buffers are mapped to disk and !data=journal, + * we don't need to open a transaction here. */ -static int ext3_writepage(struct page *page, struct writeback_control *wbc) +static int ext3_ordered_writepage(struct page *page, + struct writeback_control *wbc) { struct inode *inode = page->mapping->host; struct buffer_head *page_bufs; handle_t *handle = NULL; - int ret = 0, err; - int needed; - int order_data; + int ret = 0; + int err; J_ASSERT(PageLocked(page)); - + /* - * We give up here if we're reentered, because it might be - * for a different filesystem. One *could* look for a - * nested transaction opportunity. + * We give up here if we're reentered, because it might be for a + * different filesystem. */ - lock_kernel(); if (ext3_journal_current_handle()) goto out_fail; - needed = ext3_writepage_trans_blocks(inode); - handle = ext3_journal_start(inode, needed); - + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out_fail; } - order_data = ext3_should_order_data(inode) || - ext3_should_journal_data(inode); - - unlock_kernel(); - - page_bufs = NULL; /* Purely to prevent compiler warning */ - - /* bget() all the buffers */ - if (order_data) { - if (!page_has_buffers(page)) { - if (!PageUptodate(page)) - buffer_error(); - create_empty_buffers(page, - inode->i_sb->s_blocksize, + if (!page_has_buffers(page)) { + if (!PageUptodate(page)) + buffer_error(); + create_empty_buffers(page, inode->i_sb->s_blocksize, (1 << BH_Dirty)|(1 << BH_Uptodate)); - } - page_bufs = page_buffers(page); - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bget_one); } + page_bufs = page_buffers(page); + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bget_one); ret = block_write_full_page(page, ext3_get_block, wbc); @@ -1376,46 +1381,116 @@ static int ext3_writepage(struct page *page, struct writeback_control *wbc) * safe due to elevated refcount. */ - handle = ext3_journal_current_handle(); - lock_kernel(); - /* * And attach them to the current transaction. But only if * block_write_full_page() succeeded. Otherwise they are unmapped, * and generally junk. */ - if (order_data) { - if (ret == 0) { - err = walk_page_buffers(handle, page_bufs, - 0, PAGE_CACHE_SIZE, NULL, - journal_dirty_data_fn); - if (!ret) - ret = err; - } - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bput_one); + if (ret == 0) { + err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, + NULL, journal_dirty_data_fn); + if (!ret) + ret = err; } - + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bput_one); err = ext3_journal_stop(handle); if (!ret) ret = err; - unlock_kernel(); return ret; out_fail: - - unlock_kernel(); + __set_page_dirty_nobuffers(page); + unlock_page(page); + return ret; +} - /* - * We have to fail this writepage to avoid cross-fs transactions. - * Put the page back on mapping->dirty_pages. The page's buffers' - * dirty state will be left as-is. - */ +static int ext3_writeback_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto out_fail; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_fail; + } + + ret = block_write_full_page(page, ext3_get_block, wbc); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; + +out_fail: __set_page_dirty_nobuffers(page); unlock_page(page); return ret; } +static int ext3_journalled_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto no_write; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto no_write; + } + + if (!page_has_buffers(page) || PageChecked(page)) { + /* + * It's mmapped pagecache. Add buffers and journal it. There + * doesn't seem much point in redirtying the page here. + */ + ClearPageChecked(page); + ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, + ext3_get_block); + if (ret != 0) + goto out_unlock; + ret = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); + + err = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, commit_write_fn); + if (ret == 0) + ret = err; + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + unlock_page(page); + } else { + /* + * It may be a page full of checkpoint-mode buffers. We don't + * really know unless we go poke around in the buffer_heads. + * But block_write_full_page will do the right thing. + */ + ret = block_write_full_page(page, ext3_get_block, wbc); + } + err = ext3_journal_stop(handle); + if (!ret) + ret = err; +out: + return ret; + +no_write: + __set_page_dirty_nobuffers(page); +out_unlock: + unlock_page(page); + goto out; +} + static int ext3_readpage(struct file *file, struct page *page) { return mpage_readpage(page, ext3_get_block); @@ -1431,12 +1506,21 @@ ext3_readpages(struct file *file, struct address_space *mapping, static int ext3_invalidatepage(struct page *page, unsigned long offset) { journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + /* + * If it's a full truncate we just forget about the pending dirtying + */ + if (offset == 0) + ClearPageChecked(page); + return journal_invalidatepage(journal, page, offset); } static int ext3_releasepage(struct page *page, int wait) { journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + WARN_ON(PageChecked(page)); return journal_try_to_free_buffers(journal, page, wait); } @@ -1463,17 +1547,13 @@ static int ext3_direct_IO(int rw, struct kiocb *iocb, if (rw == WRITE) { loff_t final_size = offset + count; - lock_kernel(); handle = ext3_journal_start(inode, DIO_CREDITS); - unlock_kernel(); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } if (final_size > inode->i_size) { - lock_kernel(); ret = ext3_orphan_add(handle, inode); - unlock_kernel(); if (ret) goto out_stop; orphan = 1; @@ -1488,7 +1568,6 @@ out_stop: if (handle) { int err; - lock_kernel(); if (orphan) ext3_orphan_del(handle, inode); if (orphan && ret > 0) { @@ -1504,47 +1583,79 @@ out_stop: err = ext3_journal_stop(handle); if (ret == 0) ret = err; - unlock_kernel(); } out: return ret; } -struct address_space_operations ext3_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ +/* + * Pages can be marked dirty completely asynchronously from ext3's journalling + * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do + * much here because ->set_page_dirty is called under VFS locks. The page is + * not necessarily locked. + * + * We cannot just dirty the page and leave attached buffers clean, because the + * buffers' dirty state is "definitive". We cannot just set the buffers dirty + * or jbddirty because all the journalling code will explode. + * + * So what we do is to mark the page "pending dirty" and next time writepage + * is called, propagate that into the buffers appropriately. + */ +static int ext3_journalled_set_page_dirty(struct page *page) +{ + SetPageChecked(page); + return __set_page_dirty_nobuffers(page); +} + +static struct address_space_operations ext3_ordered_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_ordered_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ - .commit_write = ext3_commit_write, /* BKL not held. We take it */ - .bmap = ext3_bmap, /* BKL held */ - .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ - .releasepage = ext3_releasepage, /* BKL not held. Don't need */ - .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ + .prepare_write = ext3_prepare_write, + .commit_write = ext3_ordered_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, }; -/* For writeback mode, we can use mpage_writepages() */ -#if 0 /* Doesn't work for shared mappings */ -static int -ext3_writepages(struct address_space *mapping, struct writeback_control *wbc) -{ - return mpage_writepages(mapping, wbc, ext3_get_block); -} -#endif +static struct address_space_operations ext3_writeback_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_writeback_writepage, + .sync_page = block_sync_page, + .prepare_write = ext3_prepare_write, + .commit_write = ext3_writeback_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, +}; -struct address_space_operations ext3_writeback_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ +static struct address_space_operations ext3_journalled_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_journalled_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ - .commit_write = ext3_commit_write, /* BKL not held. We take it */ - .bmap = ext3_bmap, /* BKL held */ - .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ - .releasepage = ext3_releasepage, /* BKL not held. Don't need */ - .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ + .prepare_write = ext3_prepare_write, + .commit_write = ext3_journalled_commit_write, + .set_page_dirty = ext3_journalled_set_page_dirty, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, }; +void ext3_set_aops(struct inode *inode) +{ + if (ext3_should_order_data(inode)) + inode->i_mapping->a_ops = &ext3_ordered_aops; + else if (ext3_should_writeback_data(inode)) + inode->i_mapping->a_ops = &ext3_writeback_aops; + else + inode->i_mapping->a_ops = &ext3_journalled_aops; +} + /* * ext3_block_truncate_page() zeroes out a mapping from file offset `from' * up to the end of the block which corresponds to `from'. @@ -1591,11 +1702,19 @@ static int ext3_block_truncate_page(handle_t *handle, } err = 0; + if (buffer_freed(bh)) { + BUFFER_TRACE(bh, "freed: skip"); + goto unlock; + } + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "unmapped"); ext3_get_block(inode, iblock, bh, 0); /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "still unmapped"); goto unlock; + } } /* Ok, it's mapped. Make sure it's up-to-date */ @@ -1884,7 +2003,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, if (is_handle_aborted(handle)) return; - + if (depth--) { struct buffer_head *bh; int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); @@ -2034,12 +2153,10 @@ void ext3_truncate(struct inode * inode) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - lock_kernel(); ext3_discard_prealloc(inode); handle = start_transaction(inode); if (IS_ERR(handle)) { - unlock_kernel(); return; /* AKPM: return what? */ } @@ -2048,7 +2165,6 @@ void ext3_truncate(struct inode * inode) >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size); - n = ext3_block_to_path(inode, last_block, offsets, NULL); if (n == 0) @@ -2163,7 +2279,6 @@ out_stop: ext3_orphan_del(handle, inode); ext3_journal_stop(handle); - unlock_kernel(); } /* @@ -2180,7 +2295,7 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) unsigned long desc; unsigned long offset; struct ext3_group_desc * gdp; - + if ((inode->i_ino != EXT3_ROOT_INO && inode->i_ino != EXT3_JOURNAL_INO && inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || @@ -2224,9 +2339,9 @@ int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc) iloc->bh = bh; iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset); iloc->block_group = block_group; - + return 0; - + bad_inode: return -EIO; } @@ -2256,7 +2371,7 @@ void ext3_read_inode(struct inode * inode) struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh; int block; - + #ifdef CONFIG_EXT3_FS_POSIX_ACL ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; @@ -2338,10 +2453,7 @@ void ext3_read_inode(struct inode * inode) if (S_ISREG(inode->i_mode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ext3_dir_inode_operations; inode->i_fop = &ext3_dir_operations; @@ -2350,10 +2462,7 @@ void ext3_read_inode(struct inode * inode) inode->i_op = &ext3_fast_symlink_inode_operations; else { inode->i_op = &ext3_symlink_inode_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); } } else { inode->i_op = &ext3_special_inode_operations; @@ -2362,7 +2471,7 @@ void ext3_read_inode(struct inode * inode) } ext3_set_inode_flags(inode); return; - + bad_inode: make_bad_inode(inode); return; @@ -2517,13 +2626,14 @@ void ext3_write_inode(struct inode *inode, int wait) if (ext3_journal_current_handle()) { jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + dump_stack(); return; } if (!wait) return; - ext3_force_commit(inode->i_sb); + ext3_force_commit(inode->i_sb); } /* @@ -2560,8 +2670,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) return error; } - lock_kernel(); - if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; @@ -2571,7 +2679,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) error = PTR_ERR(handle); goto err_out; } - + error = ext3_orphan_add(handle, inode); EXT3_I(inode)->i_disksize = attr->ia_size; rc = ext3_mark_inode_dirty(handle, inode); @@ -2579,7 +2687,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) error = rc; ext3_journal_stop(handle); } - + rc = inode_setattr(inode, attr); /* If inode_setattr's call to ext3_truncate failed to get a @@ -2593,7 +2701,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) err_out: ext3_std_error(inode->i_sb, error); - unlock_kernel(); if (!error) error = rc; return error; @@ -2632,7 +2739,7 @@ int ext3_writepage_trans_blocks(struct inode *inode) int bpp = ext3_journal_blocks_per_page(inode); int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; int ret; - + if (ext3_should_journal_data(inode)) ret = 3 * (bpp + indirects) + 2; else @@ -2739,7 +2846,6 @@ void ext3_dirty_inode(struct inode *inode) handle_t *current_handle = ext3_journal_current_handle(); handle_t *handle; - lock_kernel(); handle = ext3_journal_start(inode, 2); if (IS_ERR(handle)) goto out; @@ -2755,7 +2861,7 @@ void ext3_dirty_inode(struct inode *inode) } ext3_journal_stop(handle); out: - unlock_kernel(); + return; } #ifdef AKPM @@ -2770,7 +2876,7 @@ static inline int ext3_pin_inode(handle_t *handle, struct inode *inode) { struct ext3_iloc iloc; - + int err = 0; if (handle) { err = ext3_get_inode_loc(inode, &iloc); @@ -2807,7 +2913,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) journal = EXT3_JOURNAL(inode); if (is_journal_aborted(journal) || IS_RDONLY(inode)) return -EROFS; - + journal_lock_updates(journal); journal_flush(journal); @@ -2836,64 +2942,6 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) handle->h_sync = 1; ext3_journal_stop(handle); ext3_std_error(inode->i_sb, err); - + return err; } - - -/* - * ext3_aops_journal_start(). - * - * - * - * We need to take the inode semaphore *outside* the - * journal_start/journal_stop. Otherwise, a different task could do a - * wait_for_commit() while holding ->i_sem, which deadlocks. The rule - * is: transaction open/closes are considered to be a locking operation - * and they nest *inside* ->i_sem. - * ---------------------------------------------------------------------------- - * Possible problem: - * ext3_file_write() - * -> generic_file_write() - * -> __alloc_pages() - * -> page_launder() - * -> ext3_writepage() - * - * And the writepage can be on a different fs while we have a - * transaction open against this one! Bad. - * - * I tried making the task PF_MEMALLOC here, but that simply results in - * 0-order allocation failures passed back to generic_file_write(). - * Instead, we rely on the reentrancy protection in ext3_writepage(). - * ---------------------------------------------------------------------------- - * When we do the journal_start() here we don't really need to reserve - * any blocks - we won't need any until we hit ext3_prepare_write(), - * which does all the needed journal extending. However! There is a - * problem with quotas: - * - * Thread 1: - * sys_sync - * ->sync_dquots - * ->commit_dquot - * ->lock_dquot - * ->write_dquot - * ->ext3_file_write - * ->journal_start - * ->ext3_prepare_write - * ->journal_extend - * ->journal_start - * Thread 2: - * ext3_create (for example) - * ->ext3_new_inode - * ->dquot_initialize - * ->lock_dquot - * - * Deadlock. Thread 1's journal_start blocks because thread 2 has a - * transaction open. Thread 2's transaction will never close because - * thread 2 is stuck waiting for the dquot lock. - * - * So. We must ensure that thread 1 *never* needs to extend the journal - * for quota writes. We do that by reserving enough journal blocks - * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we - * need to extend" test in ext3_prepare_write() succeeds. - */ diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 4ea88297ce3..3681474e57d 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -61,7 +61,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } - + /* * The JOURNAL_DATA flag can only be changed by * the relevant capability. @@ -80,7 +80,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, err = ext3_reserve_inode_write(handle, inode, &iloc); if (err) goto flags_err; - + flags = flags & EXT3_FL_USER_MODIFIABLE; flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; ei->i_flags = flags; @@ -93,7 +93,7 @@ flags_err: ext3_journal_stop(handle); if (err) return err; - + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) err = ext3_change_inode_journal_flag(inode, jflag); return err; @@ -119,13 +119,11 @@ flags_err: if (IS_ERR(handle)) return PTR_ERR(handle); err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err) - return err; - - inode->i_ctime = CURRENT_TIME; - inode->i_generation = generation; - - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (err == 0) { + inode->i_ctime = CURRENT_TIME; + inode->i_generation = generation; + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + } ext3_journal_stop(handle); return err; } diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index ea83d3cb7be..1e71616f4d9 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -263,7 +263,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent unsigned names = 0, space = 0; char *base = (char *) de; struct dx_hash_info h = *hinfo; - + printk("names: "); while ((char *) de < base + size) { @@ -546,7 +546,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); if (!(bh = ext3_bread (NULL, dir, block, 0, &err))) return err; - + de = (struct ext3_dir_entry_2 *) bh->b_data; top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize - @@ -588,11 +588,11 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, int count = 0; int ret; __u32 hashval; - + dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, start_minor_hash)); dir = dir_file->f_dentry->d_inode; - if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { + if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, @@ -663,7 +663,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size, int count = 0; char *base = (char *) de; struct dx_hash_info h = *hinfo; - + while ((char *) de < base + size) { if (de->name_len && de->inode) { @@ -798,8 +798,6 @@ static inline int search_dirblock(struct buffer_head * bh, * The returned buffer_head has ->b_count elevated. The caller is expected * to brelse() it when appropriate. */ - - static struct buffer_head * ext3_find_entry (struct dentry *dentry, struct ext3_dir_entry_2 ** res_dir) { @@ -903,7 +901,7 @@ restart: start = 0; goto restart; } - + cleanup_and_exit: /* Clean up the read-ahead blocks */ for (; ra_ptr < ra_max; ra_ptr++) @@ -926,7 +924,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, int namelen = dentry->d_name.len; const u8 *name = dentry->d_name.name; struct inode *dir = dentry->d_parent->d_inode; - + sb = dir->i_sb; if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err))) return NULL; @@ -963,7 +961,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, goto errout; } } while (retval == 1); - + *err = -ENOENT; errout: dxtrace(printk("%s not found\n", name)); @@ -981,7 +979,6 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry) if (dentry->d_name.len > EXT3_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); - lock_kernel(); bh = ext3_find_entry(dentry, &de); inode = NULL; if (bh) { @@ -989,12 +986,9 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry) brelse (bh); inode = iget(dir->i_sb, ino); - if (!inode) { - unlock_kernel(); + if (!inode) return ERR_PTR(-EACCES); - } } - unlock_kernel(); if (inode) return d_splice_alias(inode, dentry); d_add(dentry, inode); @@ -1015,17 +1009,13 @@ struct dentry *ext3_get_parent(struct dentry *child) dotdot.d_name.len = 2; dotdot.d_parent = child; /* confusing, isn't it! */ - lock_kernel(); bh = ext3_find_entry(&dotdot, &de); inode = NULL; - if (!bh) { - unlock_kernel(); + if (!bh) return ERR_PTR(-ENOENT); - } ino = le32_to_cpu(de->inode); brelse(bh); inode = iget(child->d_inode->i_sb, ino); - unlock_kernel(); if (!inode) return ERR_PTR(-EACCES); @@ -1199,7 +1189,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, unsigned short reclen; int nlen, rlen, err; char *top; - + reclen = EXT3_DIR_REC_LEN(namelen); if (!de) { de = (struct ext3_dir_entry_2 *)bh->b_data; @@ -1231,7 +1221,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, brelse(bh); return err; } - + /* By now the buffer is marked for journaling */ nlen = EXT3_DIR_REC_LEN(de->name_len); rlen = le16_to_cpu(de->rec_len); @@ -1294,7 +1284,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, unsigned blocksize; struct dx_hash_info hinfo; u32 block; - + blocksize = dir->i_sb->s_blocksize; dxtrace(printk("Creating index\n")); retval = ext3_journal_get_write_access(handle, bh); @@ -1304,7 +1294,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, return retval; } root = (struct dx_root *) bh->b_data; - + EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; bh2 = ext3_append (handle, dir, &block, &retval); if (!(bh2)) { @@ -1487,13 +1477,13 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, unsigned icount1 = icount/2, icount2 = icount - icount1; unsigned hash2 = dx_get_hash(entries + icount1); dxtrace(printk("Split index %i/%i\n", icount1, icount2)); - + BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ err = ext3_journal_get_write_access(handle, frames[0].bh); if (err) goto journal_error; - + memcpy ((char *) entries2, (char *) (entries + icount1), icount2 * sizeof(struct dx_entry)); dx_set_count (entries, icount1); @@ -1543,7 +1533,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, err = add_dirent_to_buf(handle, dentry, inode, de, bh); bh = 0; goto cleanup; - + journal_error: ext3_std_error(dir->i_sb, err); cleanup: @@ -1639,13 +1629,10 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode) struct inode * inode; int err; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1655,14 +1642,10 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode) if (!IS_ERR(inode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1673,13 +1656,10 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, struct inode *inode; int err; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1694,7 +1674,6 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1709,13 +1688,10 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) if (dir->i_nlink >= EXT3_LINK_MAX) return -EMLINK; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1768,7 +1744,6 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) d_instantiate(dentry, inode); out_stop: ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1854,7 +1829,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) struct super_block *sb = inode->i_sb; struct ext3_iloc iloc; int err = 0, rc; - + lock_super(sb); if (!list_empty(&EXT3_I(inode)->i_orphan)) goto out_unlock; @@ -1875,7 +1850,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode) err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); if (err) goto out_unlock; - + err = ext3_reserve_inode_write(handle, inode, &iloc); if (err) goto out_unlock; @@ -1993,12 +1968,9 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) struct ext3_dir_entry_2 * de; handle_t *handle; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } retval = -ENOENT; bh = ext3_find_entry (dentry, &de); @@ -2042,7 +2014,6 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) end_rmdir: ext3_journal_stop(handle); brelse (bh); - unlock_kernel(); return retval; } @@ -2054,12 +2025,9 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) struct ext3_dir_entry_2 * de; handle_t *handle; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2075,7 +2043,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) retval = -EIO; if (le32_to_cpu(de->inode) != inode->i_ino) goto end_unlink; - + if (!inode->i_nlink) { ext3_warning (inode->i_sb, "ext3_unlink", "Deleting nonexistent file (%lu), %d", @@ -2097,7 +2065,6 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) end_unlink: ext3_journal_stop(handle); - unlock_kernel(); brelse (bh); return retval; } @@ -2113,13 +2080,10 @@ static int ext3_symlink (struct inode * dir, if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2131,10 +2095,7 @@ static int ext3_symlink (struct inode * dir, if (l > sizeof (EXT3_I(inode)->i_data)) { inode->i_op = &ext3_symlink_inode_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); /* * page_symlink() calls into ext3_prepare/commit_write. * We have a transaction open. All is sweetness. It also sets @@ -2156,7 +2117,6 @@ static int ext3_symlink (struct inode * dir, err = ext3_add_nondir(handle, dentry, inode); out_stop: ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -2167,18 +2127,13 @@ static int ext3_link (struct dentry * old_dentry, struct inode *inode = old_dentry->d_inode; int err; - lock_kernel(); - if (inode->i_nlink >= EXT3_LINK_MAX) { - unlock_kernel(); + if (inode->i_nlink >= EXT3_LINK_MAX) return -EMLINK; - } handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2189,7 +2144,6 @@ static int ext3_link (struct dentry * old_dentry, err = ext3_add_nondir(handle, dentry, inode); ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -2212,13 +2166,10 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, old_bh = new_bh = dir_bh = NULL; - lock_kernel(); handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) handle->h_sync = 1; @@ -2298,7 +2249,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, */ struct buffer_head *old_bh2; struct ext3_dir_entry_2 *old_de2; - + old_bh2 = ext3_find_entry(old_dentry, &old_de2); if (old_bh2) { retval = ext3_delete_entry(handle, old_dir, @@ -2346,7 +2297,6 @@ end_rename: brelse (old_bh); brelse (new_bh); ext3_journal_stop(handle); - unlock_kernel(); return retval; } @@ -2364,9 +2314,9 @@ struct inode_operations ext3_dir_inode_operations = { .mknod = ext3_mknod, .rename = ext3_rename, .setattr = ext3_setattr, - .setxattr = ext3_setxattr, - .getxattr = ext3_getxattr, - .listxattr = ext3_listxattr, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, .permission = ext3_permission, }; @@ -2378,6 +2328,4 @@ struct inode_operations ext3_special_inode_operations = { .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, .permission = ext3_permission, -}; - - +}; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 272197d032a..b5c72519d5f 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -119,7 +119,7 @@ static void clear_ro_after(struct super_block *sb) handle_t *ext3_journal_start(struct inode *inode, int nblocks) { journal_t *journal; - + if (inode->i_sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); @@ -132,7 +132,7 @@ handle_t *ext3_journal_start(struct inode *inode, int nblocks) "Detected aborted journal"); return ERR_PTR(-EROFS); } - + return journal_start(journal, nblocks); } @@ -164,7 +164,7 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn, { char nbuf[16]; const char *errstr = ext3_decode_error(NULL, err, nbuf); - + printk(KERN_ERR "%s: aborting transaction: %s in %s", caller, errstr, err_fn); @@ -236,7 +236,7 @@ void ext3_error (struct super_block * sb, const char * function, const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) { char *errstr = NULL; - + switch (errno) { case -EIO: errstr = "IO failure"; @@ -259,7 +259,6 @@ const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16]) if (snprintf(nbuf, 16, "error %d", -errno) >= 0) errstr = nbuf; } - break; } @@ -277,7 +276,7 @@ void __ext3_std_error (struct super_block * sb, const char * function, printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", sb->s_id, function, errstr); - + ext3_handle_error(sb); } @@ -311,7 +310,7 @@ void ext3_abort (struct super_block * sb, const char * function, if (sb->s_flags & MS_RDONLY) return; - + printk (KERN_CRIT "Remounting filesystem read-only\n"); EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; sb->s_flags |= MS_RDONLY; @@ -426,10 +425,10 @@ static inline struct inode *orphan_list_entry(struct list_head *l) static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) { struct list_head *l; - + printk(KERN_ERR "sb orphan head is %d\n", le32_to_cpu(sbi->s_es->s_last_orphan)); - + printk(KERN_ERR "sb_info orphan list:\n"); list_for_each(l, &sbi->s_orphan) { struct inode *inode = orphan_list_entry(l); @@ -947,6 +946,9 @@ static int ext3_check_descriptors (struct super_block * sb) block += EXT3_BLOCKS_PER_GROUP(sb); gdp++; } + + sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); + sbi->s_es->s_free_inodes_count=cpu_to_le32(ext3_count_free_inodes(sb)); return 1; } @@ -1059,7 +1061,7 @@ static unsigned long descriptor_loc(struct super_block *sb, struct ext3_sb_info *sbi = EXT3_SB(sb); unsigned long bg, first_data_block, first_meta_bg; int has_super = 0; - + first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block); first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); @@ -1135,7 +1137,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sb->s_id); goto failed_mount; } - + /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); if (def_mount_opts & EXT3_DEFM_DEBUG) @@ -1159,7 +1161,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) set_opt(sbi->s_mount_opt, ERRORS_RO); - + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); @@ -1307,13 +1309,19 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) printk (KERN_ERR "EXT3-fs: not enough memory\n"); goto failed_mount; } - sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), + sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(u8), GFP_KERNEL); if (!sbi->s_debts) { - printk ("EXT3-fs: not enough memory\n"); + printk("EXT3-fs: not enough memory to allocate s_bgi\n"); goto failed_mount2; } - memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts)); + memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(u8)); + + percpu_counter_init(&sbi->s_freeblocks_counter); + percpu_counter_init(&sbi->s_freeinodes_counter); + percpu_counter_init(&sbi->s_dirs_counter); + bgl_lock_init(&sbi->s_blockgroup_lock); + for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); @@ -1329,7 +1337,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) goto failed_mount2; } sbi->s_gdb_count = db_count; - sbi->s_dir_count = ext3_count_dirs(sb); /* * set up enough so that it can read an inode */ @@ -1427,13 +1434,19 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": "writeback"); + percpu_counter_mod(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + percpu_counter_mod(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + percpu_counter_mod(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + return 0; failed_mount3: journal_destroy(sbi->s_journal); failed_mount2: - if (sbi->s_debts) - kfree(sbi->s_debts); + kfree(sbi->s_debts); for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); @@ -1525,7 +1538,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, "EXT3-fs: blocksize too small for journal device.\n"); goto out_bdev; } - + sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; offset = EXT3_MIN_BLOCK_SIZE % blocksize; set_blocksize(bdev, blocksize); @@ -1702,6 +1715,8 @@ static void ext3_commit_super (struct super_block * sb, if (!sbh) return; es->s_wtime = cpu_to_le32(get_seconds()); + es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); + es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); if (sync) @@ -1737,7 +1752,7 @@ static void ext3_clear_journal_err(struct super_block * sb, journal_t *journal; int j_errno; const char *errstr; - + journal = EXT3_SB(sb)->s_journal; /* @@ -1748,13 +1763,13 @@ static void ext3_clear_journal_err(struct super_block * sb, j_errno = journal_errno(journal); if (j_errno) { char nbuf[16]; - + errstr = ext3_decode_error(sb, j_errno, nbuf); ext3_warning(sb, __FUNCTION__, "Filesystem error recorded " "from previous mount: %s", errstr); ext3_warning(sb, __FUNCTION__, "Marking fs in need of " "filesystem check."); - + EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; es->s_state |= cpu_to_le16(EXT3_ERROR_FS); ext3_commit_super (sb, es, 1); @@ -1777,9 +1792,7 @@ int ext3_force_commit(struct super_block *sb) journal = EXT3_SB(sb)->s_journal; sb->s_dirt = 0; - lock_kernel(); /* important: lock down j_running_transaction */ ret = ext3_journal_force_commit(journal); - unlock_kernel(); return ret; } @@ -1794,24 +1807,21 @@ int ext3_force_commit(struct super_block *sb) void ext3_write_super (struct super_block * sb) { - lock_kernel(); if (down_trylock(&sb->s_lock) == 0) BUG(); sb->s_dirt = 0; - log_start_commit(EXT3_SB(sb)->s_journal, NULL); - unlock_kernel(); + journal_start_commit(EXT3_SB(sb)->s_journal, NULL); } static int ext3_sync_fs(struct super_block *sb, int wait) { tid_t target; - lock_kernel(); sb->s_dirt = 0; - target = log_start_commit(EXT3_SB(sb)->s_journal, NULL); - if (wait) - log_wait_commit(EXT3_SB(sb)->s_journal, target); - unlock_kernel(); + if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { + if (wait) + log_wait_commit(EXT3_SB(sb)->s_journal, target); + } return 0; } @@ -1823,7 +1833,6 @@ void ext3_write_super_lockfs(struct super_block *sb) { sb->s_dirt = 0; - lock_kernel(); /* 2.4.5 forgot to do this for us */ if (!(sb->s_flags & MS_RDONLY)) { journal_t *journal = EXT3_SB(sb)->s_journal; @@ -1835,7 +1844,6 @@ void ext3_write_super_lockfs(struct super_block *sb) EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); } - unlock_kernel(); } /* @@ -1845,14 +1853,12 @@ void ext3_write_super_lockfs(struct super_block *sb) void ext3_unlockfs(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { - lock_kernel(); lock_super(sb); /* Reser the needs_recovery flag before the fs is unlocked. */ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); unlock_super(sb); journal_unlock_updates(EXT3_SB(sb)->s_journal); - unlock_kernel(); } } @@ -1879,7 +1885,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) es = sbi->s_es; ext3_init_journal_params(sbi, sbi->s_journal); - + if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) return -EROFS; @@ -1927,7 +1933,7 @@ int ext3_remount (struct super_block * sb, int * flags, char * data) return 0; } -int ext3_statfs (struct super_block * sb, struct statfs * buf) +int ext3_statfs (struct super_block * sb, struct kstatfs * buf) { struct ext3_super_block *es = EXT3_SB(sb)->s_es; unsigned long overhead; @@ -1997,7 +2003,9 @@ static int (*old_sync_dquot)(struct dquot *dquot); static int ext3_sync_dquot(struct dquot *dquot) { - int nblocks, ret; + int nblocks; + int ret; + int err; handle_t *handle; struct quota_info *dqops = sb_dqopt(dquot->dq_sb); struct inode *qinode; @@ -2012,18 +2020,17 @@ static int ext3_sync_dquot(struct dquot *dquot) default: nblocks = EXT3_MAX_TRANS_DATA; } - lock_kernel(); qinode = dqops->files[dquot->dq_type]->f_dentry->d_inode; handle = ext3_journal_start(qinode, nblocks); if (IS_ERR(handle)) { - unlock_kernel(); - return PTR_ERR(handle); + ret = PTR_ERR(handle); + goto out; } - unlock_kernel(); ret = old_sync_dquot(dquot); - lock_kernel(); - ret = ext3_journal_stop(handle); - unlock_kernel(); + err = ext3_journal_stop(handle); + if (ret == 0) + ret = err; +out: return ret; } #endif diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index cd8cb24a344..066316459d8 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -481,7 +481,7 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, unsigned int name_len; int min_offs = sb->s_blocksize, not_found = 1, free, error; char *end; - + /* * header -- Points either into bh, or to a temporarily * allocated buffer. @@ -493,7 +493,7 @@ ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, * towards the end of the block). * end -- Points right after the block pointed to by header. */ - + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", name_index, name, value, (long)value_len); @@ -736,11 +736,11 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode, ea_bdebug(new_bh, "%s block %ld", (old_bh == new_bh) ? "keeping" : "reusing", new_bh->b_blocknr); - + error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) goto cleanup; - + error = ext3_journal_get_write_access(handle, new_bh); if (error) goto cleanup; @@ -782,7 +782,7 @@ getblk_failed: set_buffer_uptodate(new_bh); unlock_buffer(new_bh); ext3_xattr_cache_insert(new_bh); - + ext3_xattr_update_super_block(handle, sb); } error = ext3_journal_dirty_metadata(handle, new_bh); @@ -849,7 +849,6 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, handle_t *handle; int error, error2; - lock_kernel(); handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); if (IS_ERR(handle)) error = PTR_ERR(handle); @@ -857,7 +856,6 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, error = ext3_xattr_set_handle(handle, inode, name_index, name, value, value_len, flags); error2 = ext3_journal_stop(handle); - unlock_kernel(); return error ? error : error2; } @@ -1110,7 +1108,7 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header, { struct ext3_xattr_entry *here; __u32 hash = 0; - + ext3_xattr_hash_entry(header, entry); here = ENTRY(header+1); while (!IS_LAST_ENTRY(here)) { @@ -1133,7 +1131,7 @@ int __init init_ext3_xattr(void) { int err; - + err = ext3_xattr_register(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler); if (err) diff --git a/fs/fat/inode.c b/fs/fat/inode.c index d11c0fbd0a2..55df2585165 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1019,7 +1019,7 @@ out_fail: return error; } -int fat_statfs(struct super_block *sb,struct statfs *buf) +int fat_statfs(struct super_block *sb, struct kstatfs *buf) { int free,nr; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index d3ebd64c780..d49c04846e4 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -55,7 +55,7 @@ MODULE_LICENSE("Dual BSD/GPL"); static void vxfs_put_super(struct super_block *); -static int vxfs_statfs(struct super_block *, struct statfs *); +static int vxfs_statfs(struct super_block *, struct kstatfs *); static struct super_operations vxfs_super_ops = { .read_inode = vxfs_read_inode, @@ -105,7 +105,7 @@ vxfs_put_super(struct super_block *sbp) * This is everything but complete... */ static int -vxfs_statfs(struct super_block *sbp, struct statfs *bufp) +vxfs_statfs(struct super_block *sbp, struct kstatfs *bufp) { struct vxfs_sb_info *infp = VXFS_SBI(sbp); diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 8bbd871b03d..92682b02ff1 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -49,9 +49,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) { struct super_block *sb = inode->i_sb; - if (!sb) - return; /* swapper_space */ - /* * Don't do this for I_DIRTY_PAGES - that doesn't actually * dirty the inode itself @@ -90,9 +87,12 @@ void __mark_inode_dirty(struct inode *inode, int flags) * Only add valid (hashed) inodes to the superblock's * dirty list. Add blockdev inodes as well. */ - if ((hlist_unhashed(&inode->i_hash) || (inode->i_state & (I_FREEING|I_CLEAR))) - && !S_ISBLK(inode->i_mode)) - goto out; + if (!S_ISBLK(inode->i_mode)) { + if (hlist_unhashed(&inode->i_hash)) + goto out; + if (inode->i_state & (I_FREEING|I_CLEAR)) + goto out; + } /* * If the inode was already on s_dirty or s_io, don't @@ -369,6 +369,9 @@ writeback_inodes(struct writeback_control *wbc) * * A finite limit is set on the number of pages which will be written. * To prevent infinite livelock of sys_sync(). + * + * We add in the number of potentially dirty inodes, because each inode write + * can dirty pagecache in the underlying blockdev. */ void sync_inodes_sb(struct super_block *sb, int wait) { @@ -382,7 +385,9 @@ void sync_inodes_sb(struct super_block *sb, int wait) get_page_state(&ps); wbc.nr_to_write = ps.nr_dirty + ps.nr_unstable + - (ps.nr_dirty + ps.nr_unstable) / 4; + (inodes_stat.nr_inodes - inodes_stat.nr_unused) + + ps.nr_dirty + ps.nr_unstable; + wbc.nr_to_write += wbc.nr_to_write / 2; /* Bit more for luck */ spin_lock(&inode_lock); sync_sb_inodes(sb, &wbc); spin_unlock(&inode_lock); diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 48be69ce410..40891102165 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -40,7 +40,7 @@ MODULE_LICENSE("GPL"); static void hfs_read_inode(struct inode *); static void hfs_put_super(struct super_block *); -static int hfs_statfs(struct super_block *, struct statfs *); +static int hfs_statfs(struct super_block *, struct kstatfs *); static void hfs_write_super(struct super_block *); static kmem_cache_t * hfs_inode_cachep; @@ -195,7 +195,7 @@ static void hfs_put_super(struct super_block *sb) * * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. */ -static int hfs_statfs(struct super_block *sb, struct statfs *buf) +static int hfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 84d5023cac6..91f880e8836 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -310,7 +310,7 @@ int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); int hpfs_remount_fs(struct super_block *, int *, char *); void hpfs_put_super(struct super_block *); unsigned hpfs_count_one_bitmap(struct super_block *, secno); -int hpfs_statfs(struct super_block *, struct statfs *); +int hpfs_statfs(struct super_block *, struct kstatfs *); extern struct address_space_operations hpfs_aops; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 36aa38cd829..5827a006dd9 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -136,7 +136,7 @@ static unsigned count_bitmaps(struct super_block *s) return count; } -int hpfs_statfs(struct super_block *s, struct statfs *buf) +int hpfs_statfs(struct super_block *s, struct kstatfs *buf) { struct hpfs_sb_info *sbi = hpfs_sb(s); lock_kernel(); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4c83c32a190..f0d2a2c6517 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -22,7 +22,9 @@ #include #include #include +#include #include +#include #include #include @@ -43,8 +45,9 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = { static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { - struct inode *inode =file->f_dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); loff_t len; int ret; @@ -57,6 +60,18 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (vma->vm_end - vma->vm_start < HPAGE_SIZE) return -EINVAL; + len = (loff_t)(vma->vm_end - vma->vm_start); + if (sbinfo->free_blocks >= 0) { /* Check if there is any size limit. */ + spin_lock(&sbinfo->stat_lock); + if ((len >> HPAGE_SHIFT) <= sbinfo->free_blocks) { + sbinfo->free_blocks -= (len >> HPAGE_SHIFT); + spin_unlock(&sbinfo->stat_lock); + } else { + spin_unlock(&sbinfo->stat_lock); + return -ENOMEM; + } + } + down(&inode->i_sem); update_atime(inode); @@ -68,6 +83,16 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (ret == 0 && inode->i_size < len) inode->i_size = len; up(&inode->i_sem); + + /* + * If the huge page allocation has failed then increment free_blocks. + */ + if ((ret != 0) && (sbinfo->free_blocks >= 0)) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks += (len >> HPAGE_SHIFT); + spin_unlock(&sbinfo->stat_lock); + } + return ret; } @@ -154,6 +179,7 @@ void truncate_huge_page(struct page *page) void truncate_hugepages(struct address_space *mapping, loff_t lstart) { + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); const pgoff_t start = lstart >> HPAGE_SHIFT; struct pagevec pvec; pgoff_t next; @@ -178,6 +204,11 @@ void truncate_hugepages(struct address_space *mapping, loff_t lstart) ++next; truncate_huge_page(page); unlock_page(page); + if (sbinfo->free_blocks >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks++; + spin_unlock(&sbinfo->stat_lock); + } } huge_pagevec_release(&pvec); } @@ -186,6 +217,8 @@ void truncate_hugepages(struct address_space *mapping, loff_t lstart) static void hugetlbfs_delete_inode(struct inode *inode) { + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); + hlist_del_init(&inode->i_hash); list_del_init(&inode->i_list); inode->i_state |= I_FREEING; @@ -197,6 +230,12 @@ static void hugetlbfs_delete_inode(struct inode *inode) security_inode_delete(inode); + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } + clear_inode(inode); destroy_inode(inode); } @@ -204,6 +243,7 @@ static void hugetlbfs_delete_inode(struct inode *inode) static void hugetlbfs_forget_inode(struct inode *inode) { struct super_block *super_block = inode->i_sb; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(super_block); if (hlist_unhashed(&inode->i_hash)) goto out_truncate; @@ -229,6 +269,12 @@ out_truncate: if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } + clear_inode(inode); destroy_inode(inode); } @@ -341,13 +387,25 @@ out: static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, gid_t gid, int mode, dev_t dev) { - struct inode * inode = new_inode(sb); + struct inode *inode; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + if (!sbinfo->free_inodes) { + spin_unlock(&sbinfo->stat_lock); + return NULL; + } + sbinfo->free_inodes--; + spin_unlock(&sbinfo->stat_lock); + } + inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_uid = uid; inode->i_gid = gid; - inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blksize = HPAGE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; inode->i_mapping->a_ops = &hugetlbfs_aops; @@ -379,17 +437,18 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, /* * File creation. Allocate an inode, and we're done.. */ -/* SMP-safe */ static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct inode * inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + struct inode *inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, current->fsgid, mode, dev); int error = -ENOSPC; if (inode) { + dir->i_size += PSEUDO_DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ + dget(dentry); /* Extra count - pin the dentry in core */ error = 0; } return error; @@ -425,6 +484,9 @@ static int hugetlbfs_symlink(struct inode *dir, } else iput(inode); } + dir->i_size += PSEUDO_DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + return error; } @@ -436,6 +498,83 @@ int hugetlbfs_set_page_dirty(struct page *page) return 0; } +static int hugetlbfs_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + buf->f_type = HUGETLBFS_MAGIC; + buf->f_bsize = HPAGE_SIZE; + if (sbinfo) { + spin_lock(&sbinfo->stat_lock); + buf->f_blocks = sbinfo->max_blocks; + buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; + buf->f_files = sbinfo->max_inodes; + buf->f_ffree = sbinfo->free_inodes; + spin_unlock(&sbinfo->stat_lock); + } + buf->f_namelen = NAME_MAX; + return 0; +} + +static int hugetlbfs_link(struct dentry *old_dentry, + struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + + dir->i_size += PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; +} + +static int hugetlbfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + dir->i_size -= PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink--; + dput(dentry); + return 0; +} + +static int hugetlbfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + if (!simple_empty(dentry)) + return -ENOTEMPTY; + + dir->i_nlink--; + return hugetlbfs_unlink(dir, dentry); +} + +static int hugetlbfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct inode *inode = old_dentry->d_inode; + int they_are_dirs = S_ISDIR(inode->i_mode); + + if (!simple_empty(new_dentry)) + return -ENOTEMPTY; + + if (new_dentry->d_inode) { + hugetlbfs_unlink(new_dir, new_dentry); + if (they_are_dirs) + old_dir->i_nlink--; + } else if (they_are_dirs) { + old_dir->i_nlink--; + new_dir->i_nlink++; + } + + old_dir->i_size -= PSEUDO_DIRENT_SIZE; + new_dir->i_size += PSEUDO_DIRENT_SIZE; + old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = + new_dir->i_mtime = inode->i_ctime = CURRENT_TIME; + return 0; +} + static struct address_space_operations hugetlbfs_aops = { .readpage = hugetlbfs_readpage, .prepare_write = hugetlbfs_prepare_write, @@ -452,13 +591,13 @@ struct file_operations hugetlbfs_file_operations = { static struct inode_operations hugetlbfs_dir_inode_operations = { .create = hugetlbfs_create, .lookup = simple_lookup, - .link = simple_link, - .unlink = simple_unlink, + .link = hugetlbfs_link, + .unlink = hugetlbfs_unlink, .symlink = hugetlbfs_symlink, .mkdir = hugetlbfs_mkdir, - .rmdir = simple_rmdir, + .rmdir = hugetlbfs_rmdir, .mknod = hugetlbfs_mknod, - .rename = simple_rename, + .rename = hugetlbfs_rename, .setattr = hugetlbfs_setattr, }; @@ -467,29 +606,26 @@ static struct inode_operations hugetlbfs_inode_operations = { }; static struct super_operations hugetlbfs_ops = { - .statfs = simple_statfs, + .statfs = hugetlbfs_statfs, .drop_inode = hugetlbfs_drop_inode, }; static int hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) { - char *opt, *value; - int ret = 0; + char *opt, *value, *rest; if (!options) - goto out; + return 0; while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; value = strchr(opt, '='); - if (!value || !*value) { - ret = -EINVAL; - goto out; - } else { + if (!value || !*value) + return -EINVAL; + else *value++ = '\0'; - } if (!strcmp(opt, "uid")) pconfig->uid = simple_strtoul(value, &value, 0); @@ -497,22 +633,27 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) pconfig->gid = simple_strtoul(value, &value, 0); else if (!strcmp(opt, "mode")) pconfig->mode = simple_strtoul(value,&value,0) & 0777U; - else { - ret = -EINVAL; - goto out; - } + else if (!strcmp(opt, "size")) { + unsigned long long size = memparse(value, &rest); + if (*rest == '%') { + size <<= HPAGE_SHIFT; + size *= htlbpage_max; + do_div(size, 100); + rest++; + } + size &= HPAGE_MASK; + pconfig->nr_blocks = (size >> HPAGE_SHIFT); + value = rest; + } else if (!strcmp(opt,"nr_inodes")) { + pconfig->nr_inodes = memparse(value, &rest); + value = rest; + } else + return -EINVAL; - if (*value) { - ret = -EINVAL; - goto out; - } + if (*value) + return -EINVAL; } return 0; -out: - pconfig->uid = current->fsuid; - pconfig->gid = current->fsgid; - pconfig->mode = 0755; - return ret; } static int @@ -522,13 +663,30 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) struct dentry * root; int ret; struct hugetlbfs_config config; + struct hugetlbfs_sb_info *sbinfo; + + sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); + if (!sbinfo) + return -ENOMEM; + sb->s_fs_info = sbinfo; + config.nr_blocks = -1; /* No limit on size by default */ + config.nr_inodes = -1; /* No limit on number of inodes by default */ + config.uid = current->fsuid; + config.gid = current->fsgid; + config.mode = 0755; ret = hugetlbfs_parse_options(data, &config); + if (ret) return ret; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + spin_lock_init(&sbinfo->stat_lock); + sbinfo->max_blocks = config.nr_blocks; + sbinfo->free_blocks = config.nr_blocks; + sbinfo->max_inodes = config.nr_inodes; + sbinfo->free_inodes = config.nr_inodes; + sb->s_blocksize = HPAGE_SIZE; + sb->s_blocksize_bits = HPAGE_SHIFT; sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; inode = hugetlbfs_get_inode(sb, config.uid, config.gid, @@ -551,10 +709,19 @@ static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type, return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super); } +static void hugetlbfs_kill_super(struct super_block *sb) +{ + if (sb) { + if(sb->s_fs_info) + kfree(sb->s_fs_info); + kill_litter_super(sb); + } +} + static struct file_system_type hugetlbfs_fs_type = { .name = "hugetlbfs", .get_sb = hugetlbfs_get_sb, - .kill_sb = kill_litter_super, + .kill_sb = hugetlbfs_kill_super }; static struct vfsmount *hugetlbfs_vfsmount; diff --git a/fs/intermezzo/intermezzo_fs.h b/fs/intermezzo/intermezzo_fs.h index 5a91c61188d..8d2d33fcee0 100644 --- a/fs/intermezzo/intermezzo_fs.h +++ b/fs/intermezzo/intermezzo_fs.h @@ -530,7 +530,7 @@ int do_rename(struct presto_file_set *fset, struct dentry *old_dir, struct dentry *old_dentry, struct dentry *new_dir, struct dentry *new_dentry, struct lento_vfs_context *info); int presto_do_statfs (struct presto_file_set *fset, - struct statfs * buf); + struct kstatfs * buf); int lento_setattr(const char *name, struct iattr *iattr, struct lento_vfs_context *info); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 5e21abe1553..a28d5f174b9 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -74,7 +74,7 @@ static void isofs_put_super(struct super_block *sb) } static void isofs_read_inode(struct inode *); -static int isofs_statfs (struct super_block *, struct statfs *); +static int isofs_statfs (struct super_block *, struct kstatfs *); static kmem_cache_t *isofs_inode_cachep; @@ -884,7 +884,7 @@ out_freesbi: return -EINVAL; } -static int isofs_statfs (struct super_block *sb, struct statfs *buf) +static int isofs_statfs (struct super_block *sb, struct kstatfs *buf) { buf->f_type = ISOFS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index feace10833b..2052795b825 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -23,12 +23,10 @@ #include #include -extern spinlock_t journal_datalist_lock; - /* * Unlink a buffer from a transaction. * - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ static inline void __buffer_unlink(struct journal_head *jh) @@ -49,7 +47,8 @@ static inline void __buffer_unlink(struct journal_head *jh) /* * Try to release a checkpointed buffer from its transaction. * Returns 1 if we released it. - * Requires journal_datalist_lock + * Requires j_list_lock + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ static int __try_to_free_cp_buf(struct journal_head *jh) { @@ -59,40 +58,63 @@ static int __try_to_free_cp_buf(struct journal_head *jh) if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { JBUFFER_TRACE(jh, "remove from checkpoint list"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); BUFFER_TRACE(bh, "release"); __brelse(bh); ret = 1; + } else { + jbd_unlock_bh_state(bh); } return ret; } /* - * log_wait_for_space: wait until there is space in the journal. + * __log_wait_for_space: wait until there is space in the journal. * - * Called with the journal already locked, but it will be unlocked if we have - * to wait for a checkpoint to free up some space in the log. + * Called under j-state_lock *only*. It will be unlocked if we have to wait + * for a checkpoint to free up some space in the log. */ -void log_wait_for_space(journal_t *journal, int nblocks) +void __log_wait_for_space(journal_t *journal, int nblocks) { - while (log_space_left(journal) < nblocks) { + assert_spin_locked(&journal->j_state_lock); + + while (__log_space_left(journal) < nblocks) { if (journal->j_flags & JFS_ABORT) return; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); down(&journal->j_checkpoint_sem); - lock_journal(journal); - - /* Test again, another process may have checkpointed - * while we were waiting for the checkpoint lock */ - if (log_space_left(journal) < nblocks) { + + /* + * Test again, another process may have checkpointed while we + * were waiting for the checkpoint lock + */ + spin_lock(&journal->j_state_lock); + if (__log_space_left(journal) < nblocks) { + spin_unlock(&journal->j_state_lock); log_do_checkpoint(journal, nblocks); + spin_lock(&journal->j_state_lock); } up(&journal->j_checkpoint_sem); } } /* + * We were unable to perform jbd_trylock_bh_state() inside j_list_lock. + * The caller must restart a list walk. Wait for someone else to run + * jbd_unlock_bh_state(). + */ +static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh) +{ + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_lock_bh_state(bh); + jbd_unlock_bh_state(bh); + put_bh(bh); +} + +/* * Clean up a transaction's checkpoint list. * * We wait for any pending IO to complete and make sure any clean @@ -102,8 +124,7 @@ void log_wait_for_space(journal_t *journal, int nblocks) * checkpoint. (journal_remove_checkpoint() deletes the transaction when * the last checkpoint buffer is cleansed) * - * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) { @@ -111,7 +132,7 @@ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) struct buffer_head *bh; int ret = 0; - assert_spin_locked(&journal_datalist_lock); + assert_spin_locked(&journal->j_list_lock); jh = transaction->t_checkpoint_list; if (!jh) return 0; @@ -123,67 +144,70 @@ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) bh = jh2bh(jh); if (buffer_locked(bh)) { atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); __brelse(bh); goto out_return_1; } - + + /* + * This is foul + */ + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + goto out_return_1; + } + if (jh->b_transaction != NULL) { - transaction_t *transaction = jh->b_transaction; - tid_t tid = transaction->t_tid; + transaction_t *t = jh->b_transaction; + tid_t tid = t->t_tid; - spin_unlock(&journal_datalist_lock); - log_start_commit(journal, transaction); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + log_start_commit(journal, tid); log_wait_commit(journal, tid); goto out_return_1; } /* - * We used to test for (jh->b_list != BUF_CLEAN) here. - * But unmap_underlying_metadata() can place buffer onto - * BUF_CLEAN. - */ - /* - * AKPM: I think the buffer_jdirty test is redundant - it + * AKPM: I think the buffer_jbddirty test is redundant - it * shouldn't have NULL b_transaction? */ next_jh = jh->b_cpnext; - if (!buffer_dirty(bh) && !buffer_jdirty(bh)) { + if (!buffer_dirty(bh) && !buffer_jbddirty(bh)) { BUFFER_TRACE(bh, "remove from checkpoint"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); __brelse(bh); ret = 1; + } else { + jbd_unlock_bh_state(bh); } - jh = next_jh; } while (jh != last_jh); return ret; out_return_1: - lock_journal(journal); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); return 1; } #define NR_BATCH 64 -static void __flush_batch(struct buffer_head **bhs, int *batch_count) +static void +__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) { int i; - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); ll_rw_block(WRITE, *batch_count, bhs); - blk_run_queues(); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = bhs[i]; - clear_bit(BH_JWrite, &bh->b_state); + clear_buffer_jwrite(bh); BUFFER_TRACE(bh, "brelse"); __brelse(bh); } @@ -196,7 +220,8 @@ static void __flush_batch(struct buffer_head **bhs, int *batch_count) * Return 1 if something happened which requires us to abort the current * scan of the checkpoint list. * - * Called with journal_datalist_lock held. + * Called with j_list_lock held. + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ static int __flush_buffer(journal_t *journal, struct journal_head *jh, struct buffer_head **bhs, int *batch_count, @@ -207,7 +232,7 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, if (buffer_dirty(bh) && !buffer_locked(bh) && jh->b_jlist == BJ_None) { J_ASSERT_JH(jh, jh->b_transaction == NULL); - + /* * Important: we are about to write the buffer, and * possibly block, while still holding the journal lock. @@ -216,13 +241,14 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, * disk, as that would break recoverability. */ BUFFER_TRACE(bh, "queue"); - atomic_inc(&bh->b_count); - J_ASSERT_BH(bh, !test_bit(BH_JWrite, &bh->b_state)); - set_bit(BH_JWrite, &bh->b_state); + get_bh(bh); + J_ASSERT_BH(bh, !buffer_jwrite(bh)); + set_buffer_jwrite(bh); bhs[*batch_count] = bh; + jbd_unlock_bh_state(bh); (*batch_count)++; if (*batch_count == NR_BATCH) { - __flush_batch(bhs, batch_count); + __flush_batch(journal, bhs, batch_count); ret = 1; } } else { @@ -241,12 +267,11 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, return ret; } - /* * Perform an actual checkpoint. We don't write out only enough to * satisfy the current blocked requests: rather we submit a reasonably * sized chunk of the outstanding data to disk at once for - * efficiency. log_wait_for_space() will retry if we didn't free enough. + * efficiency. __log_wait_for_space() will retry if we didn't free enough. * * However, we _do_ take into account the amount requested so that once * the IO has been queued, we can return as soon as enough of it has @@ -256,9 +281,8 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, */ /* @@@ `nblocks' is unused. Should it be used? */ -int log_do_checkpoint (journal_t *journal, int nblocks) +int log_do_checkpoint(journal_t *journal, int nblocks) { - transaction_t *transaction, *last_transaction, *next_transaction; int result; int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; @@ -283,36 +307,59 @@ int log_do_checkpoint (journal_t *journal, int nblocks) * AKPM: check this code. I had a feeling a while back that it * degenerates into a busy loop at unmount time. */ - spin_lock(&journal_datalist_lock); -repeat: - transaction = journal->j_checkpoint_transactions; - if (transaction == NULL) - goto done; - last_transaction = transaction->t_cpprev; - next_transaction = transaction; - - do { + spin_lock(&journal->j_list_lock); + while (journal->j_checkpoint_transactions) { + transaction_t *transaction; struct journal_head *jh, *last_jh, *next_jh; int drop_count = 0; int cleanup_ret, retry = 0; + tid_t this_tid; - transaction = next_transaction; - next_transaction = transaction->t_cpnext; + transaction = journal->j_checkpoint_transactions->t_cpnext; + this_tid = transaction->t_tid; jh = transaction->t_checkpoint_list; last_jh = jh->b_cpprev; next_jh = jh; do { + struct buffer_head *bh; + jh = next_jh; next_jh = jh->b_cpnext; + bh = jh2bh(jh); + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + spin_lock(&journal->j_list_lock); + retry = 1; + break; + } retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); } while (jh != last_jh && !retry); if (batch_count) { - __flush_batch(bhs, &batch_count); - goto repeat; + __flush_batch(journal, bhs, &batch_count); + continue; } if (retry) - goto repeat; + continue; + + /* + * If someone emptied the checkpoint list while we slept, we're + * done. + */ + if (!journal->j_checkpoint_transactions) + break; + /* + * If someone cleaned up this transaction while we slept, we're + * done + */ + if (journal->j_checkpoint_transactions->t_cpnext != transaction) + continue; + /* + * Maybe it's a new transaction, but it fell at the same + * address + */ + if (transaction->t_tid != this_tid) + continue; /* * We have walked the whole transaction list without * finding anything to write to disk. We had better be @@ -320,15 +367,12 @@ repeat: */ cleanup_ret = __cleanup_transaction(journal, transaction); J_ASSERT(drop_count != 0 || cleanup_ret != 0); - goto repeat; /* __cleanup may have dropped lock */ - } while (transaction != last_transaction); - -done: - spin_unlock(&journal_datalist_lock); + } + spin_unlock(&journal->j_list_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; - + return 0; } @@ -362,8 +406,8 @@ int cleanup_journal_tail(journal_t *journal) * next transaction ID we will write, and where it will * start. */ - /* j_checkpoint_transactions needs locking */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); transaction = journal->j_checkpoint_transactions; if (transaction) { first_tid = transaction->t_tid; @@ -378,13 +422,15 @@ int cleanup_journal_tail(journal_t *journal) first_tid = journal->j_transaction_sequence; blocknr = journal->j_head; } - spin_unlock(&journal_datalist_lock); - J_ASSERT (blocknr != 0); + spin_unlock(&journal->j_list_lock); + J_ASSERT(blocknr != 0); /* If the oldest pinned transaction is at the tail of the log already then there's not much we can do right now. */ - if (journal->j_tail_sequence == first_tid) + if (journal->j_tail_sequence == first_tid) { + spin_unlock(&journal->j_state_lock); return 1; + } /* OK, update the superblock to recover the freed space. * Physical blocks come first: have we wrapped beyond the end of @@ -401,6 +447,7 @@ int cleanup_journal_tail(journal_t *journal) journal->j_free += freed; journal->j_tail_sequence = first_tid; journal->j_tail = blocknr; + spin_unlock(&journal->j_state_lock); if (!(journal->j_flags & JFS_ABORT)) journal_update_superblock(journal, 1); return 0; @@ -415,7 +462,7 @@ int cleanup_journal_tail(journal_t *journal) * Find all the written-back checkpoint buffers in the journal and release them. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. * Returns number of bufers reaped (for debug) */ @@ -439,10 +486,13 @@ int __journal_clean_checkpoint_list(journal_t *journal) if (jh) { struct journal_head *last_jh = jh->b_cpprev; struct journal_head *next_jh = jh; + do { jh = next_jh; next_jh = jh->b_cpnext; - ret += __try_to_free_cp_buf(jh); + /* Use trylock because of the ranknig */ + if (jbd_trylock_bh_state(jh2bh(jh))) + ret += __try_to_free_cp_buf(jh); } while (jh != last_jh); } } while (transaction != last_transaction); @@ -464,7 +514,7 @@ out: * checkpoint list. * * This function is called with the journal locked. - * This function is called with journal_datalist_lock held. + * This function is called with j_list_lock held. */ void __journal_remove_checkpoint(struct journal_head *jh) @@ -473,12 +523,11 @@ void __journal_remove_checkpoint(struct journal_head *jh) journal_t *journal; JBUFFER_TRACE(jh, "entry"); - + if ((transaction = jh->b_cp_transaction) == NULL) { JBUFFER_TRACE(jh, "not on transaction"); goto out; } - journal = transaction->t_journal; __buffer_unlink(jh); @@ -487,11 +536,15 @@ void __journal_remove_checkpoint(struct journal_head *jh) goto out; JBUFFER_TRACE(jh, "transaction has no more buffers"); - /* There is one special case to worry about: if we have just - pulled the buffer off a committing transaction's forget list, - then even if the checkpoint list is empty, the transaction - obviously cannot be dropped! */ - + /* + * There is one special case to worry about: if we have just pulled the + * buffer off a committing transaction's forget list, then even if the + * checkpoint list is empty, the transaction obviously cannot be + * dropped! + * + * The locking here around j_committing_transaction is a bit sleazy. + * See the comment at the end of journal_commit_transaction(). + */ if (transaction == journal->j_committing_transaction) { JBUFFER_TRACE(jh, "belongs to committing transaction"); goto out; @@ -509,29 +562,21 @@ out: JBUFFER_TRACE(jh, "exit"); } -void journal_remove_checkpoint(struct journal_head *jh) -{ - spin_lock(&journal_datalist_lock); - __journal_remove_checkpoint(jh); - spin_unlock(&journal_datalist_lock); -} - /* * journal_insert_checkpoint: put a committed buffer onto a checkpoint * list so that we know when it is safe to clean the transaction out of * the log. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ void __journal_insert_checkpoint(struct journal_head *jh, transaction_t *transaction) { JBUFFER_TRACE(jh, "entry"); - J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jdirty(jh2bh(jh))); + J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - assert_spin_locked(&journal_datalist_lock); jh->b_cp_transaction = transaction; if (!transaction->t_checkpoint_list) { @@ -545,14 +590,6 @@ void __journal_insert_checkpoint(struct journal_head *jh, transaction->t_checkpoint_list = jh; } -void journal_insert_checkpoint(struct journal_head *jh, - transaction_t *transaction) -{ - spin_lock(&journal_datalist_lock); - __journal_insert_checkpoint(jh, transaction); - spin_unlock(&journal_datalist_lock); -} - /* * We've finished with this transaction structure: adios... * @@ -560,12 +597,12 @@ void journal_insert_checkpoint(struct journal_head *jh, * point. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) { - assert_spin_locked(&journal_datalist_lock); + assert_spin_locked(&journal->j_list_lock); if (transaction->t_cpnext) { transaction->t_cpnext->t_cpprev = transaction->t_cpprev; transaction->t_cpprev->t_cpnext = transaction->t_cpnext; @@ -576,22 +613,19 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) journal->j_checkpoint_transactions = NULL; } - J_ASSERT (transaction->t_ilist == NULL); - J_ASSERT (transaction->t_buffers == NULL); - J_ASSERT (transaction->t_sync_datalist == NULL); - J_ASSERT (transaction->t_forget == NULL); - J_ASSERT (transaction->t_iobuf_list == NULL); - J_ASSERT (transaction->t_shadow_list == NULL); - J_ASSERT (transaction->t_log_list == NULL); - J_ASSERT (transaction->t_checkpoint_list == NULL); - J_ASSERT (transaction->t_updates == 0); - J_ASSERT (list_empty(&transaction->t_jcb)); - - J_ASSERT (transaction->t_journal->j_committing_transaction != - transaction); - - jbd_debug (1, "Dropping transaction %d, all done\n", - transaction->t_tid); - kfree (transaction); + J_ASSERT(transaction->t_state == T_FINISHED); + J_ASSERT(transaction->t_buffers == NULL); + J_ASSERT(transaction->t_sync_datalist == NULL); + J_ASSERT(transaction->t_forget == NULL); + J_ASSERT(transaction->t_iobuf_list == NULL); + J_ASSERT(transaction->t_shadow_list == NULL); + J_ASSERT(transaction->t_log_list == NULL); + J_ASSERT(transaction->t_checkpoint_list == NULL); + J_ASSERT(transaction->t_updates == 0); + J_ASSERT(list_empty(&transaction->t_jcb)); + J_ASSERT(journal->j_committing_transaction != transaction); + J_ASSERT(journal->j_running_transaction != transaction); + + jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); + kfree(transaction); } - diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index f67f28239af..b41b26d758b 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -18,10 +18,10 @@ #include #include #include +#include +#include #include -extern spinlock_t journal_datalist_lock; - /* * Default IO end handler for temporary BJ_IO buffer_heads. */ @@ -36,6 +36,49 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) } /* + * When an ext3-ordered file is truncated, it is possible that many pages are + * not sucessfully freed, because they are attached to a committing transaction. + * After the transaction commits, these pages are left on the LRU, with no + * ->mapping, and with attached buffers. These pages are trivially reclaimable + * by the VM, but their apparent absence upsets the VM accounting, and it makes + * the numbers in /proc/meminfo look odd. + * + * So here, we have a buffer which has just come off the forget list. Look to + * see if we can strip all buffers from the backing page. + * + * Called under lock_journal(), and possibly under journal_datalist_lock. The + * caller provided us with a ref against the buffer, and we drop that here. + */ +static void release_buffer_page(struct buffer_head *bh) +{ + struct page *page; + + if (buffer_dirty(bh)) + goto nope; + if (atomic_read(&bh->b_count) != 1) + goto nope; + page = bh->b_page; + if (!page) + goto nope; + if (page->mapping) + goto nope; + + /* OK, it's a truncated page */ + if (TestSetPageLocked(page)) + goto nope; + + page_cache_get(page); + __brelse(bh); + try_to_free_buffers(page); + unlock_page(page); + page_cache_release(page); + return; + +nope: + __brelse(bh); +} + +/* * journal_commit_transaction * * The primary function for committing a transaction to the log. This @@ -64,43 +107,52 @@ void journal_commit_transaction(journal_t *journal) * all outstanding updates to complete. */ - lock_journal(journal); /* Protect journal->j_running_transaction */ - #ifdef COMMIT_STATS - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); summarise_journal_usage(journal); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); #endif - lock_kernel(); + /* Do we need to erase the effects of a prior journal_flush? */ + if (journal->j_flags & JFS_FLUSHED) { + jbd_debug(3, "super block updated\n"); + journal_update_superblock(journal, 1); + } else { + jbd_debug(3, "superblock not updated\n"); + } - J_ASSERT (journal->j_running_transaction != NULL); - J_ASSERT (journal->j_committing_transaction == NULL); + J_ASSERT(journal->j_running_transaction != NULL); + J_ASSERT(journal->j_committing_transaction == NULL); commit_transaction = journal->j_running_transaction; - J_ASSERT (commit_transaction->t_state == T_RUNNING); + J_ASSERT(commit_transaction->t_state == T_RUNNING); - jbd_debug (1, "JBD: starting commit of transaction %d\n", - commit_transaction->t_tid); + jbd_debug(1, "JBD: starting commit of transaction %d\n", + commit_transaction->t_tid); + spin_lock(&journal->j_state_lock); commit_transaction->t_state = T_LOCKED; - while (commit_transaction->t_updates != 0) { - unlock_journal(journal); - sleep_on(&journal->j_wait_updates); - lock_journal(journal); + + spin_lock(&commit_transaction->t_handle_lock); + while (commit_transaction->t_updates) { + DEFINE_WAIT(wait); + + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + if (commit_transaction->t_updates) { + spin_unlock(&commit_transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); + spin_lock(&commit_transaction->t_handle_lock); + } + finish_wait(&journal->j_wait_updates, &wait); } + spin_unlock(&commit_transaction->t_handle_lock); J_ASSERT (commit_transaction->t_outstanding_credits <= journal->j_max_transaction_buffers); - /* Do we need to erase the effects of a prior journal_flush? */ - if (journal->j_flags & JFS_FLUSHED) { - jbd_debug(3, "super block updated\n"); - journal_update_superblock(journal, 1); - } else { - jbd_debug(3, "superblock not updated\n"); - } - /* * First thing we are allowed to do is to discard any remaining * BJ_Reserved buffers. Note, it is _not_ permissible to assume @@ -117,11 +169,10 @@ void journal_commit_transaction(journal_t *journal) * that multiple journal_get_write_access() calls to the same * buffer are perfectly permissable. */ - while (commit_transaction->t_reserved_list) { jh = commit_transaction->t_reserved_list; JBUFFER_TRACE(jh, "reserved, unused: refile"); - journal_refile_buffer(jh); + journal_refile_buffer(journal, jh); } /* @@ -129,43 +180,24 @@ void journal_commit_transaction(journal_t *journal) * checkpoint lists. We do this *before* commit because it potentially * frees some memory */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); __journal_clean_checkpoint_list(journal); - spin_unlock(&journal_datalist_lock); - - /* First part of the commit: force the revoke list out to disk. - * The revoke code generates its own metadata blocks on disk for this. - * - * It is important that we do this while the transaction is - * still locked. Generating the revoke records should not - * generate any IO stalls, so this should be quick; and doing - * the work while we have the transaction locked means that we - * only ever have to maintain the revoke list for one - * transaction at a time. - */ + spin_unlock(&journal->j_list_lock); jbd_debug (3, "JBD: commit phase 1\n"); - journal_write_revoke_records(journal, commit_transaction); - /* - * Now that we have built the revoke records, we can start - * reusing the revoke list for a new running transaction. We - * can now safely start committing the old transaction: time to - * get a new running transaction for incoming filesystem updates + * Switch to a new revoke table. */ + journal_switch_revoke_table(journal); commit_transaction->t_state = T_FLUSH; - - wake_up(&journal->j_wait_transaction_locked); - journal->j_committing_transaction = commit_transaction; journal->j_running_transaction = NULL; - commit_transaction->t_log_start = journal->j_head; + wake_up(&journal->j_wait_transaction_locked); + spin_unlock(&journal->j_state_lock); - unlock_kernel(); - jbd_debug (3, "JBD: commit phase 2\n"); /* @@ -185,10 +217,10 @@ write_out_data: * Cleanup any flushed data buffers from the data list. Even in * abort mode, we want to flush this out as soon as possible. * - * We take journal_datalist_lock to protect the lists from + * We take j_list_lock to protect the lists from * journal_try_to_free_buffers(). */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); write_out_data_locked: bufs = 0; @@ -210,9 +242,19 @@ write_out_data_locked: wbuf[bufs++] = bh; } else { BUFFER_TRACE(bh, "writeout complete: unfile"); + /* + * We have a lock ranking problem.. + */ + if (!jbd_trylock_bh_state(bh)) { + spin_unlock(&journal->j_list_lock); + schedule(); + spin_lock(&journal->j_list_lock); + break; + } __journal_unfile_buffer(jh); jh->b_transaction = NULL; - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); __brelse(bh); } } @@ -228,14 +270,12 @@ write_out_data_locked: if (bufs || need_resched()) { jbd_debug(2, "submit %d writes\n", bufs); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); if (bufs) ll_rw_block(WRITE, bufs, wbuf); cond_resched(); journal_brelse_array(wbuf, bufs); - lock_journal(journal); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); if (bufs) goto write_out_data_locked; } @@ -253,14 +293,12 @@ write_out_data_locked: bh = jh2bh(jh); if (buffer_locked(bh)) { get_bh(bh); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; put_bh(bh); /* the journal_head may have been removed now */ - lock_journal(journal); goto write_out_data; } else if (buffer_dirty(bh)) { goto write_out_data_locked; @@ -269,7 +307,11 @@ write_out_data_locked: goto write_out_data_locked; sync_datalist_empty: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + + journal_write_revoke_records(journal, commit_transaction); + + jbd_debug(3, "JBD: commit phase 2\n"); /* * If we found any dirty or locked buffers, then we should have @@ -301,7 +343,7 @@ sync_datalist_empty: if (is_journal_aborted(journal)) { JBUFFER_TRACE(jh, "journal is aborting: refile"); - journal_refile_buffer(jh); + journal_refile_buffer(journal, jh); /* If that was the last one, we need to clean up * any descriptor buffers which may have been * already allocated, even if we are now @@ -326,7 +368,7 @@ sync_datalist_empty: __journal_abort_hard(journal); continue; } - + bh = jh2bh(descriptor); jbd_debug(4, "JBD: got buffer %llu (%p)\n", (unsigned long long)bh->b_blocknr, bh->b_data); @@ -345,7 +387,7 @@ sync_datalist_empty: completion later */ BUFFER_TRACE(bh, "ph3: file as descriptor"); journal_file_buffer(descriptor, commit_transaction, - BJ_LogCtl); + BJ_LogCtl); } /* Where is the buffer to be written? */ @@ -419,8 +461,7 @@ sync_datalist_empty: tag->t_flags |= htonl(JFS_FLAG_LAST_TAG); start_journal_io: - unlock_journal(journal); - for (i=0; it_iobuf_list != NULL) { struct buffer_head *bh; + jh = commit_transaction->t_iobuf_list->b_tprev; bh = jh2bh(jh); if (buffer_locked(bh)) { - unlock_journal(journal); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; - lock_journal(journal); goto wait_for_iobuf; } - clear_bit(BH_JWrite, &jh2bh(jh)->b_state); + clear_buffer_jwrite(bh); JBUFFER_TRACE(jh, "ph4: unfile after journal write"); - journal_unfile_buffer(jh); + journal_unfile_buffer(journal, jh); /* * akpm: don't put back a buffer_head with stale pointers @@ -485,9 +524,8 @@ start_journal_io: * ->t_iobuf_list should contain only dummy buffer_heads * which were created by journal_write_metadata_buffer(). */ - bh = jh2bh(jh); BUFFER_TRACE(bh, "dumping temporary bh"); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); __brelse(bh); J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); free_buffer_head(bh); @@ -497,7 +535,7 @@ start_journal_io: jh = commit_transaction->t_shadow_list->b_tprev; bh = jh2bh(jh); clear_bit(BH_JWrite, &bh->b_state); - J_ASSERT_BH(bh, buffer_jdirty(bh)); + J_ASSERT_BH(bh, buffer_jbddirty(bh)); /* The metadata is now released for reuse, but we need to remember it against this transaction so that when @@ -524,29 +562,25 @@ start_journal_io: jh = commit_transaction->t_log_list->b_tprev; bh = jh2bh(jh); if (buffer_locked(bh)) { - unlock_journal(journal); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; - lock_journal(journal); goto wait_for_ctlbuf; } BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); - clear_bit(BH_JWrite, &bh->b_state); - journal_unfile_buffer(jh); + clear_buffer_jwrite(bh); + journal_unfile_buffer(journal, jh); jh->b_transaction = NULL; - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); __brelse(bh); /* One for getblk */ /* AKPM: bforget here */ } jbd_debug(3, "JBD: commit phase 6\n"); - if (is_journal_aborted(journal)) { - unlock_journal(journal); + if (is_journal_aborted(journal)) goto skip_commit; - } /* Done it all: now write the commit record. We should have * cleaned up our previous buffers by now, so if we are in abort @@ -556,7 +590,6 @@ start_journal_io: descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) { __journal_abort_hard(journal); - unlock_journal(journal); goto skip_commit; } @@ -569,7 +602,6 @@ start_journal_io: tmp->h_sequence = htonl(commit_transaction->t_tid); } - unlock_journal(journal); JBUFFER_TRACE(descriptor, "write commit block"); { struct buffer_head *bh = jh2bh(descriptor); @@ -578,7 +610,7 @@ start_journal_io: if (unlikely(!buffer_uptodate(bh))) err = -EIO; put_bh(bh); /* One for getblk() */ - journal_unlock_journal_head(descriptor); + journal_put_journal_head(descriptor); } /* End of a transaction! Finally, we can do checkpoint @@ -588,16 +620,17 @@ start_journal_io: skip_commit: /* The journal should be unlocked by now. */ - if (err) { - lock_journal(journal); + if (err) __journal_abort_hard(journal); - unlock_journal(journal); - } - - /* Call any callbacks that had been registered for handles in this + + /* + * Call any callbacks that had been registered for handles in this * transaction. It is up to the callback to free any allocated * memory. + * + * The spinlocking (t_jcb_lock) here is surely unnecessary... */ + spin_lock(&commit_transaction->t_jcb_lock); if (!list_empty(&commit_transaction->t_jcb)) { struct list_head *p, *n; int error = is_journal_aborted(journal); @@ -607,11 +640,12 @@ skip_commit: /* The journal should be unlocked by now. */ jcb = list_entry(p, struct journal_callback, jcb_list); list_del(p); + spin_unlock(&commit_transaction->t_jcb_lock); jcb->jcb_func(jcb, error); + spin_lock(&commit_transaction->t_jcb_lock); } } - - lock_journal(journal); + spin_unlock(&commit_transaction->t_jcb_lock); jbd_debug(3, "JBD: commit phase 7\n"); @@ -627,6 +661,8 @@ skip_commit: /* The journal should be unlocked by now. */ struct buffer_head *bh; jh = commit_transaction->t_forget; + bh = jh2bh(jh); + jbd_lock_bh_state(bh); J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || jh->b_transaction == journal->j_running_transaction); @@ -652,7 +688,7 @@ skip_commit: /* The journal should be unlocked by now. */ jh->b_frozen_data = NULL; } - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); cp_transaction = jh->b_cp_transaction; if (cp_transaction) { JBUFFER_TRACE(jh, "remove from old cp transaction"); @@ -665,7 +701,6 @@ skip_commit: /* The journal should be unlocked by now. */ * by journal_forget, it may no longer be dirty and * there's no point in keeping a checkpoint record for * it. */ - bh = jh2bh(jh); /* A buffer which has been freed while still being * journaled by a previous transaction may end up still @@ -679,35 +714,46 @@ skip_commit: /* The journal should be unlocked by now. */ clear_buffer_freed(bh); clear_buffer_jbddirty(bh); } - - if (buffer_jdirty(bh)) { + + if (buffer_jbddirty(bh)) { JBUFFER_TRACE(jh, "add to new checkpointing trans"); __journal_insert_checkpoint(jh, commit_transaction); JBUFFER_TRACE(jh, "refile for checkpoint writeback"); __journal_refile_buffer(jh); + jbd_unlock_bh_state(bh); } else { J_ASSERT_BH(bh, !buffer_dirty(bh)); J_ASSERT_JH(jh, jh->b_next_transaction == NULL); __journal_unfile_buffer(jh); jh->b_transaction = 0; - __journal_remove_journal_head(bh); - __brelse(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + if (buffer_freed(bh)) + release_buffer_page(bh); } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); } /* Done with this transaction! */ jbd_debug(3, "JBD: commit phase 8\n"); - J_ASSERT (commit_transaction->t_state == T_COMMIT); - commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction->t_state == T_COMMIT); - J_ASSERT (commit_transaction == journal->j_committing_transaction); + /* + * This is a bit sleazy. We borrow j_list_lock to protect + * journal->j_committing_transaction in __journal_remove_checkpoint. + * Really, __jornal_remove_checkpoint should be using j_state_lock but + * it's a bit hassle to hold that across __journal_remove_checkpoint + */ + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); + commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction == journal->j_committing_transaction); journal->j_commit_sequence = commit_transaction->t_tid; journal->j_committing_transaction = NULL; + spin_unlock(&journal->j_state_lock); - spin_lock(&journal_datalist_lock); if (commit_transaction->t_checkpoint_list == NULL) { __journal_drop_transaction(journal, commit_transaction); } else { @@ -726,11 +772,10 @@ skip_commit: /* The journal should be unlocked by now. */ commit_transaction; } } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); jbd_debug(1, "JBD: commit %d complete, head %d\n", journal->j_commit_sequence, journal->j_tail_sequence); - unlock_journal(journal); wake_up(&journal->j_wait_done_commit); } diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 2e20ac0082a..fe4bdf4a6f3 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -48,9 +48,7 @@ EXPORT_SYMBOL(journal_get_create_access); EXPORT_SYMBOL(journal_get_undo_access); EXPORT_SYMBOL(journal_dirty_data); EXPORT_SYMBOL(journal_dirty_metadata); -#if 0 EXPORT_SYMBOL(journal_release_buffer); -#endif EXPORT_SYMBOL(journal_forget); #if 0 EXPORT_SYMBOL(journal_sync_buffer); @@ -75,7 +73,7 @@ EXPORT_SYMBOL(journal_errno); EXPORT_SYMBOL(journal_ack_err); EXPORT_SYMBOL(journal_clear_err); EXPORT_SYMBOL(log_wait_commit); -EXPORT_SYMBOL(log_start_commit); +EXPORT_SYMBOL(journal_start_commit); EXPORT_SYMBOL(journal_wipe); EXPORT_SYMBOL(journal_blocks_per_page); EXPORT_SYMBOL(journal_invalidatepage); @@ -86,76 +84,6 @@ EXPORT_SYMBOL(journal_force_commit); static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); /* - * journal_datalist_lock is used to protect data buffers: - * - * bh->b_transaction - * bh->b_tprev - * bh->b_tnext - * - * journal_free_buffer() is called from journal_try_to_free_buffer(), and is - * async wrt everything else. - * - * It is also used for checkpoint data, also to protect against - * journal_try_to_free_buffer(): - * - * bh->b_cp_transaction - * bh->b_cpnext - * bh->b_cpprev - * transaction->t_checkpoint_list - * transaction->t_cpnext - * transaction->t_cpprev - * journal->j_checkpoint_transactions - * - * It is global at this time rather than per-journal because it's - * impossible for __journal_free_buffer to go from a buffer_head - * back to a journal_t unracily (well, not true. Fix later) - * - * - * The `datalist' and `checkpoint list' functions are quite - * separate and we could use two spinlocks here. - * - * lru_list_lock nests inside journal_datalist_lock. - */ -spinlock_t journal_datalist_lock = SPIN_LOCK_UNLOCKED; - -/* - * jh_splice_lock needs explantion. - * - * In a number of places we want to do things like: - * - * if (buffer_jbd(bh) && bh2jh(bh)->foo) - * - * This is racy on SMP, because another CPU could remove the journal_head - * in the middle of this expression. We need locking. - * - * But we can greatly optimise the locking cost by testing BH_JBD - * outside the lock. So, effectively: - * - * ret = 0; - * if (buffer_jbd(bh)) { - * spin_lock(&jh_splice_lock); - * if (buffer_jbd(bh)) { (* Still there? *) - * ret = bh2jh(bh)->foo; - * } - * spin_unlock(&jh_splice_lock); - * } - * return ret; - * - * Now, that protects us from races where another CPU can remove the - * journal_head. But it doesn't defend us from the situation where another - * CPU can *add* a journal_head. This is a correctness issue. But it's not - * a problem because a) the calling code was *already* racy and b) it often - * can't happen at the call site and c) the places where we add journal_heads - * tend to be under external locking. - */ -spinlock_t jh_splice_lock = SPIN_LOCK_UNLOCKED; - -/* - * List of all journals in the system. Protected by the BKL. - */ -static LIST_HEAD(all_journals); - -/* * Helper function used to manage commit timeouts */ @@ -204,8 +132,6 @@ int kjournald(void *arg) daemonize("kjournald"); - lock_kernel(); - /* Set up an interval timer which can be used to trigger a commit wakeup after the commit interval expires */ init_timer(&timer); @@ -219,130 +145,102 @@ int kjournald(void *arg) printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", journal->j_commit_interval / HZ); - list_add(&journal->j_all_journals, &all_journals); - /* And now, wait forever for commit wakeup events. */ - while (1) { - if (journal->j_flags & JFS_UNMOUNT) - break; + /* + * And now, wait forever for commit wakeup events. + */ + spin_lock(&journal->j_state_lock); - jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", - journal->j_commit_sequence, journal->j_commit_request); +loop: + jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", + journal->j_commit_sequence, journal->j_commit_request); - if (journal->j_commit_sequence != journal->j_commit_request) { - jbd_debug(1, "OK, requests differ\n"); - if (journal->j_commit_timer_active) { - journal->j_commit_timer_active = 0; - del_timer(journal->j_commit_timer); - } + if (journal->j_commit_sequence != journal->j_commit_request) { + jbd_debug(1, "OK, requests differ\n"); + spin_unlock(&journal->j_state_lock); + del_timer_sync(journal->j_commit_timer); + journal_commit_transaction(journal); + spin_lock(&journal->j_state_lock); + goto end_loop; + } - journal_commit_transaction(journal); - continue; - } + wake_up(&journal->j_wait_done_commit); + if (current->flags & PF_FREEZE) { + /* + * The simpler the better. Flushing journal isn't a + * good idea, because that depends on threads that may + * be already stopped. + */ + jbd_debug(1, "Now suspending kjournald\n"); + spin_unlock(&journal->j_state_lock); + refrigerator(PF_IOTHREAD); + spin_lock(&journal->j_state_lock); + } else { + /* + * We assume on resume that commits are already there, + * so we don't sleep + */ + DEFINE_WAIT(wait); + int should_sleep = 1; - wake_up(&journal->j_wait_done_commit); - if (current->flags & PF_FREEZE) { /* The simpler the better. Flushing journal isn't a - good idea, because that depends on threads that - may be already stopped. */ - jbd_debug(1, "Now suspending kjournald\n"); - refrigerator(PF_IOTHREAD); - jbd_debug(1, "Resuming kjournald\n"); - } else /* we assume on resume that commits are already there, - so we don't sleep */ - interruptible_sleep_on(&journal->j_wait_commit); - - jbd_debug(1, "kjournald wakes\n"); - - /* Were we woken up by a commit wakeup event? */ - if ((transaction = journal->j_running_transaction) != NULL && - time_after_eq(jiffies, transaction->t_expires)) { - journal->j_commit_request = transaction->t_tid; - jbd_debug(1, "woke because of timeout\n"); + prepare_to_wait(&journal->j_wait_commit, &wait, + TASK_INTERRUPTIBLE); + if (journal->j_commit_sequence != journal->j_commit_request) + should_sleep = 0; + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, + transaction->t_expires)) + should_sleep = 0; + if (should_sleep) { + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); } + finish_wait(&journal->j_wait_commit, &wait); } - if (journal->j_commit_timer_active) { - journal->j_commit_timer_active = 0; - del_timer_sync(journal->j_commit_timer); - } + jbd_debug(1, "kjournald wakes\n"); - list_del(&journal->j_all_journals); + /* + * Were we woken up by a commit wakeup event? + */ + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, transaction->t_expires)) { + journal->j_commit_request = transaction->t_tid; + jbd_debug(1, "woke because of timeout\n"); + } +end_loop: + if (!(journal->j_flags & JFS_UNMOUNT)) + goto loop; + spin_unlock(&journal->j_state_lock); + del_timer_sync(journal->j_commit_timer); journal->j_task = NULL; wake_up(&journal->j_wait_done_commit); jbd_debug(1, "Journal thread exiting.\n"); - unlock_kernel(); return 0; } static void journal_start_thread(journal_t *journal) { - kernel_thread(kjournald, (void *) journal, - CLONE_VM | CLONE_FS | CLONE_FILES); - while (!journal->j_task) - sleep_on(&journal->j_wait_done_commit); + kernel_thread(kjournald, journal, CLONE_VM|CLONE_FS|CLONE_FILES); + wait_event(journal->j_wait_done_commit, journal->j_task != 0); } static void journal_kill_thread(journal_t *journal) { + spin_lock(&journal->j_state_lock); journal->j_flags |= JFS_UNMOUNT; while (journal->j_task) { wake_up(&journal->j_wait_commit); - sleep_on(&journal->j_wait_done_commit); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_done_commit, journal->j_task == 0); + spin_lock(&journal->j_state_lock); } + spin_unlock(&journal->j_state_lock); } -#if 0 - -This is no longer needed - we do it in commit quite efficiently. -Note that if this function is resurrected, the loop needs to -be reorganised into the next_jh/last_jh algorithm. - -/* - * journal_clean_data_list: cleanup after data IO. - * - * Once the IO system has finished writing the buffers on the transaction's - * data list, we can remove those buffers from the list. This function - * scans the list for such buffers and removes them cleanly. - * - * We assume that the journal is already locked. - * We are called with journal_datalist_lock held. - * - * AKPM: This function looks inefficient. Approximately O(n^2) - * for potentially thousands of buffers. It no longer shows on profiles - * because these buffers are mainly dropped in journal_commit_transaction(). - */ - -void __journal_clean_data_list(transaction_t *transaction) -{ - struct journal_head *jh, *next; - - assert_spin_locked(&journal_datalist_lock); - -restart: - jh = transaction->t_sync_datalist; - if (!jh) - goto out; - do { - next = jh->b_tnext; - if (!buffer_locked(jh2bh(jh)) && !buffer_dirty(jh2bh(jh))) { - struct buffer_head *bh = jh2bh(jh); - BUFFER_TRACE(bh, "data writeout complete: unfile"); - __journal_unfile_buffer(jh); - jh->b_transaction = NULL; - __journal_remove_journal_head(bh); - __brelse(bh); - goto restart; - } - jh = next; - } while (transaction->t_sync_datalist && - jh != transaction->t_sync_datalist); -out: - return; -} -#endif - /* * journal_write_metadata_buffer: write a metadata buffer to the journal. * @@ -393,9 +291,10 @@ int journal_write_metadata_buffer(transaction_t *transaction, int do_escape = 0; char *mapped_data; struct buffer_head *new_bh; - struct journal_head * new_jh; + struct journal_head *new_jh; struct page *new_page; unsigned int new_offset; + struct buffer_head *bh_in = jh2bh(jh_in); /* * The buffer really shouldn't be locked: only the current committing @@ -406,13 +305,16 @@ int journal_write_metadata_buffer(transaction_t *transaction, * also part of a shared mapping, and another thread has * decided to launch a writepage() against this buffer. */ - J_ASSERT_JH(jh_in, buffer_jdirty(jh2bh(jh_in))); + J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); + + new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); /* * If a new transaction has already done a buffer copy-out, then * we use that version of the data for the commit. */ - + jbd_lock_bh_state(bh_in); +repeat: if (jh_in->b_frozen_data) { done_copy_out = 1; new_page = virt_to_page(jh_in->b_frozen_data); @@ -422,12 +324,13 @@ int journal_write_metadata_buffer(transaction_t *transaction, new_offset = virt_to_offset(jh2bh(jh_in)->b_data); } - mapped_data = ((char *) kmap(new_page)) + new_offset; + mapped_data = kmap_atomic(new_page, KM_USER0); /* * Check for escaping */ - if (* ((unsigned int *) mapped_data) == htonl(JFS_MAGIC_NUMBER)) { + if (*((unsigned int *)(mapped_data + new_offset)) == + htonl(JFS_MAGIC_NUMBER)) { need_copy_out = 1; do_escape = 1; } @@ -435,38 +338,47 @@ int journal_write_metadata_buffer(transaction_t *transaction, /* * Do we need to do a data copy? */ - if (need_copy_out && !done_copy_out) { char *tmp; - tmp = jbd_rep_kmalloc(jh2bh(jh_in)->b_size, GFP_NOFS); + + kunmap_atomic(mapped_data, KM_USER0); + jbd_unlock_bh_state(bh_in); + tmp = jbd_rep_kmalloc(bh_in->b_size, GFP_NOFS); + jbd_lock_bh_state(bh_in); + if (jh_in->b_frozen_data) { + kfree(new_page); + goto repeat; + } jh_in->b_frozen_data = tmp; - memcpy (tmp, mapped_data, jh2bh(jh_in)->b_size); - + mapped_data = kmap_atomic(new_page, KM_USER0); + memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); + /* If we get to this path, we'll always need the new address kmapped so that we can clear the escaped magic number below. */ - kunmap(new_page); new_page = virt_to_page(tmp); new_offset = virt_to_offset(tmp); - mapped_data = ((char *) kmap(new_page)) + new_offset; - done_copy_out = 1; } /* - * Right, time to make up the new buffer_head. + * Did we need to do an escaping? Now we've done all the + * copying, we can finally do so. */ - new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); + if (do_escape) + *((unsigned int *)(mapped_data + new_offset)) = 0; + kunmap_atomic(mapped_data, KM_USER0); /* keep subsequent assertions sane */ new_bh->b_state = 0; init_buffer(new_bh, NULL, NULL); atomic_set(&new_bh->b_count, 1); - new_jh = journal_add_journal_head(new_bh); + jbd_unlock_bh_state(bh_in); - set_bh_page(new_bh, new_page, new_offset); + new_jh = journal_add_journal_head(new_bh); /* This sleeps */ + set_bh_page(new_bh, new_page, new_offset); new_jh->b_transaction = NULL; new_bh->b_size = jh2bh(jh_in)->b_size; new_bh->b_bdev = transaction->t_journal->j_dev; @@ -477,15 +389,6 @@ int journal_write_metadata_buffer(transaction_t *transaction, *jh_out = new_jh; /* - * Did we need to do an escaping? Now we've done all the - * copying, we can finally do so. - */ - - if (do_escape) - * ((unsigned int *) mapped_data) = 0; - kunmap(new_page); - - /* * The to-be-written buffer needs to get moved to the io queue, * and the original buffer whose contents we are shadowing or * copying is moved to the transaction's shadow queue. @@ -504,17 +407,23 @@ int journal_write_metadata_buffer(transaction_t *transaction, */ /* - * log_space_left: Return the number of free blocks left in the journal. + * __log_space_left: Return the number of free blocks left in the journal. * * Called with the journal already locked. + * + * Called under j_state_lock */ -int log_space_left (journal_t *journal) +int __log_space_left(journal_t *journal) { int left = journal->j_free; - /* Be pessimistic here about the number of those free blocks - * which might be required for log descriptor control blocks. */ + assert_spin_locked(&journal->j_state_lock); + + /* + * Be pessimistic here about the number of those free blocks which + * might be required for log descriptor control blocks. + */ #define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ @@ -527,80 +436,92 @@ int log_space_left (journal_t *journal) } /* - * This function must be non-allocating for PF_MEMALLOC tasks + * Called under j_state_lock. Returns true if a transaction was started. */ -tid_t log_start_commit (journal_t *journal, transaction_t *transaction) +int __log_start_commit(journal_t *journal, tid_t target) { - tid_t target = journal->j_commit_request; - - lock_kernel(); /* Protect journal->j_running_transaction */ - - /* - * A NULL transaction asks us to commit the currently running - * transaction, if there is one. - */ - if (transaction) - target = transaction->t_tid; - else { - transaction = journal->j_running_transaction; - if (!transaction) - goto out; - target = transaction->t_tid; - } - /* * Are we already doing a recent enough commit? */ - if (tid_geq(journal->j_commit_request, target)) - goto out; + if (!tid_geq(journal->j_commit_request, target)) { + /* + * We want a new commit: OK, mark the request and wakup the + * commit thread. We do _not_ do the commit ourselves. + */ - /* - * We want a new commit: OK, mark the request and wakup the - * commit thread. We do _not_ do the commit ourselves. - */ + journal->j_commit_request = target; + jbd_debug(1, "JBD: requesting commit %d/%d\n", + journal->j_commit_request, + journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + return 1; + } + return 0; +} - journal->j_commit_request = target; - jbd_debug(1, "JBD: requesting commit %d/%d\n", - journal->j_commit_request, - journal->j_commit_sequence); - wake_up(&journal->j_wait_commit); +int log_start_commit(journal_t *journal, tid_t tid) +{ + int ret; -out: - unlock_kernel(); - return target; + spin_lock(&journal->j_state_lock); + ret = __log_start_commit(journal, tid); + spin_unlock(&journal->j_state_lock); + return ret; +} + +/* + * Start a commit of the current running transaction (if any). Returns true + * if a transaction was started, and fills its tid in at *ptid + */ +int journal_start_commit(journal_t *journal, tid_t *ptid) +{ + int ret = 0; + + spin_lock(&journal->j_state_lock); + if (journal->j_running_transaction) { + tid_t tid = journal->j_running_transaction->t_tid; + + ret = __log_start_commit(journal, tid); + if (ret && ptid) + *ptid = tid; + } + spin_unlock(&journal->j_state_lock); + return ret; } /* * Wait for a specified commit to complete. * The caller may not hold the journal lock. */ -int log_wait_commit (journal_t *journal, tid_t tid) +int log_wait_commit(journal_t *journal, tid_t tid) { int err = 0; - lock_kernel(); #ifdef CONFIG_JBD_DEBUG - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (!tid_geq(journal->j_commit_request, tid)) { printk(KERN_EMERG "%s: error: j_commit_request=%d, tid=%d\n", __FUNCTION__, journal->j_commit_request, tid); } - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); #endif + spin_lock(&journal->j_state_lock); while (tid_gt(tid, journal->j_commit_sequence)) { jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n", tid, journal->j_commit_sequence); wake_up(&journal->j_wait_commit); - sleep_on(&journal->j_wait_done_commit); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_done_commit, + !tid_gt(tid, journal->j_commit_sequence)); + spin_lock(&journal->j_state_lock); } + spin_unlock(&journal->j_state_lock); if (unlikely(is_journal_aborted(journal))) { printk(KERN_EMERG "journal commit I/O error\n"); err = -EIO; } - - unlock_kernel(); return err; } @@ -612,6 +533,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) { unsigned long blocknr; + spin_lock(&journal->j_state_lock); J_ASSERT(journal->j_free > 1); blocknr = journal->j_head; @@ -619,6 +541,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp) journal->j_free--; if (journal->j_head == journal->j_last) journal->j_head = journal->j_first; + spin_unlock(&journal->j_state_lock); return journal_bmap(journal, blocknr, retp); } @@ -706,7 +629,9 @@ static journal_t * journal_init_common (void) init_waitqueue_head(&journal->j_wait_updates); init_MUTEX(&journal->j_barrier); init_MUTEX(&journal->j_checkpoint_sem); - init_MUTEX(&journal->j_sem); + spin_lock_init(&journal->j_revoke_lock); + spin_lock_init(&journal->j_list_lock); + spin_lock_init(&journal->j_state_lock); journal->j_commit_interval = (HZ * 5); @@ -807,7 +732,7 @@ journal_t * journal_init_inode (struct inode *inode) kfree(journal); return NULL; } - + bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; @@ -835,7 +760,7 @@ static void journal_fail_superblock (journal_t *journal) * subsequent use. */ -static int journal_reset (journal_t *journal) +static int journal_reset(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; unsigned int first, last; @@ -858,11 +783,7 @@ static int journal_reset (journal_t *journal) /* Add the dynamic fields and write it to disk. */ journal_update_superblock(journal, 1); - - lock_journal(journal); journal_start_thread(journal); - unlock_journal(journal); - return 0; } @@ -950,12 +871,30 @@ void journal_update_superblock(journal_t *journal, int wait) journal_superblock_t *sb = journal->j_superblock; struct buffer_head *bh = journal->j_sb_buffer; + /* + * As a special case, if the on-disk copy is already marked as needing + * no recovery (s_start == 0) and there are no outstanding transactions + * in the filesystem, then we can safely defer the superblock update + * until the next commit by setting JFS_FLUSHED. This avoids + * attempting a write to a potential-readonly device. + */ + if (sb->s_start == 0 && journal->j_tail_sequence == + journal->j_transaction_sequence) { + jbd_debug(1,"JBD: Skipping superblock update on recovered sb " + "(start %ld, seq %d, errno %d)\n", + journal->j_tail, journal->j_tail_sequence, + journal->j_errno); + goto out; + } + + spin_lock(&journal->j_state_lock); jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", journal->j_tail, journal->j_tail_sequence, journal->j_errno); sb->s_sequence = htonl(journal->j_tail_sequence); sb->s_start = htonl(journal->j_tail); sb->s_errno = htonl(journal->j_errno); + spin_unlock(&journal->j_state_lock); BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); @@ -964,17 +903,19 @@ void journal_update_superblock(journal_t *journal, int wait) else ll_rw_block(WRITE, 1, &bh); +out: /* If we have just flushed the log (by marking s_start==0), then * any future commit will have to be careful to update the * superblock again to re-record the true start of the log. */ + spin_lock(&journal->j_state_lock); if (sb->s_start) journal->j_flags &= ~JFS_FLUSHED; else journal->j_flags |= JFS_FLUSHED; + spin_unlock(&journal->j_state_lock); } - /* * Read the superblock for a given journal, performing initial * validation of the format. @@ -985,7 +926,7 @@ static int journal_get_superblock(journal_t *journal) struct buffer_head *bh; journal_superblock_t *sb; int err = -EIO; - + bh = journal->j_sb_buffer; J_ASSERT(bh != NULL); @@ -1002,7 +943,7 @@ static int journal_get_superblock(journal_t *journal) sb = journal->j_superblock; err = -EINVAL; - + if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || sb->s_blocksize != htonl(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); @@ -1116,11 +1057,11 @@ recovery_error: /** * void journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. -* + * * Release a journal_t structure once it is no longer in use by the * journaled object. */ -void journal_destroy (journal_t *journal) +void journal_destroy(journal_t *journal) { /* Wait for the commit thread to wake up and die. */ journal_kill_thread(journal); @@ -1130,13 +1071,19 @@ void journal_destroy (journal_t *journal) journal_commit_transaction(journal); /* Force any old transactions to disk */ - lock_journal(journal); - while (journal->j_checkpoint_transactions != NULL) + + /* Totally anal locking here... */ + spin_lock(&journal->j_list_lock); + while (journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); log_do_checkpoint(journal, 1); + spin_lock(&journal->j_list_lock); + } J_ASSERT(journal->j_running_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL); J_ASSERT(journal->j_checkpoint_transactions == NULL); + spin_unlock(&journal->j_list_lock); /* We can now mark the journal as empty. */ journal->j_tail = 0; @@ -1150,8 +1097,6 @@ void journal_destroy (journal_t *journal) iput(journal->j_inode); if (journal->j_revoke) journal_destroy_revoke(journal); - - unlock_journal(journal); kfree(journal); } @@ -1310,29 +1255,39 @@ static int journal_convert_superblock_v1(journal_t *journal, * recovery does not need to happen on remount. */ -int journal_flush (journal_t *journal) +int journal_flush(journal_t *journal) { int err = 0; transaction_t *transaction = NULL; unsigned long old_tail; - lock_kernel(); - + spin_lock(&journal->j_state_lock); + /* Force everything buffered to the log... */ if (journal->j_running_transaction) { transaction = journal->j_running_transaction; - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; /* Wait for the log commit to complete... */ - if (transaction) - log_wait_commit(journal, transaction->t_tid); + if (transaction) { + tid_t tid = transaction->t_tid; + + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + } else { + spin_unlock(&journal->j_state_lock); + } /* ...and flush everything in the log out to disk. */ - lock_journal(journal); - while (!err && journal->j_checkpoint_transactions != NULL) + spin_lock(&journal->j_list_lock); + while (!err && journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); err = log_do_checkpoint(journal, journal->j_maxlen); + spin_lock(&journal->j_list_lock); + } + spin_unlock(&journal->j_list_lock); cleanup_journal_tail(journal); /* Finally, mark the journal as really needing no recovery. @@ -1340,21 +1295,20 @@ int journal_flush (journal_t *journal) * the magic code for a fully-recovered superblock. Any future * commits of data to the journal will restore the current * s_start value. */ + spin_lock(&journal->j_state_lock); old_tail = journal->j_tail; journal->j_tail = 0; + spin_unlock(&journal->j_state_lock); journal_update_superblock(journal, 1); + spin_lock(&journal->j_state_lock); journal->j_tail = old_tail; - unlock_journal(journal); - J_ASSERT(!journal->j_running_transaction); J_ASSERT(!journal->j_committing_transaction); J_ASSERT(!journal->j_checkpoint_transactions); J_ASSERT(journal->j_head == journal->j_tail); J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); - - unlock_kernel(); - + spin_unlock(&journal->j_state_lock); return err; } @@ -1371,7 +1325,7 @@ int journal_flush (journal_t *journal) * we merely suppress recovery. */ -int journal_wipe (journal_t *journal, int write) +int journal_wipe(journal_t *journal, int write) { journal_superblock_t *sb; int err = 0; @@ -1423,10 +1377,12 @@ const char *journal_dev_name(journal_t *journal, char *buffer) * itself are here. */ -/* Quick version for internal journal use (doesn't lock the journal). +/* + * Quick version for internal journal use (doesn't lock the journal). * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, - * and don't attempt to make any other journal updates. */ -void __journal_abort_hard (journal_t *journal) + * and don't attempt to make any other journal updates. + */ +void __journal_abort_hard(journal_t *journal) { transaction_t *transaction; char b[BDEVNAME_SIZE]; @@ -1434,13 +1390,15 @@ void __journal_abort_hard (journal_t *journal) if (journal->j_flags & JFS_ABORT) return; - printk (KERN_ERR "Aborting journal on device %s.\n", + printk(KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal, b)); + spin_lock(&journal->j_state_lock); journal->j_flags |= JFS_ABORT; transaction = journal->j_running_transaction; if (transaction) - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); } /* Soft abort: record the abort error status in the journal superblock, @@ -1505,11 +1463,9 @@ void __journal_abort_soft (journal_t *journal, int errno) * */ -void journal_abort (journal_t *journal, int errno) +void journal_abort(journal_t *journal, int errno) { - lock_journal(journal); __journal_abort_soft(journal, errno); - unlock_journal(journal); } /** @@ -1523,53 +1479,50 @@ void journal_abort (journal_t *journal, int errno) * If the journal has been aborted on this mount time -EROFS will * be returned. */ -int journal_errno (journal_t *journal) +int journal_errno(journal_t *journal) { int err; - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_flags & JFS_ABORT) err = -EROFS; else err = journal->j_errno; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); return err; } - - /** * int journal_clear_err () - clears the journal's error state * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -int journal_clear_err (journal_t *journal) +int journal_clear_err(journal_t *journal) { int err = 0; - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_flags & JFS_ABORT) err = -EROFS; else journal->j_errno = 0; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); return err; } - /** * void journal_ack_err() - Ack journal err. * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -void journal_ack_err (journal_t *journal) +void journal_ack_err(journal_t *journal) { - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_errno) journal->j_flags |= JFS_ACK_ERR; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); } int journal_blocks_per_page(struct inode *inode) @@ -1578,26 +1531,6 @@ int journal_blocks_per_page(struct inode *inode) } /* - * shrink_journal_memory(). - * Called when we're under memory pressure. Free up all the written-back - * checkpointed metadata buffers. - */ -void shrink_journal_memory(void) -{ - struct list_head *list; - - lock_kernel(); - list_for_each(list, &all_journals) { - journal_t *journal = - list_entry(list, journal_t, j_all_journals); - spin_lock(&journal_datalist_lock); - __journal_clean_checkpoint_list(journal); - spin_unlock(&journal_datalist_lock); - } - unlock_kernel(); -} - -/* * Simple support for retying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ @@ -1607,7 +1540,7 @@ void shrink_journal_memory(void) */ void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry) { - return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); + return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0)); } /* @@ -1703,7 +1636,7 @@ static void journal_free_journal_head(struct journal_head *jh) * _before_ attaching the journal_head to a transaction. To protect the * journal_head in this situation, journal_add_journal_head elevates the * journal_head's b_jcount refcount by one. The caller must call - * journal_unlock_journal_head() to undo this. + * journal_put_journal_head() to undo this. * * So the typical usage would be: * @@ -1711,7 +1644,7 @@ static void journal_free_journal_head(struct journal_head *jh) * struct journal_head *jh = journal_add_journal_head(bh); * ... * jh->b_transaction = xxx; - * journal_unlock_journal_head(jh); + * journal_put_journal_head(jh); * * Now, the journal_head's b_jcount is zero, but it is safe from being released * because it has a non-zero b_transaction. @@ -1722,70 +1655,70 @@ static void journal_free_journal_head(struct journal_head *jh) * * Doesn't need the journal lock. * May sleep. - * Cannot be called with journal_datalist_lock held. */ struct journal_head *journal_add_journal_head(struct buffer_head *bh) { struct journal_head *jh; + struct journal_head *new_jh = NULL; - spin_lock(&journal_datalist_lock); +repeat: + if (!buffer_jbd(bh)) { + new_jh = journal_alloc_journal_head(); + memset(new_jh, 0, sizeof(*new_jh)); + } + + jbd_lock_bh_journal_head(bh); if (buffer_jbd(bh)) { jh = bh2jh(bh); } else { J_ASSERT_BH(bh, (atomic_read(&bh->b_count) > 0) || (bh->b_page && bh->b_page->mapping)); - spin_unlock(&journal_datalist_lock); - jh = journal_alloc_journal_head(); - memset(jh, 0, sizeof(*jh)); - spin_lock(&journal_datalist_lock); - - if (buffer_jbd(bh)) { - /* Someone did it for us! */ - J_ASSERT_BH(bh, bh->b_private != NULL); - journal_free_journal_head(jh); - jh = bh->b_private; - } else { - /* - * We actually don't need jh_splice_lock when - * adding a journal_head - only on removal. - */ - spin_lock(&jh_splice_lock); - set_bit(BH_JBD, &bh->b_state); - bh->b_private = jh; - jh->b_bh = bh; - atomic_inc(&bh->b_count); - spin_unlock(&jh_splice_lock); - BUFFER_TRACE(bh, "added journal_head"); + + if (!new_jh) { + jbd_unlock_bh_journal_head(bh); + goto repeat; } + + jh = new_jh; + new_jh = NULL; /* We consumed it */ + set_buffer_jbd(bh); + bh->b_private = jh; + jh->b_bh = bh; + get_bh(bh); + BUFFER_TRACE(bh, "added journal_head"); } jh->b_jcount++; - spin_unlock(&journal_datalist_lock); + jbd_unlock_bh_journal_head(bh); + if (new_jh) + journal_free_journal_head(new_jh); return bh->b_private; } /* - * journal_remove_journal_head(): if the buffer isn't attached to a transaction - * and has a zero b_jcount then remove and release its journal_head. If we did - * see that the buffer is not used by any transaction we also "logically" - * decrement ->b_count. - * - * We in fact take an additional increment on ->b_count as a convenience, - * because the caller usually wants to do additional things with the bh - * after calling here. - * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some - * time. Once the caller has run __brelse(), the buffer is eligible for - * reaping by try_to_free_buffers(). - * - * Requires journal_datalist_lock. + * Grab a ref against this buffer_head's journal_head. If it ended up not + * having a journal_head, return NULL */ -void __journal_remove_journal_head(struct buffer_head *bh) +struct journal_head *journal_grab_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh = NULL; + + jbd_lock_bh_journal_head(bh); + if (buffer_jbd(bh)) { + jh = bh2jh(bh); + jh->b_jcount++; + } + jbd_unlock_bh_journal_head(bh); + return jh; +} + +static void __journal_remove_journal_head(struct buffer_head *bh) { struct journal_head *jh = bh2jh(bh); - assert_spin_locked(&journal_datalist_lock); J_ASSERT_JH(jh, jh->b_jcount >= 0); - atomic_inc(&bh->b_count); + + get_bh(bh); if (jh->b_jcount == 0) { if (jh->b_transaction == NULL && jh->b_next_transaction == NULL && @@ -1793,12 +1726,10 @@ void __journal_remove_journal_head(struct buffer_head *bh) J_ASSERT_BH(bh, buffer_jbd(bh)); J_ASSERT_BH(bh, jh2bh(jh) == bh); BUFFER_TRACE(bh, "remove journal_head"); - spin_lock(&jh_splice_lock); bh->b_private = NULL; jh->b_bh = NULL; /* debug, really */ - clear_bit(BH_JBD, &bh->b_state); + clear_buffer_jbd(bh); __brelse(bh); - spin_unlock(&jh_splice_lock); journal_free_journal_head(jh); } else { BUFFER_TRACE(bh, "journal_head was locked"); @@ -1806,26 +1737,42 @@ void __journal_remove_journal_head(struct buffer_head *bh) } } -void journal_unlock_journal_head(struct journal_head *jh) +/* + * journal_remove_journal_head(): if the buffer isn't attached to a transaction + * and has a zero b_jcount then remove and release its journal_head. If we did + * see that the buffer is not used by any transaction we also "logically" + * decrement ->b_count. + * + * We in fact take an additional increment on ->b_count as a convenience, + * because the caller usually wants to do additional things with the bh + * after calling here. + * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some + * time. Once the caller has run __brelse(), the buffer is eligible for + * reaping by try_to_free_buffers(). + */ +void journal_remove_journal_head(struct buffer_head *bh) { - spin_lock(&journal_datalist_lock); + jbd_lock_bh_journal_head(bh); + __journal_remove_journal_head(bh); + jbd_unlock_bh_journal_head(bh); +} + +/* + * Drop a reference on the passed journal_head. If it fell to zero then try to + * release the journal_head from the buffer_head. + */ +void journal_put_journal_head(struct journal_head *jh) +{ + struct buffer_head *bh = jh2bh(jh); + + jbd_lock_bh_journal_head(bh); J_ASSERT_JH(jh, jh->b_jcount > 0); --jh->b_jcount; if (!jh->b_jcount && !jh->b_transaction) { - struct buffer_head *bh; - bh = jh2bh(jh); __journal_remove_journal_head(bh); __brelse(bh); } - - spin_unlock(&journal_datalist_lock); -} - -void journal_remove_journal_head(struct buffer_head *bh) -{ - spin_lock(&journal_datalist_lock); - __journal_remove_journal_head(bh); - spin_unlock(&journal_datalist_lock); + jbd_unlock_bh_journal_head(bh); } /* diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index d9afa22f5de..d6e080c8c5e 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -29,9 +29,9 @@ */ struct recovery_info { - tid_t start_transaction; + tid_t start_transaction; tid_t end_transaction; - + int nr_replays; int nr_revokes; int nr_revoke_hits; @@ -72,9 +72,9 @@ static int do_readahead(journal_t *journal, unsigned int start) unsigned int max, nbufs, next; unsigned long blocknr; struct buffer_head *bh; - + struct buffer_head * bufs[MAXBUF]; - + /* Do up to 128K of readahead */ max = start + (128 * 1024 / journal->j_blocksize); if (max > journal->j_maxlen) @@ -82,9 +82,9 @@ static int do_readahead(journal_t *journal, unsigned int start) /* Do the readahead itself. We'll submit MAXBUF buffer_heads at * a time to the block device IO layer. */ - + nbufs = 0; - + for (next = start; next < max; next++) { err = journal_bmap(journal, next, &blocknr); @@ -115,7 +115,7 @@ static int do_readahead(journal_t *journal, unsigned int start) ll_rw_block(READ, nbufs, bufs); err = 0; -failed: +failed: if (nbufs) journal_brelse_array(bufs, nbufs); return err; @@ -138,7 +138,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, *bhp = NULL; J_ASSERT (offset < journal->j_maxlen); - + err = journal_bmap(journal, offset, &blocknr); if (err) { @@ -224,10 +224,10 @@ int journal_recover(journal_t *journal) journal_superblock_t * sb; struct recovery_info info; - + memset(&info, 0, sizeof(info)); sb = journal->j_superblock; - + /* * The journal superblock's s_start field (the current log head) * is always zero if, and only if, the journal was cleanly @@ -240,7 +240,6 @@ int journal_recover(journal_t *journal) journal->j_transaction_sequence = ntohl(sb->s_sequence) + 1; return 0; } - err = do_one_pass(journal, &info, PASS_SCAN); if (!err) @@ -257,7 +256,7 @@ int journal_recover(journal_t *journal) /* Restart the log at the next transaction ID, thus invalidating * any existing commit records in the log. */ journal->j_transaction_sequence = ++info.end_transaction; - + journal_clear_revoke(journal); sync_blockdev(journal->j_fs_dev); return err; @@ -282,10 +281,10 @@ int journal_skip_recovery(journal_t *journal) journal_superblock_t * sb; struct recovery_info info; - + memset (&info, 0, sizeof(info)); sb = journal->j_superblock; - + err = do_one_pass(journal, &info, PASS_SCAN); if (err) { @@ -295,7 +294,6 @@ int journal_skip_recovery(journal_t *journal) #ifdef CONFIG_JBD_DEBUG int dropped = info.end_transaction - ntohl(sb->s_sequence); #endif - jbd_debug(0, "JBD: ignoring %d transaction%s from the journal.\n", dropped, (dropped == 1) ? "" : "s"); @@ -303,14 +301,12 @@ int journal_skip_recovery(journal_t *journal) } journal->j_tail = 0; - return err; } static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass) { - unsigned int first_commit_ID, next_commit_ID; unsigned long next_log_block; int err, success = 0; @@ -319,7 +315,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * bh; unsigned int sequence; int blocktype; - + /* Precompute the maximum metadata descriptors in a descriptor block */ int MAX_BLOCKS_PER_DESC; MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t)) @@ -354,11 +350,11 @@ static int do_one_pass(journal_t *journal, journal_block_tag_t * tag; struct buffer_head * obh; struct buffer_head * nbh; - + /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of * the log. */ - + if (pass != PASS_SCAN) if (tid_geq(next_commit_ID, info->end_transaction)) break; @@ -369,7 +365,7 @@ static int do_one_pass(journal_t *journal, /* Skip over each chunk of the transaction looking * either the next descriptor block or the final commit * record. */ - + jbd_debug(3, "JBD: checking block %ld\n", next_log_block); err = jread(&bh, journal, next_log_block); if (err) @@ -377,7 +373,7 @@ static int do_one_pass(journal_t *journal, next_log_block++; wrap(journal, next_log_block); - + /* What kind of buffer is it? * * If it is a descriptor block, check that it has the @@ -385,7 +381,7 @@ static int do_one_pass(journal_t *journal, * here. */ tmp = (journal_header_t *)bh->b_data; - + if (tmp->h_magic != htonl(JFS_MAGIC_NUMBER)) { brelse(bh); break; @@ -395,12 +391,12 @@ static int do_one_pass(journal_t *journal, sequence = ntohl(tmp->h_sequence); jbd_debug(3, "Found magic %d, sequence %d\n", blocktype, sequence); - + if (sequence != next_commit_ID) { brelse(bh); break; } - + /* OK, we have a valid descriptor block which matches * all of the sequence number checks. What are we going * to do with it? That depends on the pass... */ @@ -429,7 +425,7 @@ static int do_one_pass(journal_t *journal, tag = (journal_block_tag_t *) tagp; flags = ntohl(tag->t_flags); - + io_block = next_log_block++; wrap(journal, next_log_block); err = jread(&obh, journal, io_block); @@ -443,7 +439,7 @@ static int do_one_pass(journal_t *journal, err, io_block); } else { unsigned long blocknr; - + J_ASSERT(obh != NULL); blocknr = ntohl(tag->t_blocknr); @@ -457,7 +453,7 @@ static int do_one_pass(journal_t *journal, ++info->nr_revoke_hits; goto skip_write; } - + /* Find a buffer for the new * data being restored */ nbh = __getblk(journal->j_fs_dev, @@ -491,7 +487,7 @@ static int do_one_pass(journal_t *journal, brelse(obh); brelse(nbh); } - + skip_write: tagp += sizeof(journal_block_tag_t); if (!(flags & JFS_FLAG_SAME_UUID)) @@ -500,7 +496,7 @@ static int do_one_pass(journal_t *journal, if (flags & JFS_FLAG_LAST_TAG) break; } - + brelse(bh); continue; @@ -541,7 +537,7 @@ static int do_one_pass(journal_t *journal, * log. If the latter happened, then we know that the "current" * transaction marks the end of the valid log. */ - + if (pass == PASS_SCAN) info->end_transaction = next_commit_ID; else { @@ -574,11 +570,11 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, header = (journal_revoke_header_t *) bh->b_data; offset = sizeof(journal_revoke_header_t); max = ntohl(header->r_count); - + while (offset < max) { unsigned long blocknr; int err; - + blocknr = ntohl(* ((unsigned int *) (bh->b_data+offset))); offset += 4; err = journal_set_revoke(journal, blocknr, sequence); diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 8aa1f896983..0ab15014f95 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -81,7 +81,7 @@ struct jbd_revoke_record_s { struct list_head hash; tid_t sequence; /* Used for recovery only */ - unsigned long blocknr; + unsigned long blocknr; }; @@ -110,7 +110,7 @@ static inline int hash(journal_t *journal, unsigned long block) { struct jbd_revoke_table_s *table = journal->j_revoke; int hash_shift = table->hash_shift; - + return ((block << (hash_shift - 6)) ^ (block >> 13) ^ (block << (hash_shift - 12))) & (table->hash_size - 1); @@ -129,7 +129,9 @@ repeat: record->sequence = seq; record->blocknr = blocknr; hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + spin_lock(&journal->j_revoke_lock); list_add(&record->hash, hash_list); + spin_unlock(&journal->j_revoke_lock); return 0; oom: @@ -147,15 +149,19 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, { struct list_head *hash_list; struct jbd_revoke_record_s *record; - + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + spin_lock(&journal->j_revoke_lock); record = (struct jbd_revoke_record_s *) hash_list->next; while (&(record->hash) != hash_list) { - if (record->blocknr == blocknr) + if (record->blocknr == blocknr) { + spin_unlock(&journal->j_revoke_lock); return record; + } record = (struct jbd_revoke_record_s *) record->hash.next; } + spin_unlock(&journal->j_revoke_lock); return NULL; } @@ -176,7 +182,7 @@ int __init journal_init_revoke_caches(void) return -ENOMEM; } return 0; -} +} void journal_destroy_revoke_caches(void) { @@ -191,35 +197,68 @@ void journal_destroy_revoke_caches(void) int journal_init_revoke(journal_t *journal, int hash_size) { int shift, tmp; - - J_ASSERT (journal->j_revoke == NULL); - - journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); - if (!journal->j_revoke) - return -ENOMEM; - - /* Check that the hash_size is a power of two */ - J_ASSERT ((hash_size & (hash_size-1)) == 0); - journal->j_revoke->hash_size = hash_size; + J_ASSERT (journal->j_revoke_table[0] == NULL); shift = 0; tmp = hash_size; while((tmp >>= 1UL) != 0UL) shift++; + + journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[0]) + return -ENOMEM; + journal->j_revoke = journal->j_revoke_table[0]; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + journal->j_revoke->hash_shift = shift; journal->j_revoke->hash_table = kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); if (!journal->j_revoke->hash_table) { - kmem_cache_free(revoke_table_cache, journal->j_revoke); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); journal->j_revoke = NULL; return -ENOMEM; } - + for (tmp = 0; tmp < hash_size; tmp++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); - + + journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[1]) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + return -ENOMEM; + } + + journal->j_revoke = journal->j_revoke_table[1]; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + + journal->j_revoke->hash_shift = shift; + + journal->j_revoke->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); + if (!journal->j_revoke->hash_table) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); + journal->j_revoke = NULL; + return -ENOMEM; + } + + for (tmp = 0; tmp < hash_size; tmp++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + + spin_lock_init(&journal->j_revoke_lock); + return 0; } @@ -230,16 +269,29 @@ void journal_destroy_revoke(journal_t *journal) struct jbd_revoke_table_s *table; struct list_head *hash_list; int i; - - table = journal->j_revoke; + + table = journal->j_revoke_table[0]; + if (!table) + return; + + for (i=0; ihash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT (list_empty(hash_list)); + } + + kfree(table->hash_table); + kmem_cache_free(revoke_table_cache, table); + journal->j_revoke = NULL; + + table = journal->j_revoke_table[1]; if (!table) return; - + for (i=0; ihash_size; i++) { hash_list = &table->hash_table[i]; J_ASSERT (list_empty(hash_list)); } - + kfree(table->hash_table); kmem_cache_free(revoke_table_cache, table); journal->j_revoke = NULL; @@ -337,11 +389,9 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, } } - lock_journal(journal); jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); err = insert_revoke_hash(journal, blocknr, handle->h_transaction->t_tid); - unlock_journal(journal); BUFFER_TRACE(bh_in, "exit"); return err; } @@ -370,7 +420,7 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) int need_cancel; int did_revoke = 0; /* akpm: debug */ struct buffer_head *bh = jh2bh(jh); - + jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); /* Is the existing Revoke bit valid? If so, we trust it, and @@ -389,7 +439,9 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) if (record) { jbd_debug(4, "cancelled existing revoke on " "blocknr %llu\n", (u64)bh->b_blocknr); + spin_lock(&journal->j_revoke_lock); list_del(&record->hash); + spin_unlock(&journal->j_revoke_lock); kmem_cache_free(revoke_record_cache, record); did_revoke = 1; } @@ -414,10 +466,25 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) __brelse(bh2); } } - return did_revoke; } +/* journal_switch_revoke table select j_revoke for next transaction + * we do not want to suspend any processing until all revokes are + * written -bzzz + */ +void journal_switch_revoke_table(journal_t *journal) +{ + int i; + + if (journal->j_revoke == journal->j_revoke_table[0]) + journal->j_revoke = journal->j_revoke_table[1]; + else + journal->j_revoke = journal->j_revoke_table[0]; + + for (i = 0; i < journal->j_revoke->hash_size; i++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); +} /* * Write revoke records to the journal for all entries in the current @@ -438,8 +505,11 @@ void journal_write_revoke_records(journal_t *journal, descriptor = NULL; offset = 0; count = 0; - revoke = journal->j_revoke; - + + /* select revoke table for committing transaction */ + revoke = journal->j_revoke == journal->j_revoke_table[0] ? + journal->j_revoke_table[1] : journal->j_revoke_table[0]; + for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; @@ -491,7 +561,7 @@ static void write_one_revoke_record(journal_t *journal, descriptor = NULL; } } - + if (!descriptor) { descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) @@ -508,7 +578,7 @@ static void write_one_revoke_record(journal_t *journal, offset = sizeof(journal_revoke_header_t); *descriptorp = descriptor; } - + * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) = htonl(record->blocknr); offset += 4; @@ -533,7 +603,7 @@ static void flush_descriptor(journal_t *journal, __brelse(jh2bh(descriptor)); return; } - + header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; header->r_count = htonl(offset); set_bit(BH_JWrite, &jh2bh(descriptor)->b_state); @@ -574,7 +644,7 @@ int journal_set_revoke(journal_t *journal, tid_t sequence) { struct jbd_revoke_record_s *record; - + record = find_revoke_record(journal, blocknr); if (record) { /* If we have multiple occurrences, only record the @@ -598,7 +668,7 @@ int journal_test_revoke(journal_t *journal, tid_t sequence) { struct jbd_revoke_record_s *record; - + record = find_revoke_record(journal, blocknr); if (!record) return 0; @@ -618,9 +688,9 @@ void journal_clear_revoke(journal_t *journal) struct list_head *hash_list; struct jbd_revoke_record_s *record; struct jbd_revoke_table_s *revoke; - + revoke = journal->j_revoke; - + for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; while (!list_empty(hash_list)) { @@ -630,4 +700,3 @@ void journal_clear_revoke(journal_t *journal) } } } - diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index f309a7249fc..54e16b97fda 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -27,8 +27,6 @@ #include #include -extern spinlock_t journal_datalist_lock; - /* * get_transaction: obtain a new transaction_t object. * @@ -41,31 +39,26 @@ extern spinlock_t journal_datalist_lock; * The journal MUST be locked. We don't perform atomic mallocs on the * new transaction and we can't block without protecting against other * processes trying to touch the journal while it is in transition. + * + * Called under j_state_lock */ -static transaction_t * get_transaction (journal_t * journal, int is_try) +static transaction_t * +get_transaction(journal_t *journal, transaction_t *transaction) { - transaction_t * transaction; - - transaction = jbd_kmalloc (sizeof (transaction_t), GFP_NOFS); - if (!transaction) - return NULL; - - memset (transaction, 0, sizeof (transaction_t)); - transaction->t_journal = journal; transaction->t_state = T_RUNNING; transaction->t_tid = journal->j_transaction_sequence++; transaction->t_expires = jiffies + journal->j_commit_interval; INIT_LIST_HEAD(&transaction->t_jcb); + spin_lock_init(&transaction->t_handle_lock); + spin_lock_init(&transaction->t_jcb_lock); /* Set up the commit timer for the new transaction. */ - J_ASSERT (!journal->j_commit_timer_active); - journal->j_commit_timer_active = 1; journal->j_commit_timer->expires = transaction->t_expires; add_timer(journal->j_commit_timer); - - J_ASSERT (journal->j_running_transaction == NULL); + + J_ASSERT(journal->j_running_transaction == NULL); journal->j_running_transaction = transaction; return transaction; @@ -91,69 +84,101 @@ static int start_this_handle(journal_t *journal, handle_t *handle) transaction_t *transaction; int needed; int nblocks = handle->h_buffer_credits; + transaction_t *new_transaction = NULL; + int ret; if (nblocks > journal->j_max_transaction_buffers) { printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", current->comm, nblocks, journal->j_max_transaction_buffers); - return -ENOSPC; + ret = -ENOSPC; + goto out; + } + +alloc_transaction: + if (!journal->j_running_transaction) { + new_transaction = jbd_kmalloc(sizeof(*new_transaction), + GFP_NOFS); + if (!new_transaction) { + ret = -ENOMEM; + goto out; + } + memset(new_transaction, 0, sizeof(*new_transaction)); } jbd_debug(3, "New handle %p going live.\n", handle); repeat: - lock_journal(journal); - + /* + * We need to hold j_state_lock until t_updates has been incremented, + * for proper journal barrier handling + */ + spin_lock(&journal->j_state_lock); +repeat_locked: if (is_journal_aborted(journal) || (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { - unlock_journal(journal); - return -EROFS; + spin_unlock(&journal->j_state_lock); + ret = -EROFS; + goto out; } /* Wait on the journal's transaction barrier if necessary */ if (journal->j_barrier_count) { - unlock_journal(journal); - sleep_on(&journal->j_wait_transaction_locked); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_transaction_locked, + journal->j_barrier_count == 0); goto repeat; } - -repeat_locked: - if (!journal->j_running_transaction) - get_transaction(journal, 0); - /* @@@ Error? */ - J_ASSERT(journal->j_running_transaction); - - transaction = journal->j_running_transaction; - /* If the current transaction is locked down for commit, wait - * for the lock to be released. */ + if (!journal->j_running_transaction) { + if (!new_transaction) { + spin_unlock(&journal->j_state_lock); + goto alloc_transaction; + } + get_transaction(journal, new_transaction); + new_transaction = NULL; + } + + transaction = journal->j_running_transaction; + /* + * If the current transaction is locked down for commit, wait for the + * lock to be released. + */ if (transaction->t_state == T_LOCKED) { - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); jbd_debug(3, "Handle %p stalling...\n", handle); - sleep_on(&journal->j_wait_transaction_locked); + wait_event(journal->j_wait_transaction_locked, + transaction->t_state != T_LOCKED); goto repeat; } - - /* If there is not enough space left in the log to write all - * potential buffers requested by this operation, we need to - * stall pending a log checkpoint to free some more log - * space. */ + /* + * If there is not enough space left in the log to write all potential + * buffers requested by this operation, we need to stall pending a log + * checkpoint to free some more log space. + */ + spin_lock(&transaction->t_handle_lock); needed = transaction->t_outstanding_credits + nblocks; if (needed > journal->j_max_transaction_buffers) { - /* If the current transaction is already too large, then - * start to commit it: we can then go back and attach - * this handle to a new transaction. */ - + /* + * If the current transaction is already too large, then start + * to commit it: we can then go back and attach this handle to + * a new transaction. + */ + DEFINE_WAIT(wait); + jbd_debug(2, "Handle %p starting new commit...\n", handle); - log_start_commit(journal, transaction); - unlock_journal(journal); - sleep_on(&journal->j_wait_transaction_locked); - lock_journal(journal); - goto repeat_locked; + spin_unlock(&transaction->t_handle_lock); + prepare_to_wait(&journal->j_wait_transaction_locked, &wait, + TASK_UNINTERRUPTIBLE); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_transaction_locked, &wait); + goto repeat; } /* @@ -185,10 +210,11 @@ repeat_locked: if (journal->j_committing_transaction) needed += journal->j_committing_transaction-> t_outstanding_credits; - - if (log_space_left(journal) < needed) { + + if (__log_space_left(journal) < needed) { jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); - log_wait_for_space(journal, needed); + spin_unlock(&transaction->t_handle_lock); + __log_wait_for_space(journal, needed); goto repeat_locked; } @@ -201,10 +227,12 @@ repeat_locked: transaction->t_handle_count++; jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", handle, nblocks, transaction->t_outstanding_credits, - log_space_left(journal)); - - unlock_journal(journal); - + __log_space_left(journal)); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); +out: + if (new_transaction) + kfree(new_transaction); return 0; } @@ -240,7 +268,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) { handle_t *handle = journal_current_handle(); int err; - + if (!journal) return ERR_PTR(-EROFS); @@ -260,9 +288,8 @@ handle_t *journal_start(journal_t *journal, int nblocks) if (err < 0) { jbd_free_handle(handle); current->journal_info = NULL; - return ERR_PTR(err); + handle = ERR_PTR(err); } - return handle; } @@ -286,50 +313,52 @@ handle_t *journal_start(journal_t *journal, int nblocks) * return code < 0 implies an error * return code > 0 implies normal transaction-full status. */ -int journal_extend (handle_t *handle, int nblocks) +int journal_extend(handle_t *handle, int nblocks) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int result; int wanted; - lock_journal (journal); - result = -EIO; if (is_handle_aborted(handle)) goto error_out; result = 1; - + + spin_lock(&journal->j_state_lock); + /* Don't extend a locked-down transaction! */ if (handle->h_transaction->t_state != T_RUNNING) { jbd_debug(3, "denied handle %p %d blocks: " "transaction not running\n", handle, nblocks); goto error_out; } - + + spin_lock(&transaction->t_handle_lock); wanted = transaction->t_outstanding_credits + nblocks; - + if (wanted > journal->j_max_transaction_buffers) { jbd_debug(3, "denied handle %p %d blocks: " "transaction too large\n", handle, nblocks); - goto error_out; + goto unlock; } - if (wanted > log_space_left(journal)) { + if (wanted > __log_space_left(journal)) { jbd_debug(3, "denied handle %p %d blocks: " "insufficient log space\n", handle, nblocks); - goto error_out; + goto unlock; } - + handle->h_buffer_credits += nblocks; transaction->t_outstanding_credits += nblocks; result = 0; jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); - +unlock: + spin_unlock(&transaction->t_handle_lock); error_out: - unlock_journal (journal); + spin_unlock(&journal->j_state_lock); return result; } @@ -359,21 +388,26 @@ int journal_restart(handle_t *handle, int nblocks) * actually doing the restart! */ if (is_handle_aborted(handle)) return 0; - - /* First unlink the handle from its current transaction, and - * start the commit on that. */ - - J_ASSERT (transaction->t_updates > 0); - J_ASSERT (journal_current_handle() == handle); + /* + * First unlink the handle from its current transaction, and start the + * commit on that. + */ + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); + + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) wake_up(&journal->j_wait_updates); + spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "restarting handle %p\n", handle); - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); handle->h_buffer_credits = nblocks; ret = start_this_handle(journal, handle); @@ -391,30 +425,41 @@ int journal_restart(handle_t *handle, int nblocks) * * The journal lock should not be held on entry. */ -void journal_lock_updates (journal_t *journal) +void journal_lock_updates(journal_t *journal) { - lock_journal(journal); + DEFINE_WAIT(wait); + + spin_lock(&journal->j_state_lock); ++journal->j_barrier_count; /* Wait until there are no running updates */ while (1) { transaction_t *transaction = journal->j_running_transaction; + if (!transaction) break; - if (!transaction->t_updates) + + spin_lock(&transaction->t_handle_lock); + if (!transaction->t_updates) { + spin_unlock(&transaction->t_handle_lock); break; - - unlock_journal(journal); - sleep_on(&journal->j_wait_updates); - lock_journal(journal); + } + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_updates, &wait); + spin_lock(&journal->j_state_lock); } + spin_unlock(&journal->j_state_lock); - unlock_journal(journal); - - /* We have now established a barrier against other normal - * updates, but we also need to barrier against other - * journal_lock_updates() calls to make sure that we serialise - * special journal-locked operations too. */ + /* + * We have now established a barrier against other normal updates, but + * we also need to barrier against other journal_lock_updates() calls + * to make sure that we serialise special journal-locked operations + * too. + */ down(&journal->j_barrier); } @@ -428,14 +473,13 @@ void journal_lock_updates (journal_t *journal) */ void journal_unlock_updates (journal_t *journal) { - lock_journal(journal); + J_ASSERT(journal->j_barrier_count != 0); - J_ASSERT (journal->j_barrier_count != 0); - up(&journal->j_barrier); + spin_lock(&journal->j_state_lock); --journal->j_barrier_count; + spin_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_transaction_locked); - unlock_journal(journal); } /* @@ -445,14 +489,14 @@ void journal_unlock_updates (journal_t *journal) * continuing as gracefully as possible. # * * The caller should already hold the journal lock and - * journal_datalist_lock spinlock: most callers will need those anyway + * j_list_lock spinlock: most callers will need those anyway * in order to probe the buffer's journaling state safely. */ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) { struct buffer_head *bh = jh2bh(jh); int jlist; - + if (buffer_dirty(bh)) { /* If this buffer is one which might reasonably be dirty * --- ie. data, or not part of this journal --- then @@ -460,7 +504,7 @@ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) * move the dirty bit to the journal's own internal * JBDDirty bit. */ jlist = jh->b_jlist; - + if (jlist == BJ_Metadata || jlist == BJ_Reserved || jlist == BJ_Shadow || jlist == BJ_Forget) { if (test_clear_buffer_dirty(jh2bh(jh))) { @@ -482,7 +526,8 @@ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) */ static int -do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) +do_get_write_access(handle_t *handle, struct journal_head *jh, + int force_copy, int *credits) { struct buffer_head *bh; transaction_t *transaction = handle->h_transaction; @@ -490,7 +535,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) int error; char *frozen_buffer = NULL; int need_copy = 0; - int locked; jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); @@ -500,16 +544,9 @@ repeat: /* @@@ Need to check for errors here at some point. */ - locked = test_set_buffer_locked(bh); - if (locked) { - /* We can't reliably test the buffer state if we found - * it already locked, so just wait for the lock and - * retry. */ - unlock_journal(journal); - wait_on_buffer(bh); - lock_journal(journal); - goto repeat; - } + lock_buffer(bh); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); /* We now hold the buffer lock so it is safe to query the buffer * state. Is the buffer dirty? @@ -525,7 +562,6 @@ repeat: * the buffer dirtied, ugh.) */ if (buffer_dirty(bh)) { - spin_lock(&journal_datalist_lock); /* First question: is this buffer already part of the * current transaction or the existing committing * transaction? */ @@ -540,18 +576,18 @@ repeat: JBUFFER_TRACE(jh, "Unexpected dirty buffer"); jbd_unexpected_dirty_buffer(jh); } - spin_unlock(&journal_datalist_lock); } unlock_buffer(bh); error = -EROFS; - if (is_handle_aborted(handle)) + if (is_handle_aborted(handle)) { + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); goto out_unlocked; + } error = 0; - spin_lock(&journal_datalist_lock); - /* The buffer is already part of this transaction if * b_transaction or b_next_transaction points to it. */ @@ -569,9 +605,11 @@ repeat: J_ASSERT_JH(jh, handle->h_buffer_credits > 0); handle->h_buffer_credits--; + if (credits) + (*credits)++; goto done_locked; } - + /* Is there data here we need to preserve? */ if (jh->b_transaction && jh->b_transaction != transaction) { @@ -593,15 +631,14 @@ repeat: wait_queue_head_t *wqh; JBUFFER_TRACE(jh, "on shadow: sleep"); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); /* commit wakes up all shadow buffers after IO */ wqh = bh_waitq_head(jh2bh(jh)); wait_event(*wqh, (jh->b_jlist != BJ_Shadow)); - lock_journal(journal); goto repeat; } - + /* Only do the copy if the currently-owning transaction * still needs it. If it is on the Forget list, the * committing transaction is past that stage. The @@ -620,18 +657,18 @@ repeat: JBUFFER_TRACE(jh, "generate frozen data"); if (!frozen_buffer) { JBUFFER_TRACE(jh, "allocate memory for buffer"); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); frozen_buffer = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS); - lock_journal(journal); if (!frozen_buffer) { printk(KERN_EMERG "%s: OOM for frozen_buffer\n", __FUNCTION__); JBUFFER_TRACE(jh, "oom!"); error = -ENOMEM; - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); goto done_locked; } goto repeat; @@ -646,6 +683,8 @@ repeat: J_ASSERT(handle->h_buffer_credits > 0); handle->h_buffer_credits--; + if (credits) + (*credits)++; /* Finally, if the buffer is not journaled right now, we need to * make sure it doesn't get written to disk before the caller @@ -658,9 +697,9 @@ repeat: JBUFFER_TRACE(jh, "file as BJ_Reserved"); __journal_file_buffer(jh, transaction, BJ_Reserved); } - + done_locked: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); if (need_copy) { struct page *page; int offset; @@ -670,11 +709,11 @@ done_locked: "Possible IO failure.\n"); page = jh2bh(jh)->b_page; offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK; - source = kmap(page); + source = kmap_atomic(page, KM_USER0); memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); - kunmap(page); + kunmap_atomic(source, KM_USER0); } - + jbd_unlock_bh_state(bh); /* If we are about to journal a buffer, then any revoke pending on it is no longer valid. */ @@ -699,20 +738,17 @@ out_unlocked: * because we're write()ing a buffer which is also part of a shared mapping. */ -int journal_get_write_access (handle_t *handle, struct buffer_head *bh) +int journal_get_write_access(handle_t *handle, + struct buffer_head *bh, int *credits) { - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; struct journal_head *jh = journal_add_journal_head(bh); int rc; /* We do not want to get caught playing with fields which the * log thread also manipulates. Make sure that the buffer * completes any outstanding IO before proceeding. */ - lock_journal(journal); - rc = do_get_write_access(handle, jh, 0); - journal_unlock_journal_head(jh); - unlock_journal(journal); + rc = do_get_write_access(handle, jh, 0, NULL); + journal_put_journal_head(jh); return rc; } @@ -736,29 +772,32 @@ int journal_get_write_access (handle_t *handle, struct buffer_head *bh) * * Call this if you create a new bh. */ -int journal_get_create_access (handle_t *handle, struct buffer_head *bh) +int journal_get_create_access(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; struct journal_head *jh = journal_add_journal_head(bh); int err; - + jbd_debug(5, "journal_head %p\n", jh); - lock_journal(journal); err = -EROFS; if (is_handle_aborted(handle)) goto out; err = 0; - + JBUFFER_TRACE(jh, "entry"); - /* The buffer may already belong to this transaction due to - * pre-zeroing in the filesystem's new_block code. It may also - * be on the previous, committing transaction's lists, but it - * HAS to be in Forget state in that case: the transaction must - * have deleted the buffer for it to be reused here. */ + /* + * The buffer may already belong to this transaction due to pre-zeroing + * in the filesystem's new_block code. It may also be on the previous, + * committing transaction's lists, but it HAS to be in Forget state in + * that case: the transaction must have deleted the buffer for it to be + * reused here. + */ + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && + jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && jh->b_jlist == BJ_Forget))); J_ASSERT_JH(jh, jh->b_next_transaction == NULL); @@ -767,7 +806,6 @@ int journal_get_create_access (handle_t *handle, struct buffer_head *bh) J_ASSERT_JH(jh, handle->h_buffer_credits > 0); handle->h_buffer_credits--; - spin_lock(&journal_datalist_lock); if (jh->b_transaction == NULL) { jh->b_transaction = transaction; JBUFFER_TRACE(jh, "file as BJ_Reserved"); @@ -776,7 +814,8 @@ int journal_get_create_access (handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); /* * akpm: I added this. ext3_alloc_branch can pick up new indirect @@ -787,19 +826,18 @@ int journal_get_create_access (handle_t *handle, struct buffer_head *bh) */ JBUFFER_TRACE(jh, "cancelling revoke"); journal_cancel_revoke(handle, jh); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); out: - unlock_journal(journal); return err; } - - /** - * int journal_get_undo_access() - Notify intent to modify metadata with non-rewindable consequences + * int journal_get_undo_access() - Notify intent to modify metadata with + * non-rewindable consequences * @handle: transaction * @bh: buffer to undo - * + * @credits: store the number of taken credits here (if not NULL) + * * Sometimes there is a need to distinguish between metadata which has * been committed to disk and that which has not. The ext3fs code uses * this for freeing and allocating space, we have to make sure that we @@ -818,47 +856,56 @@ out: * will be committed to a new transaction in due course, at which point * we can discard the old committed data pointer. * - * Returns error number or 0 on success. + * Returns error number or 0 on success. */ -int journal_get_undo_access (handle_t *handle, struct buffer_head *bh) +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh, + int *credits) { - journal_t *journal = handle->h_transaction->t_journal; int err; struct journal_head *jh = journal_add_journal_head(bh); + char *committed_data = NULL; JBUFFER_TRACE(jh, "entry"); - lock_journal(journal); - /* Do this first --- it can drop the journal lock, so we want to + /* + * Do this first --- it can drop the journal lock, so we want to * make sure that obtaining the committed_data is done - * atomically wrt. completion of any outstanding commits. */ - err = do_get_write_access (handle, jh, 1); + * atomically wrt. completion of any outstanding commits. + */ + err = do_get_write_access(handle, jh, 1, credits); if (err) goto out; - + +repeat: if (!jh->b_committed_data) { - /* Copy out the current buffer contents into the - * preserved, committed copy. */ - JBUFFER_TRACE(jh, "generate b_committed data"); - jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, - GFP_NOFS); - if (!jh->b_committed_data) { - printk(KERN_EMERG - "%s: No memory for committed data!\n", - __FUNCTION__); + committed_data = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS); + if (!committed_data) { + printk(KERN_EMERG "%s: No memory for committed data\n", + __FUNCTION__); err = -ENOMEM; goto out; } - - memcpy (jh->b_committed_data, jh2bh(jh)->b_data, - jh2bh(jh)->b_size); } + jbd_lock_bh_state(bh); + if (!jh->b_committed_data) { + /* Copy out the current buffer contents into the + * preserved, committed copy. */ + JBUFFER_TRACE(jh, "generate b_committed data"); + if (!committed_data) { + jbd_unlock_bh_state(bh); + goto repeat; + } + + jh->b_committed_data = committed_data; + committed_data = NULL; + memcpy(jh->b_committed_data, bh->b_data, bh->b_size); + } + jbd_unlock_bh_state(bh); out: - if (!err) - J_ASSERT_JH(jh, jh->b_committed_data); - journal_unlock_journal_head(jh); - unlock_journal(journal); + journal_put_journal_head(jh); + if (committed_data) + kfree(committed_data); return err; } @@ -875,10 +922,9 @@ out: * Returns error number or 0 on success. * * journal_dirty_data() can be called via page_launder->ext3_writepage - * by kswapd. So it cannot block. Happily, there's nothing here - * which needs lock_journal if `async' is set. + * by kswapd. */ -int journal_dirty_data (handle_t *handle, struct buffer_head *bh) +int journal_dirty_data(handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; int need_brelse = 0; @@ -886,7 +932,7 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh) if (is_handle_aborted(handle)) return 0; - + jh = journal_add_journal_head(bh); JBUFFER_TRACE(jh, "entry"); @@ -917,7 +963,8 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh) * never, ever allow this to happen: there's nothing we can do * about it in this layer. */ - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (jh->b_transaction) { JBUFFER_TRACE(jh, "has transaction"); if (jh->b_transaction != handle->h_transaction) { @@ -971,11 +1018,13 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh) * commit to never terminate. */ if (buffer_dirty(bh)) { - atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); need_brelse = 1; sync_dirty_buffer(bh); - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); /* The buffer may become locked again at any time if it is redirtied */ } @@ -1009,13 +1058,14 @@ int journal_dirty_data (handle_t *handle, struct buffer_head *bh) __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); } no_journal: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); if (need_brelse) { BUFFER_TRACE(bh, "brelse"); __brelse(bh); } JBUFFER_TRACE(jh, "exit"); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); return 0; } @@ -1038,7 +1088,7 @@ no_journal: * buffer: that only gets done when the old transaction finally * completes its commit. */ -int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) +int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1046,15 +1096,41 @@ int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) jbd_debug(5, "journal_head %p\n", jh); JBUFFER_TRACE(jh, "entry"); - lock_journal(journal); if (is_handle_aborted(handle)) - goto out_unlock; - - spin_lock(&journal_datalist_lock); - set_bit(BH_JBDDirty, &bh->b_state); + goto out; + + jbd_lock_bh_state(bh); + + /* + * fastpath, to avoid expensive locking. If this buffer is already + * on the running transaction's metadata list there is nothing to do. + * Nobody can take it off again because there is a handle open. + * I _think_ we're OK here with SMP barriers - a mistaken decision will + * result in this test being false, so we go in and take the locks. + */ + if (jh->b_transaction == handle->h_transaction && + jh->b_jlist == BJ_Metadata) { + JBUFFER_TRACE(jh, "fastpath"); + console_verbose(); + if (jh->b_transaction != journal->j_running_transaction) { + printk("jh->b_transaction=%p\n", jh->b_transaction); + printk("journal->j_running_transaction=%p\n", + journal->j_running_transaction); + printk("handle->h_transaction=%p\n", + handle->h_transaction); + printk("journal->j_committing_transaction=%p\n", + journal->j_committing_transaction); + } + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_running_transaction); + goto out_unlock_bh; + } + + spin_lock(&journal->j_list_lock); + set_buffer_jbddirty(bh); J_ASSERT_JH(jh, jh->b_transaction != NULL); - + /* * Metadata already on the current transaction list doesn't * need to be filed. Metadata on another transaction's list must @@ -1070,8 +1146,7 @@ int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) /* And this case is illegal: we can't reuse another * transaction's data buffer, ever. */ /* FIXME: writepage() should be journalled */ - J_ASSERT_JH(jh, jh->b_jlist != BJ_SyncData); - goto done_locked; + goto out_unlock_list; } /* That test should have eliminated the following case: */ @@ -1080,49 +1155,51 @@ int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) JBUFFER_TRACE(jh, "file as BJ_Metadata"); __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); -done_locked: - spin_unlock(&journal_datalist_lock); +out_unlock_list: + spin_unlock(&journal->j_list_lock); +out_unlock_bh: + jbd_unlock_bh_state(bh); +out: JBUFFER_TRACE(jh, "exit"); -out_unlock: - unlock_journal(journal); return 0; } -#if 0 /* * journal_release_buffer: undo a get_write_access without any buffer * updates, if the update decided in the end that it didn't need access. * * journal_get_write_access() can block, so it is quite possible for a * journaling component to decide after the write access is returned - * that global state has changed and the update is no longer required. */ - -void journal_release_buffer (handle_t *handle, struct buffer_head *bh) + * that global state has changed and the update is no longer required. + * + * The caller passes in the number of credits which should be put back for + * this buffer (zero or one). + */ +void +journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; struct journal_head *jh = bh2jh(bh); - lock_journal(journal); JBUFFER_TRACE(jh, "entry"); /* If the buffer is reserved but not modified by this * transaction, then it is safe to release it. In all other * cases, just leave the buffer as it is. */ - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (jh->b_jlist == BJ_Reserved && jh->b_transaction == transaction && - !buffer_jdirty(jh2bh(jh))) { + !buffer_jbddirty(jh2bh(jh))) { JBUFFER_TRACE(jh, "unused: refiling it"); - handle->h_buffer_credits++; __journal_refile_buffer(jh); } - spin_unlock(&journal_datalist_lock); - + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + handle->h_buffer_credits += credits; JBUFFER_TRACE(jh, "exit"); - unlock_journal(journal); } -#endif /** * void journal_forget() - bforget() for potentially-journaled buffers. @@ -1141,7 +1218,7 @@ void journal_release_buffer (handle_t *handle, struct buffer_head *bh) * Allow this call even if the handle has aborted --- it may be part of * the caller's cleanup after an abort. */ -void journal_forget (handle_t *handle, struct buffer_head *bh) +void journal_forget(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1149,8 +1226,8 @@ void journal_forget (handle_t *handle, struct buffer_head *bh) BUFFER_TRACE(bh, "entry"); - lock_journal(journal); - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (!buffer_jbd(bh)) goto not_jbd; @@ -1163,7 +1240,7 @@ void journal_forget (handle_t *handle, struct buffer_head *bh) * of this transaction, then we can just drop it from * the transaction immediately. */ clear_buffer_dirty(bh); - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); J_ASSERT_JH(jh, !jh->b_committed_data); @@ -1186,16 +1263,15 @@ void journal_forget (handle_t *handle, struct buffer_head *bh) if (jh->b_cp_transaction) { __journal_file_buffer(jh, transaction, BJ_Forget); } else { - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); if (!buffer_jbd(bh)) { - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); __bforget(bh); return; } } - } else if (jh->b_transaction) { J_ASSERT_JH(jh, (jh->b_transaction == journal->j_committing_transaction)); @@ -1212,72 +1288,12 @@ void journal_forget (handle_t *handle, struct buffer_head *bh) } not_jbd: - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); __brelse(bh); return; } -#if 0 /* Unused */ -/* - * journal_sync_buffer: flush a potentially-journaled buffer to disk. - * - * Used for O_SYNC filesystem operations. If the buffer is journaled, - * we need to complete the O_SYNC by waiting for the transaction to - * complete. It is an error to call journal_sync_buffer before - * journal_stop! - */ - -void journal_sync_buffer(struct buffer_head *bh) -{ - transaction_t *transaction; - journal_t *journal; - long sequence; - struct journal_head *jh; - - /* If the buffer isn't journaled, this is easy: just sync it to - * disk. */ - BUFFER_TRACE(bh, "entry"); - - spin_lock(&journal_datalist_lock); - if (!buffer_jbd(bh)) { - spin_unlock(&journal_datalist_lock); - return; - } - jh = bh2jh(bh); - if (jh->b_transaction == NULL) { - /* If the buffer has already been journaled, then this - * is a noop. */ - if (jh->b_cp_transaction == NULL) { - spin_unlock(&journal_datalist_lock); - return; - } - atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); - sync_dirty_buffer(bh); - __brelse(bh); - goto out; - } - - /* Otherwise, just wait until the transaction is synced to disk. */ - transaction = jh->b_transaction; - journal = transaction->t_journal; - sequence = transaction->t_tid; - spin_unlock(&journal_datalist_lock); - - jbd_debug(2, "requesting commit for jh %p\n", jh); - log_start_commit (journal, transaction); - - while (tid_gt(sequence, journal->j_commit_sequence)) { - wake_up(&journal->j_wait_done_commit); - sleep_on(&journal->j_wait_done_commit); - } - JBUFFER_TRACE(jh, "exit"); -out: - return; -} -#endif - /** * void journal_callback_set() - Register a callback function for this handle. * @handle: handle to attach the callback to. @@ -1299,14 +1315,15 @@ out: * and has the caller-specific data afterwards. */ void journal_callback_set(handle_t *handle, - void (*func)(struct journal_callback *jcb, int error), - struct journal_callback *jcb) + void (*func)(struct journal_callback *jcb, int error), + struct journal_callback *jcb) { + spin_lock(&handle->h_transaction->t_jcb_lock); list_add_tail(&jcb->jcb_list, &handle->h_jcb); + spin_unlock(&handle->h_transaction->t_jcb_lock); jcb->jcb_func = func; } - /** * int journal_stop() - complete a transaction * @handle: tranaction to complete. @@ -1328,18 +1345,18 @@ int journal_stop(handle_t *handle) transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int old_handle_count, err; - + if (!handle) return 0; - J_ASSERT (transaction->t_updates > 0); - J_ASSERT (journal_current_handle() == handle); - + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); + if (is_handle_aborted(handle)) err = -EIO; else err = 0; - + if (--handle->h_ref > 0) { jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, handle->h_ref); @@ -1366,6 +1383,8 @@ int journal_stop(handle_t *handle) } current->journal_info = NULL; + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) { @@ -1375,7 +1394,9 @@ int journal_stop(handle_t *handle) } /* Move callbacks from the handle to the transaction. */ + spin_lock(&transaction->t_jcb_lock); list_splice(&handle->h_jcb, &transaction->t_jcb); + spin_unlock(&transaction->t_jcb_lock); /* * If the handle is marked SYNC, we need to set another commit @@ -1391,19 +1412,25 @@ int journal_stop(handle_t *handle) * completes the commit thread, it just doesn't write * anything to disk. */ tid_t tid = transaction->t_tid; - + + spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "transaction too old, requesting commit for " "handle %p\n", handle); /* This is non-blocking */ - log_start_commit(journal, transaction); - + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + /* * Special case: JFS_SYNC synchronous updates require us * to wait for the commit to complete. */ if (handle->h_sync && !(current->flags & PF_MEMALLOC)) err = log_wait_commit(journal, tid); + } else { + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); } + jbd_free_handle(handle); return err; } @@ -1420,16 +1447,13 @@ int journal_force_commit(journal_t *journal) handle_t *handle; int ret; - lock_kernel(); handle = journal_start(journal, 1); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out; + } else { + handle->h_sync = 1; + ret = journal_stop(handle); } - handle->h_sync = 1; - ret = journal_stop(handle); -out: - unlock_kernel(); return ret; } @@ -1443,7 +1467,10 @@ out: /* * Append a buffer to a transaction list, given the transaction's list head * pointer. - * journal_datalist_lock is held. + * + * j_list_lock is held. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. */ static inline void @@ -1465,8 +1492,9 @@ __blist_add_buffer(struct journal_head **list, struct journal_head *jh) * Remove a buffer from a transaction list, given the transaction's list * head pointer. * - * Called with journal_datalist_lock held, and the journal may not - * be locked. + * Called with j_list_lock held, and the journal may not be locked. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. */ static inline void @@ -1490,23 +1518,20 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh) * is holding onto a copy of one of thee pointers, it could go bad. * Generally the caller needs to re-read the pointer from the transaction_t. * - * If bh->b_jlist is BJ_SyncData then we may have been called - * via journal_try_to_free_buffer() or journal_clean_data_list(). In that - * case, journal_datalist_lock will be held, and the journal may not be locked. + * Called under j_list_lock. The journal may not be locked. */ void __journal_unfile_buffer(struct journal_head *jh) { struct journal_head **list = 0; - transaction_t * transaction; + transaction_t *transaction; + struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); transaction = jh->b_transaction; + if (transaction) + assert_spin_locked(&transaction->t_journal->j_list_lock); -#ifdef __SMP__ - J_ASSERT (current->lock_depth >= 0); -#endif J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - if (jh->b_jlist != BJ_None) J_ASSERT_JH(jh, transaction != 0); @@ -1537,41 +1562,32 @@ void __journal_unfile_buffer(struct journal_head *jh) list = &transaction->t_reserved_list; break; } - + __blist_del_buffer(list, jh); jh->b_jlist = BJ_None; - if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) - mark_buffer_dirty(jh2bh(jh)); /* Expose it to the VM */ + if (test_clear_buffer_jbddirty(bh)) + mark_buffer_dirty(bh); /* Expose it to the VM */ } -void journal_unfile_buffer(struct journal_head *jh) +void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) { - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&journal->j_list_lock); __journal_unfile_buffer(jh); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); } /* - * Called from journal_try_to_free_buffers(). The journal is not - * locked. lru_list_lock is not held. - * - * Here we see why journal_datalist_lock is global and not per-journal. - * We cannot get back to this buffer's journal pointer without locking - * out journal_clean_data_list() in some manner. - * - * One could use journal_datalist_lock to get unracy access to a - * per-journal lock. + * Called from journal_try_to_free_buffers(). * - * Called with journal_datalist_lock held. - * - * Returns non-zero iff we were able to free the journal_head. + * Called under jbd_lock_bh_state(bh) */ -static inline int __journal_try_to_free_buffer(struct buffer_head *bh) +static void +__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) { struct journal_head *jh; - assert_spin_locked(&journal_datalist_lock); - jh = bh2jh(bh); if (buffer_locked(bh) || buffer_dirty(bh)) @@ -1580,13 +1596,14 @@ static inline int __journal_try_to_free_buffer(struct buffer_head *bh) if (jh->b_next_transaction != 0) goto out; + spin_lock(&journal->j_list_lock); if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { if (jh->b_jlist == BJ_SyncData) { /* A written-back ordered data buffer */ JBUFFER_TRACE(jh, "release data"); __journal_unfile_buffer(jh); jh->b_transaction = 0; - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { @@ -1594,14 +1611,13 @@ static inline int __journal_try_to_free_buffer(struct buffer_head *bh) if (jh->b_jlist == BJ_None) { JBUFFER_TRACE(jh, "remove from checkpoint list"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } } - return !buffer_jbd(bh); - + spin_unlock(&journal->j_list_lock); out: - return 0; + return; } @@ -1650,14 +1666,25 @@ int journal_try_to_free_buffers(journal_t *journal, head = page_buffers(page); bh = head; - spin_lock(&journal_datalist_lock); do { - if (buffer_jbd(bh) && !__journal_try_to_free_buffer(bh)) { - spin_unlock(&journal_datalist_lock); + struct journal_head *jh; + + /* + * We take our own ref against the journal_head here to avoid + * having to add tons of locking around each instance of + * journal_remove_journal_head() and journal_put_journal_head(). + */ + jh = journal_grab_journal_head(bh); + if (!jh) + continue; + + jbd_lock_bh_state(bh); + __journal_try_to_free_buffer(journal, bh); + journal_put_journal_head(jh); + jbd_unlock_bh_state(bh); + if (buffer_jbd(bh)) goto busy; - } } while ((bh = bh->b_this_page) != head); - spin_unlock(&journal_datalist_lock); ret = try_to_free_buffers(page); busy: return ret; @@ -1670,28 +1697,29 @@ busy: * this transaction commits. If the buffer isn't on a checkpoint list, we * release it. * Returns non-zero if JBD no longer has an interest in the buffer. + * + * Called under j_list_lock. + * + * Called under jbd_lock_bh_state(bh). */ -static int dispose_buffer(struct journal_head *jh, - transaction_t *transaction) +static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) { int may_free = 1; struct buffer_head *bh = jh2bh(jh); - spin_lock(&journal_datalist_lock); __journal_unfile_buffer(jh); jh->b_transaction = 0; if (jh->b_cp_transaction) { JBUFFER_TRACE(jh, "on running+cp transaction"); __journal_file_buffer(jh, transaction, BJ_Forget); - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); may_free = 0; } else { JBUFFER_TRACE(jh, "on running transaction"); - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } - spin_unlock(&journal_datalist_lock); return may_free; } @@ -1747,14 +1775,27 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) transaction_t *transaction; struct journal_head *jh; int may_free = 1; + int ret; BUFFER_TRACE(bh, "entry"); - /* It is safe to proceed here without the - * journal_datalist_spinlock because the buffers cannot be - * stolen by try_to_free_buffers as long as we are holding the - * page lock. --sct */ + /* + * It is safe to proceed here without the j_list_lock because the + * buffers cannot be stolen by try_to_free_buffers as long as we are + * holding the page lock. --sct + */ + + if (!buffer_jbd(bh)) + goto zap_buffer_unlocked; + + spin_lock(&journal->j_state_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + /* + * Now we have the locks, check again to see whether kjournald has + * taken the buffer off the transaction. + */ if (!buffer_jbd(bh)) goto zap_buffer; @@ -1769,7 +1810,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) JBUFFER_TRACE(jh, "not on any transaction: zap"); goto zap_buffer; } - + if (!buffer_dirty(bh)) { /* bdflush has written it. We can drop it now */ goto zap_buffer; @@ -1784,8 +1825,12 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * committed, the buffer won't be needed any * longer. */ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - return dispose_buffer(jh, + ret = __dispose_buffer(jh, journal->j_running_transaction); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; } else { /* There is no currently-running transaction. So the * orphan record which we wrote for this file must have @@ -1793,12 +1838,16 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * the committing transaction, if it exists. */ if (journal->j_committing_transaction) { JBUFFER_TRACE(jh, "give to committing trans"); - return dispose_buffer(jh, + ret = __dispose_buffer(jh, journal->j_committing_transaction); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; } else { /* The orphan record's transaction has * committed. We can cleanse this buffer */ - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); goto zap_buffer; } } @@ -1814,6 +1863,9 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) journal->j_running_transaction); jh->b_next_transaction = NULL; } + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); return 0; } else { /* Good, the buffer belongs to the running transaction. @@ -1823,12 +1875,16 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) * i_size already for this truncate so recovery will not * expose the disk blocks we are discarding here.) */ J_ASSERT_JH(jh, transaction == journal->j_running_transaction); - may_free = dispose_buffer(jh, transaction); + may_free = __dispose_buffer(jh, transaction); } -zap_buffer: +zap_buffer: + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); +zap_buffer_unlocked: clear_buffer_dirty(bh); - J_ASSERT_BH(bh, !buffer_jdirty(bh)); + J_ASSERT_BH(bh, !buffer_jbddirty(bh)); clear_buffer_mapped(bh); clear_buffer_req(bh); clear_buffer_new(bh); @@ -1853,7 +1909,7 @@ int journal_invalidatepage(journal_t *journal, struct buffer_head *head, *bh, *next; unsigned int curr_off = 0; int may_free = 1; - + if (!PageLocked(page)) BUG(); if (!page_has_buffers(page)) @@ -1862,7 +1918,6 @@ int journal_invalidatepage(journal_t *journal, /* We will potentially be playing with lists other than just the * data lists (especially for journaled data mode), so be * cautious in our locking. */ - lock_journal(journal); head = bh = page_buffers(page); do { @@ -1881,8 +1936,6 @@ int journal_invalidatepage(journal_t *journal, } while (bh != head); - unlock_journal(journal); - if (!offset) { if (!may_free || !try_to_free_buffers(page)) return 0; @@ -1901,8 +1954,9 @@ void __journal_file_buffer(struct journal_head *jh, int was_dirty = 0; struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); - + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + assert_spin_locked(&transaction->t_journal->j_list_lock); + #ifdef __SMP__ J_ASSERT (current->lock_depth >= 0); #endif @@ -1912,7 +1966,7 @@ void __journal_file_buffer(struct journal_head *jh, if (jh->b_transaction && jh->b_jlist == jlist) return; - + /* The following list of buffer states needs to be consistent * with __jbd_unexpected_dirty_buffer()'s handling of dirty * state. */ @@ -1968,9 +2022,11 @@ void __journal_file_buffer(struct journal_head *jh, void journal_file_buffer(struct journal_head *jh, transaction_t *transaction, int jlist) { - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&transaction->t_journal->j_list_lock); __journal_file_buffer(jh, transaction, jlist); - spin_unlock(&journal_datalist_lock); + spin_unlock(&transaction->t_journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); } /* @@ -1978,14 +2034,19 @@ void journal_file_buffer(struct journal_head *jh, * dropping it from its current transaction entirely. If the buffer has * already started to be used by a subsequent transaction, refile the * buffer on that transaction's metadata list. + * + * Called under journal->j_list_lock + * + * Called under jbd_lock_bh_state(jh2bh(jh)) */ - void __journal_refile_buffer(struct journal_head *jh) { int was_dirty; + struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); - J_ASSERT_JH(jh, kernel_locked()); + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + if (jh->b_transaction) + assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock); /* If the buffer is now unused, just drop it. */ if (jh->b_next_transaction == NULL) { @@ -1993,11 +2054,13 @@ void __journal_refile_buffer(struct journal_head *jh) jh->b_transaction = NULL; return; } - - /* It has been modified by a later transaction: add it to the - * new transaction's metadata list. */ - was_dirty = test_clear_buffer_jbddirty(jh2bh(jh)); + /* + * It has been modified by a later transaction: add it to the new + * transaction's metadata list. + */ + + was_dirty = test_clear_buffer_jbddirty(bh); __journal_unfile_buffer(jh); jh->b_transaction = jh->b_next_transaction; jh->b_next_transaction = NULL; @@ -2005,7 +2068,7 @@ void __journal_refile_buffer(struct journal_head *jh) J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); if (was_dirty) - set_buffer_jbddirty(jh2bh(jh)); + set_buffer_jbddirty(bh); } /* @@ -2022,16 +2085,17 @@ void __journal_refile_buffer(struct journal_head *jh) * * *** The journal_head may be freed by this call! *** */ -void journal_refile_buffer(struct journal_head *jh) +void journal_refile_buffer(journal_t *journal, struct journal_head *jh) { - struct buffer_head *bh; + struct buffer_head *bh = jh2bh(jh); - spin_lock(&journal_datalist_lock); - bh = jh2bh(jh); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); __journal_refile_buffer(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); __brelse(bh); } diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 74036f743e3..32a123400a7 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -117,7 +117,7 @@ static void jfs_destroy_inode(struct inode *inode) kmem_cache_free(jfs_inode_cachep, ji); } -static int jfs_statfs(struct super_block *sb, struct statfs *buf) +static int jfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct jfs_sb_info *sbi = JFS_SBI(sb); s64 maxinodes; diff --git a/fs/libfs.c b/fs/libfs.c index 2553f546341..62fb3c0fbc2 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -16,7 +16,7 @@ int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } -int simple_statfs(struct super_block *sb, struct statfs *buf) +int simple_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = sb->s_magic; buf->f_bsize = PAGE_CACHE_SIZE; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 052e5518a7e..7492f61754a 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -34,6 +34,7 @@ #include #include #include +#include #define NLMDBG_FACILITY NLMDBG_SVC #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) @@ -118,9 +119,11 @@ lockd(struct svc_rqst *rqstp) * NFS mount or NFS daemon has gone away, and we've been sent a * signal, or else another process has taken over our job. */ - while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) - { + while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { long timeout = MAX_SCHEDULE_TIMEOUT; + + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); if (signalled()) { flush_signals(current); if (nlmsvc_ops) { diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 93005e83d31..710e4688660 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -19,7 +19,7 @@ static void minix_read_inode(struct inode * inode); static void minix_write_inode(struct inode * inode, int wait); -static int minix_statfs(struct super_block *sb, struct statfs *buf); +static int minix_statfs(struct super_block *sb, struct kstatfs *buf); static int minix_remount (struct super_block * sb, int * flags, char * data); static void minix_delete_inode(struct inode *inode) @@ -294,7 +294,7 @@ out_bad_sb: return -EINVAL; } -static int minix_statfs(struct super_block *sb, struct statfs *buf) +static int minix_statfs(struct super_block *sb, struct kstatfs *buf) { struct minix_sb_info *sbi = minix_sb(sb); buf->f_type = sb->s_magic; diff --git a/fs/namei.c b/fs/namei.c index 28feeb2366c..8c847a1963f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -985,6 +985,8 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. * 9. We can't remove a root or mountpoint. + * 10. We don't allow removal of NFS sillyrenamed files; it's handled by + * nfs_async_unlink(). */ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) { @@ -1008,6 +1010,8 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) return -EISDIR; if (IS_DEADDIR(dir)) return -ENOENT; + if (victim->d_flags & DCACHE_NFSFS_RENAMED) + return -EBUSY; return 0; } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index a982e1f14dc..70eab796137 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -39,7 +39,7 @@ static void ncp_delete_inode(struct inode *); static void ncp_put_super(struct super_block *); -static int ncp_statfs(struct super_block *, struct statfs *); +static int ncp_statfs(struct super_block *, struct kstatfs *); static kmem_cache_t * ncp_inode_cachep; @@ -717,7 +717,7 @@ static void ncp_put_super(struct super_block *sb) kfree(server); } -static int ncp_statfs(struct super_block *sb, struct statfs *buf) +static int ncp_statfs(struct super_block *sb, struct kstatfs *buf) { struct dentry* d; struct inode* i; diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 128d3188cd4..7767f1e6619 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -521,7 +521,7 @@ static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) { return result; } if (result > len) { - printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %u)\n", result, len); + printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len); return -EIO; } return result; @@ -614,7 +614,7 @@ skipdata:; goto skipdata2; } if (datalen > req->datalen + 8) { - printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %d)\n", datalen, req->datalen + 8); + printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8); server->rcv.state = 3; goto skipdata; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 825108da3ef..cdf78285b73 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -53,7 +53,7 @@ static void nfs_delete_inode(struct inode *); static void nfs_put_super(struct super_block *); static void nfs_clear_inode(struct inode *); static void nfs_umount_begin(struct super_block *); -static int nfs_statfs(struct super_block *, struct statfs *); +static int nfs_statfs(struct super_block *, struct kstatfs *); static int nfs_show_options(struct seq_file *, struct vfsmount *); static struct super_operations nfs_sops = { @@ -474,7 +474,7 @@ out_fail: } static int -nfs_statfs(struct super_block *sb, struct statfs *buf) +nfs_statfs(struct super_block *sb, struct kstatfs *buf) { struct nfs_server *server = NFS_SB(sb); unsigned char blockbits; @@ -715,7 +715,6 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) if (fattr->valid & NFS_ATTR_FATTR_V4) nfsi->change_attr = fattr->change_attr; inode->i_size = nfs_size_to_loff_t(fattr->size); - inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; inode->i_gid = fattr->gid; diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 12fa97fe1bf..6b1327d9310 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -17,9 +17,6 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) struct svc_cred *cred = &rqstp->rq_cred; int i; - if (rqstp->rq_userset) - return; - if (exp->ex_flags & NFSEXP_ALLSQUASH) { cred->cr_uid = exp->ex_anon_uid; cred->cr_gid = exp->ex_anon_gid; @@ -57,5 +54,4 @@ nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) current->cap_permitted); } - rqstp->rq_userset = 1; } diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 5411f9b7f8c..f6236a33225 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -153,9 +153,13 @@ int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) goto out; dprintk("Path seems to be <%s>\n", buf); err = 0; - if (len == 0) + if (len == 0) { + struct svc_expkey *ek; set_bit(CACHE_NEGATIVE, &key.h.flags); - else { + ek = svc_expkey_lookup(&key, 2); + if (ek) + expkey_put(&ek->h, &svc_expkey_cache); + } else { struct nameidata nd; struct svc_expkey *ek; struct svc_export *exp; diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index ea64d649de3..b3bcce53d60 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -866,7 +866,7 @@ int nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p, struct nfsd3_fsstatres *resp) { - struct statfs *s = &resp->stats; + struct kstatfs *s = &resp->stats; u64 bs = s->f_bsize; *p++ = xdr_zero; /* no post_op_attr */ diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0568af67b3f..17728674ad0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -147,12 +147,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open return 0; } -static inline int -nfsd4_renew(clientid_t *clientid) -{ - return nfs_ok; -} - /* * filehandle-manipulating ops. */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c5a87b73e8f..8c24df4f5c9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ time_t boot_time; static u32 current_clientid = 1; static u32 current_ownerid = 0; static u32 current_fileid = 0; +static u32 nfs4_init = 0; /* debug counters */ u32 list_add_perfile = 0; @@ -105,11 +107,28 @@ static void release_stateid(struct nfs4_stateid *stp); * * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed * setclientid info. + * + * client_lru holds client queue ordered by nfs4_client.cl_time + * for lease renewal. */ static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; +static struct list_head client_lru; + +static inline void +renew_client(struct nfs4_client *clp) +{ + /* + * Move client to the end to the LRU list. + */ + dprintk("renewing client (clientid %08x/%08x)\n", + clp->cl_clientid.cl_boot, + clp->cl_clientid.cl_id); + list_move_tail(&clp->cl_lru, &client_lru); + clp->cl_time = get_seconds(); +} /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ static int @@ -160,6 +179,7 @@ expire_client(struct nfs4_client *clp) dprintk("NFSD: expire_client\n"); list_del(&clp->cl_idhash); list_del(&clp->cl_strhash); + list_del(&clp->cl_lru); while (!list_empty(&clp->cl_perclient)) { sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient); release_stateowner(sop); @@ -176,6 +196,7 @@ create_client(struct xdr_netobj name) { INIT_LIST_HEAD(&clp->cl_idhash); INIT_LIST_HEAD(&clp->cl_strhash); INIT_LIST_HEAD(&clp->cl_perclient); + INIT_LIST_HEAD(&clp->cl_lru); out: return clp; } @@ -264,6 +285,8 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); + list_add_tail(&clp->cl_lru, &client_lru); + clp->cl_time = get_seconds(); } void @@ -271,13 +294,13 @@ move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval) { unsigned int strhashval; - printk("ANDROS: move_to_confirm nfs4_client %p\n", clp); list_del_init(&clp->cl_strhash); list_del_init(&clp->cl_idhash); list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len); list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); + renew_client(clp); } /* @@ -940,9 +963,7 @@ instantiate_new_owner: open->op_stateowner = sop; status = nfs_ok; renew: - /* XXX implement LRU and state recovery thread - * renew will place nfs4_client at end of LRU - */ + renew_client(sop->so_client); out: up(&client_sema); /*XXX need finer grained locking */ return status; @@ -1048,13 +1069,98 @@ out_free: kfree(stp); goto out; } +static struct work_struct laundromat_work; +static void laundromat_main(void *); +static DECLARE_WORK(laundromat_work, laundromat_main, NULL); + +int +nfsd4_renew(clientid_t *clid) +{ + struct nfs4_client *clp; + struct list_head *pos, *next; + unsigned int idhashval; + int status; + + down(&client_sema); + printk("process_renew(%08x/%08x): starting\n", + clid->cl_boot, clid->cl_id); + status = nfserr_stale_clientid; + if (STALE_CLIENTID(clid)) + goto out; + status = nfs_ok; + idhashval = clientid_hashval(clid->cl_id); + list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_idhash); + if (!cmp_clid(&clp->cl_clientid, clid)) + continue; + renew_client(clp); + goto out; + } + list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_idhash); + if (!cmp_clid(&clp->cl_clientid, clid)) + continue; + renew_client(clp); + goto out; + } + /* + * Couldn't find an nfs4_client for this clientid. + * Presumably this is because the client took too long to + * RENEW, so return NFS4ERR_EXPIRED. + */ + printk("nfsd4_renew: clientid not found!\n"); + status = nfserr_expired; +out: + up(&client_sema); + return status; +} + +time_t +nfs4_laundromat(void) +{ + struct nfs4_client *clp; + struct list_head *pos, *next; + time_t cutoff = get_seconds() - NFSD_LEASE_TIME; + time_t t, return_val = NFSD_LEASE_TIME; + + down(&client_sema); + + dprintk("NFSD: laundromat service - starting, examining clients\n"); + list_for_each_safe(pos, next, &client_lru) { + clp = list_entry(pos, struct nfs4_client, cl_lru); + if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { + t = clp->cl_time - cutoff; + if (return_val > t) + return_val = t; + break; + } + dprintk("NFSD: purging unused client (clientid %08x)\n", + clp->cl_clientid.cl_id); + expire_client(clp); + } + if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT) + return_val = NFSD_LAUNDROMAT_MINTIMEOUT; + up(&client_sema); + return return_val; +} + +void +laundromat_main(void *not_used) +{ + time_t t; + + t = nfs4_laundromat(); + dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); + schedule_delayed_work(&laundromat_work, t*HZ); +} void nfs4_state_init(void) { - struct timespec tv; int i; + if (nfs4_init) + return; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); @@ -1067,9 +1173,13 @@ nfs4_state_init(void) for (i = 0; i < OWNER_HASH_SIZE; i++) { INIT_LIST_HEAD(&ownerstr_hashtbl[i]); } + INIT_LIST_HEAD(&client_lru); init_MUTEX(&client_sema); - tv = CURRENT_TIME; - boot_time = tv.tv_sec; + boot_time = get_seconds(); + INIT_WORK(&laundromat_work,laundromat_main, NULL); + schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ); + nfs4_init = 1; + } static void @@ -1089,6 +1199,9 @@ __nfs4_state_shutdown(void) } } release_all_files(); + cancel_delayed_work(&laundromat_work); + flush_scheduled_work(); + nfs4_init = 0; dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n", list_add_perfile, list_del_perfile); dprintk("NFSD: add_perclient %d del_perclient %d\n", diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 47973389c0a..26cf94635f6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1039,6 +1039,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) *p++ = htonl((u32)(n)); \ } while (0) #define WRITEMEM(ptr,nbytes) do { \ + *(p + XDR_QUADLEN(nbytes) -1) = 0; \ memcpy(p, ptr, nbytes); \ p += XDR_QUADLEN(nbytes); \ } while (0) @@ -1080,7 +1081,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct name_ent *owner = NULL; struct name_ent *group = NULL; struct svc_fh tempfh; - struct statfs statfs; + struct kstatfs statfs; int buflen = *countp << 2; u32 *attrlenp; u32 dummy; @@ -1425,6 +1426,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, u32 *p = cd->buffer; u32 *attrlenp; struct dentry *dentry; + struct svc_export *exp = cd->rd_fhp->fh_export; u32 bmval0, bmval1; int nfserr = 0; @@ -1454,9 +1456,7 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1) { /* * "Heavyweight" case: we have no choice except to - * call nfsd4_encode_fattr(). As far as I know, - * only Windows clients will trigger this code - * path. + * call nfsd4_encode_fattr(). */ dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); if (IS_ERR(dentry)) { @@ -1464,10 +1464,25 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, goto error; } - nfserr = nfsd4_encode_fattr(NULL, cd->rd_fhp->fh_export, - dentry, p, &buflen, cd->rd_bmval); - dput(dentry); + if (d_mountpoint(dentry)) { + if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, + &exp))) { + /* + * -EAGAIN is the only error returned from + * nfsd_cross_mnt() and it indicates that an + * up-call has been initiated to fill in the export + * options on exp. When the answer comes back, + * this call will be retried. + */ + dput(dentry); + nfserr = nfserr_dropit; + goto error; + } + + } + nfserr = nfsd4_encode_fattr(NULL, exp, + dentry, p, &buflen, cd->rd_bmval); if (!nfserr) { p += buflen; goto out; diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 93dfe60fdb3..73b90ab7f43 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -453,7 +453,6 @@ static int __init init_nfsd(void) nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ - nfs4_state_init(); /* NFSv4 State */ if (proc_mkdir("fs/nfs", 0)) { struct proc_dir_entry *entry; entry = create_proc_entry("fs/nfs/exports", 0, NULL); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 1b1e2d68bc9..6d023b27ff6 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -161,9 +161,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) goto out; } - /* Set user creds if we haven't done so already. */ - nfsd_setuser(rqstp, exp); - /* * Look up the dentry using the NFS file handle. */ @@ -223,6 +220,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) inode = dentry->d_inode; + + /* Set user creds for this exportpoint */ + nfsd_setuser(rqstp, exp); + /* Type check. The correct error return for type mismatches * does not seem to be generally agreed upon. SunOS seems to * use EISDIR if file isn't S_IFREG; a comment in the NFSv3 diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 1388b77c86f..b41f63972df 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -591,6 +591,7 @@ nfserrno (int errno) { nfserr_dquot, -EDQUOT }, #endif { nfserr_stale, -ESTALE }, + { nfserr_dropit, -EAGAIN }, { nfserr_dropit, -ENOMEM }, { -1, -EIO } }; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index dd406043469..d09dfaf2911 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -91,6 +91,7 @@ nfsd_svc(unsigned short port, int nrservs) /* Readahead param cache - will no-op if it already exists */ error = nfsd_racache_init(2*nrservs); + nfs4_state_init(); if (error<0) goto out; if (!nfsd_serv) { diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index f28c4c0d250..f724778dc44 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -441,7 +441,7 @@ int nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p, struct nfsd_statfsres *resp) { - struct statfs *stat = &resp->stats; + struct kstatfs *stat = &resp->stats; *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */ *p++ = htonl(stat->f_bsize); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 05541f7f9ef..8759cb1076a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -74,6 +74,46 @@ struct raparms { static struct raparms * raparml; static struct raparms * raparm_cache; +/* + * Called from nfsd_lookup and encode_dirent. Check if we have crossed + * a mount point. + * Returns -EAGAIN leaving *dpp and *expp unchanged, + * or nfs_ok having possibly changed *dpp and *expp + */ +int +nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp) +{ + struct svc_export *exp = *expp, *exp2 = NULL; + struct dentry *dentry = *dpp; + struct vfsmount *mnt = mntget(exp->ex_mnt); + struct dentry *mounts = dget(dentry); + int err = nfs_ok; + + while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); + + exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); + if (IS_ERR(exp2)) { + err = PTR_ERR(exp2); + dput(mounts); + mntput(mnt); + goto out; + } + if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMNT) || EX_NOHIDE(exp2))) { + /* successfully crossed mount point */ + exp_put(exp); + *expp = exp2; + dput(dentry); + *dpp = mounts; + } else { + if (exp2) exp_put(exp2); + dput(mounts); + } + mntput(mnt); +out: + return err; +} + /* * Look up one component of a pathname. * N.B. After this call _both_ fhp and resfh need an fh_put @@ -154,34 +194,10 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { - struct svc_export *exp2 = NULL; - struct vfsmount *mnt = mntget(exp->ex_mnt); - struct dentry *mounts = dget(dentry); - while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)) - ; - - exp2 = exp_get_by_name(exp->ex_client, mnt, - mounts, &rqstp->rq_chandle); - if (IS_ERR(exp2)) { - err = PTR_ERR(exp2); - dput(mounts); - dput(dentry); - mntput(mnt); - goto out; - } - if (exp2 && - ((exp->ex_flags & NFSEXP_CROSSMNT) - || EX_NOHIDE(exp2))) { - /* successfully crossed mount point */ - exp_put(exp); - exp = exp2; + if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { dput(dentry); - dentry = mounts; - } else { - if (exp2) exp_put(exp2); - dput(mounts); + goto out_nfserr; } - mntput(mnt); } } /* @@ -1489,7 +1505,7 @@ out: * N.B. After this call fhp needs an fh_put */ int -nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat) +nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) { int err = fh_verify(rqstp, fhp, 0, MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat)) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 475799f476a..aaa7ec00b63 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1251,7 +1251,7 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol) * * Return 0 on success or -errno on error. */ -static int ntfs_statfs(struct super_block *sb, struct statfs *sfs) +static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs) { ntfs_volume *vol = NTFS_SB(sb); s64 size; diff --git a/fs/open.c b/fs/open.c index fac3d44702d..2e2e4e4dae9 100644 --- a/fs/open.c +++ b/fs/open.c @@ -23,23 +23,85 @@ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) -int vfs_statfs(struct super_block *sb, struct statfs *buf) +int vfs_statfs(struct super_block *sb, struct kstatfs *buf) { int retval = -ENODEV; if (sb) { retval = -ENOSYS; if (sb->s_op->statfs) { - memset(buf, 0, sizeof(struct statfs)); + memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(sb); if (retval) return retval; retval = sb->s_op->statfs(sb, buf); + if (retval == 0 && buf->f_frsize == 0) + buf->f_frsize = buf->f_bsize; } } return retval; } +static int vfs_statfs_native(struct super_block *sb, struct statfs *buf) +{ + struct kstatfs st; + int retval; + + retval = vfs_statfs(sb, &st); + if (retval) + return retval; + + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { + if (sizeof buf->f_blocks == 4) { + if ((st.f_blocks | st.f_bfree | + st.f_bavail | st.f_files | st.f_ffree) & + 0xffffffff00000000ULL) + return -EOVERFLOW; + } + + buf->f_type = st.f_type; + buf->f_bsize = st.f_bsize; + buf->f_blocks = st.f_blocks; + buf->f_bfree = st.f_bfree; + buf->f_bavail = st.f_bavail; + buf->f_files = st.f_files; + buf->f_ffree = st.f_ffree; + buf->f_fsid = st.f_fsid; + buf->f_namelen = st.f_namelen; + buf->f_frsize = st.f_frsize; + memset(buf->f_spare, 0, sizeof(buf->f_spare)); + } + return 0; +} + +static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf) +{ + struct kstatfs st; + int retval; + + retval = vfs_statfs(sb, &st); + if (retval) + return retval; + + if (sizeof(*buf) == sizeof(st)) + memcpy(buf, &st, sizeof(st)); + else { + buf->f_type = st.f_type; + buf->f_bsize = st.f_bsize; + buf->f_blocks = st.f_blocks; + buf->f_bfree = st.f_bfree; + buf->f_bavail = st.f_bavail; + buf->f_files = st.f_files; + buf->f_ffree = st.f_ffree; + buf->f_fsid = st.f_fsid; + buf->f_namelen = st.f_namelen; + buf->f_frsize = st.f_frsize; + memset(buf->f_spare, 0, sizeof(buf->f_spare)); + } + return 0; +} asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) { @@ -49,14 +111,34 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; - error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs))) + error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; path_release(&nd); } return error; } + +asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf) +{ + struct nameidata nd; + long error; + + if (sz != sizeof(*buf)) + return -EINVAL; + error = user_path_walk(path, &nd); + if (!error) { + struct statfs64 tmp; + error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + path_release(&nd); + } + return error; +} + + asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) { struct file * file; @@ -67,8 +149,29 @@ asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user * buf) file = fget(fd); if (!file) goto out; - error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs))) + error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) + error = -EFAULT; + fput(file); +out: + return error; +} + +asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user *buf) +{ + struct file * file; + struct statfs64 tmp; + int error; + + if (sz != sizeof(*buf)) + return -EINVAL; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp); + if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; fput(file); out: diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index 5b51ac3c3a4..34e7225c303 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig @@ -20,7 +20,17 @@ config ACORN_PARTITION help Support hard disks partitioned under Acorn operating systems. -# bool ' Cumana partition support' CONFIG_ACORN_PARTITION_CUMANA +config ACORN_PARTITION_CUMANA + bool "Cumana partition support" if PARTITION_ADVANCED && ACORN_PARTITION + default y if !PARTITION_ADVANCED && ARCH_ACORN + help + Say Y here if you would like to use hard disks under Linux which + were partitioned using the Cumana interface on Acorn machines. + +config ACORN_PARTITION_EESOX + bool "EESOX partition support" if PARTITION_ADVANCED && ACORN_PARTITION + default y if !PARTITION_ADVANCED && ARCH_ACORN + config ACORN_PARTITION_ICS bool "ICS partition support" if PARTITION_ADVANCED && ACORN_PARTITION default y if !PARTITION_ADVANCED && ARCH_ACORN diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index 2516a2027b0..5706a8893f3 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -7,14 +7,25 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Scan ADFS partitions on hard disk drives. + * Scan ADFS partitions on hard disk drives. Unfortunately, there + * isn't a standard for partitioning drives on Acorn machines, so + * every single manufacturer of SCSI and IDE cards created their own + * method. */ #include #include +#include #include "check.h" #include "acorn.h" +/* + * Partition types. (Oh for reusability) + */ +#define PARTITION_RISCIX_MFM 1 +#define PARTITION_RISCIX_SCSI 2 +#define PARTITION_LINUX 9 + static struct adfs_discrecord * adfs_partition(struct parsed_partitions *state, char *name, char *data, unsigned long first_sector, int slot) @@ -40,6 +51,21 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data, } #ifdef CONFIG_ACORN_PARTITION_RISCIX + +struct riscix_part { + __u32 start; + __u32 length; + __u32 one; + char name[16]; +}; + +struct riscix_record { + __u32 magic; +#define RISCIX_MAGIC (0x4a657320) + __u32 date; + struct riscix_part part[8]; +}; + static int riscix_partition(struct parsed_partitions *state, struct block_device *bdev, unsigned long first_sect, int slot, unsigned long nr_sects) @@ -81,6 +107,15 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev, } #endif +#define LINUX_NATIVE_MAGIC 0xdeafa1de +#define LINUX_SWAP_MAGIC 0xdeafab1e + +struct linux_part { + __u32 magic; + __u32 start_sect; + __u32 nr_sects; +}; + static int linux_partition(struct parsed_partitions *state, struct block_device *bdev, unsigned long first_sect, int slot, unsigned long nr_sects) @@ -114,7 +149,7 @@ linux_partition(struct parsed_partitions *state, struct block_device *bdev, } #ifdef CONFIG_ACORN_PARTITION_CUMANA -static int +int adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev) { unsigned long first_sector = 0; @@ -126,7 +161,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev int slot = 1; /* - * Try Cumana style partitions - sector 3 contains ADFS boot block + * Try Cumana style partitions - sector 6 contains ADFS boot block * with pointer to next 'drive'. * * There are unknowns in this code - is the 'cylinder number' of the @@ -206,7 +241,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev * hda1 = ADFS partition on first drive. * hda2 = non-ADFS partition. */ -static int +int adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev) { unsigned long start_sect, nr_sects, sectscyl, heads; @@ -263,11 +298,18 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev) break; } } + printk("\n"); return 1; } #endif #ifdef CONFIG_ACORN_PARTITION_ICS + +struct ics_part { + __u32 start; + __s32 size; +}; + static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block) { Sector sect; @@ -284,6 +326,22 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc } /* + * Check for a valid ICS partition using the checksum. + */ +static inline int valid_ics_sector(const unsigned char *data) +{ + unsigned long sum; + int i; + + for (i = 0, sum = 0x50617274; i < 508; i++) + sum += data[i]; + + sum -= le32_to_cpu(*(__u32 *)(&data[508])); + + return sum == 0; +} + +/* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. * dev - device number to access. @@ -293,15 +351,13 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -static int +int adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) { - Sector sect; - unsigned char *data; - unsigned long sum; - unsigned int i; + const unsigned char *data; + const struct ics_part *p; int slot; - struct ics_part *p; + Sector sect; /* * Try ICS style partitions - sector 0 contains partition info. @@ -310,33 +366,33 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) if (!data) return -1; - /* - * check for a valid checksum - */ - for (i = 0, sum = 0x50617274; i < 508; i++) - sum += data[i]; - - sum -= le32_to_cpu(*(__u32 *)(&data[508])); - if (sum) { + if (!valid_ics_sector(data)) { put_dev_sector(sect); - return 0; /* not ICS partition table */ + return 0; } printk(" [ICS]"); - for (slot = 1, p = (struct ics_part *)data; p->size; p++) { + for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { u32 start = le32_to_cpu(p->start); - u32 size = le32_to_cpu(p->size); + s32 size = le32_to_cpu(p->size); /* yes, it's signed. */ if (slot == state->limit) break; + /* + * Negative sizes tell the RISC OS ICS driver to ignore + * this partition - in effect it says that this does not + * contain an ADFS filesystem. + */ if (size < 0) { size = -size; /* - * We use the first sector to identify what type - * this partition is... + * Our own extension - We use the first sector + * of the partition to identify what type this + * partition is. We must not make this visible + * to the filesystem. */ if (size > 1 && adfspart_check_ICSLinux(bdev, start)) { start += 1; @@ -349,10 +405,39 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) } put_dev_sector(sect); + printk("\n"); return 1; } #endif +#ifdef CONFIG_ACORN_PARTITION_POWERTEC +struct ptec_part { + __u32 unused1; + __u32 unused2; + __u32 start; + __u32 size; + __u32 unused5; + char type[8]; +}; + +static inline int valid_ptec_sector(const unsigned char *data) +{ + unsigned char checksum = 0x2a; + int i; + + /* + * If it looks like a PC/BIOS partition, then it + * probably isn't PowerTec. + */ + if (data[510] == 0x55 && data[511] == 0xaa) + return 0; + + for (i = 0; i < 511; i++) + checksum += data[i]; + + return checksum == data[511]; +} + /* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. @@ -363,14 +448,12 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -#ifdef CONFIG_ACORN_PARTITION_POWERTEC -static int +int adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev) { Sector sect; - unsigned char *data; - struct ptec_partition *p; - unsigned char checksum; + const unsigned char *data; + const struct ptec_part *p; int slot = 1; int i; @@ -378,17 +461,14 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd if (!data) return -1; - for (checksum = 0x2a, i = 0; i < 511; i++) - checksum += data[i]; - - if (checksum != data[511]) { + if (!valid_ptec_sector(data)) { put_dev_sector(sect); return 0; } printk(" [POWERTEC]"); - for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { + for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { u32 start = le32_to_cpu(p->start); u32 size = le32_to_cpu(p->size); @@ -397,46 +477,81 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd } put_dev_sector(sect); + printk("\n"); return 1; } #endif -static int (*partfn[])(struct parsed_partitions *, struct block_device *) = { -#ifdef CONFIG_ACORN_PARTITION_ICS - adfspart_check_ICS, -#endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - adfspart_check_POWERTEC, -#endif -#ifdef CONFIG_ACORN_PARTITION_CUMANA - adfspart_check_CUMANA, -#endif -#ifdef CONFIG_ACORN_PARTITION_ADFS - adfspart_check_ADFS, -#endif - NULL +#ifdef CONFIG_ACORN_PARTITION_EESOX +struct eesox_part { + char magic[6]; + char name[10]; + u32 start; + u32 unused6; + u32 unused7; + u32 unused8; +}; + +/* + * Guess who created this format? + */ +static const char eesox_name[] = { + 'N', 'e', 'i', 'l', ' ', + 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' }; + /* - * Purpose: initialise all the partitions on an ADFS drive. - * These may be other ADFS partitions or a Linux/RiscBSD/RISCiX - * partition. + * EESOX SCSI partition format. * - * Params : hd - pointer to gendisk structure - * dev - device number to access + * This is a goddamned awful partition format. We don't seem to store + * the size of the partition in this table, only the start addresses. * - * Returns: -1 on error, 0 if not ADFS format, 1 if ok. + * There are two possibilities where the size comes from: + * 1. The individual ADFS boot block entries that are placed on the disk. + * 2. The start address of the next entry. */ -int acorn_partition(struct parsed_partitions *state, struct block_device *bdev) +int +adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev) { - int i; + Sector sect; + const unsigned char *data; + unsigned char buffer[256]; + struct eesox_part *p; + u32 start = 0; + int i, slot = 1; - for (i = 0; partfn[i]; i++) { - int r = partfn[i](state, bdev); - if (r) { - if (r > 0) - printk("\n"); - return r; - } + data = read_dev_sector(bdev, 7, §); + if (!data) + return -1; + + /* + * "Decrypt" the partition table. God knows why... + */ + for (i = 0; i < 256; i++) + buffer[i] = data[i] ^ eesox_name[i & 15]; + + put_dev_sector(sect); + + for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { + u32 next; + + if (memcmp(p->magic, "Eesox", 6)) + break; + + next = le32_to_cpu(p->start) + first_sector; + if (i) + put_partition(state, slot++, start, next - start); + start = next; } - return 0; + + if (i != 0) { + unsigned long size; + + size = hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects; + add_gd_partition(hd, minor++, start, size - start); + printk("\n"); + } + + return i ? 1 : 0; } +#endif diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h dissimilarity index 98% index 7c984234ae8..81fd50ecc08 100644 --- a/fs/partitions/acorn.h +++ b/fs/partitions/acorn.h @@ -1,53 +1,14 @@ -/* - * fs/partitions/acorn.h - * - * Copyright (C) 1996-1998 Russell King - */ -#include - -/* - * Partition types. (Oh for reusability) - */ -#define PARTITION_RISCIX_MFM 1 -#define PARTITION_RISCIX_SCSI 2 -#define PARTITION_LINUX 9 - -struct riscix_part { - __u32 start; - __u32 length; - __u32 one; - char name[16]; -}; - -struct riscix_record { - __u32 magic; -#define RISCIX_MAGIC (0x4a657320) - __u32 date; - struct riscix_part part[8]; -}; - -#define LINUX_NATIVE_MAGIC 0xdeafa1de -#define LINUX_SWAP_MAGIC 0xdeafab1e - -struct linux_part { - __u32 magic; - __u32 start_sect; - __u32 nr_sects; -}; - -struct ics_part { - __u32 start; - __s32 size; -}; - -struct ptec_partition { - __u32 unused1; - __u32 unused2; - __u32 start; - __u32 size; - __u32 unused5; - char type[8]; -}; - - -int acorn_partition(struct parsed_partitions *state, struct block_device *bdev); +/* + * linux/fs/partitions/acorn.h + * + * Copyright (C) 1996-2001 Russell King. + * + * I _hate_ this partitioning mess - why can't we have one defined + * format, and everyone stick to it? + */ + +int adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev); +int adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev); +int adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev); +int adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev); +int adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 88344a47bf2..f504430d7f0 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -45,9 +45,33 @@ extern void md_autodetect_dev(dev_t dev); int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = { -#ifdef CONFIG_ACORN_PARTITION - acorn_partition, + /* + * Probe partition formats with tables at disk address 0 + * that also have an ADFS boot block at 0xdc0. + */ +#ifdef CONFIG_ACORN_PARTITION_ICS + adfspart_check_ICS, #endif +#ifdef CONFIG_ACORN_PARTITION_POWERTEC + adfspart_check_POWERTEC, +#endif +#ifdef CONFIG_ACORN_PARTITION_EESOX + adfspart_check_EESOX, +#endif + + /* + * Now move on to formats that only have partition info at + * disk address 0xdc0. Since these may also have stale + * PC/BIOS partition tables, they need to come before + * the msdos entry. + */ +#ifdef CONFIG_ACORN_PARTITION_CUMANA + adfspart_check_CUMANA, +#endif +#ifdef CONFIG_ACORN_PARTITION_ADFS + adfspart_check_ADFS, +#endif + #ifdef CONFIG_EFI_PARTITION efi_partition, /* this must come before msdos */ #endif diff --git a/fs/proc/base.c b/fs/proc/base.c index d6415745561..e843c6584cc 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1362,10 +1362,11 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry) inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO); - put_task_struct(task); - if (!inode) + if (!inode) { + put_task_struct(task); goto out; + } inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_base_inode_operations; inode->i_fop = &proc_base_operations; @@ -1379,6 +1380,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry) d_add(dentry, inode); spin_unlock(&task->proc_lock); + put_task_struct(task); return NULL; out: return ERR_PTR(-ENOENT); diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index e70d8b03ddd..fa9f9cc4d51 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -451,8 +451,20 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t kfree(elf_buf); } else { if (kern_addr_valid(start)) { - if (copy_to_user(buffer, (char *)start, tsz)) - return -EFAULT; + unsigned long n; + + n = copy_to_user(buffer, (char *)start, tsz); + /* + * We cannot distingush between fault on source + * and fault on destination. When this happens + * we clear too and hope it will trigger the + * EFAULT again. + */ + if (n) { + if (clear_user(buffer + tsz - n, + tsz - n)) + return -EFAULT; + } } else { if (clear_user(buffer, tsz)) return -EFAULT; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index a9d6f99c186..3d7d759c63d 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -91,13 +91,13 @@ static int show_map(struct seq_file *m, void *v) } seq_printf(m, "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %lu %n", - 2*sizeof(void*), map->vm_start, - 2*sizeof(void*), map->vm_end, + (int) (2*sizeof(void*)), map->vm_start, + (int) (2*sizeof(void*)), map->vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', - 2*sizeof(void*), map->vm_pgoff << PAGE_SHIFT, + (int) (2*sizeof(void*)), map->vm_pgoff << PAGE_SHIFT, MAJOR(dev), MINOR(dev), ino, &len); if (map->vm_file) { diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 90f7a0034e6..c894b7ecac0 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -126,7 +126,7 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb); static void qnx4_destroy_inode(struct inode *inode); static void qnx4_read_inode(struct inode *); static int qnx4_remount(struct super_block *sb, int *flags, char *data); -static int qnx4_statfs(struct super_block *, struct statfs *); +static int qnx4_statfs(struct super_block *, struct kstatfs *); static struct super_operations qnx4_sops = { @@ -276,7 +276,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) return block; } -static int qnx4_statfs(struct super_block *sb, struct statfs *buf) +static int qnx4_statfs(struct super_block *sb, struct kstatfs *buf) { lock_kernel(); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 8ff47e47a2e..9f37ffd9276 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -62,7 +62,7 @@ int is_reiserfs_super (struct super_block *s) } static int reiserfs_remount (struct super_block * s, int * flags, char * data); -static int reiserfs_statfs (struct super_block * s, struct statfs * buf); +static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf); static void reiserfs_write_super (struct super_block * s) { @@ -1414,13 +1414,11 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent) } -static int reiserfs_statfs (struct super_block * s, struct statfs * buf) +static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf) { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); buf->f_namelen = (REISERFS_MAX_NAME (s->s_blocksize)); - buf->f_ffree = -1; - buf->f_files = -1; buf->f_bfree = sb_free_blocks(rs); buf->f_bavail = buf->f_bfree; buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index dd52de09689..fb60389d42f 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -176,7 +176,7 @@ outnobh: /* That's simple too. */ static int -romfs_statfs(struct super_block *sb, struct statfs *buf) +romfs_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = ROMFS_MAGIC; buf->f_bsize = ROMBSIZE; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index abe004b1e78..b3dd504d88e 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -47,7 +47,7 @@ static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); -static int smb_statfs(struct super_block *, struct statfs *); +static int smb_statfs(struct super_block *, struct kstatfs *); static int smb_show_options(struct seq_file *, struct vfsmount *); static kmem_cache_t *smb_inode_cachep; @@ -610,7 +610,7 @@ out_no_server: } static int -smb_statfs(struct super_block *sb, struct statfs *buf) +smb_statfs(struct super_block *sb, struct kstatfs *buf) { int result; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index e3221e28b88..8c386131c9e 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -3160,7 +3160,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr) } int -smb_proc_dskattr(struct super_block *sb, struct statfs *attr) +smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr) { struct smb_sb_info *server = SMB_SB(sb); int result; diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index ec44bad0e84..e42cf69c061 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -29,7 +29,7 @@ extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr); extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, unsigned int major, unsigned int minor); extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr); -extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr); +extern int smb_proc_dskattr(struct super_block *sb, struct kstatfs *attr); extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len); extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath); extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry); diff --git a/fs/super.c b/fs/super.c index 2aae8ed4cdc..8f1f26de167 100644 --- a/fs/super.c +++ b/fs/super.c @@ -409,7 +409,7 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf) { struct super_block *s; struct ustat tmp; - struct statfs sbuf; + struct kstatfs sbuf; int err = -EINVAL; s = user_get_super(dev); diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d433042d358..9a4564610aa 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -75,7 +75,7 @@ static void sysv_put_super(struct super_block *sb) kfree(sbi); } -static int sysv_statfs(struct super_block *sb, struct statfs *buf) +static int sysv_statfs(struct super_block *sb, struct kstatfs *buf) { struct sysv_sb_info *sbi = SYSV_SB(sb); diff --git a/fs/udf/super.c b/fs/udf/super.c index 00bfdd3d6a1..2b82a045181 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -95,7 +95,7 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); -static int udf_statfs(struct super_block *, struct statfs *); +static int udf_statfs(struct super_block *, struct kstatfs *); /* UDF filesystem type */ static struct super_block *udf_get_sb(struct file_system_type *fs_type, @@ -1720,7 +1720,7 @@ udf_put_super(struct super_block *sb) * Written, tested, and released. */ static int -udf_statfs(struct super_block *sb, struct statfs *buf) +udf_statfs(struct super_block *sb, struct kstatfs *buf) { buf->f_type = UDF_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index d9d96adb467..802ca517153 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -973,7 +973,7 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data) return 0; } -int ufs_statfs (struct super_block * sb, struct statfs * buf) +int ufs_statfs (struct super_block * sb, struct kstatfs * buf) { struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; @@ -988,8 +988,8 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf) buf->f_blocks = uspi->s_dsize; buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); - buf->f_bavail = (buf->f_bfree > ((buf->f_blocks / 100) * uspi->s_minfree)) - ? (buf->f_bfree - ((buf->f_blocks / 100) * uspi->s_minfree)) : 0; + buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree)) + ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0; buf->f_files = uspi->s_ncg * uspi->s_ipg; buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); buf->f_namelen = UFS_MAXNAMLEN; diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 7d2662e5903..160db99c007 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -477,7 +477,7 @@ linvfs_write_super( STATIC int linvfs_statfs( struct super_block *sb, - struct statfs *statp) + struct kstatfs *statp) { vfs_t *vfsp = LINVFS_GET_VFS(sb); int error; @@ -673,7 +673,7 @@ linvfs_fill_super( vnode_t *rootvp; struct vfs *vfsp = vfs_allocate(); struct xfs_mount_args *args = args_allocate(sb); - struct statfs statvfs; + struct kstatfs statvfs; int error; vfsp->vfs_super = sb; diff --git a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c index 86329735784..938a2a44947 100644 --- a/fs/xfs/linux/xfs_vfs.c +++ b/fs/xfs/linux/xfs_vfs.c @@ -134,7 +134,7 @@ vfs_root( int vfs_statvfs( struct bhv_desc *bdp, - struct statfs *sp, + struct kstatfs *sp, struct vnode *vp) { struct bhv_desc *next = bdp; diff --git a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h index 3379ecbdc28..4fdc33919ee 100644 --- a/fs/xfs/linux/xfs_vfs.h +++ b/fs/xfs/linux/xfs_vfs.h @@ -37,7 +37,7 @@ struct fid; struct cred; struct vnode; -struct statfs; +struct kstatfs; struct seq_file; struct super_block; struct xfs_mount_args; @@ -100,7 +100,7 @@ typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, struct xfs_mount_args *); typedef int (*vfs_root_t)(bhv_desc_t *, struct vnode **); -typedef int (*vfs_statvfs_t)(bhv_desc_t *, struct statfs *, struct vnode *); +typedef int (*vfs_statvfs_t)(bhv_desc_t *, struct kstatfs *, struct vnode *); typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); typedef int (*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *); typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); @@ -167,7 +167,7 @@ extern int vfs_showargs(bhv_desc_t *, struct seq_file *); extern int vfs_unmount(bhv_desc_t *, int, struct cred *); extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); extern int vfs_root(bhv_desc_t *, struct vnode **); -extern int vfs_statvfs(bhv_desc_t *, struct statfs *, struct vnode *); +extern int vfs_statvfs(bhv_desc_t *, struct kstatfs *, struct vnode *); extern int vfs_sync(bhv_desc_t *, int, struct cred *); extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *); extern int vfs_dmapiops(bhv_desc_t *, caddr_t); diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index f19ace802b6..4f1af83546f 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -752,7 +752,7 @@ xfs_root( STATIC int xfs_statvfs( bhv_desc_t *bdp, - struct statfs *statp, + struct kstatfs *statp, vnode_t *vp) { __uint64_t fakeinos; @@ -782,7 +782,7 @@ xfs_statvfs( if (!mp->m_inoadd) #endif statp->f_files = - MIN(statp->f_files, (long)mp->m_maxicount); + min_t(sector_t, statp->f_files, mp->m_maxicount); statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); XFS_SB_UNLOCK(mp, s); diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 3fda218d6de..329cdaafe22 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20030522 +#define ACPI_CA_VERSION 0x20030619 /* Maximum objects in the various object caches */ diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 254d11a7ac5..8520f1372cc 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -105,6 +105,7 @@ ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; */ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width; +ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; diff --git a/include/acpi/achware.h b/include/acpi/achware.h index 4be6958950e..9fbb1b0e9c8 100644 --- a/include/acpi/achware.h +++ b/include/acpi/achware.h @@ -108,7 +108,7 @@ acpi_hw_low_level_write ( acpi_status acpi_hw_clear_acpi_status ( - void); + u32 flags); /* GPE support */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 0d495da9ab1..bb6df66442b 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -287,15 +287,15 @@ acpi_os_derive_pci_id( * Miscellaneous */ -BOOLEAN +u8 acpi_os_readable ( void *pointer, - u32 length); + acpi_size length); -BOOLEAN +u8 acpi_os_writable ( void *pointer, - u32 length); + acpi_size length); u32 acpi_os_get_timer ( diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index d077d741968..beec737952a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -50,11 +50,14 @@ /* * Data type ranges + * Note: These macros are designed to be compiler independent as well as + * working around problems that some 32-bit compilers have with 64-bit + * constants. */ -#define ACPI_UINT8_MAX (~((UINT8) 0)) -#define ACPI_UINT16_MAX (~((UINT16) 0)) -#define ACPI_UINT32_MAX (~((UINT32) 0)) -#define ACPI_UINT64_MAX (~((UINT64) 0)) +#define ACPI_UINT8_MAX (UINT8) (~((UINT8) 0)) /* 0xFF */ +#define ACPI_UINT16_MAX (UINT16)(~((UINT16) 0)) /* 0xFFFF */ +#define ACPI_UINT32_MAX (UINT32)(~((UINT32) 0)) /* 0xFFFFFFFF */ +#define ACPI_UINT64_MAX (UINT64)(~((UINT64) 0)) /* 0xFFFFFFFFFFFFFFFF */ #define ACPI_ASCII_MAX 0x7F @@ -299,8 +302,6 @@ struct uint32_struct typedef u32 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT32_MAX #define ACPI_INTEGER_BIT_SIZE 32 -#define ACPI_MAX_BCD_VALUE 99999999 -#define ACPI_MAX_BCD_DIGITS 8 #define ACPI_MAX_DECIMAL_DIGITS 10 #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */ @@ -313,12 +314,6 @@ typedef u32 acpi_integer; typedef u64 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 -#if ACPI_MACHINE_WIDTH == 64 -#define ACPI_MAX_BCD_VALUE 9999999999999999UL -#else -#define ACPI_MAX_BCD_VALUE 9999999999999999ULL -#endif -#define ACPI_MAX_BCD_DIGITS 16 #define ACPI_MAX_DECIMAL_DIGITS 19 #if ACPI_MACHINE_WIDTH == 64 diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index d23b1f5db70..34d0376dc32 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -194,6 +194,18 @@ pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index +/* Bus number == domain number until we get above 256 busses */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + int domain = pci_domain_nr(bus) + if (domain < 256) { + sprintf(name, "%02x", domain); + } else { + sprintf(name, "%04x:%02x", domain, bus->number); + } + return 0; +} + #endif /* __KERNEL__ */ /* Values for the `which' argument to sys_pciconfig_iobase. */ diff --git a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h index 1526b07d625..29c69713304 100644 --- a/include/asm-alpha/smp.h +++ b/include/asm-alpha/smp.h @@ -57,6 +57,15 @@ num_online_cpus(void) return hweight64(cpu_online_map); } +extern inline int +any_online_cpu(unsigned int mask) +{ + if (mask & cpu_online_map) + return __ffs(mask & cpu_online_map); + + return -1; +} + extern int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, unsigned long cpu); #else /* CONFIG_SMP */ diff --git a/include/asm-alpha/statfs.h b/include/asm-alpha/statfs.h index cc4ba1de0ed..ad15830baef 100644 --- a/include/asm-alpha/statfs.h +++ b/include/asm-alpha/statfs.h @@ -1,25 +1,6 @@ #ifndef _ALPHA_STATFS_H #define _ALPHA_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - int f_type; - int f_bsize; - int f_blocks; - int f_bfree; - int f_bavail; - int f_files; - int f_ffree; - __kernel_fsid_t f_fsid; - int f_namelen; - int f_spare[6]; -}; +#include #endif diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index 7b500d3cfda..38faced4d0a 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h @@ -593,13 +593,7 @@ static inline long read(int fd, char * buf, size_t nr) return sys_read(fd, buf, nr); } -extern int __kernel_execve(char *, char **, char **, struct pt_regs *); -static inline long execve(char * file, char ** argvp, char ** envp) -{ - struct pt_regs regs; - memset(®s, 0, sizeof(regs)); - return __kernel_execve(file, argvp, envp, ®s); -} +extern long execve(char *, char **, char **); extern long sys_setsid(void); static inline long setsid(void) diff --git a/include/asm-alpha/xor.h b/include/asm-alpha/xor.h index a88d79d6e3a..5ee1c2bc049 100644 --- a/include/asm-alpha/xor.h +++ b/include/asm-alpha/xor.h @@ -822,19 +822,19 @@ xor_alpha_prefetch_5: \n\ "); static struct xor_block_template xor_block_alpha = { - name: "alpha", - do_2: xor_alpha_2, - do_3: xor_alpha_3, - do_4: xor_alpha_4, - do_5: xor_alpha_5, + .name = "alpha", + .do_2 = xor_alpha_2, + .do_3 = xor_alpha_3, + .do_4 = xor_alpha_4, + .do_5 = xor_alpha_5, }; static struct xor_block_template xor_block_alpha_prefetch = { - name: "alpha prefetch", - do_2: xor_alpha_prefetch_2, - do_3: xor_alpha_prefetch_3, - do_4: xor_alpha_prefetch_4, - do_5: xor_alpha_prefetch_5, + .name = "alpha prefetch", + .do_2 = xor_alpha_prefetch_2, + .do_3 = xor_alpha_prefetch_3, + .do_4 = xor_alpha_prefetch_4, + .do_5 = xor_alpha_prefetch_5, }; /* For grins, also test the generic routines. */ diff --git a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h new file mode 100644 index 00000000000..b4c839de547 --- /dev/null +++ b/include/asm-arm/hardware/amba.h @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/hardware/amba.h + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASMARM_AMBA_H +#define ASMARM_AMBA_H + +struct amba_device { + struct device dev; + struct resource res; + unsigned int irq; + unsigned int periphid; +}; + +struct amba_id { + unsigned int id; + unsigned int mask; + void *data; +}; + +struct amba_driver { + struct device_driver drv; + int (*probe)(struct amba_device *, void *); + int (*remove)(struct amba_device *); + void (*shutdown)(struct amba_device *); + int (*suspend)(struct amba_device *, u32, u32); + int (*resume)(struct amba_device *, u32); + struct amba_id *id_table; +}; + +#define amba_get_drvdata(d) dev_get_drvdata(&d->dev) +#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p) + +int amba_driver_register(struct amba_driver *); +void amba_driver_unregister(struct amba_driver *); +int amba_device_register(struct amba_device *, struct resource *); +void amba_device_unregister(struct amba_device *); + +#endif diff --git a/include/asm-arm/hardware/icst525.h b/include/asm-arm/hardware/icst525.h new file mode 100644 index 00000000000..edd5a570440 --- /dev/null +++ b/include/asm-arm/hardware/icst525.h @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/hardware/icst525.h + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST525 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + */ +#ifndef ASMARM_HARDWARE_ICST525_H +#define ASMARM_HARDWARE_ICST525_H + +struct icst525_params { + unsigned long ref; + unsigned long vco_max; /* inclusive */ + unsigned short vd_min; /* inclusive */ + unsigned short vd_max; /* inclusive */ + unsigned char rd_min; /* inclusive */ + unsigned char rd_max; /* inclusive */ +}; + +struct icst525_vco { + unsigned short v; + unsigned char r; + unsigned char s; +}; + +unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco); +struct icst525_vco icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq); +struct icst525_vco icst525_ps_to_vco(const struct icst525_params *p, unsigned long period); + +#endif diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h index 38682a28d12..1b61a0e02c2 100644 --- a/include/asm-arm/memory.h +++ b/include/asm-arm/memory.h @@ -27,6 +27,9 @@ /* * These are *only* valid on the kernel direct mapped RAM memory. + * Note: Drivers should NOT use these. They are the wrong + * translation for translating DMA addresses. Use the driver + * DMA support - see dma-mapping.h. */ static inline unsigned long virt_to_phys(void *x) { @@ -38,6 +41,9 @@ static inline void *phys_to_virt(unsigned long x) return (void *)(__phys_to_virt((unsigned long)(x))); } +/* + * Drivers should NOT use these either. + */ #define __pa(x) __virt_to_phys((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) @@ -72,7 +78,7 @@ static inline void *phys_to_virt(unsigned long x) #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) -#define virt_addr_valid(kaddr) ((kaddr) >= PAGE_OFFSET && (kaddr) < (unsigned long)high_memory) +#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) #define PHYS_TO_NID(addr) (0) diff --git a/include/asm-arm/proc-armv/uaccess.h b/include/asm-arm/proc-armv/uaccess.h index 25154d53177..b871c78160b 100644 --- a/include/asm-arm/proc-armv/uaccess.h +++ b/include/asm-arm/proc-armv/uaccess.h @@ -87,10 +87,18 @@ static inline void set_fs (mm_segment_t fs) : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ : "cc") +#ifndef __ARMEB__ +#define __reg_oper0 "%R2" +#define __reg_oper1 "%Q2" +#else +#define __reg_oper0 "%Q2" +#define __reg_oper1 "%R2" +#endif + #define __put_user_asm_dword(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strt %Q2, [%1], #4\n" \ - "2: strt %R2, [%1], #0\n" \ + "1: strt " __reg_oper1 ", [%1], #4\n" \ + "2: strt " __reg_oper0 ", [%1], #0\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ diff --git a/include/asm-arm/statfs.h b/include/asm-arm/statfs.h index a1eba73ded9..e81f82783b8 100644 --- a/include/asm-arm/statfs.h +++ b/include/asm-arm/statfs.h @@ -1,25 +1,6 @@ #ifndef _ASMARM_STATFS_H #define _ASMARM_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-cris/statfs.h b/include/asm-cris/statfs.h index 9bfcc5ea280..fdaf921844b 100644 --- a/include/asm-cris/statfs.h +++ b/include/asm-cris/statfs.h @@ -1,25 +1,6 @@ #ifndef _CRIS_STATFS_H #define _CRIS_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-generic/statfs.h b/include/asm-generic/statfs.h new file mode 100644 index 00000000000..fecaf8fd5c1 --- /dev/null +++ b/include/asm-generic/statfs.h @@ -0,0 +1,37 @@ +#ifndef _GENERIC_STATFS_H +#define _GENERIC_STATFS_H + +#ifndef __KERNEL_STRICT_NAMES +# include +typedef __kernel_fsid_t fsid_t; +#endif + +struct statfs { + __u32 f_type; + __u32 f_bsize; + __u32 f_blocks; + __u32 f_bfree; + __u32 f_bavail; + __u32 f_files; + __u32 f_ffree; + __kernel_fsid_t f_fsid; + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; + +struct statfs64 { + __u32 f_type; + __u32 f_bsize; + __u64 f_blocks; + __u64 f_bfree; + __u64 f_bavail; + __u64 f_files; + __u64 f_ffree; + __kernel_fsid_t f_fsid; + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; + +#endif diff --git a/include/asm-h8300/statfs.h b/include/asm-h8300/statfs.h index 9e3be68f0c0..b96efa712aa 100644 --- a/include/asm-h8300/statfs.h +++ b/include/asm-h8300/statfs.h @@ -1,25 +1,6 @@ #ifndef _H8300_STATFS_H #define _H8300_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif /* _H8300_STATFS_H */ diff --git a/include/asm-h8300/uaccess.h b/include/asm-h8300/uaccess.h index 24a0b92b13e..6996b612f4a 100644 --- a/include/asm-h8300/uaccess.h +++ b/include/asm-h8300/uaccess.h @@ -6,6 +6,8 @@ */ #include #include +#include + #include #define VERIFY_READ 0 @@ -159,7 +161,7 @@ static inline unsigned long clear_user(void *to, unsigned long n) { memset(to, 0, n); - return(0); + return 0; } #endif /* _H8300_UACCESS_H */ diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index cdb2f1ecfc0..0f158dc1615 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -106,6 +106,10 @@ :"0"(n_hi), "1"(n_lo)) +#ifdef CONFIG_ACPI_HT_ONLY +extern int acpi_lapic; +#define acpi_ioapic 0 +#else #ifndef CONFIG_ACPI_BOOT #define acpi_lapic 0 #define acpi_ioapic 0 @@ -120,6 +124,7 @@ extern int acpi_ioapic; #else #define acpi_ioapic 0 #endif +#endif /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index b8d28b5cced..bee92c982f6 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h @@ -81,6 +81,8 @@ extern void setup_secondary_APIC_clock (void); extern void setup_apic_nmi_watchdog (void); extern void disable_lapic_nmi_watchdog(void); extern void enable_lapic_nmi_watchdog(void); +extern void disable_timer_nmi_watchdog(void); +extern void enable_timer_nmi_watchdog(void); extern inline void nmi_watchdog_tick (struct pt_regs * regs); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); diff --git a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h index 0fb2bd405e9..9b85a2259b4 100644 --- a/include/asm-i386/genapic.h +++ b/include/asm-i386/genapic.h @@ -43,6 +43,7 @@ struct genapic { struct mpc_config_translation *t); void (*setup_portio_remap)(void); int (*check_phys_apicid_present)(int boot_cpu_physical_apicid); + void (*enable_apic_mode)(void); /* mpparse */ void (*mpc_oem_bus_info)(struct mpc_config_bus *, char *, @@ -101,6 +102,7 @@ struct genapic { APICFUNC(send_IPI_mask), \ APICFUNC(send_IPI_allbutself), \ APICFUNC(send_IPI_all), \ + APICFUNC(enable_apic_mode), \ } extern struct genapic *genapic; diff --git a/include/asm-i386/mach-default/mach_resources.h b/include/asm-i386/mach-default/mach_resources.h index 2b0eadaaca2..b37858d0d0b 100644 --- a/include/asm-i386/mach-default/mach_resources.h +++ b/include/asm-i386/mach-default/mach_resources.h @@ -9,18 +9,14 @@ struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, - { "pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + { "pic1", 0x20, 0x21, IORESOURCE_BUSY }, { "timer", 0x40, 0x5f, IORESOURCE_BUSY }, { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY }, { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, - { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY }, { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY }, { "fpu", 0xf0, 0xff, IORESOURCE_BUSY } }; -#ifdef CONFIG_MELAN -standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY }; -standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY }; -#endif #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) diff --git a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h index 54fa2a48b23..71b4849614b 100644 --- a/include/asm-i386/mach-generic/mach_apic.h +++ b/include/asm-i386/mach-generic/mach_apic.h @@ -25,5 +25,6 @@ #define check_phys_apicid_present (genapic->check_phys_apicid_present) #define check_apicid_used (genapic->check_apicid_used) #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) +#define enable_apic_mode (genapic->enable_apic_mode) #endif /* __ASM_MACH_APIC_H */ diff --git a/include/asm-i386/mach-pc9800/setup_arch_pre.h b/include/asm-i386/mach-pc9800/setup_arch_pre.h index 47d5f0c7c14..bd53bddd695 100644 --- a/include/asm-i386/mach-pc9800/setup_arch_pre.h +++ b/include/asm-i386/mach-pc9800/setup_arch_pre.h @@ -25,8 +25,8 @@ static inline void arch_setup_pc9800(void) { CLOCK_TICK_RATE = PC9800_8MHz_P() ? 1996800 : 2457600; printk(KERN_DEBUG "CLOCK_TICK_RATE = %d\n", CLOCK_TICK_RATE); - tick_usec = TICK_USEC; /* ACTHZ period (usec) */ - tick_nsec = TICK_NSEC; /* USER_HZ period (nsec) */ + tick_usec = TICK_USEC; /* USER_HZ period (usec) */ + tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */ pc9800_misc_flags = PC9800_MISC_FLAGS; #ifdef CONFIG_SMP diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 77093812903..ac14135d83b 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -468,6 +468,7 @@ extern void prepare_to_copy(struct task_struct *tsk); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern unsigned long thread_saved_pc(struct task_struct *tsk); +void show_trace(struct task_struct *task, unsigned long *stack); unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)->thread_info))[1019]) diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 71dd76aa0d8..ea83e1dc866 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -78,12 +78,12 @@ static inline int num_booting_cpus(void) extern void map_cpu_to_logical_apicid(void); extern void unmap_cpu_to_logical_apicid(int cpu); -extern inline int any_online_cpu(unsigned int mask) +extern inline unsigned int any_online_cpu(unsigned int mask) { if (mask & cpu_online_map) return __ffs(mask & cpu_online_map); - return -1; + return NR_CPUS; } #ifdef CONFIG_X86_LOCAL_APIC diff --git a/include/asm-i386/statfs.h b/include/asm-i386/statfs.h index 113d5d428aa..24972c17513 100644 --- a/include/asm-i386/statfs.h +++ b/include/asm-i386/statfs.h @@ -1,25 +1,6 @@ #ifndef _I386_STATFS_H #define _I386_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h index 07caa21a978..b7744806aed 100644 --- a/include/asm-i386/uaccess.h +++ b/include/asm-i386/uaccess.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #define VERIFY_READ 0 @@ -494,6 +495,8 @@ copy_from_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); + else + memset(to, 0, n); return n; } diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 84d35a14522..b1bdc016eed 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h @@ -273,8 +273,10 @@ #define __NR_clock_gettime (__NR_timer_create+6) #define __NR_clock_getres (__NR_timer_create+7) #define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 -#define NR_syscalls 268 +#define NR_syscalls 270 /* user-visible error numbers are in the range -1 - -124: see */ diff --git a/include/asm-ia64/a.out.h b/include/asm-ia64/a.out.h index 79fa7cf39ff..1660b798c8e 100644 --- a/include/asm-ia64/a.out.h +++ b/include/asm-ia64/a.out.h @@ -30,9 +30,6 @@ struct exec { #define N_TXTOFF(x) 0 #ifdef __KERNEL__ -# include -# define STACK_TOP (0x6000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) -# define IA64_RBS_BOT (STACK_TOP - 0x80000000L + PAGE_SIZE) /* bottom of reg. backing store */ +#include #endif - #endif /* _ASM_IA64_A_OUT_H */ diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h index d3c3a0998f4..198c4c202c4 100644 --- a/include/asm-ia64/asmmacro.h +++ b/include/asm-ia64/asmmacro.h @@ -43,21 +43,25 @@ name: .section "__ex_table", "a" // declare section & section attributes .previous -#if __GNUC__ >= 3 # define EX(y,x...) \ .xdata4 "__ex_table", 99f-., y-.; \ [99:] x # define EXCLR(y,x...) \ .xdata4 "__ex_table", 99f-., y-.+4; \ [99:] x -#else -# define EX(y,x...) \ - .xdata4 "__ex_table", 99f-., y-.; \ - 99: x -# define EXCLR(y,x...) \ - .xdata4 "__ex_table", 99f-., y-.+4; \ - 99: x -#endif + +/* + * Mark instructions that need a load of a virtual address patched to be + * a load of a physical address. We use this either in critical performance + * path (ivt.S - TLB miss processing) or in places where it might not be + * safe to use a "tpa" instruction (mca_asm.S - error recovery). + */ + .section ".data.patch.vtop", "a" // declare section & section attributes + .previous + +#define LOAD_PHYSICAL(pr, reg, obj) \ +[1:](pr)movl reg = obj; \ + .xdata4 ".data.patch.vtop", 1b-. /* * For now, we always put in the McKinley E9 workaround. On CPUs that don't need it, @@ -65,11 +69,11 @@ name: */ #define DO_MCKINLEY_E9_WORKAROUND #ifdef DO_MCKINLEY_E9_WORKAROUND - .section "__mckinley_e9_bundles", "a" + .section ".data.patch.mckinley_e9", "a" .previous /* workaround for Itanium 2 Errata 9: */ # define MCKINLEY_E9_WORKAROUND \ - .xdata4 "__mckinley_e9_bundles", 1f-.; \ + .xdata4 ".data.patch.mckinley_e9", 1f-.;\ 1:{ .mib; \ nop.m 0; \ nop.i 0; \ diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h index 9473a87a525..b8c101e54e4 100644 --- a/include/asm-ia64/compat.h +++ b/include/asm-ia64/compat.h @@ -99,7 +99,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff @@ -128,4 +129,11 @@ compat_ptr (compat_uptr_t uptr) return (void *) (unsigned long) uptr; } +static __inline__ void * +compat_alloc_user_space (long len) +{ + struct pt_regs *regs = ia64_task_regs(current); + return (void *) ((regs->r12 & -16) - len); +} + #endif /* _ASM_IA64_COMPAT_H */ diff --git a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h index 4ff7995fae2..1423a707498 100644 --- a/include/asm-ia64/elf.h +++ b/include/asm-ia64/elf.h @@ -42,6 +42,93 @@ */ #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x800000000) +#define PT_IA_64_UNWIND 0x70000001 + +/* IA-64 relocations: */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym+add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym+add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym+add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym+add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym+add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym+add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym+add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym+add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym+add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym+add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym+add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym+add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym+add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym+add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym+add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym+add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym+add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym+add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym+add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym+add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym+add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym+add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym+add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), 4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), 4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), 8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), 8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym+add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym+add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym+add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym+add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym+add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym+add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym+add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym+add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym+add), ptb, call */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym+add), imm22 */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym+add), imm64 */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* dynamic reloc, data copy */ +#define R_IA64_SUB 0x85 /* -symbol + addend, add imm22 */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym+add), add imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym+add), add imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym+add), add imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym+add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), add imm22 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym+add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym+add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(s+a)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym+add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym+add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym+add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym+add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym+add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym+add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* IA-64 specific section flags: */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ /* * We use (abuse?) this macro to insert the (empty) vm_area that is @@ -62,7 +149,7 @@ extern void ia64_init_addr_space (void); * b0-b7 * ip cfm psr * ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec + * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ #define ELF_NGREG 128 /* we really need just 72 but let's leave some headroom... */ #define ELF_NFPREG 128 /* f0 and f1 could be omitted, but so what... */ @@ -91,28 +178,72 @@ extern void ia64_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst); #define ELF_PLATFORM 0 /* - * This should go into linux/elf.h... + * Architecture-neutral AT_ values are in the range 0-17. Leave some room for more of + * them, start the architecture-specific ones at 32. */ #define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 #ifdef __KERNEL__ struct elf64_hdr; extern void ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter); #define SET_PERSONALITY(ex, ibcs2) ia64_set_personality(&(ex), ibcs2) +struct task_struct; + extern int dump_task_regs(struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); #define ELF_CORE_COPY_TASK_REGS(tsk, elf_gregs) dump_task_regs(tsk, elf_gregs) #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) -#ifdef CONFIG_FSYS -#define ARCH_DLINFO \ -do { \ - extern char syscall_via_epc[], __start_gate_section[]; \ - NEW_AUX_ENT(AT_SYSINFO, GATE_ADDR + (syscall_via_epc - __start_gate_section)); \ +#define GATE_EHDR ((const struct elfhdr *) GATE_ADDR) + +#define ARCH_DLINFO \ +do { \ + extern char __kernel_syscall_via_epc[]; \ + NEW_AUX_ENT(AT_SYSINFO, __kernel_syscall_via_epc); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, (unsigned long) GATE_EHDR); \ +} while (0) + +/* + * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out extra segments + * containing the gate DSO contents. Dumping its contents makes post-mortem fully + * interpretable later without matching up the same kernel and hardware config to see what + * IP values meant. Dumping its extra ELF program headers includes all the other + * information a debugger needs to easily find how the gate DSO was being used. + */ +#define ELF_CORE_EXTRA_PHDRS (GATE_EHDR->e_phnum) +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +do { \ + const struct elf_phdr *const gate_phdrs = \ + (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff); \ + int i; \ + Elf64_Off ofs = 0; \ + for (i = 0; i < GATE_EHDR->e_phnum; ++i) { \ + struct elf_phdr phdr = gate_phdrs[i]; \ + if (phdr.p_type == PT_LOAD) { \ + ofs = phdr.p_offset = offset; \ + offset += phdr.p_filesz; \ + } else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} while (0) + +#define ELF_CORE_WRITE_EXTRA_DATA \ +do { \ + const struct elf_phdr *const gate_phdrs = \ + (const struct elf_phdr *) (GATE_ADDR \ + + GATE_EHDR->e_phoff); \ + int i; \ + for (i = 0; i < GATE_EHDR->e_phnum; ++i) { \ + if (gate_phdrs[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) gate_phdrs[i].p_vaddr, \ + gate_phdrs[i].p_filesz); \ + } \ } while (0) -#endif #endif /* __KERNEL__ */ diff --git a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h dissimilarity index 96% index a8b5c44a898..0694eb94107 100644 --- a/include/asm-ia64/ia32.h +++ b/include/asm-ia64/ia32.h @@ -1,481 +1,22 @@ -#ifndef _ASM_IA64_IA32_H -#define _ASM_IA64_IA32_H - -#include - -#ifdef CONFIG_IA32_SUPPORT - -#include -#include - -/* - * 32 bit structures for IA32 support. - */ - -#define IA32_PAGE_SHIFT 12 /* 4KB pages */ -#define IA32_PAGE_SIZE (1UL << IA32_PAGE_SHIFT) -#define IA32_PAGE_MASK (~(IA32_PAGE_SIZE - 1)) -#define IA32_PAGE_ALIGN(addr) (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK) -#define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ - -/* sigcontext.h */ -/* - * As documented in the iBCS2 standard.. - * - * The first part of "struct _fpstate" is just the - * normal i387 hardware setup, the extra "status" - * word is used to save the coprocessor status word - * before entering the handler. - */ -struct _fpreg_ia32 { - unsigned short significand[4]; - unsigned short exponent; -}; - -struct _fpxreg_ia32 { - unsigned short significand[4]; - unsigned short exponent; - unsigned short padding[3]; -}; - -struct _xmmreg_ia32 { - unsigned int element[4]; -}; - - -struct _fpstate_ia32 { - unsigned int cw, - sw, - tag, - ipoff, - cssel, - dataoff, - datasel; - struct _fpreg_ia32 _st[8]; - unsigned short status; - unsigned short magic; /* 0xffff = regular FPU data only */ - - /* FXSR FPU environment */ - unsigned int _fxsr_env[6]; /* FXSR FPU env is ignored */ - unsigned int mxcsr; - unsigned int reserved; - struct _fpxreg_ia32 _fxsr_st[8]; /* FXSR FPU reg data is ignored */ - struct _xmmreg_ia32 _xmm[8]; - unsigned int padding[56]; -}; - -struct sigcontext_ia32 { - unsigned short gs, __gsh; - unsigned short fs, __fsh; - unsigned short es, __esh; - unsigned short ds, __dsh; - unsigned int edi; - unsigned int esi; - unsigned int ebp; - unsigned int esp; - unsigned int ebx; - unsigned int edx; - unsigned int ecx; - unsigned int eax; - unsigned int trapno; - unsigned int err; - unsigned int eip; - unsigned short cs, __csh; - unsigned int eflags; - unsigned int esp_at_signal; - unsigned short ss, __ssh; - unsigned int fpstate; /* really (struct _fpstate_ia32 *) */ - unsigned int oldmask; - unsigned int cr2; -}; - -/* user.h */ -/* - * IA32 (Pentium III/4) FXSR, SSE support - * - * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for - * interacting with the FXSR-format floating point environment. Floating - * point data can be accessed in the regular format in the usual manner, - * and both the standard and SIMD floating point data can be accessed via - * the new ptrace requests. In either case, changes to the FPU environment - * will be reflected in the task's state as expected. - */ -struct ia32_user_i387_struct { - int cwd; - int swd; - int twd; - int fip; - int fcs; - int foo; - int fos; - int st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ -}; - -struct ia32_user_fxsr_struct { - unsigned short cwd; - unsigned short swd; - unsigned short twd; - unsigned short fop; - int fip; - int fcs; - int foo; - int fos; - int mxcsr; - int reserved; - int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ - int xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ - int padding[56]; -}; - -/* signal.h */ -#define IA32_SET_SA_HANDLER(ka,handler,restorer) \ - ((ka)->sa.sa_handler = (__sighandler_t) \ - (((unsigned long)(restorer) << 32) \ - | ((handler) & 0xffffffff))) -#define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) -#define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) - -struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ - unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ - compat_sigset_t sa_mask; /* A 32 bit mask */ -}; - -struct old_sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal - with 32 bits */ - compat_old_sigset_t sa_mask; /* A 32 bit mask */ - unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ -}; - -typedef struct sigaltstack_ia32 { - unsigned int ss_sp; - int ss_flags; - unsigned int ss_size; -} stack_ia32_t; - -struct ucontext_ia32 { - unsigned int uc_flags; - unsigned int uc_link; - stack_ia32_t uc_stack; - struct sigcontext_ia32 uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ -}; - -struct stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; - unsigned int __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned short st_rdev; - unsigned char __pad3[10]; - unsigned int st_size_lo; - unsigned int st_size_hi; - unsigned int st_blksize; - unsigned int st_blocks; /* Number 512-byte blocks allocated. */ - unsigned int __pad4; /* future possible st_blocks high bits */ - unsigned int st_atime; - unsigned int st_atime_nsec; - unsigned int st_mtime; - unsigned int st_mtime_nsec; - unsigned int st_ctime; - unsigned int st_ctime_nsec; - unsigned int st_ino_lo; - unsigned int st_ino_hi; -}; - -typedef union sigval32 { - int sival_int; - unsigned int sival_ptr; -} sigval_t32; - -typedef struct siginfo32 { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[((128/sizeof(int)) - 3)]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof(unsigned int) - sizeof(int)]; - sigval_t32 _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - sigval_t32 _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} siginfo_t32; - -struct linux32_dirent { - u32 d_ino; - u32 d_off; - u16 d_reclen; - char d_name[256]; -}; - -struct old_linux32_dirent { - u32 d_ino; - u32 d_offset; - u16 d_namlen; - char d_name[1]; -}; - -/* - * IA-32 ELF specific definitions for IA-64. - */ - -#define _ASM_IA64_ELF_H /* Don't include elf.h */ - -#include -#include - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ((x)->e_machine == EM_386) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB -#define ELF_ARCH EM_386 - -#define IA32_PAGE_OFFSET 0xc0000000 -#define IA32_STACK_TOP IA32_PAGE_OFFSET - -/* - * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can - * access them. - */ -#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) -#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) -#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) - -#define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE - -/* - * This is the location that an ET_DYN program is loaded if exec'ed. - * Typical use of this is to invoke "./ld.so someprog" to test out a - * new version of the loader. We need to make sure that it is out of - * the way of the program that it will "exec", and that there is - * sufficient room for the brk. - */ -#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) - -void ia64_elf32_init(struct pt_regs *regs); -#define ELF_PLAT_INIT(_r, load_addr) ia64_elf32_init(_r) - -#define elf_addr_t u32 - -/* ELF register definitions. This is needed for core dump support. */ - -#define ELF_NGREG 128 /* XXX fix me */ -#define ELF_NFPREG 128 /* XXX fix me */ - -typedef unsigned long elf_greg_t; -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef struct { - unsigned long w0; - unsigned long w1; -} elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; - -/* This macro yields a bitmask that programs can use to figure out - what instruction set this CPU supports. */ -#define ELF_HWCAP 0 - -/* This macro yields a string that ld.so will use to load - implementation specific libraries for optimization. Not terribly - relevant until we have real hardware to play with... */ -#define ELF_PLATFORM 0 - -#ifdef __KERNEL__ -# define SET_PERSONALITY(EX,IBCS2) \ - (current->personality = (IBCS2) ? PER_SVR4 : PER_LINUX) -#endif - -#define IA32_EFLAG 0x200 - -/* - * IA-32 ELF specific definitions for IA-64. - */ - -#define __USER_CS 0x23 -#define __USER_DS 0x2B - -#define FIRST_TSS_ENTRY 6 -#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) -#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) -#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) - -#define IA32_SEGSEL_RPL (0x3 << 0) -#define IA32_SEGSEL_TI (0x1 << 2) -#define IA32_SEGSEL_INDEX_SHIFT 3 - -#define IA32_SEG_BASE 16 -#define IA32_SEG_TYPE 40 -#define IA32_SEG_SYS 44 -#define IA32_SEG_DPL 45 -#define IA32_SEG_P 47 -#define IA32_SEG_HIGH_LIMIT 48 -#define IA32_SEG_AVL 52 -#define IA32_SEG_DB 54 -#define IA32_SEG_G 55 -#define IA32_SEG_HIGH_BASE 56 - -#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran) \ - (((limit) & 0xffff) \ - | (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE) \ - | ((unsigned long) (segtype) << IA32_SEG_TYPE) \ - | ((unsigned long) (nonsysseg) << IA32_SEG_SYS) \ - | ((unsigned long) (dpl) << IA32_SEG_DPL) \ - | ((unsigned long) (segpresent) << IA32_SEG_P) \ - | ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT) \ - | ((unsigned long) (avl) << IA32_SEG_AVL) \ - | ((unsigned long) (segdb) << IA32_SEG_DB) \ - | ((unsigned long) (gran) << IA32_SEG_G) \ - | ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE)) - -#define SEG_LIM 32 -#define SEG_TYPE 52 -#define SEG_SYS 56 -#define SEG_DPL 57 -#define SEG_P 59 -#define SEG_AVL 60 -#define SEG_DB 62 -#define SEG_G 63 - -/* Unscramble an IA-32 segment descriptor into the IA-64 format. */ -#define IA32_SEG_UNSCRAMBLE(sd) \ - ( (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \ - | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM) \ - | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE) \ - | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS) \ - | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL) \ - | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P) \ - | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL) \ - | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB) \ - | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G)) - -#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ - -#define IA32_CR0 0x80000001 /* Enable PG and PE bits */ -#define IA32_CR4 0x600 /* MMXEX and FXSR on */ - -/* - * IA32 floating point control registers starting values - */ - -#define IA32_FSR_DEFAULT 0x55550000 /* set all tag bits */ -#define IA32_FCR_DEFAULT 0x17800000037fUL /* extended precision, all masks */ - -#define IA32_PTRACE_GETREGS 12 -#define IA32_PTRACE_SETREGS 13 -#define IA32_PTRACE_GETFPREGS 14 -#define IA32_PTRACE_SETFPREGS 15 -#define IA32_PTRACE_GETFPXREGS 18 -#define IA32_PTRACE_SETFPXREGS 19 - -#define ia32_start_thread(regs,new_ip,new_sp) do { \ - set_fs(USER_DS); \ - ia64_psr(regs)->cpl = 3; /* set user mode */ \ - ia64_psr(regs)->ri = 0; /* clear return slot number */ \ - ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \ - regs->cr_iip = new_ip; \ - regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \ - regs->ar_rnat = 0; \ - regs->loadrs = 0; \ - regs->r12 = new_sp; \ -} while (0) - -/* - * Local Descriptor Table (LDT) related declarations. - */ - -#define IA32_LDT_ENTRIES 8192 /* Maximum number of LDT entries supported. */ -#define IA32_LDT_ENTRY_SIZE 8 /* The size of each LDT entry. */ - -struct ia32_modify_ldt_ldt_s { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; -}; - -struct linux_binprm; - -extern void ia32_gdt_init (void); -extern void ia32_init_addr_space (struct pt_regs *regs); -extern int ia32_setup_arg_pages (struct linux_binprm *bprm); -extern int ia32_exception (struct pt_regs *regs, unsigned long isr); -extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); -extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); -extern void ia32_load_segment_descriptors (struct task_struct *task); - -#define ia32f2ia64f(dst,src) \ - do { \ - register double f6 asm ("f6"); \ - asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ - } while(0) - -#define ia64f2ia32f(dst,src) \ - do { \ - register double f6 asm ("f6"); \ - asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ - } while(0) - -#endif /* !CONFIG_IA32_SUPPORT */ - -/* Declare this uncondiontally, so we don't get warnings for unreachable code. */ -extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs); - -#endif /* _ASM_IA64_IA32_H */ +#ifndef _ASM_IA64_IA32_H +#define _ASM_IA64_IA32_H + +#include + +#include +#include + +#ifdef CONFIG_IA32_SUPPORT + +extern void ia32_cpu_init (void); +extern void ia32_gdt_init (void); +extern int ia32_exception (struct pt_regs *regs, unsigned long isr); +extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); + +#endif /* !CONFIG_IA32_SUPPORT */ + +/* Declare this unconditionally, so we don't get warnings for unreachable code. */ +extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs); + +#endif /* _ASM_IA64_IA32_H */ diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h index fcc63e10cfb..cc2f3d6803c 100644 --- a/include/asm-ia64/io.h +++ b/include/asm-ia64/io.h @@ -413,4 +413,17 @@ extern void __ia64_memset_c_io (unsigned long, unsigned long, long); # endif /* __KERNEL__ */ +/* + * It makes no sense at all to have this BIO_VMERGE_BOUNDARY macro here. Should be + * replaced by dma_merge_mask() or something of that sort. Note: the only way + * BIO_VMERGE_BOUNDARY is used is to mask off bits. Effectively, our definition gets + * expanded into: + * + * addr & ((ia64_max_iommu_merge_mask + 1) - 1) == (addr & ia64_max_iommu_vmerge_mask) + * + * which is precisely what we want. + */ +extern unsigned long ia64_max_iommu_merge_mask; +#define BIO_VMERGE_BOUNDARY (ia64_max_iommu_merge_mask + 1) + #endif /* _ASM_IA64_IO_H */ diff --git a/include/asm-ia64/ioctl32.h b/include/asm-ia64/ioctl32.h new file mode 100644 index 00000000000..d0d227f45e0 --- /dev/null +++ b/include/asm-ia64/ioctl32.h @@ -0,0 +1 @@ +#include diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h index 173777837e5..5162e365e33 100644 --- a/include/asm-ia64/kregs.h +++ b/include/asm-ia64/kregs.h @@ -72,7 +72,7 @@ #define IA64_PSR_BITS_TO_CLEAR (IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \ IA64_PSR_TB | IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA) -#define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH) +#define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH | IA64_PSR_SP) #define IA64_PSR_BE (__IA64_UL(1) << IA64_PSR_BE_BIT) #define IA64_PSR_UP (__IA64_UL(1) << IA64_PSR_UP_BIT) diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 5f23c350b99..a277c8ff959 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -74,8 +74,6 @@ extern void machvec_memory_fence (void); # include # elif defined (CONFIG_IA64_HP_ZX1) # include -# elif defined (CONFIG_IA64_SGI_SN1) -# include # elif defined (CONFIG_IA64_SGI_SN2) # include # elif defined (CONFIG_IA64_GENERIC) diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h index 63853a256f7..ed140d1f54f 100644 --- a/include/asm-ia64/mca.h +++ b/include/asm-ia64/mca.h @@ -92,6 +92,8 @@ typedef struct ia64_mca_sal_to_os_state_s { u64 imsto_sal_check_ra; /* Return address in SAL_CHECK while going * back to SAL from OS after MCA handling. */ + u64 pal_min_state; /* from PAL in r17 */ + u64 proc_state_param; /* from PAL in r18. See SDV 2:268 11.3.2.1 */ } ia64_mca_sal_to_os_state_t; enum { diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h index 104c938b2e5..bcca098828e 100644 --- a/include/asm-ia64/mca_asm.h +++ b/include/asm-ia64/mca_asm.h @@ -35,7 +35,7 @@ * 1. Lop off bits 61 thru 63 in the virtual address */ #define DATA_VA_TO_PA(addr) \ - dep addr = 0, addr, 61, 3 + tpa addr = addr /* * This macro converts a data physical address to a virtual address * Right now for simulation purposes the virtual addresses are diff --git a/include/asm-ia64/nodedata.h b/include/asm-ia64/nodedata.h index 0e9c6243691..9acdcb7ffe5 100644 --- a/include/asm-ia64/nodedata.h +++ b/include/asm-ia64/nodedata.h @@ -22,6 +22,7 @@ struct pglist_data; struct ia64_node_data { + short active_cpu_count; short node; struct pglist_data *pg_data_ptrs[NR_NODES]; struct page *bank_mem_map_base[NR_BANKS]; diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index a2d44476fdf..44b3f419c85 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -33,6 +33,8 @@ #define PERCPU_PAGE_SHIFT 16 /* log2() of max. size of per-CPU area */ #define PERCPU_PAGE_SIZE (__IA64_UL_CONST(1) << PERCPU_PAGE_SHIFT) +#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ + #ifdef CONFIG_HUGETLB_PAGE # if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB) @@ -60,6 +62,7 @@ # define HPAGE_SIZE (__IA64_UL_CONST(1) << HPAGE_SHIFT) # define HPAGE_MASK (~(HPAGE_SIZE - 1)) # define HAVE_ARCH_HUGETLB_UNMAPPED_AREA +# define ARCH_HAS_VALID_HUGEPAGE_RANGE #endif /* CONFIG_HUGETLB_PAGE */ #ifdef __ASSEMBLY__ @@ -131,9 +134,7 @@ typedef union ia64_va { # define htlbpage_to_page(x) ((REGION_NUMBER(x) << 61) \ | (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT))) # define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) -extern int is_invalid_hugepage_range(unsigned long addr, unsigned long len); -#else -#define is_invalid_hugepage_range(addr, len) 0 +extern int check_valid_hugepage_range(unsigned long addr, unsigned long len); #endif static __inline__ int diff --git a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h new file mode 100644 index 00000000000..4797f3535e6 --- /dev/null +++ b/include/asm-ia64/patch.h @@ -0,0 +1,25 @@ +#ifndef _ASM_IA64_PATCH_H +#define _ASM_IA64_PATCH_H + +/* + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + * + * There are a number of reasons for patching instructions. Rather than duplicating code + * all over the place, we put the common stuff here. Reasons for patching: in-kernel + * module-loader, virtual-to-physical patch-list, McKinley Errata 9 workaround, and gate + * shared library. Undoubtedly, some of these reasons will disappear and others will + * be added over time. + */ +#include +#include + +extern void ia64_patch (u64 insn_addr, u64 mask, u64 val); /* patch any insn slot */ +extern void ia64_patch_imm64 (u64 insn_addr, u64 val); /* patch "movl" w/abs. value*/ +extern void ia64_patch_imm60 (u64 insn_addr, u64 val); /* patch "brl" w/ip-rel value */ + +extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end); +extern void ia64_patch_vtop (unsigned long start, unsigned long end); +extern void ia64_patch_gate (void); + +#endif /* _ASM_IA64_PATCH_H */ diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h index 8ec46341fb2..129436b9e73 100644 --- a/include/asm-ia64/pci.h +++ b/include/asm-ia64/pci.h @@ -26,11 +26,19 @@ struct pci_bus * pcibios_scan_root(void *acpi_handle, int segment, int bus); struct pci_dev; /* - * The PCI address space does equal the physical memory address space. - * The networking and block device layers use this boolean for bounce - * buffer decisions. + * PCI_DMA_BUS_IS_PHYS should be set to 1 if there is _necessarily_ a direct correspondence + * between device bus addresses and CPU physical addresses. Platforms with a hardware I/O + * MMU _must_ turn this off to suppress the bounce buffer handling code in the block and + * network device layers. Platforms with separate bus address spaces _must_ turn this off + * and provide a device DMA mapping implementation that takes care of the necessary + * address translation. + * + * For now, the ia64 platforms which may have separate/multiple bus address spaces all + * have I/O MMUs which support the merging of physically discontiguous buffers, so we can + * use that as the sole factor to determine the setting of PCI_DMA_BUS_IS_PHYS. */ -#define PCI_DMA_BUS_IS_PHYS (1) +extern unsigned long ia64_max_iommu_merge_mask; +#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL) static inline void pcibios_set_master (struct pci_dev *dev) @@ -94,6 +102,16 @@ struct pci_controller { #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata) #define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment) +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + if (pci_domain_nr(bus) == 0) { + sprintf(name, "%02x", bus->number); + } else { + sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number); + } + return 0; +} + /* generic pci stuff */ #include diff --git a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h dissimilarity index 69% index 9db86e58710..26afeeb46ea 100644 --- a/include/asm-ia64/perfmon.h +++ b/include/asm-ia64/perfmon.h @@ -1,205 +1,254 @@ -/* - * Copyright (C) 2001-2003 Hewlett-Packard Co - * Stephane Eranian - */ - -#ifndef _ASM_IA64_PERFMON_H -#define _ASM_IA64_PERFMON_H - -/* - * perfmon comamnds supported on all CPU models - */ -#define PFM_WRITE_PMCS 0x01 -#define PFM_WRITE_PMDS 0x02 -#define PFM_READ_PMDS 0x03 -#define PFM_STOP 0x04 -#define PFM_START 0x05 -#define PFM_ENABLE 0x06 -#define PFM_DISABLE 0x07 -#define PFM_CREATE_CONTEXT 0x08 -#define PFM_DESTROY_CONTEXT 0x09 -#define PFM_RESTART 0x0a -#define PFM_PROTECT_CONTEXT 0x0b -#define PFM_GET_FEATURES 0x0c -#define PFM_DEBUG 0x0d -#define PFM_UNPROTECT_CONTEXT 0x0e -#define PFM_GET_PMC_RESET_VAL 0x0f - - -/* - * CPU model specific commands (may not be supported on all models) - */ -#define PFM_WRITE_IBRS 0x20 -#define PFM_WRITE_DBRS 0x21 - -/* - * context flags - */ -#define PFM_FL_INHERIT_NONE 0x00 /* never inherit a context across fork (default) */ -#define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ -#define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ -#define PFM_FL_NOTIFY_BLOCK 0x04 /* block task on user level notifications */ -#define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ -#define PFM_FL_EXCL_IDLE 0x20 /* exclude idle task from system wide session */ -#define PFM_FL_UNSECURE 0x40 /* allow unsecure monitoring for non self-monitoring task */ - -/* - * PMC flags - */ -#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ -#define PFM_REGFL_RANDOM 0x2 /* randomize sampling periods */ - -/* - * PMD/PMC/IBR/DBR return flags (ignored on input) - * - * Those flags are used on output and must be checked in case EAGAIN is returned - * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. - */ -#define PFM_REG_RETFL_NOTAVAIL (1U<<31) /* set if register is implemented but not available */ -#define PFM_REG_RETFL_EINVAL (1U<<30) /* set if register entry is invalid */ -#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) - -#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) - -/* - * Request structure used to define a context - */ -typedef struct { - unsigned long ctx_smpl_entries; /* how many entries in sampling buffer */ - unsigned long ctx_smpl_regs[4]; /* which pmds to record on overflow */ - - pid_t ctx_notify_pid; /* which process to notify on overflow */ - int ctx_flags; /* noblock/block, inherit flags */ - void *ctx_smpl_vaddr; /* returns address of BTB buffer */ - - unsigned long ctx_cpu_mask; /* on which CPU to enable perfmon (systemwide) */ - - unsigned long reserved[8]; /* for future use */ -} pfarg_context_t; - -/* - * Request structure used to write/read a PMC or PMD - */ -typedef struct { - unsigned int reg_num; /* which register */ - unsigned int reg_flags; /* PMC: notify/don't notify. PMD/PMC: return flags */ - unsigned long reg_value; /* configuration (PMC) or initial value (PMD) */ - - unsigned long reg_long_reset; /* reset after sampling buffer overflow (large) */ - unsigned long reg_short_reset;/* reset after counter overflow (small) */ - - unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ - unsigned long reg_random_seed; /* seed value when randomization is used */ - unsigned long reg_random_mask; /* bitmask used to limit random value */ - unsigned long reg_last_reset_value;/* last value used to reset the PMD (PFM_READ_PMDS) */ - - unsigned long reserved[13]; /* for future use */ -} pfarg_reg_t; - -typedef struct { - unsigned int dbreg_num; /* which register */ - unsigned int dbreg_flags; /* dbregs return flags */ - unsigned long dbreg_value; /* configuration (PMC) or initial value (PMD) */ - unsigned long reserved[6]; -} pfarg_dbreg_t; - -typedef struct { - unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ - unsigned int ft_smpl_version;/* sampling format: major [16-31], minor [0-15] */ - unsigned long reserved[4]; /* for future use */ -} pfarg_features_t; - -/* - * This header is at the beginning of the sampling buffer returned to the user. - * It is exported as Read-Only at this point. It is directly followed by the - * first record. - */ -typedef struct { - unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ - unsigned int reserved; - unsigned long hdr_entry_size; /* size of one entry in bytes */ - unsigned long hdr_count; /* how many valid entries */ - unsigned long hdr_pmds[4]; /* which pmds are recorded */ -} perfmon_smpl_hdr_t; - -/* - * Define the version numbers for both perfmon as a whole and the sampling buffer format. - */ -#define PFM_VERSION_MAJ 1U -#define PFM_VERSION_MIN 4U -#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) - -#define PFM_SMPL_VERSION_MAJ 1U -#define PFM_SMPL_VERSION_MIN 0U -#define PFM_SMPL_VERSION (((PFM_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_SMPL_VERSION_MIN & 0xffff)) - - -#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) -#define PFM_VERSION_MINOR(x) ((x) & 0xffff) - -/* - * Entry header in the sampling buffer. The header is directly followed - * with the PMDs saved in increasing index order: PMD4, PMD5, .... How - * many PMDs are present is determined by the user program during - * context creation. - * - * XXX: in this version of the entry, only up to 64 registers can be - * recorded. This should be enough for quite some time. Always check - * sampling format before parsing entries! - * - * In the case where multiple counters overflow at the same time, the - * last_reset_value member indicates the initial value of the PMD with - * the smallest index. For instance, if PMD2 and PMD5 have overflowed, - * the last_reset_value member contains the initial value of PMD2. - */ -typedef struct { - int pid; /* identification of process */ - int cpu; /* which cpu was used */ - unsigned long last_reset_value; /* initial value of counter that overflowed */ - unsigned long stamp; /* timestamp */ - unsigned long ip; /* where did the overflow interrupt happened */ - unsigned long regs; /* bitmask of which registers overflowed */ - unsigned long reserved; /* unused */ -} perfmon_smpl_entry_t; - -extern long perfmonctl(pid_t pid, int cmd, void *arg, int narg); - -#ifdef __KERNEL__ - -typedef struct { - void (*handler)(int irq, void *arg, struct pt_regs *regs); -} pfm_intr_handler_desc_t; - -extern void pfm_save_regs (struct task_struct *); -extern void pfm_load_regs (struct task_struct *); - -extern int pfm_inherit (struct task_struct *, struct pt_regs *); -extern void pfm_context_exit (struct task_struct *); -extern void pfm_flush_regs (struct task_struct *); -extern void pfm_cleanup_notifiers (struct task_struct *); -extern void pfm_cleanup_owners (struct task_struct *); -extern int pfm_use_debug_registers(struct task_struct *); -extern int pfm_release_debug_registers(struct task_struct *); -extern int pfm_cleanup_smpl_buf(struct task_struct *); -extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin); -extern void pfm_ovfl_block_reset(void); -extern void pfm_init_percpu(void); - -/* - * hooks to allow VTune/Prospect to cooperate with perfmon. - * (reserved for system wide monitoring modules only) - */ -extern int pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h); -extern int pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h); - -/* - * describe the content of the local_cpu_date->pfm_syst_info field - */ -#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exist */ -#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ -#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ - - -#endif /* __KERNEL__ */ - -#endif /* _ASM_IA64_PERFMON_H */ +/* + * Copyright (C) 2001-2003 Hewlett-Packard Co + * Stephane Eranian + */ + +#ifndef _ASM_IA64_PERFMON_H +#define _ASM_IA64_PERFMON_H + +/* + * perfmon comamnds supported on all CPU models + */ +#define PFM_WRITE_PMCS 0x01 +#define PFM_WRITE_PMDS 0x02 +#define PFM_READ_PMDS 0x03 +#define PFM_STOP 0x04 +#define PFM_START 0x05 +#define PFM_ENABLE 0x06 /* obsolete */ +#define PFM_DISABLE 0x07 /* obsolete */ +#define PFM_CREATE_CONTEXT 0x08 +#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ +#define PFM_RESTART 0x0a +#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ +#define PFM_GET_FEATURES 0x0c +#define PFM_DEBUG 0x0d +#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ +#define PFM_GET_PMC_RESET_VAL 0x0f +#define PFM_LOAD_CONTEXT 0x10 +#define PFM_UNLOAD_CONTEXT 0x11 + +/* + * PMU model specific commands (may not be supported on all PMU models) + */ +#define PFM_WRITE_IBRS 0x20 +#define PFM_WRITE_DBRS 0x21 + +/* + * context flags + */ +#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ +#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ +#define PFM_FL_UNSECURE 0x04 /* allow unsecure monitoring for non self-monitoring task */ +#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ + +/* + * event set flags + */ +#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ + +/* + * PMC flags + */ +#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ +#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ + +/* + * PMD/PMC/IBR/DBR return flags (ignored on input) + * + * Those flags are used on output and must be checked in case EAGAIN is returned + * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. + */ +#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ +#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ +#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) + +#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) + +typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ + +/* + * Request structure used to define a context + */ +typedef struct { + pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ + unsigned long ctx_flags; /* noblock/block */ + unsigned int ctx_nextra_sets; /* number of extra event sets (you always get 1) */ + int ctx_fd; /* return arg: unique identification for context */ + void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ + unsigned long ctx_reserved[11]; /* for future use */ +} pfarg_context_t; + +/* + * Request structure used to write/read a PMC or PMD + */ +typedef struct { + unsigned int reg_num; /* which register */ + unsigned int reg_set; /* event set for this register */ + + unsigned long reg_value; /* initial pmc/pmd value */ + unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ + + unsigned long reg_long_reset; /* reset after buffer overflow notification */ + unsigned long reg_short_reset; /* reset after counter overflow */ + + unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ + unsigned long reg_random_seed; /* seed value when randomization is used */ + unsigned long reg_random_mask; /* bitmask used to limit random value */ + unsigned long reg_last_reset_val;/* return: PMD last reset value */ + + unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ + unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ + + unsigned long reserved[3]; /* for future use */ +} pfarg_reg_t; + +typedef struct { + unsigned int dbreg_num; /* which debug register */ + unsigned int dbreg_set; /* event set for this register */ + unsigned long dbreg_value; /* value for debug register */ + unsigned long dbreg_flags; /* return: dbreg error */ + unsigned long dbreg_reserved[1]; /* for future use */ +} pfarg_dbreg_t; + +typedef struct { + unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ + unsigned int ft_reserved; /* reserved for future use */ + unsigned long reserved[4]; /* for future use */ +} pfarg_features_t; + +typedef struct { + pid_t load_pid; /* process to load the context into */ + unsigned int load_set; /* first event set to load */ + unsigned long load_reserved[2]; /* for future use */ +} pfarg_load_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ + unsigned int msg_active_set; /* active set at the time of overflow */ + unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ +} pfm_ovfl_msg_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_end_msg_t; + +typedef struct { + int msg_type; /* type of the message */ + int msg_ctx_fd; /* unique identifier for the context */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_gen_msg_t; + +#define PFM_MSG_OVFL 1 /* an overflow happened */ +#define PFM_MSG_END 2 /* task to which context was attached ended */ + +typedef union { + pfm_ovfl_msg_t pfm_ovfl_msg; + pfm_end_msg_t pfm_end_msg; + pfm_gen_msg_t pfm_gen_msg; +} pfm_msg_t; + +/* + * Define the version numbers for both perfmon as a whole and the sampling buffer format. + */ +#define PFM_VERSION_MAJ 2U +#define PFM_VERSION_MIN 0U +#define PFM_SMPL_HDR_VERSION_MAJ 2U +#define PFM_SMPL_HDR_VERSION_MIN 0U +#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) +#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) +#define PFM_VERSION_MINOR(x) ((x) & 0xffff) + + +/* + * miscellaneous architected definitions + */ +#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ +#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ +#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ + +#ifdef __KERNEL__ + +extern long perfmonctl(int fd, int cmd, void *arg, int narg); + +extern void pfm_save_regs (struct task_struct *); +extern void pfm_load_regs (struct task_struct *); + +extern void pfm_exit_thread(struct task_struct *); +extern int pfm_use_debug_registers(struct task_struct *); +extern int pfm_release_debug_registers(struct task_struct *); +extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin); +extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); +extern void pfm_init_percpu(void); +extern void pfm_handle_work(void); + +/* + * Reset PMD register flags + */ +#define PFM_PMD_NO_RESET 0 +#define PFM_PMD_LONG_RESET 1 +#define PFM_PMD_SHORT_RESET 2 + +typedef struct { + unsigned int notify_user:1; /* notify user program of overflow */ + unsigned int reset_pmds :2; /* PFM_PMD_NO_RESET, PFM_PMD_LONG_RESET, PFM_PMD_SHORT_RESET */ + unsigned int block:1; /* block monitored task on kernel exit */ + unsigned int stop_monitoring:1; /* will mask monitoring via PMCx.plm */ + unsigned int reserved:26; /* for future use */ +} pfm_ovfl_ctrl_t; + +typedef struct { + unsigned long ovfl_pmds[4]; /* bitmask of overflowed pmds */ + unsigned long ovfl_notify[4]; /* bitmask of overflow pmds which asked for notification */ + unsigned long pmd_value; /* current 64-bit value of 1st pmd which overflowed */ + unsigned long pmd_last_reset; /* last reset value of 1st pmd which overflowed */ + unsigned long pmd_eventid; /* eventid associated with 1st pmd which overflowed */ + unsigned int active_set; /* event set active at the time of the overflow */ + unsigned int reserved1; + unsigned long smpl_pmds[4]; + unsigned long smpl_pmds_values[PMU_MAX_PMDS]; + pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */ +} pfm_ovfl_arg_t; + + +typedef struct _pfm_buffer_fmt_t { + char *fmt_name; + pfm_uuid_t fmt_uuid; + size_t fmt_arg_size; + unsigned long fmt_flags; + + int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg); + int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size); + int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg); + int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs); + int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs); + + struct _pfm_buffer_fmt_t *fmt_next; + struct _pfm_buffer_fmt_t *fmt_prev; +} pfm_buffer_fmt_t; + +extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt); +extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid); + +/* + * perfmon interface exported to modules + */ +extern long pfm_mod_fast_read_pmds(struct task_struct *, unsigned long mask[4], unsigned long *addr, struct pt_regs *regs); +extern long pfm_mod_read_pmds(struct task_struct *, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs); +extern long pfm_mod_write_pmcs(struct task_struct *, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs); + +/* + * describe the content of the local_cpu_date->pfm_syst_info field + */ +#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */ +#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ +#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IA64_PERFMON_H */ diff --git a/include/asm-ia64/perfmon_default_smpl.h b/include/asm-ia64/perfmon_default_smpl.h new file mode 100644 index 00000000000..77709625f96 --- /dev/null +++ b/include/asm-ia64/perfmon_default_smpl.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for Linux/ia64 perfmon subsystem. + */ +#ifndef __PERFMON_DEFAULT_SMPL_H__ +#define __PERFMON_DEFAULT_SMPL_H__ 1 + +#define PFM_DEFAULT_SMPL_UUID { \ + 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} + +/* + * format specific parameters (passed at context creation) + */ +typedef struct { + unsigned long buf_size; /* size of the buffer in bytes */ + unsigned long reserved[3]; /* for future use */ +} pfm_default_smpl_arg_t; + +/* + * combined context+format specific structure. Can be passed + * to PFM_CONTEXT_CREATE + */ +typedef struct { + pfarg_context_t ctx_arg; + pfm_default_smpl_arg_t buf_arg; +} pfm_default_smpl_ctx_arg_t; + +/* + * This header is at the beginning of the sampling buffer returned to the user. + * It is directly followed by the first record. + */ +typedef struct { + unsigned long hdr_count; /* how many valid entries */ + void *hdr_cur_pos; /* current position in the buffer */ + void *hdr_last_pos; /* first byte beyond buffer */ + + unsigned long hdr_overflows; /* how many times the buffer overflowed */ + unsigned long hdr_buf_size; /* how many bytes in the buffer */ + unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ + unsigned int hdr_reserved1; /* for future use */ + unsigned long hdr_reserved[10]; /* for future use */ +} pfm_default_smpl_hdr_t; + +/* + * Entry header in the sampling buffer. The header is directly followed + * with the PMDs saved in increasing index order: PMD4, PMD5, .... How + * many PMDs are present depends on how the session was programmed. + * + * XXX: in this version of the entry, only up to 64 registers can be + * recorded. This should be enough for quite some time. Always check + * sampling format before parsing entries! + * + * In the case where multiple counters overflow at the same time, the + * last_reset_value member indicates the initial value of the + * overflowed PMD with the smallest index. For instance, if PMD2 and + * PMD5 have overflowed, the last_reset_value member contains the + * initial value of PMD2. + */ +typedef struct { + int pid; /* current process at PMU interrupt point */ + int cpu; /* cpu on which the overfow occured */ + unsigned long last_reset_val; /* initial value of 1st overflowed PMD */ + unsigned long ip; /* where did the overflow interrupt happened */ + unsigned long ovfl_pmds; /* which PMDS registers overflowed (64 max) */ + unsigned long tstamp; /* ar.itc on the CPU that took the overflow */ + unsigned int set; /* event set active when overflow ocurred */ + unsigned int reserved1; /* for future use */ +} pfm_default_smpl_entry_t; + +#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */ +#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS)) +#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE) + +#define PFM_DEFAULT_SMPL_VERSION_MAJ 2U +#define PFM_DEFAULT_SMPL_VERSION_MIN 0U +#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff)) + +#endif /* __PERFMON_DEFAULT_SMPL_H__ */ diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 4f56ceb9c42..68be9d57c7d 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -158,29 +158,4 @@ pte_free_kernel (pte_t *pte) extern void check_pgt_cache (void); -/* - * IA-64 doesn't have any external MMU info: the page tables contain all the necessary - * information. However, we use this macro to take care of any (delayed) i-cache flushing - * that may be necessary. - */ -static inline void -update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) -{ - unsigned long addr; - struct page *page; - - if (!pte_exec(pte)) - return; /* not an executable page... */ - - page = pte_page(pte); - /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ - addr = (unsigned long) page_address(page); - - if (test_bit(PG_arch_1, &page->flags)) - return; /* i-cache is already coherent with d-cache */ - - flush_icache_range(addr, addr + PAGE_SIZE); - set_bit(PG_arch_1, &page->flags); /* mark page as clean */ -} - #endif /* _ASM_IA64_PGALLOC_H */ diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index d8cc52c3b09..3da4c69db57 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -8,7 +8,7 @@ * This hopefully works with any (fixed) IA-64 page-size, as defined * in (currently 8192). * - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang */ @@ -75,6 +75,8 @@ #define _PAGE_SIZE_16M 24 #define _PAGE_SIZE_64M 26 #define _PAGE_SIZE_256M 28 +#define _PAGE_SIZE_1G 30 +#define _PAGE_SIZE_4G 32 #define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB #define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB @@ -202,16 +204,21 @@ ia64_phys_addr_valid (unsigned long addr) #define set_pte(ptep, pteval) (*(ptep) = (pteval)) #define RGN_SIZE (1UL << 61) -#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ #define RGN_KERNEL 7 -#define VMALLOC_START (0xa000000000000000 + 3*PERCPU_PAGE_SIZE) +#define VMALLOC_START 0xa000000200000000 #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#ifdef CONFIG_VIRTUAL_MEM_MAP +# define VMALLOC_END_INIT (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +# define VMALLOC_END vmalloc_end + extern unsigned long vmalloc_end; +#else +# define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#endif /* fs/proc/kcore.c */ -#define kc_vaddr_to_offset(v) ((v) - 0xA000000000000000) -#define kc_offset_to_vaddr(o) ((o) + 0xA000000000000000) +#define kc_vaddr_to_offset(v) ((v) - 0xa000000000000000) +#define kc_offset_to_vaddr(o) ((o) + 0xa000000000000000) /* * Conversion functions: convert page frame number (pfn) and a protection value to a page @@ -255,6 +262,7 @@ ia64_phys_addr_valid (unsigned long addr) /* * The following have defined behavior only work if pte_present() is true. */ +#define pte_user(pte) ((pte_val(pte) & _PAGE_PL_MASK) == _PAGE_PL_3) #define pte_read(pte) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) < 6) #define pte_write(pte) ((unsigned) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) - 2) <= 4) #define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0) @@ -274,10 +282,9 @@ ia64_phys_addr_valid (unsigned long addr) #define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D)) /* - * Macro to make mark a page protection value as "uncacheable". Note - * that "protection" is really a misnomer here as the protection value - * contains the memory attribute bits, dirty bits, and various other - * bits as well. + * Macro to a page protection value as "uncacheable". Note that "protection" is really a + * misnomer here as the protection value contains the memory attribute bits, dirty bits, + * and various other bits as well. */ #define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) @@ -446,13 +453,27 @@ extern void paging_init (void); * for zero-mapped memory areas etc.. */ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) +extern struct page *zero_page_memmap_ptr; +#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr) /* We provide our own get_unmapped_area to cope with VA holes for userland */ #define HAVE_ARCH_UNMAPPED_AREA typedef pte_t *pte_addr_t; +/* + * IA-64 doesn't have any external MMU info: the page tables contain all the necessary + * information. However, we use this routine to take care of any (delayed) i-cache + * flushing that may be necessary. + */ +extern void update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte); + +# ifdef CONFIG_VIRTUAL_MEM_MAP + /* arch mem_map init routine is needed due to holes in a virtual mem_map */ +# define __HAVE_ARCH_MEMMAP_INIT + extern void memmap_init (struct page *start, unsigned long size, int nid, unsigned long zone, + unsigned long start_pfn); +# endif /* CONFIG_VIRTUAL_MEM_MAP */ # endif /* !__ASSEMBLY__ */ /* @@ -471,11 +492,14 @@ typedef pte_t *pte_addr_t; */ #define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M #define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) -#define KERNEL_TR_PAGE_NUM ((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE) /* * No page table caches to initialise */ #define pgtable_cache_init() do { } while (0) +/* These tell get_user_pages() that the first gate page is accessible from user-level. */ +#define FIXADDR_USER_START GATE_ADDR +#define FIXADDR_USER_END (GATE_ADDR + 2*PAGE_SIZE) + #endif /* _ASM_IA64_PGTABLE_H */ diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h index 6838714a802..1c1bfb1f1fc 100644 --- a/include/asm-ia64/processor.h +++ b/include/asm-ia64/processor.h @@ -17,7 +17,7 @@ #include #include -#include +#include #define IA64_NUM_DBG_REGS 8 /* @@ -87,9 +87,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -236,6 +236,7 @@ struct thread_struct { __u64 ksp; /* kernel stack pointer */ __u64 map_base; /* base address for get_unmapped_area() */ __u64 task_size; /* limit for task size */ + __u64 rbs_bot; /* the base address for the RBS */ int last_fph_cpu; /* CPU that may hold the contents of f32-f127 */ #ifdef CONFIG_IA32_SUPPORT @@ -244,8 +245,6 @@ struct thread_struct { __u64 fcr; /* IA32 floating pt control reg */ __u64 fir; /* IA32 fp except. instr. reg */ __u64 fdr; /* IA32 fp except. data reg */ - __u64 csd; /* IA32 code selector descriptor */ - __u64 ssd; /* IA32 stack selector descriptor */ __u64 old_k1; /* old value of ar.k1 */ __u64 old_iob; /* old IOBase value */ # define INIT_THREAD_IA32 .eflag = 0, \ @@ -253,28 +252,20 @@ struct thread_struct { .fcr = 0x17800000037fULL, \ .fir = 0, \ .fdr = 0, \ - .csd = 0, \ - .ssd = 0, \ .old_k1 = 0, \ .old_iob = 0, #else # define INIT_THREAD_IA32 #endif /* CONFIG_IA32_SUPPORT */ #ifdef CONFIG_PERFMON - __u64 pmc[IA64_NUM_PMC_REGS]; - __u64 pmd[IA64_NUM_PMD_REGS]; - unsigned long pfm_ovfl_block_reset;/* non-zero if we need to block or reset regs on ovfl */ - void *pfm_context; /* pointer to detailed PMU context */ - atomic_t pfm_notifiers_check; /* when >0, will cleanup ctx_notify_task in tasklist */ - atomic_t pfm_owners_check; /* when >0, will cleanup ctx_owner in tasklist */ - void *pfm_smpl_buf_list; /* list of sampling buffers to vfree */ -# define INIT_THREAD_PM .pmc = {0, }, \ - .pmd = {0, }, \ - .pfm_ovfl_block_reset = 0, \ - .pfm_context = NULL, \ - .pfm_notifiers_check = { 0 }, \ - .pfm_owners_check = { 0 }, \ - .pfm_smpl_buf_list = NULL, + __u64 pmcs[IA64_NUM_PMC_REGS]; + __u64 pmds[IA64_NUM_PMD_REGS]; + void *pfm_context; /* pointer to detailed PMU context */ + unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */ +# define INIT_THREAD_PM .pmcs = {0UL, }, \ + .pmds = {0UL, }, \ + .pfm_context = NULL, \ + .pfm_needs_checking = 0UL, #else # define INIT_THREAD_PM #endif @@ -288,8 +279,9 @@ struct thread_struct { .on_ustack = 0, \ .ksp = 0, \ .map_base = DEFAULT_MAP_BASE, \ + .rbs_bot = DEFAULT_USER_STACK_SIZE, \ .task_size = DEFAULT_TASK_SIZE, \ - .last_fph_cpu = 0, \ + .last_fph_cpu = -1, \ INIT_THREAD_IA32 \ INIT_THREAD_PM \ .dbr = {0, }, \ @@ -304,36 +296,18 @@ struct thread_struct { regs->cr_iip = new_ip; \ regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ regs->ar_rnat = 0; \ - regs->ar_bspstore = IA64_RBS_BOT; \ + regs->ar_bspstore = current->thread.rbs_bot; \ regs->ar_fpsr = FPSR_DEFAULT; \ regs->loadrs = 0; \ regs->r8 = current->mm->dumpable; /* set "don't zap registers" flag */ \ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - if (unlikely(!current->mm->dumpable)) { \ + if (unlikely(!current->mm->dumpable)) { \ /* \ * Zap scratch regs to avoid leaking bits between processes with different \ * uid/privileges. \ */ \ - regs->ar_pfs = 0; \ - regs->pr = 0; \ - /* \ - * XXX fix me: everything below can go away once we stop preserving scratch \ - * regs on a system call. \ - */ \ - regs->b6 = 0; \ - regs->r1 = 0; regs->r2 = 0; regs->r3 = 0; \ - regs->r13 = 0; regs->r14 = 0; regs->r15 = 0; \ - regs->r9 = 0; regs->r11 = 0; \ - regs->r16 = 0; regs->r17 = 0; regs->r18 = 0; regs->r19 = 0; \ - regs->r20 = 0; regs->r21 = 0; regs->r22 = 0; regs->r23 = 0; \ - regs->r24 = 0; regs->r25 = 0; regs->r26 = 0; regs->r27 = 0; \ - regs->r28 = 0; regs->r29 = 0; regs->r30 = 0; regs->r31 = 0; \ - regs->ar_ccv = 0; \ - regs->b0 = 0; regs->b7 = 0; \ - regs->f6.u.bits[0] = 0; regs->f6.u.bits[1] = 0; \ - regs->f7.u.bits[0] = 0; regs->f7.u.bits[1] = 0; \ - regs->f8.u.bits[0] = 0; regs->f8.u.bits[1] = 0; \ - regs->f9.u.bits[0] = 0; regs->f9.u.bits[1] = 0; \ + regs->ar_pfs = 0; regs->b0 = 0; regs->pr = 0; \ + regs->r1 = 0; regs->r9 = 0; regs->r11 = 0; regs->r13 = 0; regs->r15 = 0; \ } \ } while (0) @@ -346,11 +320,7 @@ struct task_struct; * parent of DEAD_TASK has collected the exist status of the task via * wait(). */ -#ifdef CONFIG_PERFMON - extern void release_thread (struct task_struct *task); -#else -# define release_thread(dead_task) -#endif +#define release_thread(dead_task) /* Prepare to copy thread state - unlazy all lazy status */ #define prepare_to_copy(tsk) do { } while (0) @@ -369,7 +339,7 @@ struct task_struct; * do_basic_setup() and the timing is such that free_initmem() has * been called already. */ -extern int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); +extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); /* Get wait channel for task P. */ extern unsigned long get_wchan (struct task_struct *p); @@ -417,17 +387,28 @@ ia64_set_kr (unsigned long regnum, unsigned long r) } } -static inline struct task_struct * -ia64_get_fpu_owner (void) -{ - return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER); -} +/* + * The following three macros can't be inline functions because we don't have struct + * task_struct at this point. + */ -static inline void -ia64_set_fpu_owner (struct task_struct *t) -{ - ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t); -} +/* Return TRUE if task T owns the fph partition of the CPU we're running on. */ +#define ia64_is_local_fpu_owner(t) \ +({ \ + struct task_struct *__ia64_islfo_task = (t); \ + (__ia64_islfo_task->thread.last_fph_cpu == smp_processor_id() \ + && __ia64_islfo_task == (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER)); \ +}) + +/* Mark task T as owning the fph partition of the CPU we're running on. */ +#define ia64_set_local_fpu_owner(t) do { \ + struct task_struct *__ia64_slfo_task = (t); \ + __ia64_slfo_task->thread.last_fph_cpu = smp_processor_id(); \ + ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) __ia64_slfo_task); \ +} while (0) + +/* Mark the fph partition of task T as being invalid on all CPUs. */ +#define ia64_drop_fpu(t) ((t)->thread.last_fph_cpu = -1) extern void __ia64_init_fpu (void); extern void __ia64_save_fpu (struct ia64_fpreg *fph); @@ -636,8 +617,13 @@ ia64_set_lrr0 (unsigned long val) asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory"); } -#define cpu_relax() barrier() +static inline void +ia64_hint_pause (void) +{ + asm volatile ("hint @pause" ::: "memory"); +} +#define cpu_relax() ia64_hint_pause() static inline void ia64_set_lrr1 (unsigned long val) @@ -918,6 +904,18 @@ ia64_tpa (__u64 addr) return result; } +/* + * Take a mapped kernel address and return the equivalent address + * in the region 7 identity mapped virtual area. + */ +static inline void * +ia64_imva (void *addr) +{ + void *result; + asm ("tpa %0=%1" : "=r"(result) : "r"(addr)); + return __va(result); +} + #define ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCHW #define ARCH_HAS_SPINLOCK_PREFETCH diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index 7092f717e3f..6125e24cc29 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h @@ -5,6 +5,10 @@ * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang * Stephane Eranian + * Copyright (C) 2003 Intel Co + * Suresh Siddha + * Fenghua Yu + * Arun Sharma * * 12/07/98 S. Eranian added pt_regs & switch_stack * 12/21/98 D. Mosberger updated to match latest code @@ -93,6 +97,16 @@ */ struct pt_regs { /* The following registers are saved by SAVE_MIN: */ + unsigned long b6; /* scratch */ + unsigned long b7; /* scratch */ + + unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ + unsigned long ar_ssd; /* reserved for future use (scratch) */ + + unsigned long r8; /* scratch (return value register 0) */ + unsigned long r9; /* scratch (return value register 1) */ + unsigned long r10; /* scratch (return value register 2) */ + unsigned long r11; /* scratch (return value register 3) */ unsigned long cr_ipsr; /* interrupted task's psr */ unsigned long cr_iip; /* interrupted task's instruction pointer */ @@ -106,24 +120,23 @@ struct pt_regs { unsigned long ar_bspstore; /* RSE bspstore */ unsigned long pr; /* 64 predicate registers (1 bit each) */ - unsigned long b6; /* scratch */ + unsigned long b0; /* return pointer (bp) */ unsigned long loadrs; /* size of dirty partition << 16 */ unsigned long r1; /* the gp pointer */ - unsigned long r2; /* scratch */ - unsigned long r3; /* scratch */ unsigned long r12; /* interrupted task's memory stack pointer */ unsigned long r13; /* thread pointer */ - unsigned long r14; /* scratch */ + + unsigned long ar_fpsr; /* floating point status (preserved) */ unsigned long r15; /* scratch */ - unsigned long r8; /* scratch (return value register 0) */ - unsigned long r9; /* scratch (return value register 1) */ - unsigned long r10; /* scratch (return value register 2) */ - unsigned long r11; /* scratch (return value register 3) */ + /* The remaining registers are NOT saved for system calls. */ - /* The following registers are saved by SAVE_REST: */ + unsigned long r14; /* scratch */ + unsigned long r2; /* scratch */ + unsigned long r3; /* scratch */ + /* The following registers are saved by SAVE_REST: */ unsigned long r16; /* scratch */ unsigned long r17; /* scratch */ unsigned long r18; /* scratch */ @@ -142,18 +155,16 @@ struct pt_regs { unsigned long r31; /* scratch */ unsigned long ar_ccv; /* compare/exchange value (scratch) */ - unsigned long ar_fpsr; /* floating point status (preserved) */ - unsigned long b0; /* return pointer (bp) */ - unsigned long b7; /* scratch */ /* - * Floating point registers that the kernel considers - * scratch: + * Floating point registers that the kernel considers scratch: */ struct ia64_fpreg f6; /* scratch */ struct ia64_fpreg f7; /* scratch */ struct ia64_fpreg f8; /* scratch */ struct ia64_fpreg f9; /* scratch */ + struct ia64_fpreg f10; /* scratch */ + struct ia64_fpreg f11; /* scratch */ }; /* @@ -170,8 +181,6 @@ struct switch_stack { struct ia64_fpreg f4; /* preserved */ struct ia64_fpreg f5; /* preserved */ - struct ia64_fpreg f10; /* scratch, but untouched by kernel */ - struct ia64_fpreg f11; /* scratch, but untouched by kernel */ struct ia64_fpreg f12; /* scratch, but untouched by kernel */ struct ia64_fpreg f13; /* scratch, but untouched by kernel */ struct ia64_fpreg f14; /* scratch, but untouched by kernel */ @@ -226,6 +235,20 @@ struct switch_stack { !user_mode(_regs) && user_stack(_task, _regs); \ }) + /* + * System call handlers that, upon successful completion, need to return a negative value + * should call force_successful_syscall_return() right before returning. On architectures + * where the syscall convention provides for a separate error flag (e.g., alpha, ia64, + * ppc{,64}, sparc{,64}, possibly others), this macro can be used to ensure that the error + * flag will not get set. On architectures which do not support a separate error flag, + * the macro is a no-op and the spurious error condition needs to be filtered out by some + * other means (e.g., in user-level, by passing an extra argument to the syscall handler, + * or something along those lines). + * + * On ia64, we can clear the user's pt_regs->r8 to force a successful syscall. + */ +# define force_successful_syscall_return() (ia64_task_regs(current)->r8 = 0) + struct task_struct; /* forward decl */ struct unw_frame_info; /* forward decl */ @@ -250,11 +273,6 @@ struct switch_stack { extern void ia64_increment_ip (struct pt_regs *pt); extern void ia64_decrement_ip (struct pt_regs *pt); -#define force_successful_syscall_return() \ - do { \ - ia64_task_regs(current)->r8 = 0; \ - } while (0) - #endif /* !__KERNEL__ */ /* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ diff --git a/include/asm-ia64/ptrace_offsets.h b/include/asm-ia64/ptrace_offsets.h index 44a76cdcc4e..b712773c759 100644 --- a/include/asm-ia64/ptrace_offsets.h +++ b/include/asm-ia64/ptrace_offsets.h @@ -2,8 +2,8 @@ #define _ASM_IA64_PTRACE_OFFSETS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999, 2003 Hewlett-Packard Co + * David Mosberger-Tang */ /* * The "uarea" that can be accessed via PEEKUSER and POKEUSER is a @@ -11,9 +11,59 @@ * * struct uarea { * struct ia64_fpreg fph[96]; // f32-f127 - * struct switch_stack sw; - * struct pt_regs pt; - * unsigned long rsvd1[712]; + * unsigned long nat_bits; + * unsigned long empty1; + * struct ia64_fpreg f2; // f2-f5 + * : + * struct ia64_fpreg f5; + * struct ia64_fpreg f10; // f10-f31 + * : + * struct ia64_fpreg f31; + * unsigned long r4; // r4-r7 + * : + * unsigned long r7; + * unsigned long b1; // b1-b5 + * : + * unsigned long b5; + * unsigned long ar_ec; + * unsigned long ar_lc; + * unsigned long empty2[5]; + * unsigned long cr_ipsr; + * unsigned long cr_iip; + * unsigned long cfm; + * unsigned long ar_unat; + * unsigned long ar_pfs; + * unsigned long ar_rsc; + * unsigned long ar_rnat; + * unsigned long ar_bspstore; + * unsigned long pr; + * unsigned long b6; + * unsigned long ar_bsp; + * unsigned long r1; + * unsigned long r2; + * unsigned long r3; + * unsigned long r12; + * unsigned long r13; + * unsigned long r14; + * unsigned long r15; + * unsigned long r8; + * unsigned long r9; + * unsigned long r10; + * unsigned long r11; + * unsigned long r16; + * : + * unsigned long r31; + * unsigned long ar_ccv; + * unsigned long ar_fpsr; + * unsigned long b0; + * unsigned long b7; + * unsigned long f6; + * unsigned long f7; + * unsigned long f8; + * unsigned long f9; + * unsigned long ar_csd; + * unsigned long ar_ssd; + * unsigned long rsvd1[710]; * unsigned long dbr[8]; * unsigned long rsvd2[504]; * unsigned long ibr[8]; @@ -119,7 +169,7 @@ #define PT_F125 0x05d0 #define PT_F126 0x05e0 #define PT_F127 0x05f0 -/* switch stack: */ + #define PT_NAT_BITS 0x0600 #define PT_F2 0x0610 @@ -162,7 +212,6 @@ #define PT_AR_EC 0x0800 #define PT_AR_LC 0x0808 -/* pt_regs */ #define PT_CR_IPSR 0x0830 #define PT_CR_IIP 0x0838 #define PT_CFM 0x0840 @@ -209,6 +258,8 @@ #define PT_F7 0x0990 #define PT_F8 0x09a0 #define PT_F9 0x09b0 +#define PT_AR_CSD 0x09c0 +#define PT_AR_SSD 0x09c8 #define PT_DBR 0x2000 /* data breakpoint registers */ #define PT_IBR 0x3000 /* instruction breakpoint registers */ diff --git a/include/asm-ia64/resource.h b/include/asm-ia64/resource.h index 40223b9c327..92febf01f63 100644 --- a/include/asm-ia64/resource.h +++ b/include/asm-ia64/resource.h @@ -8,6 +8,8 @@ * Copyright (C) 1998, 1999 David Mosberger-Tang */ +#include + #define RLIMIT_CPU 0 /* CPU time in ms */ #define RLIMIT_FSIZE 1 /* Maximum filesize */ #define RLIMIT_DATA 2 /* max data size */ @@ -35,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ - { _STK_LIM, RLIM_INFINITY }, \ + { _STK_LIM, DEFAULT_USER_STACK_SIZE }, \ { 0, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ diff --git a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h index eccac9ce694..fff3680a628 100644 --- a/include/asm-ia64/sal.h +++ b/include/asm-ia64/sal.h @@ -23,6 +23,18 @@ * (plus examples of platform error info structures from smariset @ Intel) */ +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT 0 +#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT 1 +#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT 2 +#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT 3 + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1< #include @@ -162,11 +174,6 @@ typedef struct ia64_sal_desc_memory { u8 oem_reserved[8]; } ia64_sal_desc_memory_t; -#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1 << 0) -#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT (1 << 1) -#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT (1 << 2) -#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT (1 << 3) - typedef struct ia64_sal_desc_platform_feature { u8 type; u8 feature_mask; @@ -790,4 +797,6 @@ ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size, extern unsigned long sal_platform_features; +#endif /* __ASSEMBLY__ */ + #endif /* _ASM_IA64_PAL_H */ diff --git a/include/asm-ia64/sigcontext.h b/include/asm-ia64/sigcontext.h index 1ca82168e48..57ff777bcc4 100644 --- a/include/asm-ia64/sigcontext.h +++ b/include/asm-ia64/sigcontext.h @@ -56,7 +56,7 @@ struct sigcontext { unsigned long sc_rbs_base; /* NULL or new base of sighandler's rbs */ unsigned long sc_loadrs; /* see description above */ - unsigned long sc_ar25; /* rsvd for scratch use */ + unsigned long sc_ar25; /* cmp8xchg16 uses this */ unsigned long sc_ar26; /* rsvd for scratch use */ unsigned long sc_rsvd[12]; /* reserved for future use */ /* diff --git a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h index e924fcd0fc7..16de6f10c1e 100644 --- a/include/asm-ia64/siginfo.h +++ b/include/asm-ia64/siginfo.h @@ -69,13 +69,6 @@ typedef struct siginfo { long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ int _fd; } _sigpoll; - - /* SIGPROF */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - unsigned long _pfm_ovfl_counters[4]; /* which PMU counter overflowed */ - } _sigprof; } _sifields; } siginfo_t; @@ -95,14 +88,6 @@ typedef struct siginfo { #define __ISR_VALID (1 << __ISR_VALID_BIT) /* - * si_code values - * Positive values for kernel-generated signals. - */ -#ifdef __KERNEL__ -#define __SI_PROF (6 << 16) -#endif - -/* * SIGILL si_codes */ #define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ @@ -137,11 +122,6 @@ typedef struct siginfo { #undef NSIGTRAP #define NSIGTRAP 4 -/* - * SIGPROF si_codes - */ -#define PROF_OVFL (__SI_PROF|1) /* some counters overflowed */ - #ifdef __KERNEL__ #include @@ -151,8 +131,8 @@ copy_siginfo (siginfo_t *to, siginfo_t *from) if (from->si_code < 0) memcpy(to, from, sizeof(siginfo_t)); else - /* _sigprof is currently the largest know union member */ - memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigprof)); + /* _sigchld is currently the largest know union member */ + memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h index df4b07cf7f4..0b9a1253845 100644 --- a/include/asm-ia64/smp.h +++ b/include/asm-ia64/smp.h @@ -56,12 +56,12 @@ num_online_cpus (void) return hweight64(cpu_online_map); } -static inline int +static inline unsigned int any_online_cpu (unsigned int mask) { if (mask & cpu_online_map) return __ffs(mask & cpu_online_map); - return -1; + return NR_CPUS; } /* diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h index e77dd4b29bf..7b3f5d8614e 100644 --- a/include/asm-ia64/sn/addrs.h +++ b/include/asm-ia64/sn/addrs.h @@ -1,26 +1,17 @@ - /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992-1999,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1999,2001-2003 Silicon Graphics, Inc. All rights reserved. */ - #ifndef _ASM_IA64_SN_ADDRS_H #define _ASM_IA64_SN_ADDRS_H #include -#if defined (CONFIG_IA64_SGI_SN1) -#include -#elif defined (CONFIG_IA64_SGI_SN2) #include -#else -#error <<>> -#endif /* !SN1 && !SN2 */ #ifndef __ASSEMBLY__ #include @@ -30,11 +21,7 @@ #define PS_UINT_CAST (__psunsigned_t) #define UINT64_CAST (uint64_t) -#ifdef CONFIG_IA64_SGI_SN2 #define HUBREG_CAST (volatile mmr_t *) -#else -#define HUBREG_CAST (volatile hubreg_t *) -#endif #elif __ASSEMBLY__ @@ -52,11 +39,7 @@ * node's address space. */ -#ifdef CONFIG_IA64_SGI_SN2 /* SN2 has an extra AS field between node offset and node id (nasid) */ #define NODE_OFFSET(_n) (UINT64_CAST (_n) << NASID_SHFT) -#else -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#endif #define NODE_CAC_BASE(_n) (CAC_BASE + NODE_OFFSET(_n)) #define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) @@ -83,7 +66,7 @@ */ #define SWIN_SIZE_BITS 24 -#define SWIN_SIZE (UINT64_CAST 1 << 24) +#define SWIN_SIZE (1UL<<24) #define SWIN_SIZEMASK (SWIN_SIZE - 1) #define SWIN_WIDGET_MASK 0xF @@ -119,44 +102,13 @@ * references to the local hub's registers. */ -#if defined CONFIG_IA64_SGI_SN1 -#define LREG_BASE (HSPEC_BASE + 0x10000000) -#define LREG_SIZE 0x8000000 /* 128 MB */ -#define LREG_LIMIT (LREG_BASE + LREG_SIZE) -#define LBOOT_BASE (LREG_LIMIT) -#define LBOOT_SIZE 0x8000000 /* 128 MB */ -#define LBOOT_LIMIT (LBOOT_BASE + LBOOT_SIZE) -#define LBOOT_STRIDE 0x2000000 /* two PROMs, on 32M boundaries */ -#endif - #define HUB_REGISTER_WIDGET 1 -#ifdef CONFIG_IA64_SGI_SN2 #define IALIAS_BASE LOCAL_SWIN_BASE(HUB_REGISTER_WIDGET) -#else -#define IALIAS_BASE NODE_SWIN_BASE(0, HUB_REGISTER_WIDGET) -#endif #define IALIAS_SIZE 0x800000 /* 8 Megabytes */ #define IS_IALIAS(_a) (((_a) >= IALIAS_BASE) && \ ((_a) < (IALIAS_BASE + IALIAS_SIZE))) /* - * Macro for referring to Hub's RBOOT space - */ - -#if defined CONFIG_IA64_SGI_SN1 - -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define NODE_LREG_LIMIT(_n) (NODE_LREG_BASE(_n) + LREG_SIZE) -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) -#define RREG_LIMIT(_n) (NODE_LREG_LIMIT(_n)) -#define RBOOT_SIZE 0x8000000 /* 128 Megabytes */ -#define NODE_RBOOT_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x38000000) -#define NODE_RBOOT_LIMIT(_n) (NODE_RBOOT_BASE(_n) + RBOOT_SIZE) - -#endif - - -/* * The following macros produce the correct base virtual address for * the hub registers. The LOCAL_HUB_* macros produce the appropriate * address for the local registers. The REMOTE_HUB_* macro produce @@ -166,11 +118,10 @@ */ -#ifdef CONFIG_IA64_SGI_SN2 /* - * SN2 has II mmr's located inside small window space like SN0 & SN1, - * but has all other non-II mmr's located at the top of big window - * space, unlike SN0 & SN1. + * SN2 has II mmr's located inside small window space. + * As all other non-II mmr's located at the top of big window + * space. */ #define LOCAL_HUB_BASE(_x) (LOCAL_MMR_ADDR(_x) | (((~(_x)) & BWIN_TOP)>>8)) #define REMOTE_HUB_BASE(_x) \ @@ -182,18 +133,6 @@ #define REMOTE_HUB(_n, _x) \ (HUBREG_CAST (REMOTE_HUB_BASE(_x) | ((((long)(_n))<offset -#else -#define KLCONFIG_OFFSET(nasid) \ - ia64_sn_get_klconfig_addr(nasid) -#endif /* CONFIG_IA64_SGI_SN2 */ +#define KLCONFIG_OFFSET(nasid) ia64_sn_get_klconfig_addr(nasid) #define KLCONFIG_ADDR(nasid) \ TO_NODE_CAC((nasid), KLCONFIG_OFFSET(nasid)) diff --git a/include/asm-ia64/sn/alenlist.h b/include/asm-ia64/sn/alenlist.h index 81243e7c244..5853ee93075 100644 --- a/include/asm-ia64/sn/alenlist.h +++ b/include/asm-ia64/sn/alenlist.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ALENLIST_H #define _ASM_IA64_SN_ALENLIST_H diff --git a/include/asm-ia64/sn/arc/hinv.h b/include/asm-ia64/sn/arc/hinv.h index 9ae8feb80de..b2ebb3f31b6 100644 --- a/include/asm-ia64/sn/arc/hinv.h +++ b/include/asm-ia64/sn/arc/hinv.h @@ -1,13 +1,11 @@ /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ - /* $Id$ * * ARCS hardware/memory inventory/configuration and system ID definitions. diff --git a/include/asm-ia64/sn/arc/types.h b/include/asm-ia64/sn/arc/types.h index 53c5d4d8186..fff10f87856 100644 --- a/include/asm-ia64/sn/arc/types.h +++ b/include/asm-ia64/sn/arc/types.h @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (c) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright 1999 Ralf Baechle (ralf@gnu.org) - * Copyright 1999,2001 Silicon Graphics, Inc. */ #ifndef _ASM_SN_ARC_TYPES_H #define _ASM_SN_ARC_TYPES_H diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h index 85fadf519f9..a22d12db3e9 100644 --- a/include/asm-ia64/sn/arch.h +++ b/include/asm-ia64/sn/arch.h @@ -6,7 +6,7 @@ * * SGI specific setup. * - * Copyright (C) 1995-1997,1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1995-1997,1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) */ #ifndef _ASM_IA64_SN_ARCH_H @@ -17,23 +17,12 @@ #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif - -#if defined(CONFIG_IA64_SGI_SN1) -typedef u64 bdrkreg_t; -#elif defined(CONFIG_IA64_SGI_SN2) typedef u64 shubreg_t; -#endif - typedef u64 hubreg_t; typedef u64 mmr_t; typedef u64 nic_t; -typedef char cnodeid_t; #define CNODE_TO_CPU_BASE(_cnode) (NODEPDA(_cnode)->node_first_cpu) diff --git a/include/asm-ia64/sn/ate_utils.h b/include/asm-ia64/sn/ate_utils.h index 02bd7cd678c..d2bc0b82095 100644 --- a/include/asm-ia64/sn/ate_utils.h +++ b/include/asm-ia64/sn/ate_utils.h @@ -7,7 +7,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff --git a/include/asm-ia64/sn/bte.h b/include/asm-ia64/sn/bte.h index 5cc1eb60b48..0a17504d62b 100644 --- a/include/asm-ia64/sn/bte.h +++ b/include/asm-ia64/sn/bte.h @@ -1,7 +1,7 @@ /* * * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -36,11 +36,28 @@ #ifndef _ASM_IA64_SN_BTE_H #define _ASM_IA64_SN_BTE_H -#ident "$Revision: 1.1 $" - +#include #include #include #include +#include + + +/* #define BTE_DEBUG */ +/* #define BTE_DEBUG_VERBOSE */ + +#ifdef BTE_DEBUG +# define BTE_PRINTK(x) printk x /* Terse */ +# ifdef BTE_DEBUG_VERBOSE +# define BTE_PRINTKV(x) printk x /* Verbose */ +# else +# define BTE_PRINTKV(x) +# endif /* BTE_DEBUG_VERBOSE */ +#else +# define BTE_PRINTK(x) +# define BTE_PRINTKV(x) +#endif /* BTE_DEBUG */ + /* BTE status register only supports 16 bits for length field */ #define BTE_LEN_BITS (16) @@ -48,40 +65,60 @@ #define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES) -/* - * Constants used in determining the best and worst case transfer - * times. To help explain the two, the following graph of transfer - * status vs time may help. - * - * active +------------------:-+ : - * status | : | : - * idle +__________________:_+======= - * 0 Time MaxT MinT - * - * Therefore, MaxT is the maximum thoeretical rate for transfering - * the request block (assuming ideal circumstances) - * - * MinT is the minimum theoretical rate for transferring the - * requested block (assuming maximum link distance and contention) - * - * The following defines are the inverse of the above. They are - * used for calculating the MaxT time and MinT time given the - * number of lines in the transfer. - */ -#define BTE_MAXT_LINES_PER_SECOND 800 -#define BTE_MINT_LINES_PER_SECOND 600 - - /* Define hardware */ #define BTES_PER_NODE 2 + /* Define hardware modes */ #define BTE_NOTIFY (IBCT_NOTIFY) #define BTE_NORMAL BTE_NOTIFY #define BTE_ZERO_FILL (BTE_NOTIFY | IBCT_ZFIL_MODE) - /* Use a reserved bit to let the caller specify a wait for any BTE */ #define BTE_WACQUIRE (0x4000) +/* macro to force the IBCT0 value valid */ +#define BTE_VALID_MODE(x) ((x) & (IBCT_NOTIFY | IBCT_ZFIL_MODE)) + + +/* + * Handle locking of the bte interfaces. + * + * All transfers spinlock the interface before setting up the SHUB + * registers. Sync transfers hold the lock until all processing is + * complete. Async transfers release the lock as soon as the transfer + * is initiated. + * + * To determine if an interface is available, we must check both the + * busy bit and the spinlock for that interface. + */ +#define BTE_LOCK_IF_AVAIL(_x) (\ + (*pda->cpu_bte_if[_x]->most_rcnt_na & (IBLS_BUSY | IBLS_ERROR)) && \ + (!(spin_trylock(&(pda->cpu_bte_if[_x]->spinlock)))) \ + ) + +/* + * Some macros to simplify reading. + * Start with macros to locate the BTE control registers. + */ +#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) +#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) +#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) +#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) +#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) + + +/* Possible results from bte_copy and bte_unaligned_copy */ +typedef enum { + BTE_SUCCESS, /* 0 is success */ + BTEFAIL_NOTAVAIL, /* BTE not available */ + BTEFAIL_POISON, /* poison page */ + BTEFAIL_PROT, /* Protection violation */ + BTEFAIL_ACCESS, /* access error */ + BTEFAIL_TOUT, /* Time out */ + BTEFAIL_XTERR, /* Diretory error */ + BTEFAIL_DIR, /* Diretory error */ + BTEFAIL_ERROR, /* Generic error */ +} bte_result_t; + /* * Structure defining a bte. An instance of this @@ -90,28 +127,41 @@ * This structure contains everything necessary * to work with a BTE. */ -typedef struct bteinfo_s { +struct bteinfo_s { u64 volatile notify ____cacheline_aligned; char *bte_base_addr ____cacheline_aligned; spinlock_t spinlock; - u64 ideal_xfr_tmo; /* Time out */ - u64 ideal_xfr_tmo_cnt; - /* u64 most_recent_src; - * u64 most_recent_dest; - * u64 most_recent_len; - * u64 most_recent_mode; */ + cnodeid_t bte_cnode; /* cnode */ + int bte_error_count; /* Number of errors encountered */ + int bte_num; /* 0 --> BTE0, 1 --> BTE1 */ + int cleanup_active; /* Interface is locked for cleanup */ + volatile bte_result_t bh_error; /* error while processing */ u64 volatile *most_rcnt_na; - void *bte_test_buf; -} bteinfo_t; + void *scratch_buf; /* Node local scratch buffer */ +}; -/* Possible results from bte_copy and bte_unaligned_copy */ -typedef enum { - BTE_SUCCESS, /* 0 is success */ - BTEFAIL_NOTAVAIL, /* BTE not available */ - BTEFAIL_ERROR, /* Generic error */ - BTEFAIL_DIR /* Diretory error */ -} bte_result_t; -void bte_reset_nasid(nasid_t); +/* + * Function prototypes (functions defined in bte.c, used elsewhere) + */ +extern bte_result_t bte_copy(u64, u64, u64, u64, void *); +extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); +extern void bte_error_handler(unsigned long); + + +/* + * The following is the prefered way of calling bte_unaligned_copy + * If the copy is fully cache line aligned, then bte_copy is + * used instead. Since bte_copy is inlined, this saves a call + * stack. NOTE: bte_copy is called synchronously and does block + * until the transfer is complete. In order to get the asynch + * version of bte_copy, you must perform this check yourself. + */ +#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ + (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ + (dest & L1_CACHE_MASK)) ? \ + bte_unaligned_copy(src, dest, len, mode) : \ + bte_copy(src, dest, len, mode, NULL)) + -#endif /* _ASM_IA64_SN_BTE_H */ +#endif /* _ASM_IA64_SN_BTE_H */ diff --git a/include/asm-ia64/sn/bte_copy.h b/include/asm-ia64/sn/bte_copy.h deleted file mode 100644 index 51c45ea1526..00000000000 --- a/include/asm-ia64/sn/bte_copy.h +++ /dev/null @@ -1,385 +0,0 @@ -/* - * - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#ifndef _ASM_IA64_SN_BTE_COPY_H -#define _ASM_IA64_SN_BTE_COPY_H - -#ident "$Revision: 1.1 $" - -#include -#include -#include -#include -#include -#include - -#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) - -/* - * BTE_LOCKING support - When CONFIG_IA64_SGI_BTE_LOCKING is - * not defined, the bte_copy code supports one bte per cpu in - * synchronous mode. Even if bte_copy is called with a - * notify address, the bte will spin and wait for the transfer - * to complete. By defining the following, spin_locks and - * busy checks are placed around the initiation of a BTE - * transfer and multiple bte's per cpu are supported. - */ -#if 0 -#define CONFIG_IA64_SGI_BTE_LOCKING 1 -#endif - -/* - * Handle locking of the bte interfaces. - * - * All transfers spinlock the interface before setting up the SHUB - * registers. Sync transfers hold the lock until all processing is - * complete. Async transfers release the lock as soon as the transfer - * is initiated. - * - * To determine if an interface is available, we must check both the - * busy bit and the spinlock for that interface. - */ -#define BTE_LOCK_IF_AVAIL(_x) (\ - (*pda.cpu_bte_if[_x]->most_rcnt_na & IBLS_BUSY) && \ - (!(spin_trylock(&(pda.cpu_bte_if[_x]->spinlock)))) \ - ) - -/* - * Some macros to simplify reading. - * - * Start with macros to locate the BTE control registers. - */ - -#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) -#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) -#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) -#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) -#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) - -/* Some macros to force the IBCT0 value valid. */ - -#define BTE_VALID_MODES BTE_NOTIFY -#define BTE_VLD_MODE(x) (x & BTE_VALID_MODES) - -// #define BTE_DEBUG -// #define BTE_DEBUG_VERBOSE -// #define BTE_TIME - -#ifdef BTE_DEBUG -# define BTE_PRINTK(x) printk x /* Terse */ -# ifdef BTE_DEBUG_VERBOSE -# define BTE_PRINTKV(x) printk x /* Verbose */ -# else -# define BTE_PRINTKV(x) -# endif /* BTE_DEBUG_VERBOSE */ -#else -# define BTE_PRINTK(x) -# define BTE_PRINTKV(x) -#endif /* BTE_DEBUG */ - -#define BTE_IDEAL_TMO(x) (jiffies + \ - (HZ / BTE_MAXT_LINES_PER_SECOND * x)) - -#ifdef BTE_TIME -volatile extern u64 bte_setup_time; -volatile extern u64 bte_transfer_time; -volatile extern u64 bte_tear_down_time; -volatile extern u64 bte_execute_time; - -#define BTE_TIME_DECLARE() \ - u64 btcp_strt_tm = 0; \ - u64 btcp_cplt_tm = 0; \ - u64 xfr_strt_tm = 0; \ - u64 xfr_cplt_tm = 0; \ - -#define BTE_TIME_START() \ - btcp_strt_tm = xfr_strt_tm = xfr_cplt_tm = ia64_get_itc(); - -#define BTE_TIME_XFR_START() \ - xfr_strt_tm = ia64_get_itc(); - -#define BTE_TIME_XFR_STOP() \ - xfr_cplt_tm = ia64_get_itc(); - -#define BTE_TIME_STOP() \ - btcp_cplt_tm = ia64_get_itc(); \ - bte_setup_time = xfr_strt_tm - btcp_strt_tm; \ - bte_transfer_time = xfr_cplt_tm - xfr_strt_tm; \ - bte_tear_down_time = btcp_cplt_tm - xfr_cplt_tm; \ - bte_execute_time = btcp_cplt_tm - btcp_strt_tm; \ - -#else /* BTE_TIME */ -#define BTE_TIME_DECLARE() -#define BTE_TIME_START() -#define BTE_TIME_XFR_START() -#define BTE_TIME_XFR_STOP() -#define BTE_TIME_STOP() -#endif /* BTE_TIME */ - -/* - * bte_copy(src, dest, len, mode, notification) - * - * use the block transfer engine to move kernel - * memory from src to dest using the assigned mode. - * - * Paramaters: - * src - physical address of the transfer source. - * dest - physical address of the transfer destination. - * len - number of bytes to transfer from source to dest. - * mode - hardware defined. See reference information - * for IBCT0/1 in the SHUB Programmers Reference - * notification - kernel virtual address of the notification cache - * line. If NULL, the default is used and - * the bte_copy is synchronous. - * - * NOTE: This function requires src, dest, and len to - * be cache line aligned. - */ -extern __inline__ bte_result_t -bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) -{ -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - int bte_to_use; -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - u64 transfer_size; - u64 lines_remaining; - bteinfo_t *bte; - BTE_TIME_DECLARE(); - - BTE_TIME_START(); - - BTE_PRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", - src, dest, len, mode, notification)); - - if (len == 0) { - BTE_TIME_STOP(); - return (BTE_SUCCESS); - } - - ASSERT(!((len & L1_CACHE_MASK) || - (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); - - ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - { - bte_to_use = 0; - - /* Attempt to lock one of the BTE interfaces */ - while ((bte_to_use < BTES_PER_NODE) && - BTE_LOCK_IF_AVAIL(bte_to_use)) { - - bte_to_use++; - } - - if ((bte_to_use >= BTES_PER_NODE) && - !(mode & BTE_WACQUIRE)) { - BTE_TIME_STOP(); - return (BTEFAIL_NOTAVAIL); - } - - /* Wait until a bte is available. */ - } - while (bte_to_use >= BTES_PER_NODE); - - bte = pda.cpu_bte_if[bte_to_use]; - BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); -#else - /* Assuming one BTE per CPU. */ - bte = pda->cpu_bte_if[0]; -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - - /* - * The following are removed for optimization but is - * available in the event that the SHUB exhibits - * notification problems similar to the hub, bedrock et al. - * - * bte->mostRecentSrc = src; - * bte->mostRecentDest = dest; - * bte->mostRecentLen = len; - * bte->mostRecentMode = mode; - */ - if (notification == NULL) { - /* User does not want to be notified. */ - bte->most_rcnt_na = &bte->notify; - } else { - bte->most_rcnt_na = notification; - } - - /* Calculate the number of cache lines to transfer. */ - transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); - - BTE_PRINTKV(("Calculated transfer size of %d cache lines\n", - transfer_size)); - - /* Initialize the notification to a known value. */ - *bte->most_rcnt_na = -1L; - - - BTE_PRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - /* Set the status reg busy bit and transfer length */ - BTE_PRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n", - BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); - HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); - - /* Set the source and destination registers */ - BTE_PRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SRC_ADDR, - (TO_PHYS(src)))); - HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); - BTE_PRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, - (TO_PHYS(dest)))); - HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); - - /* Set the notification register */ - BTE_PRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR, - (TO_PHYS(__pa(bte->most_rcnt_na))))); - HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(__pa(bte->most_rcnt_na)))); - - /* Initiate the transfer */ - BTE_PRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode)); - BTE_TIME_XFR_START(); - HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode)); - - BTE_PRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - if (notification == NULL) { - /* - * Calculate our timeout - * - * What are we doing here? We are trying to determine - * the fastest time the BTE could have transfered our - * block of data. By takine the clock frequency (ticks/sec) - * divided by the BTE MaxT Transfer Rate (lines/sec) - * times the transfer size (lines), we get a tick - * offset from current time that the transfer should - * complete. - * - * Why do this? We are watching for a notification - * failure from the BTE. This behaviour has been - * seen in the SN0 and SN1 hardware on rare circumstances - * and is expected in SN2. By checking at the - * ideal transfer timeout, we minimize our time - * delay from hardware completing our request and - * our detecting the failure. - */ - bte->ideal_xfr_tmo = BTE_IDEAL_TMO(transfer_size); - - while (bte->notify == -1UL) { - /* - * Notification Workaround: When the max - * theoretical time has elapsed, read the hub - * status register into the notification area. - * This fakes the shub performing the copy. - */ - BTE_PRINTKV((" Timing. IBLS = 0x%lx, " - "notify= 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - if (time_after(jiffies, bte->ideal_xfr_tmo)) { - lines_remaining = HUB_L(BTEREG_LNSTAT_ADDR) & - BTE_LEN_MASK; - bte->ideal_xfr_tmo_cnt++; - bte->ideal_xfr_tmo = - BTE_IDEAL_TMO(lines_remaining); - - BTE_PRINTKV((" Timeout. cpu %d " - "IBLS = 0x%lx, " - "notify= 0x%lx, " - "Lines remaining = %d. " - "New timeout = %d.\n", - smp_processor_id(), - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify, - lines_remaining, - bte->ideal_xfr_tmo)); - } - } - BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, notify= 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - BTE_TIME_XFR_STOP(); - if (bte->notify & IBLS_ERROR) { - /* >>> Need to do real error checking. */ - transfer_size = 0; - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - BTE_PRINTKV(("Erroring status is 0x%lx and " - "notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - - BTE_TIME_STOP(); - bte->notify = 0L; - return (BTEFAIL_ERROR); - } - - } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - BTE_TIME_STOP(); - BTE_PRINTKV(("Returning status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - return (BTE_SUCCESS); -} - -/* - * Define the bte_unaligned_copy as an extern. - */ -extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); - -/* - * The following is the prefered way of calling bte_unaligned_copy - * If the copy is fully cache line aligned, then bte_copy is - * used instead. Since bte_copy is inlined, this saves a call - * stack. NOTE: bte_copy is called synchronously and does block - * until the transfer is complete. In order to get the asynch - * version of bte_copy, you must perform this check yourself. - */ -#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ - (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ - (dest & L1_CACHE_MASK)) ? \ - bte_unaligned_copy(src, dest, len, mode) : \ - bte_copy(src, dest, len, mode, NULL)) - -#endif /* _ASM_IA64_SN_BTE_COPY_H */ diff --git a/include/asm-ia64/sn/cdl.h b/include/asm-ia64/sn/cdl.h dissimilarity index 87% index 35c7f8ec37b..6f551e1ca85 100644 --- a/include/asm-ia64/sn/cdl.h +++ b/include/asm-ia64/sn/cdl.h @@ -1,195 +1,41 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_CDL_H -#define _ASM_IA64_SN_CDL_H - -#include - -/* - * cdl: connection/driver list - * - * support code for bus infrastructure for busses - * that have self-identifying devices; initially - * constructed for xtalk, pciio and gioio modules. - */ -typedef struct cdl *cdl_p; - -/* - * cdl_itr_f is the type for the functions - * that are handled by cdl_iterate. - */ - -typedef void -cdl_iter_f (devfs_handle_t vhdl); - -/* - * cdl_drv_f is the type for the functions - * that are called by cdl_add_driver and - * cdl_del_driver. - */ - -typedef void -cdl_drv_f (devfs_handle_t vhdl, int key1, int key2, int error); - -/* - * If CDL_PRI_HI is specified in the flags - * parameter for cdl_add_driver, then that driver's - * attach routine will be called for future connect - * points before any (non-CDL_PRI_HI) drivers. - * - * The IOC3 driver uses this facility to make sure - * that the ioc3_attach() function is called before - * the attach routines of any subdevices. - * - * Drivers for bridge-based crosstalk cards that - * are almost but not quite generic can use it to - * arrange that their attach() functions get called - * before the generic bridge drivers, so they can - * leave behind "hint" structures that will - * properly configure the generic driver. - */ -#define CDL_PRI_HI 0x0001 - -/* - * cdl_new: construct a new connection/driver list - * - * Called once for each "kind" of bus. Returns an - * opaque cookie representing the particular list - * that will be operated on by the other calls. - */ -extern cdl_p cdl_new(char *, char *, char *); - -/* - * cdl_del: destroy a connection/driver list. - * - * Releases all dynamically allocated resources - * associated with the specified list. Forgets what - * drivers might be involved in this kind of bus, - * forgets what connection points have been noticed - * on this kind of bus. - */ -extern void cdl_del(cdl_p reg); - -/* - * cdl_add_driver: register a device driver - * - * Calls the driver's attach routine with all - * connection points on the list that have the same - * key information as the driver; call-back the - * specified function to notify the driver of the - * attach status for each device. Place the driver - * on the list so that any connection points - * discovered in the future that match the driver - * can be handed off to the driver's attach - * routine. - * - * CDL_PRI_HI may be specified (see above). - */ - -extern int cdl_add_driver(cdl_p reg, - int key1, - int key2, - char *prefix, - int flags, - cdl_drv_f *func); - -/* - * cdl_del_driver: remove a device driver - * - * Calls the driver's detach routine with all - * connection points on the list that match the - * driver; call-back the specified function to - * notify the driver of the detach status for each - * device. Then forget about the driver. Future - * calls to cdl_add_connpt with connections that - * would match this driver no longer trigger calls - * to the driver's attach routine. - * - * NOTE: Yes, I said CONNECTION POINTS, not - * verticies that the driver has been attached to - * with hwgraph_driver_add(); this gives the driver - * a chance to clean up anything it did to the - * connection point in its attach routine. Also, - * this is done whether or not the attach routine - * was successful. - */ -extern void cdl_del_driver(cdl_p reg, - char *prefix, - cdl_drv_f *func); - -/* - * cdl_add_connpt: add a connection point - * - * Calls the attach routines of all the drivers on - * the list that match this connection point, in - * the order that they were added to the list, - * except that CDL_PRI_HI drivers are called first. - * - * Then the vertex is added to the list, so it can - * be presented to any matching drivers that may be - * subsequently added to the list. - */ -extern int cdl_add_connpt(cdl_p reg, - int key1, - int key2, - devfs_handle_t conn, - int drv_flags); - -/* - * cdl_del_connpt: delete a connection point - * - * Calls the detach routines of all matching - * drivers for this connection point, in the same - * order that the attach routines were called; then - * forgets about this vertex, so drivers added in - * the future will not be told about it. - * - * NOTE: Same caveat here about the detach calls as - * in the cdl_del_driver() comment above. - */ -extern int cdl_del_connpt(cdl_p reg, - int key1, - int key2, - devfs_handle_t conn, - int drv_flags); - -/* - * cdl_iterate: find all verticies in the registry - * corresponding to the named driver and call them - * with the specified function (giving the vertex - * as the parameter). - */ - -extern void cdl_iterate(cdl_p reg, - char *prefix, - cdl_iter_f *func); - -/* - * An INFO_LBL_ASYNC_ATTACH label is attached to a vertex, pointing to - * an instance of async_attach_s to indicate that asynchronous - * attachment may be applied to that device ... if the corresponding - * driver allows it. - */ - -struct async_attach_s { - struct semaphore async_sema; - int async_count; -}; -typedef struct async_attach_s *async_attach_t; - -async_attach_t async_attach_new(void); -void async_attach_free(async_attach_t); -async_attach_t async_attach_get_info(devfs_handle_t); -void async_attach_add_info(devfs_handle_t, async_attach_t); -void async_attach_del_info(devfs_handle_t); -void async_attach_signal_start(async_attach_t); -void async_attach_signal_done(async_attach_t); -void async_attach_waitall(async_attach_t); - -#endif /* _ASM_IA64_SN_CDL_H */ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_IA64_SN_CDL_H +#define _ASM_IA64_SN_CDL_H + +#include + +struct cdl { + int part_num; /* Part part number */ + int mfg_num; /* Part MFG number */ + int (*attach)(vertex_hdl_t); /* Attach routine */ +}; + + +/* + * cdl: connection/driver list + * + * support code for bus infrastructure for busses + * that have self-identifying devices; initially + * constructed for xtalk, pciio and gioio modules. + */ +typedef struct cdl *cdl_p; + +/* + * cdl_add_connpt: add a connection point + * + * Calls the attach routines of all the drivers on + * the list that match this connection point, in + * the order that they were added to the list. + */ +extern int cdl_add_connpt(int key1, + int key2, + vertex_hdl_t conn, + int drv_flags); +#endif /* _ASM_IA64_SN_CDL_H */ diff --git a/include/asm-ia64/sn/clksupport.h b/include/asm-ia64/sn/clksupport.h index 98b9cac4d28..f619c692c81 100644 --- a/include/asm-ia64/sn/clksupport.h +++ b/include/asm-ia64/sn/clksupport.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* @@ -31,28 +31,10 @@ typedef long clkreg_t; extern unsigned long sn_rtc_cycles_per_second; - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#include - -extern nasid_t master_nasid; - -#define RTC_MASK (0x007fffffffffffff) -/* clocks are not synchronized yet on SN1 - used node 0 (problem if no NASID 0) */ -#define RTC_COUNTER_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COUNTER)) -#define RTC_COMPARE_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_A)) -#define RTC_COMPARE_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_B)) -#define RTC_INT_PENDING_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_A)) -#define RTC_INT_PENDING_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_B)) -#define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_A)) -#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_B)) -#else /* !CONFIG_IA64_SGI_SN1 */ #include #include #include #include -#define RTC_MASK (SH_RTC_MASK) #define RTC_COUNTER_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) @@ -60,8 +42,6 @@ extern nasid_t master_nasid; #define RTC_INT_PENDING_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) -#endif /* CONFIG_IA64_SGI_SN1 */ - #define GET_RTC_COUNTER() (*RTC_COUNTER_ADDR) #define rtc_time() GET_RTC_COUNTER() diff --git a/include/asm-ia64/sn/dmamap.h b/include/asm-ia64/sn/dmamap.h index 6f56cac7f86..2f34eda46bf 100644 --- a/include/asm-ia64/sn/dmamap.h +++ b/include/asm-ia64/sn/dmamap.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DMAMAP_H #define _ASM_IA64_SN_DMAMAP_H @@ -54,9 +54,6 @@ extern void dma_mapfree(dmamap_t *); extern int dma_map(dmamap_t *, caddr_t, int); extern int dma_map2(dmamap_t *, caddr_t, caddr_t, int); extern paddr_t dma_mapaddr(dmamap_t *, caddr_t); -#ifdef LATER -extern int dma_mapbp(dmamap_t *, buf_t *, int); -#endif extern int dma_map_alenlist(dmamap_t *, struct alenlist_s *, size_t); extern uint ev_kvtoiopnum(caddr_t); diff --git a/include/asm-ia64/sn/driver.h b/include/asm-ia64/sn/driver.h index 17a76381d6b..c23e70d92ae 100644 --- a/include/asm-ia64/sn/driver.h +++ b/include/asm-ia64/sn/driver.h @@ -4,12 +4,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DRIVER_H #define _ASM_IA64_SN_DRIVER_H -#include +#include #include /* @@ -75,7 +75,7 @@ typedef struct device_desc_s { /* TBD: allocated badwidth requirements */ /* interrupt description */ - devfs_handle_t intr_target; /* Hardware locator string */ + vertex_hdl_t intr_target; /* Hardware locator string */ int intr_policy; /* TBD */ ilvl_t intr_swlevel; /* software level for blocking intr */ char *intr_name; /* name of interrupt, if any */ diff --git a/include/asm-ia64/sn/eeprom.h b/include/asm-ia64/sn/eeprom.h deleted file mode 100644 index cc358591dd3..00000000000 --- a/include/asm-ia64/sn/eeprom.h +++ /dev/null @@ -1,384 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Public interface for reading Atmel EEPROMs via L1 system controllers - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_EEPROM_H -#define _ASM_IA64_SN_EEPROM_H - -#include -#include -#include -#include -#include -#include - -/* - * The following structures are an implementation of the EEPROM info - * areas described in the SN1 EEPROM spec and the IPMI FRU Information - * Storage definition - */ - -/* Maximum lengths for EEPROM fields - */ -#define EEPROM_PARTNUM_LEN 20 -#define EEPROM_SERNUM_LEN 10 -#define EEPROM_MANUF_NAME_LEN 10 -#define EEPROM_PROD_NAME_LEN 14 - - - -/* The EEPROM "common header", which contains offsets to the other - * info areas in the EEPROM - */ -typedef struct eeprom_common_hdr_t -{ - uchar_t format; /* common header format byte */ - uchar_t internal_use; /* offsets to various info areas */ - uchar_t chassis; /* (in doubleword units) */ - uchar_t board; - uchar_t product; - uchar_t multi_record; - uchar_t pad; - uchar_t checksum; -} eeprom_common_hdr_t; - - -/* The chassis (brick) info area - */ -typedef struct eeprom_chassis_ia_t -{ - uchar_t format; /* format byte */ - uchar_t length; /* info area length in doublewords */ - uchar_t type; /* chassis type (always 0x17 "rack mount") */ - uchar_t part_num_tl; /* type/length of part number field */ - - char part_num[EEPROM_PARTNUM_LEN]; - /* ASCII part number */ - - uchar_t serial_num_tl; /* type/length of serial number field */ - - char serial_num[EEPROM_SERNUM_LEN]; - /* ASCII serial number */ - - uchar_t checksum; - -} eeprom_chassis_ia_t; - - -/* The board info area - */ -typedef struct eeprom_board_ia_t -{ - uchar_t format; /* format byte */ - uchar_t length; /* info area length in doublewords */ - uchar_t language; /* language code, always 0x00 "English" */ - int mfg_date; /* date & time of manufacture, in minutes - since 0:00 1/1/96 */ - uchar_t manuf_tl; /* type/length of manufacturer name field */ - - char manuf[EEPROM_MANUF_NAME_LEN]; - /* ASCII manufacturer name */ - - uchar_t product_tl; /* type/length of product name field */ - - char product[EEPROM_PROD_NAME_LEN]; - /* ASCII product name */ - - uchar_t serial_num_tl; /* type/length of board serial number */ - - char serial_num[EEPROM_SERNUM_LEN]; - /* ASCII serial number */ - - uchar_t part_num_tl; /* type/length of board part number */ - - char part_num[EEPROM_PARTNUM_LEN]; - /* ASCII part number */ - - /* - * "custom" fields -- see SN1 EEPROM Spec - */ - uchar_t board_rev_tl; /* type/length of board rev (always 0xC2) */ - - char board_rev[2]; /* ASCII board revision */ - - uchar_t eeprom_size_tl; /* type/length of eeprom size field */ - uchar_t eeprom_size; /* size code for eeprom */ - uchar_t temp_waiver_tl; /* type/length of temp waiver field (0xC2) */ - char temp_waiver[2]; /* temp waiver */ - - - /* - * these fields only appear in main boards' EEPROMs - */ - uchar_t ekey_G_tl; /* type/length of encryption key "G" */ - uint32_t ekey_G; /* encryption key "G" */ - uchar_t ekey_P_tl; /* type/length of encryption key "P" */ - uint32_t ekey_P; /* encryption key "P" */ - uchar_t ekey_Y_tl; /* type/length of encryption key "Y" */ - uint32_t ekey_Y; /* encryption key "Y" */ - - - /* - * these fields are used for I bricks only - */ - uchar_t mac_addr_tl; /* type/length of MAC address */ - char mac_addr[12]; /* MAC address */ - uchar_t ieee1394_cfg_tl; /* type/length of IEEE 1394 info */ - uchar_t ieee1394_cfg[32]; /* IEEE 1394 config info */ - - - /* - * all boards have a checksum - */ - uchar_t checksum; - -} eeprom_board_ia_t; - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ); - - -/* EEPROM Serial Presence Detect record (used for DIMMs in IP35) - */ -typedef struct eeprom_spd_t -{ - /* 0*/ uchar_t spd_used; /* # of bytes written to serial memory by manufacturer */ - /* 1*/ uchar_t spd_size; /* Total # of bytes of SPD memory device */ - /* 2*/ uchar_t mem_type; /* Fundamental memory type (FPM, EDO, SDRAM..) */ - /* 3*/ uchar_t num_rows; /* # of row addresses on this assembly */ - /* 4*/ uchar_t num_cols; /* # Column Addresses on this assembly */ - /* 5*/ uchar_t mod_rows; /* # Module Rows on this assembly */ - /* 6*/ uchar_t data_width[2]; /* Data Width of this assembly (16b little-endian) */ - /* 8*/ uchar_t volt_if; /* Voltage interface standard of this assembly */ - /* 9*/ uchar_t cyc_time; /* SDRAM Cycle time, CL=X (highest CAS latency) */ - /* A*/ uchar_t acc_time; /* SDRAM Access from Clock (highest CAS latency) */ - /* B*/ uchar_t dimm_cfg; /* DIMM Configuration type (non-parity, ECC) */ - /* C*/ uchar_t refresh_rt; /* Refresh Rate/Type */ - /* D*/ uchar_t prim_width; /* Primary SDRAM Width */ - /* E*/ uchar_t ec_width; /* Error Checking SDRAM width */ - /* F*/ uchar_t min_delay; /* Min Clock Delay Back to Back Random Col Address */ - /*10*/ uchar_t burst_len; /* Burst Lengths Supported */ - /*11*/ uchar_t num_banks; /* # of Banks on Each SDRAM Device */ - /*12*/ uchar_t cas_latencies; /* CAS# Latencies Supported */ - /*13*/ uchar_t cs_latencies; /* CS# Latencies Supported */ - /*14*/ uchar_t we_latencies; /* Write Latencies Supported */ - /*15*/ uchar_t mod_attrib; /* SDRAM Module Attributes */ - /*16*/ uchar_t dev_attrib; /* SDRAM Device Attributes: General */ - /*17*/ uchar_t cyc_time2; /* Min SDRAM Cycle time at CL X-1 (2nd highest CAS latency) */ - /*18*/ uchar_t acc_time2; /* SDRAM Access from Clock at CL X-1 (2nd highest CAS latency) */ - /*19*/ uchar_t cyc_time3; /* Min SDRAM Cycle time at CL X-2 (3rd highest CAS latency) */ - /*1A*/ uchar_t acc_time3; /* Max SDRAM Access from Clock at CL X-2 (3nd highest CAS latency) */ - /*1B*/ uchar_t min_row_prechg; /* Min Row Precharge Time (Trp) */ - /*1C*/ uchar_t min_ra_to_ra; /* Min Row Active to Row Active (Trrd) */ - /*1D*/ uchar_t min_ras_to_cas; /* Min RAS to CAS Delay (Trcd) */ - /*1E*/ uchar_t min_ras_pulse; /* Minimum RAS Pulse Width (Tras) */ - /*1F*/ uchar_t row_density; /* Density of each row on module */ - /*20*/ uchar_t ca_setup; /* Command and Address signal input setup time */ - /*21*/ uchar_t ca_hold; /* Command and Address signal input hold time */ - /*22*/ uchar_t d_setup; /* Data signal input setup time */ - /*23*/ uchar_t d_hold; /* Data signal input hold time */ - - /*24*/ uchar_t pad0[26]; /* unused */ - - /*3E*/ uchar_t data_rev; /* SPD Data Revision Code */ - /*3F*/ uchar_t checksum; /* Checksum for bytes 0-62 */ - /*40*/ uchar_t jedec_id[8]; /* Manufacturer's JEDEC ID code */ - - /*48*/ uchar_t mfg_loc; /* Manufacturing Location */ - /*49*/ uchar_t part_num[18]; /* Manufacturer's Part Number */ - - /*5B*/ uchar_t rev_code[2]; /* Revision Code */ - - /*5D*/ uchar_t mfg_date[2]; /* Manufacturing Date */ - - /*5F*/ uchar_t ser_num[4]; /* Assembly Serial Number */ - - /*63*/ uchar_t manuf_data[27]; /* Manufacturer Specific Data */ - - /*7E*/ uchar_t intel_freq; /* Intel specification frequency */ - /*7F*/ uchar_t intel_100MHz; /* Intel spec details for 100MHz support */ - -} eeprom_spd_t; - - -#define EEPROM_SPD_RECORD_MAXLEN 256 - -typedef union eeprom_spd_u -{ - eeprom_spd_t fields; - char bytes[EEPROM_SPD_RECORD_MAXLEN]; - -} eeprom_spd_u; - - -/* EEPROM board record - */ -typedef struct eeprom_brd_record_t -{ - eeprom_chassis_ia_t *chassis_ia; - eeprom_board_ia_t *board_ia; - eeprom_spd_u *spd; - -} eeprom_brd_record_t; - - -/* End-of-fields marker - */ -#define EEPROM_EOF 0xc1 - - -/* masks for dissecting the type/length bytes - */ -#define FIELD_FORMAT_MASK 0xc0 -#define FIELD_LENGTH_MASK 0x3f - - -/* field format codes (used in type/length bytes) - */ -#define FIELD_FORMAT_BINARY 0x00 /* binary format */ -#define FIELD_FORMAT_BCD 0x40 /* BCD */ -#define FIELD_FORMAT_PACKED 0x80 /* packed 6-bit ASCII */ -#define FIELD_FORMAT_ASCII 0xC0 /* 8-bit ASCII */ - - - - -/* codes specifying brick and board type - */ -#define C_BRICK 0x100 - -#define C_PIMM (C_BRICK | 0x10) -#define C_PIMM_0 (C_PIMM) /* | 0x0 */ -#define C_PIMM_1 (C_PIMM | 0x1) - -#define C_DIMM (C_BRICK | 0x20) -#define C_DIMM_0 (C_DIMM) /* | 0x0 */ -#define C_DIMM_1 (C_DIMM | 0x1) -#define C_DIMM_2 (C_DIMM | 0x2) -#define C_DIMM_3 (C_DIMM | 0x3) -#define C_DIMM_4 (C_DIMM | 0x4) -#define C_DIMM_5 (C_DIMM | 0x5) -#define C_DIMM_6 (C_DIMM | 0x6) -#define C_DIMM_7 (C_DIMM | 0x7) - -#define R_BRICK 0x200 -#define R_POWER (R_BRICK | 0x10) - -#define VECTOR 0x300 /* used in vector ops when the destination - * could be a cbrick or an rbrick */ - -#define IO_BRICK 0x400 -#define IO_POWER (IO_BRICK | 0x10) - -#define BRICK_MASK 0xf00 -#define SUBORD_MASK 0xf0 /* AND with component specification; if the - the result is non-zero, then the component - is a subordinate board of some kind */ -#define COMPT_MASK 0xf /* if there's more than one instance of a - particular type of subordinate board, this - masks out which one we're talking about */ - - - -/* functions & macros for obtaining "NIC-like" strings from EEPROMs - */ - -#ifdef CONFIG_IA64_SGI_SN1 - -int eeprom_str( char *nic_str, nasid_t nasid, int component ); -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ); - -#define CBRICK_EEPROM_STR(s,n) eeprom_str((s),(n),C_BRICK) -#define IOBRICK_EEPROM_STR(s,n) eeprom_str((s),(n),IO_BRICK) -#define RBRICK_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),R_BRICK,p) -#define VECTOR_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),VECTOR,p) - -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/* functions for obtaining formatted records from EEPROMs - */ - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ); -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ); -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ); - - - -/* retrieve the ethernet MAC address for an I-brick - */ - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ); - - -/* error codes - */ - -#define EEP_OK 0 -#define EEP_L1 1 -#define EEP_FAIL 2 -#define EEP_BAD_CHECKSUM 3 -#define EEP_NICIFY 4 -#define EEP_PARAM 6 -#define EEP_NOMEM 7 - - - -/* given a hardware graph vertex and an indication of the brick type, - * brick and board to be read, this functions reads the eeprom and - * attaches a "NIC"-format string of manufacturing information to the - * vertex. If the vertex already has the string, just returns the - * string. If component is not VECTOR or R_BRICK, the path parameter - * is ignored. - */ - -#ifdef LATER -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ); -#endif - - - -/* We may need to differentiate between an XBridge and other types of - * bridges during discovery to tell whether the bridge in question - * is part of an IO brick. The following function reads the WIDGET_ID - * register of the bridge under examination and returns a positive value - * if the part and mfg numbers stored there indicate that this widget - * is an XBridge (and so must be part of a brick). - */ -#ifdef LATER -int is_iobrick( int nasid, int widget_num ); -#endif - -/* the following macro derives the widget number from the register - * address passed to it and uses is_iobrick to determine whether - * the widget in question is part of an SN1 IO brick. - */ -#define IS_IOBRICK(rg) is_iobrick( NASID_GET((rg)), SWIN_WIDGETNUM((rg)) ) - - - -/* macros for NIC compatibility */ -/* always invoked on "this" cbrick */ -#define HUB_VERTEX_MFG_INFO(v) \ - eeprom_vertex_info_set( C_BRICK, get_nasid(), (v), 0 ) - -#define BRIDGE_VERTEX_MFG_INFO(v, r) \ - ( IS_IOBRICK((r)) ? eeprom_vertex_info_set \ - ( IO_BRICK, NASID_GET((r)), (v), 0 ) \ - : nic_bridge_vertex_info((v), (r)) ) - -#endif /* _ASM_IA64_SN_EEPROM_H */ diff --git a/include/asm-ia64/sn/fetchop.h b/include/asm-ia64/sn/fetchop.h index 53b7b4f3fbb..9a5b9a06b5b 100644 --- a/include/asm-ia64/sn/fetchop.h +++ b/include/asm-ia64/sn/fetchop.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_FETCHOP_H @@ -39,28 +39,10 @@ #ifdef __KERNEL__ /* - * Initialize a FETCHOP line. The argument should point to the beginning - * of the line. - * SN1 - region mask is in word 0, data in word 1 - * SN2 - no region mask. Data in word 0 - */ -#ifdef CONFIG_IA64_SGI_SN1 -#define FETCHOP_INIT_LINE(p) *(p) = 0xffffffffffffffffUL -#elif CONFIG_IA64_SGI_SN2 -#define FETCHOP_INIT_LINE(p) -#endif - -/* - * Convert a region 7 (kaddr) address to the address of the fetchop variable + * Convert a region 6 (kaddr) address to the address of the fetchop variable */ #define FETCHOP_KADDR_TO_MSPEC_ADDR(kaddr) TO_MSPEC(kaddr) -/* - * Convert a page struct (page) address to the address of the first - * fetchop variable in the page - */ -#define FETCHOP_PAGE_TO_MSPEC_ADDR(page) FETCHOP_KADDR_TO_MSPEC_ADDR(__pa(page_address(page))) - /* * Each Atomic Memory Operation (AMO formerly known as fetchop) @@ -80,21 +62,21 @@ * inconsistency. */ typedef struct { - -#ifdef CONFIG_IA64_SGI_SN1 - u64 permissions; -#endif u64 variable; - -#ifdef CONFIG_IA64_SGI_SN1 - u64 unused[6]; -#else u64 unused[7]; -#endif - } AMO_t; +/* + * The following APIs are externalized to the kernel to allocate/free fetchop variables. + * fetchop_kalloc_one - Allocate/initialize 1 fetchop variable on the specified cnode. + * fetchop_kfree_one - Free a previously allocated fetchop variable + */ + +unsigned long fetchop_kalloc_one(int nid); +void fetchop_kfree_one(unsigned long maddr); + + #endif /* __KERNEL__ */ #endif /* _ASM_IA64_SN_FETCHOP_H */ diff --git a/include/asm-ia64/sn/gda.h b/include/asm-ia64/sn/gda.h deleted file mode 100644 index d57b89a7e88..00000000000 --- a/include/asm-ia64/sn/gda.h +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Derived from IRIX . - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - * - * gda.h -- Contains the data structure for the global data area, - * The GDA contains information communicated between the - * PROM, SYMMON, and the kernel. - */ -#ifndef _ASM_IA64_SN_GDA_H -#define _ASM_IA64_SN_GDA_H - -#include -#include - -#define GDA_MAGIC 0x58464552 - -/* - * GDA Version History - * - * Version # | Change - * -------------+------------------------------------------------------- - * 1 | Initial IP27 version - * 2 | Prom sets g_partid field to the partition number. 0 IS - * | a valid partition #. - */ - -#define GDA_VERSION 2 /* Current GDA version # */ - -#define G_MAGICOFF 0 -#define G_VERSIONOFF 4 -#define G_PROMOPOFF 6 -#define G_MASTEROFF 8 -#define G_VDSOFF 12 -#define G_HKDNORMOFF 16 -#define G_HKDUTLBOFF 24 -#define G_HKDXUTLBOFF 32 -#define G_PARTIDOFF 40 -#define G_TABLEOFF 128 - -#ifndef __ASSEMBLY__ - -typedef struct gda { - u32 g_magic; /* GDA magic number */ - u16 g_version; /* Version of this structure */ - u16 g_masterid; /* The NASID:CPUNUM of the master cpu */ - u32 g_promop; /* Passes requests from the kernel to prom */ - u32 g_vds; /* Store the virtual dipswitches here */ - void **g_hooked_norm;/* ptr to pda loc for norm hndlr */ - void **g_hooked_utlb;/* ptr to pda loc for utlb hndlr */ - void **g_hooked_xtlb;/* ptr to pda loc for xtlb hndlr */ - int g_partid; /* partition id */ - int g_symmax; /* Max symbols in name table. */ - void *g_dbstab; /* Address of idbg symbol table */ - char *g_nametab; /* Address of idbg name table */ - void *g_ktext_repmask; - /* Pointer to a mask of nodes with copies - * of the kernel. */ - char g_padding[56]; /* pad out to 128 bytes */ - nasid_t g_nasidtable[MAX_COMPACT_NODES+1]; /* NASID of each node, - * indexed by cnodeid. - */ -} gda_t; - -#define GDA ((gda_t*) GDA_ADDR(get_nasid())) - -#endif /* __ASSEMBLY__ */ -/* - * Define: PART_GDA_VERSION - * Purpose: Define the minimum version of the GDA required, lower - * revisions assume GDA is NOT set up, and read partition - * information from the board info. - */ -#define PART_GDA_VERSION 2 - -/* - * The following requests can be sent to the PROM during startup. - */ - -#define PROMOP_MAGIC 0x0ead0000 -#define PROMOP_MAGIC_MASK 0x0fff0000 - -#define PROMOP_BIST_SHIFT 11 -#define PROMOP_BIST_MASK (0x3 << 11) - -#define PROMOP_REG PI_ERR_STACK_ADDR_A - -#define PROMOP_INVALID (PROMOP_MAGIC | 0x00) -#define PROMOP_HALT (PROMOP_MAGIC | 0x10) -#define PROMOP_POWERDOWN (PROMOP_MAGIC | 0x20) -#define PROMOP_RESTART (PROMOP_MAGIC | 0x30) -#define PROMOP_REBOOT (PROMOP_MAGIC | 0x40) -#define PROMOP_IMODE (PROMOP_MAGIC | 0x50) - -#define PROMOP_CMD_MASK 0x00f0 -#define PROMOP_OPTIONS_MASK 0xfff0 - -#define PROMOP_SKIP_DIAGS 0x0100 /* don't bother running diags */ -#define PROMOP_SKIP_MEMINIT 0x0200 /* don't bother initing memory */ -#define PROMOP_SKIP_DEVINIT 0x0400 /* don't bother initing devices */ -#define PROMOP_BIST1 0x0800 /* keep track of which BIST ran */ -#define PROMOP_BIST2 0x1000 /* keep track of which BIST ran */ - -#endif /* _ASM_IA64_SN_GDA_H */ diff --git a/include/asm-ia64/sn/geo.h b/include/asm-ia64/sn/geo.h index 130d0b64cbf..cf4a2f7452f 100644 --- a/include/asm-ia64/sn/geo.h +++ b/include/asm-ia64/sn/geo.h @@ -17,15 +17,7 @@ * GEO_MAX_LEN: The maximum length of a geoid, formatted for printing */ -#include - -#ifdef CONFIG_IA64_SGI_SN2 #include -#else - -#error <> - -#endif /* !SN2 && ... */ /* Declarations applicable to all platforms */ diff --git a/include/asm-ia64/sn/hack.h b/include/asm-ia64/sn/hack.h deleted file mode 100644 index b4f8a8f2893..00000000000 --- a/include/asm-ia64/sn/hack.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_HACK_H -#define _ASM_IA64_SN_HACK_H - -#include -#include -#include -#include /* for copy_??_user */ - -/****************************************** - * Definitions that do not exist in linux * - ******************************************/ - -typedef int cred_t; /* This is for compilation reasons */ -struct cred { int x; }; - - -/* - * Hardware Graph routines that are currently stubbed! - */ -#include - -#define DELAY(a) - -/************************************************ - * Routines redefined to use linux equivalents. * - ************************************************/ - -/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ - -#define FIXME(s) - -extern devfs_handle_t dummy_vrtx; -#define cpuid_to_vertex(cpuid) dummy_vrtx /* (pdaindr[cpuid].pda->p_vertex) */ - -#define PUTBUF_LOCK(a) { FIXME("PUTBUF_LOCK"); } -#define PUTBUF_UNLOCK(a) { FIXME("PUTBUF_UNLOCK"); } - -typedef int (*splfunc_t)(void); - -/* move to stubs.c yet */ -#define dev_to_vhdl(dev) 0 -#define get_timestamp() 0 -#define us_delay(a) -#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); -#define splhi() 0 -#define spl7 splhi() -#define splx(s) - -extern void * snia_kmem_alloc_node(register size_t, register int, cnodeid_t); -extern void * snia_kmem_zalloc(size_t, int); -extern void * snia_kmem_zalloc_node(register size_t, register int, cnodeid_t ); -extern void * snia_kmem_zone_alloc(register struct zone *, int); -extern struct zone * snia_kmem_zone_init(register int , char *); -extern void snia_kmem_zone_free(register struct zone *, void *); -extern int is_specified(char *); -extern int cap_able(uint64_t); -extern int compare_and_swap_ptr(void **, void *, void *); - -#endif /* _ASM_IA64_SN_HACK_H */ diff --git a/include/asm-ia64/sn/hcl.h b/include/asm-ia64/sn/hcl.h dissimilarity index 62% index 2c91163420d..34aa4d3a0a3 100644 --- a/include/asm-ia64/sn/hcl.h +++ b/include/asm-ia64/sn/hcl.h @@ -1,115 +1,110 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_HCL_H -#define _ASM_IA64_SN_HCL_H - -#include -#include -#include - -extern devfs_handle_t hcl_handle; /* HCL driver */ -extern devfs_handle_t hwgraph_root; -extern devfs_handle_t linux_busnum; - - -typedef long labelcl_info_place_t; -typedef long arbitrary_info_t; -typedef long arb_info_desc_t; - -/* Support for INVENTORY */ -struct inventory_s; -struct invplace_s; - - -/* - * Reserve room in every vertex for 2 pieces of fast access indexed information - * Note that we do not save a pointer to the bdevsw or cdevsw[] tables anymore. - */ -#define HWGRAPH_NUM_INDEX_INFO 2 /* MAX Entries */ -#define HWGRAPH_CONNECTPT 0 /* connect point (aprent) */ -#define HWGRAPH_FASTINFO 1 /* callee's private handle */ - -/* - * Reserved edge_place_t values, used as the "place" parameter to edge_get_next. - * Every vertex in the hwgraph has up to 2 *implicit* edges. There is an implicit - * edge called "." that points to the current vertex. There is an implicit edge - * called ".." that points to the vertex' connect point. - */ -#define EDGE_PLACE_WANT_CURRENT 0 /* "." */ -#define EDGE_PLACE_WANT_CONNECTPT 1 /* ".." */ -#define EDGE_PLACE_WANT_REAL_EDGES 2 /* Get the first real edge */ -#define HWGRAPH_RESERVED_PLACES 2 - - -/* - * Special pre-defined edge labels. - */ -#define HWGRAPH_EDGELBL_HW "hw" -#define HWGRAPH_EDGELBL_DOT "." -#define HWGRAPH_EDGELBL_DOTDOT ".." -#define graph_edge_place_t uint - -/* - * External declarations of EXPORTED SYMBOLS in hcl.c - */ -extern devfs_handle_t hwgraph_register(devfs_handle_t, const char *, - unsigned int, unsigned int, unsigned int, unsigned int, - umode_t, uid_t, gid_t, struct file_operations *, void *); - -extern int hwgraph_mk_symlink(devfs_handle_t, const char *, unsigned int, - unsigned int, const char *, unsigned int, devfs_handle_t *, void *); - -extern int hwgraph_vertex_destroy(devfs_handle_t); - -extern int hwgraph_edge_add(devfs_handle_t, devfs_handle_t, char *); -extern int hwgraph_edge_get(devfs_handle_t, char *, devfs_handle_t *); - -extern arbitrary_info_t hwgraph_fastinfo_get(devfs_handle_t); -extern void hwgraph_fastinfo_set(devfs_handle_t, arbitrary_info_t ); -extern devfs_handle_t hwgraph_mk_dir(devfs_handle_t, const char *, unsigned int, void *); - -extern int hwgraph_connectpt_set(devfs_handle_t, devfs_handle_t); -extern devfs_handle_t hwgraph_connectpt_get(devfs_handle_t); -extern int hwgraph_edge_get_next(devfs_handle_t, char *, devfs_handle_t *, uint *); -extern graph_error_t hwgraph_edge_remove(devfs_handle_t, char *, devfs_handle_t *); - -extern graph_error_t hwgraph_traverse(devfs_handle_t, char *, devfs_handle_t *); - -extern int hwgraph_vertex_get_next(devfs_handle_t *, devfs_handle_t *); -extern int hwgraph_inventory_get_next(devfs_handle_t, invplace_t *, - inventory_t **); -extern int hwgraph_inventory_add(devfs_handle_t, int, int, major_t, minor_t, int); -extern int hwgraph_inventory_remove(devfs_handle_t, int, int, major_t, minor_t, int); -extern int hwgraph_controller_num_get(devfs_handle_t); -extern void hwgraph_controller_num_set(devfs_handle_t, int); -extern int hwgraph_path_ad(devfs_handle_t, char *, devfs_handle_t *); -extern devfs_handle_t hwgraph_path_to_vertex(char *); -extern devfs_handle_t hwgraph_path_to_dev(char *); -extern devfs_handle_t hwgraph_block_device_get(devfs_handle_t); -extern devfs_handle_t hwgraph_char_device_get(devfs_handle_t); -extern graph_error_t hwgraph_char_device_add(devfs_handle_t, char *, char *, devfs_handle_t *); -extern int hwgraph_path_add(devfs_handle_t, char *, devfs_handle_t *); -extern int hwgraph_info_add_LBL(devfs_handle_t, char *, arbitrary_info_t); -extern int hwgraph_info_get_LBL(devfs_handle_t, char *, arbitrary_info_t *); -extern int hwgraph_info_replace_LBL(devfs_handle_t, char *, arbitrary_info_t, - arbitrary_info_t *); -extern int hwgraph_info_get_exported_LBL(devfs_handle_t, char *, int *, arbitrary_info_t *); -extern int hwgraph_info_get_next_LBL(devfs_handle_t, char *, arbitrary_info_t *, - labelcl_info_place_t *); - -extern int hwgraph_path_lookup(devfs_handle_t, char *, devfs_handle_t *, char **); -extern int hwgraph_info_export_LBL(devfs_handle_t, char *, int); -extern int hwgraph_info_unexport_LBL(devfs_handle_t, char *); -extern int hwgraph_info_remove_LBL(devfs_handle_t, char *, arbitrary_info_t *); -extern char * vertex_to_name(devfs_handle_t, char *, uint); -extern graph_error_t hwgraph_vertex_unref(devfs_handle_t); - - - -#endif /* _ASM_IA64_SN_HCL_H */ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ +#ifndef _ASM_IA64_SN_HCL_H +#define _ASM_IA64_SN_HCL_H + +#include + +extern vertex_hdl_t hwgraph_root; +extern vertex_hdl_t linux_busnum; + + +typedef long labelcl_info_place_t; +typedef long arbitrary_info_t; +typedef long arb_info_desc_t; + +/* Support for INVENTORY */ +struct inventory_s; +struct invplace_s; + + +/* + * Reserve room in every vertex for 2 pieces of fast access indexed information + * Note that we do not save a pointer to the bdevsw or cdevsw[] tables anymore. + */ +#define HWGRAPH_NUM_INDEX_INFO 2 /* MAX Entries */ +#define HWGRAPH_CONNECTPT 0 /* connect point (aprent) */ +#define HWGRAPH_FASTINFO 1 /* callee's private handle */ + +/* + * Reserved edge_place_t values, used as the "place" parameter to edge_get_next. + * Every vertex in the hwgraph has up to 2 *implicit* edges. There is an implicit + * edge called "." that points to the current vertex. There is an implicit edge + * called ".." that points to the vertex' connect point. + */ +#define EDGE_PLACE_WANT_CURRENT 0 /* "." */ +#define EDGE_PLACE_WANT_CONNECTPT 1 /* ".." */ +#define EDGE_PLACE_WANT_REAL_EDGES 2 /* Get the first real edge */ +#define HWGRAPH_RESERVED_PLACES 2 + + +/* + * Special pre-defined edge labels. + */ +#define HWGRAPH_EDGELBL_HW "hw" +#define HWGRAPH_EDGELBL_DOT "." +#define HWGRAPH_EDGELBL_DOTDOT ".." +#define graph_edge_place_t uint + +/* + * External declarations of EXPORTED SYMBOLS in hcl.c + */ +extern vertex_hdl_t hwgraph_register(vertex_hdl_t, const char *, + unsigned int, unsigned int, unsigned int, unsigned int, + umode_t, uid_t, gid_t, struct file_operations *, void *); + +extern int hwgraph_mk_symlink(vertex_hdl_t, const char *, unsigned int, + unsigned int, const char *, unsigned int, vertex_hdl_t *, void *); + +extern int hwgraph_vertex_destroy(vertex_hdl_t); + +extern int hwgraph_edge_add(vertex_hdl_t, vertex_hdl_t, char *); +extern int hwgraph_edge_get(vertex_hdl_t, char *, vertex_hdl_t *); + +extern arbitrary_info_t hwgraph_fastinfo_get(vertex_hdl_t); +extern void hwgraph_fastinfo_set(vertex_hdl_t, arbitrary_info_t ); +extern vertex_hdl_t hwgraph_mk_dir(vertex_hdl_t, const char *, unsigned int, void *); + +extern int hwgraph_connectpt_set(vertex_hdl_t, vertex_hdl_t); +extern vertex_hdl_t hwgraph_connectpt_get(vertex_hdl_t); +extern int hwgraph_edge_get_next(vertex_hdl_t, char *, vertex_hdl_t *, uint *); +extern graph_error_t hwgraph_edge_remove(vertex_hdl_t, char *, vertex_hdl_t *); + +extern graph_error_t hwgraph_traverse(vertex_hdl_t, char *, vertex_hdl_t *); + +extern int hwgraph_vertex_get_next(vertex_hdl_t *, vertex_hdl_t *); +extern int hwgraph_inventory_get_next(vertex_hdl_t, invplace_t *, + inventory_t **); +extern int hwgraph_inventory_add(vertex_hdl_t, int, int, major_t, minor_t, int); +extern int hwgraph_inventory_remove(vertex_hdl_t, int, int, major_t, minor_t, int); +extern int hwgraph_controller_num_get(vertex_hdl_t); +extern void hwgraph_controller_num_set(vertex_hdl_t, int); +extern int hwgraph_path_ad(vertex_hdl_t, char *, vertex_hdl_t *); +extern vertex_hdl_t hwgraph_path_to_vertex(char *); +extern vertex_hdl_t hwgraph_path_to_dev(char *); +extern vertex_hdl_t hwgraph_block_device_get(vertex_hdl_t); +extern vertex_hdl_t hwgraph_char_device_get(vertex_hdl_t); +extern graph_error_t hwgraph_char_device_add(vertex_hdl_t, char *, char *, vertex_hdl_t *); +extern int hwgraph_path_add(vertex_hdl_t, char *, vertex_hdl_t *); +extern int hwgraph_info_add_LBL(vertex_hdl_t, char *, arbitrary_info_t); +extern int hwgraph_info_get_LBL(vertex_hdl_t, char *, arbitrary_info_t *); +extern int hwgraph_info_replace_LBL(vertex_hdl_t, char *, arbitrary_info_t, + arbitrary_info_t *); +extern int hwgraph_info_get_exported_LBL(vertex_hdl_t, char *, int *, arbitrary_info_t *); +extern int hwgraph_info_get_next_LBL(vertex_hdl_t, char *, arbitrary_info_t *, + labelcl_info_place_t *); +extern int hwgraph_path_lookup(vertex_hdl_t, char *, vertex_hdl_t *, char **); +extern int hwgraph_info_export_LBL(vertex_hdl_t, char *, int); +extern int hwgraph_info_unexport_LBL(vertex_hdl_t, char *); +extern int hwgraph_info_remove_LBL(vertex_hdl_t, char *, arbitrary_info_t *); +extern char * vertex_to_name(vertex_hdl_t, char *, uint); +extern graph_error_t hwgraph_vertex_unref(vertex_hdl_t); + + +#endif /* _ASM_IA64_SN_HCL_H */ diff --git a/include/asm-ia64/sn/hcl_util.h b/include/asm-ia64/sn/hcl_util.h index 781b4ccbec0..5a083a1693f 100644 --- a/include/asm-ia64/sn/hcl_util.h +++ b/include/asm-ia64/sn/hcl_util.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_HCL_UTIL_H @@ -12,11 +12,11 @@ #include -extern char * dev_to_name(devfs_handle_t, char *, uint); -extern int device_master_set(devfs_handle_t, devfs_handle_t); -extern devfs_handle_t device_master_get(devfs_handle_t); -extern cnodeid_t master_node_get(devfs_handle_t); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t); -extern void mark_nodevertex_as_node(devfs_handle_t, cnodeid_t); +extern char * dev_to_name(vertex_hdl_t, char *, uint); +extern int device_master_set(vertex_hdl_t, vertex_hdl_t); +extern vertex_hdl_t device_master_get(vertex_hdl_t); +extern cnodeid_t master_node_get(vertex_hdl_t); +extern cnodeid_t nodevertex_to_cnodeid(vertex_hdl_t); +extern void mark_nodevertex_as_node(vertex_hdl_t, cnodeid_t); #endif /* _ASM_IA64_SN_HCL_UTIL_H */ diff --git a/include/asm-ia64/sn/hires_clock.h b/include/asm-ia64/sn/hires_clock.h deleted file mode 100644 index d85f8547bbd..00000000000 --- a/include/asm-ia64/sn/hires_clock.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved. - * - * SGI Hi Resolution Clock - * - * SGI SN platforms provide a high resolution clock that is - * synchronized across all nodes. The clock can be memory mapped - * and directly read from user space. - * - * Access to the clock is thru the following: - * (error checking not shown) - * - * (Note: should library routines be provided to encapsulate this??) - * - * int fd: - * volatile long *clk; - * - * fd = open (HIRES_FULLNAME, O_RDONLY); - * clk = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); - * clk += ioctl(fd, HIRES_IOCQGETOFFSET, 0); - * - * At this point, clk is a pointer to the high resolution clock. - * - * The clock period can be obtained via: - * - * long picosec_per_tick; - * picosec_per_tick = ioctl(fd, HIRES_IOCQGETPICOSEC, 0); - */ - -#ifndef _ASM_IA64_SN_HIRES_CLOCK_H -#define _ASM_IA64_SN_HIRES_CLOCK_H - - -#define HIRES_BASENAME "sgi_hires_clock" -#define HIRES_FULLNAME "/dev/sgi_hires_clock" -#define HIRES_IOC_BASE 's' - - -/* Get page offset of hires timer */ -#define HIRES_IOCQGETOFFSET _IO( HIRES_IOC_BASE, 0 ) - -/* get clock period in picoseconds per tick */ -#define HIRES_IOCQGETPICOSEC _IO( HIRES_IOC_BASE, 1 ) - -/* get number of significant bits in clock counter */ -#define HIRES_IOCQGETCLOCKBITS _IO( HIRES_IOC_BASE, 2 ) - -#endif /* _ASM_IA64_SN_HIRES_CLOCK_H */ diff --git a/include/asm-ia64/sn/hwgfs.h b/include/asm-ia64/sn/hwgfs.h new file mode 100644 index 00000000000..4ae1e0bdb9b --- /dev/null +++ b/include/asm-ia64/sn/hwgfs.h @@ -0,0 +1,35 @@ +#ifndef _ASM_IA64_SN_HWGFS_H +#define _ASM_IA64_SN_HWGFS_H + +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +typedef struct dentry *hwgfs_handle_t; + +extern hwgfs_handle_t hwgfs_register(hwgfs_handle_t dir, const char *name, + unsigned int flags, + unsigned int major, unsigned int minor, + umode_t mode, void *ops, void *info); +extern int hwgfs_mk_symlink(hwgfs_handle_t dir, const char *name, + unsigned int flags, const char *link, + hwgfs_handle_t *handle, void *info); +extern hwgfs_handle_t hwgfs_mk_dir(hwgfs_handle_t dir, const char *name, + void *info); +extern void hwgfs_unregister(hwgfs_handle_t de); + +extern hwgfs_handle_t hwgfs_find_handle(hwgfs_handle_t dir, const char *name, + unsigned int major,unsigned int minor, + char type, int traverse_symlinks); +extern hwgfs_handle_t hwgfs_get_parent(hwgfs_handle_t de); +extern int hwgfs_generate_path(hwgfs_handle_t de, char *path, int buflen); + +extern void *hwgfs_get_info(hwgfs_handle_t de); +extern int hwgfs_set_info(hwgfs_handle_t de, void *info); + +#endif diff --git a/include/asm-ia64/sn/idle.h b/include/asm-ia64/sn/idle.h deleted file mode 100644 index c1f5688457b..00000000000 --- a/include/asm-ia64/sn/idle.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _ASM_IA64_SN_IDLE_H -#define _ASM_IA64_SN_IDLE_H - -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include - -static __inline__ void -snidle(void) { -#if 0 -#ifdef CONFIG_IA64_SGI_AUTOTEST - { - extern int autotest_enabled; - if (autotest_enabled) { - extern void llsc_main(int); - llsc_main(smp_processor_id()); - } - } -#endif - - if (pda.idle_flag == 0) { - /* - * Turn the activity LED off. - */ - set_led_bits(0, LED_CPU_ACTIVITY); - } - -#ifdef CONFIG_IA64_SGI_SN_SIM - if (IS_RUNNING_ON_SIMULATOR()) - SIMULATOR_SLEEP(); -#endif - - pda.idle_flag = 1; -#endif -} - -static __inline__ void -snidleoff(void) { -#if 0 - /* - * Turn the activity LED on. - */ - set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); - - pda.idle_flag = 0; -#endif -} - -#endif /* _ASM_IA64_SN_IDLE_H */ diff --git a/include/asm-ia64/sn/ifconfig_net.h b/include/asm-ia64/sn/ifconfig_net.h index 8eb976c35fd..183c93bfa00 100644 --- a/include/asm-ia64/sn/ifconfig_net.h +++ b/include/asm-ia64/sn/ifconfig_net.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IFCONFIG_NET_H diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h index 36e3af325cc..021141586f9 100644 --- a/include/asm-ia64/sn/intr.h +++ b/include/asm-ia64/sn/intr.h @@ -4,21 +4,18 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INTR_H #define _ASM_IA64_SN_INTR_H #include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif extern void sn_send_IPI_phys(long, int, int); -#define CPU_VECTOR_TO_IRQ(cpuid,vector) ((cpuid) << 8 | (vector)) +#define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) +#define SN_CPU_FROM_IRQ(irq) (0) +#define SN_IVEC_FROM_IRQ(irq) (irq) #endif /* _ASM_IA64_SN_INTR_H */ diff --git a/include/asm-ia64/sn/intr_public.h b/include/asm-ia64/sn/intr_public.h deleted file mode 100644 index 44367a4580c..00000000000 --- a/include/asm-ia64/sn/intr_public.h +++ /dev/null @@ -1,19 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_INTR_PUBLIC_H -#define _ASM_IA64_SN_INTR_PUBLIC_H - -#include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) -#endif - -#endif /* _ASM_IA64_SN_INTR_PUBLIC_H */ diff --git a/include/asm-ia64/sn/invent.h b/include/asm-ia64/sn/invent.h index e75c156d843..a495e6f2bd0 100644 --- a/include/asm-ia64/sn/invent.h +++ b/include/asm-ia64/sn/invent.h @@ -4,14 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INVENT_H #define _ASM_IA64_SN_INVENT_H #include -#include - +#include /* * sys/sn/invent.h -- Kernel Hardware Inventory * @@ -31,7 +30,7 @@ #define minor_t int #define app32_ptr_t unsigned long #define graph_vertex_place_t long -#define GRAPH_VERTEX_NONE ((devfs_handle_t)-1) +#define GRAPH_VERTEX_NONE ((vertex_hdl_t)-1) #define GRAPH_EDGE_PLACE_NONE ((graph_edge_place_t)0) #define GRAPH_INFO_PLACE_NONE ((graph_info_place_t)0) #define GRAPH_VERTEX_PLACE_NONE ((graph_vertex_place_t)0) @@ -713,8 +712,8 @@ typedef struct irix5_inventory_s { } irix5_inventory_t; typedef struct invplace_s { - devfs_handle_t invplace_vhdl; /* current vertex */ - devfs_handle_t invplace_vplace; /* place in vertex list */ + vertex_hdl_t invplace_vhdl; /* current vertex */ + vertex_hdl_t invplace_vplace; /* place in vertex list */ inventory_t *invplace_inv; /* place in inv list on vertex */ } invplace_t; /* Magic cookie placeholder in inventory list */ @@ -730,7 +729,7 @@ extern inventory_t *find_inventory(inventory_t *, int, int, int, int, int); extern int scaninvent(int (*)(inventory_t *, void *), void *); extern int get_sizeof_inventory(int); -extern void device_inventory_add( devfs_handle_t device, +extern void device_inventory_add( vertex_hdl_t device, int class, int type, major_t ctlr, @@ -738,11 +737,11 @@ extern void device_inventory_add( devfs_handle_t device, int state); -extern inventory_t *device_inventory_get_next( devfs_handle_t device, +extern inventory_t *device_inventory_get_next( vertex_hdl_t device, invplace_t *); -extern void device_controller_num_set( devfs_handle_t, +extern void device_controller_num_set( vertex_hdl_t, int); -extern int device_controller_num_get( devfs_handle_t); +extern int device_controller_num_get( vertex_hdl_t); #endif /* __KERNEL__ */ #endif /* _ASM_IA64_SN_INVENT_H */ diff --git a/include/asm-ia64/sn/io.h b/include/asm-ia64/sn/io.h index 6d1f8668a16..2aee7cf8cbc 100644 --- a/include/asm-ia64/sn/io.h +++ b/include/asm-ia64/sn/io.h @@ -56,27 +56,8 @@ (_x) : \ (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) ) -#if defined(CONFIG_IA64_SGI_SN1) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include #include -#endif /* * Used to ensure write ordering (like mb(), but for I/O space) diff --git a/include/asm-ia64/sn/ioc3.h b/include/asm-ia64/sn/ioc3.h index 26afbf127cd..379b632eb1d 100644 --- a/include/asm-ia64/sn/ioc3.h +++ b/include/asm-ia64/sn/ioc3.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff --git a/include/asm-ia64/sn/ioc4.h b/include/asm-ia64/sn/ioc4.h new file mode 100644 index 00000000000..7df3cea7e14 --- /dev/null +++ b/include/asm-ia64/sn/ioc4.h @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + */ + +#ifndef _ASM_IA64_SN_IOC4_H +#define _ASM_IA64_SN_IOC4_H + +#if 0 + +/* + * ioc4.h - IOC4 chip header file + */ + +/* Notes: + * The IOC4 chip is a 32-bit PCI device that provides 4 serial ports, + * an IDE bus interface, a PC keyboard/mouse interface, and a real-time + * external interrupt interface. + * + * It includes an optimized DMA buffer management, and a store-and-forward + * buffer RAM. + * + * All IOC4 registers are 32 bits wide. + */ +typedef __uint32_t ioc4reg_t; + +/* + * PCI Configuration Space Register Address Map, use offset from IOC4 PCI + * configuration base such that this can be used for multiple IOC4s + */ +#define IOC4_PCI_ID 0x0 /* ID */ + +#define IOC4_VENDOR_ID_NUM 0x10A9 +#define IOC4_DEVICE_ID_NUM 0x100A +#define IOC4_ADDRSPACE_MASK 0xfff00000ULL + +#define IOC4_PCI_SCR 0x4 /* Status/Command */ +#define IOC4_PCI_REV 0x8 /* Revision */ +#define IOC4_PCI_LAT 0xC /* Latency Timer */ +#define IOC4_PCI_BAR0 0x10 /* IOC4 base address 0 */ +#define IOC4_PCI_SIDV 0x2c /* Subsys ID and vendor */ +#define IOC4_PCI_CAP 0x34 /* Capability pointer */ +#define IOC4_PCI_LATGNTINT 0x3c /* Max_lat, min_gnt, int_pin, int_line */ + +/* + * PCI Memory Space Map + */ +#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */ +#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0) +#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1) +#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5) +#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6) + +/* Master IDs contained in PCI_ERR_ADDR_MST_ID_MSK */ +#define IOC4_MST_ID_S0_TX 0 +#define IOC4_MST_ID_S0_RX 1 +#define IOC4_MST_ID_S1_TX 2 +#define IOC4_MST_ID_S1_RX 3 +#define IOC4_MST_ID_S2_TX 4 +#define IOC4_MST_ID_S2_RX 5 +#define IOC4_MST_ID_S3_TX 6 +#define IOC4_MST_ID_S3_RX 7 +#define IOC4_MST_ID_ATA 8 + +#define IOC4_PCI_ERR_ADDR_H 0x004 /* High Error Address */ + +#define IOC4_SIO_IR 0x008 /* SIO Interrupt Register */ +#define IOC4_OTHER_IR 0x00C /* Other Interrupt Register */ + +/* These registers are read-only for general kernel code. To modify + * them use the functions in ioc4.c + */ +#define IOC4_SIO_IES_RO 0x010 /* SIO Interrupt Enable Set Reg */ +#define IOC4_OTHER_IES_RO 0x014 /* Other Interrupt Enable Set Reg */ +#define IOC4_SIO_IEC_RO 0x018 /* SIO Interrupt Enable Clear Reg */ +#define IOC4_OTHER_IEC_RO 0x01C /* Other Interrupt Enable Clear Reg */ + +#define IOC4_SIO_CR 0x020 /* SIO Control Reg */ +#define IOC4_INT_OUT 0x028 /* INT_OUT Reg (realtime interrupt) */ +#define IOC4_GPCR_S 0x030 /* GenericPIO Cntrl Set Register */ +#define IOC4_GPCR_C 0x034 /* GenericPIO Cntrl Clear Register */ +#define IOC4_GPDR 0x038 /* GenericPIO Data Register */ +#define IOC4_GPPR_0 0x040 /* GenericPIO Pin Registers */ +#define IOC4_GPPR_OFF 0x4 +#define IOC4_GPPR(x) (IOC4_GPPR_0+(x)*IOC4_GPPR_OFF) + +/* ATAPI Registers */ +#define IOC4_ATA_0 0x100 /* Data w/timing */ +#define IOC4_ATA_1 0x104 /* Error/Features w/timing */ +#define IOC4_ATA_2 0x108 /* Sector Count w/timing */ +#define IOC4_ATA_3 0x10C /* Sector Number w/timing */ +#define IOC4_ATA_4 0x110 /* Cyliner Low w/timing */ +#define IOC4_ATA_5 0x114 /* Cylinder High w/timing */ +#define IOC4_ATA_6 0x118 /* Device/Head w/timing */ +#define IOC4_ATA_7 0x11C /* Status/Command w/timing */ +#define IOC4_ATA_0_AUX 0x120 /* Aux Status/Device Cntrl w/timing */ +#define IOC4_ATA_TIMING 0x140 /* Timing value register 0 */ +#define IOC4_ATA_DMA_PTR_L 0x144 /* Low Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_PTR_H 0x148 /* High Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_ADDR_L 0x14C /* Low Memory DMA Address */ +#define IOC4_ATA_DMA_ADDR_H 0x150 /* High Memory DMA Addresss */ +#define IOC4_ATA_BC_DEV 0x154 /* DMA Byte Count at Device */ +#define IOC4_ATA_BC_MEM 0x158 /* DMA Byte Count at Memory */ +#define IOC4_ATA_DMA_CTRL 0x15C /* DMA Control/Status */ + +/* Keyboard and Mouse Registers */ +#define IOC4_KM_CSR 0x200 /* Kbd and Mouse Cntrl/Status Reg */ +#define IOC4_K_RD 0x204 /* Kbd Read Data Register */ +#define IOC4_M_RD 0x208 /* Mouse Read Data Register */ +#define IOC4_K_WD 0x20C /* Kbd Write Data Register */ +#define IOC4_M_WD 0x210 /* Mouse Write Data Register */ + +/* Serial Port Registers used for DMA mode serial I/O */ +#define IOC4_SBBR01_H 0x300 /* Serial Port Ring Buffers + Base Reg High for Channels 0 1*/ +#define IOC4_SBBR01_L 0x304 /* Serial Port Ring Buffers + Base Reg Low for Channels 0 1 */ +#define IOC4_SBBR23_H 0x308 /* Serial Port Ring Buffers + Base Reg High for Channels 2 3*/ +#define IOC4_SBBR23_L 0x30C /* Serial Port Ring Buffers + Base Reg Low for Channels 2 3 */ + +#define IOC4_SSCR_0 0x310 /* Serial Port 0 Control */ +#define IOC4_STPIR_0 0x314 /* Serial Port 0 TX Produce */ +#define IOC4_STCIR_0 0x318 /* Serial Port 0 TX Consume */ +#define IOC4_SRPIR_0 0x31C /* Serial Port 0 RX Produce */ +#define IOC4_SRCIR_0 0x320 /* Serial Port 0 RX Consume */ +#define IOC4_SRTR_0 0x324 /* Serial Port 0 Receive Timer Reg */ +#define IOC4_SHADOW_0 0x328 /* Serial Port 0 16550 Shadow Reg */ + +#define IOC4_SSCR_1 0x32C /* Serial Port 1 Control */ +#define IOC4_STPIR_1 0x330 /* Serial Port 1 TX Produce */ +#define IOC4_STCIR_1 0x334 /* Serial Port 1 TX Consume */ +#define IOC4_SRPIR_1 0x338 /* Serial Port 1 RX Produce */ +#define IOC4_SRCIR_1 0x33C /* Serial Port 1 RX Consume */ +#define IOC4_SRTR_1 0x340 /* Serial Port 1 Receive Timer Reg */ +#define IOC4_SHADOW_1 0x344 /* Serial Port 1 16550 Shadow Reg */ + +#define IOC4_SSCR_2 0x348 /* Serial Port 2 Control */ +#define IOC4_STPIR_2 0x34C /* Serial Port 2 TX Produce */ +#define IOC4_STCIR_2 0x350 /* Serial Port 2 TX Consume */ +#define IOC4_SRPIR_2 0x354 /* Serial Port 2 RX Produce */ +#define IOC4_SRCIR_2 0x358 /* Serial Port 2 RX Consume */ +#define IOC4_SRTR_2 0x35C /* Serial Port 2 Receive Timer Reg */ +#define IOC4_SHADOW_2 0x360 /* Serial Port 2 16550 Shadow Reg */ + +#define IOC4_SSCR_3 0x364 /* Serial Port 3 Control */ +#define IOC4_STPIR_3 0x368 /* Serial Port 3 TX Produce */ +#define IOC4_STCIR_3 0x36C /* Serial Port 3 TX Consume */ +#define IOC4_SRPIR_3 0x370 /* Serial Port 3 RX Produce */ +#define IOC4_SRCIR_3 0x374 /* Serial Port 3 RX Consume */ +#define IOC4_SRTR_3 0x378 /* Serial Port 3 Receive Timer Reg */ +#define IOC4_SHADOW_3 0x37C /* Serial Port 3 16550 Shadow Reg */ + +#define IOC4_UART0_BASE 0x380 /* UART 0 */ +#define IOC4_UART1_BASE 0x388 /* UART 1 */ +#define IOC4_UART2_BASE 0x390 /* UART 2 */ +#define IOC4_UART3_BASE 0x398 /* UART 3 */ + +/* Private page address aliases for usermode mapping */ +#define IOC4_INT_OUT_P 0x04000 /* INT_OUT Reg */ + +#define IOC4_SSCR_0_P 0x08000 /* Serial Port 0 */ +#define IOC4_STPIR_0_P 0x08004 +#define IOC4_STCIR_0_P 0x08008 /* (read-only) */ +#define IOC4_SRPIR_0_P 0x0800C /* (read-only) */ +#define IOC4_SRCIR_0_P 0x08010 +#define IOC4_SRTR_0_P 0x08014 +#define IOC4_UART_LSMSMCR_0_P 0x08018 /* (read-only) */ + +#define IOC4_SSCR_1_P 0x0C000 /* Serial Port 1 */ +#define IOC4_STPIR_1_P 0x0C004 +#define IOC4_STCIR_1_P 0x0C008 /* (read-only) */ +#define IOC4_SRPIR_1_P 0x0C00C /* (read-only) */ +#define IOC4_SRCIR_1_P 0x0C010 +#define IOC4_SRTR_1_P 0x0C014 +#define IOC4_UART_LSMSMCR_1_P 0x0C018 /* (read-only) */ + +#define IOC4_SSCR_2_P 0x10000 /* Serial Port 2 */ +#define IOC4_STPIR_2_P 0x10004 +#define IOC4_STCIR_2_P 0x10008 /* (read-only) */ +#define IOC4_SRPIR_2_P 0x1000C /* (read-only) */ +#define IOC4_SRCIR_2_P 0x10010 +#define IOC4_SRTR_2_P 0x10014 +#define IOC4_UART_LSMSMCR_2_P 0x10018 /* (read-only) */ + +#define IOC4_SSCR_3_P 0x14000 /* Serial Port 3 */ +#define IOC4_STPIR_3_P 0x14004 +#define IOC4_STCIR_3_P 0x14008 /* (read-only) */ +#define IOC4_SRPIR_3_P 0x1400C /* (read-only) */ +#define IOC4_SRCIR_3_P 0x14010 +#define IOC4_SRTR_3_P 0x14014 +#define IOC4_UART_LSMSMCR_3_P 0x14018 /* (read-only) */ + +#define IOC4_ALIAS_PAGE_SIZE 0x4000 + +/* Interrupt types */ +typedef enum ioc4_intr_type_e { + ioc4_sio_intr_type, + ioc4_other_intr_type, + ioc4_num_intr_types +} ioc4_intr_type_t; +#define ioc4_first_intr_type ioc4_sio_intr_type + +/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */ +#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */ +#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */ +#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */ +#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */ +#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */ +#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */ +#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */ +#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */ +#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */ +#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */ +#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */ +#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */ +#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */ +#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */ +#define IOC4_SIO_IR_S1_INT 0x00004000 /* */ +#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */ +#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */ +#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */ +#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */ +#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */ +#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */ +#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */ +#define IOC4_SIO_IR_S2_INT 0x00400000 /* */ +#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */ +#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */ +#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */ +#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */ +#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */ +#define IOC4_SIO_IR_S3_INT 0x40000000 /* */ +#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */ + +/* Per device interrupt masks */ +#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ + IOC4_SIO_IR_S0_RX_FULL | \ + IOC4_SIO_IR_S0_RX_HIGH | \ + IOC4_SIO_IR_S0_RX_TIMER | \ + IOC4_SIO_IR_S0_DELTA_DCD | \ + IOC4_SIO_IR_S0_DELTA_CTS | \ + IOC4_SIO_IR_S0_INT | \ + IOC4_SIO_IR_S0_TX_EXPLICIT) +#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ + IOC4_SIO_IR_S1_RX_FULL | \ + IOC4_SIO_IR_S1_RX_HIGH | \ + IOC4_SIO_IR_S1_RX_TIMER | \ + IOC4_SIO_IR_S1_DELTA_DCD | \ + IOC4_SIO_IR_S1_DELTA_CTS | \ + IOC4_SIO_IR_S1_INT | \ + IOC4_SIO_IR_S1_TX_EXPLICIT) +#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ + IOC4_SIO_IR_S2_RX_FULL | \ + IOC4_SIO_IR_S2_RX_HIGH | \ + IOC4_SIO_IR_S2_RX_TIMER | \ + IOC4_SIO_IR_S2_DELTA_DCD | \ + IOC4_SIO_IR_S2_DELTA_CTS | \ + IOC4_SIO_IR_S2_INT | \ + IOC4_SIO_IR_S2_TX_EXPLICIT) +#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ + IOC4_SIO_IR_S3_RX_FULL | \ + IOC4_SIO_IR_S3_RX_HIGH | \ + IOC4_SIO_IR_S3_RX_TIMER | \ + IOC4_SIO_IR_S3_DELTA_DCD | \ + IOC4_SIO_IR_S3_DELTA_CTS | \ + IOC4_SIO_IR_S3_INT | \ + IOC4_SIO_IR_S3_TX_EXPLICIT) + +/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Kbd/mouse intr */ +#define IOC4_OTHER_IR_ATA_DMAINT 0x00000089 /* ATAPI DMA intr */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* RT output pulse */ +#define IOC4_OTHER_IR_GEN_INT1 0x02000000 /* RT input pulse */ +#define IOC4_OTHER_IR_GEN_INT_SHIFT 25 + +/* Per device interrupt masks */ +#define IOC4_OTHER_IR_ATA (IOC4_OTHER_IR_ATA_INT | \ + IOC4_OTHER_IR_ATA_MEMERR | \ + IOC4_OTHER_IR_ATA_DMAINT) +#define IOC4_OTHER_IR_RT (IOC4_OTHER_IR_RT_INT | IOC4_OTHER_IR_GEN_INT1) + +/* Macro to load pending interrupts */ +#define IOC4_PENDING_SIO_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \ + PCI_INW(&((mem)->sio_ies_ro))) +#define IOC4_PENDING_OTHER_INTRS(mem) (PCI_INW(&((mem)->other_ir)) & \ + PCI_INW(&((mem)->other_ies_ro))) + +/* Bitmasks for IOC4_SIO_CR */ +#define IOC4_SIO_SR_CMD_PULSE 0x00000004 /* Byte bus strobe length */ +#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 +#define IOC4_SIO_CR_ARB_DIAG 0x00000070 /* Current non-ATA PCI bus + requester (ro) */ +#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000 +#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010 +#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020 +#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030 +#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040 +#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050 +#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060 +#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070 +#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among + serial ports (ro) */ +#define IOC4_SIO_CR_ATA_DIAG_IDLE 0x00000100 /* 0 -> active request from + ATA port */ +#define IOC4_SIO_CR_ATA_DIAG_ACTIVE 0x00000200 /* 1 -> ATA request is winner */ + +/* Bitmasks for IOC4_INT_OUT */ +#define IOC4_INT_OUT_COUNT 0x0000ffff /* Pulse interval timer */ +#define IOC4_INT_OUT_MODE 0x00070000 /* Mode mask */ +#define IOC4_INT_OUT_MODE_0 0x00000000 /* Set output to 0 */ +#define IOC4_INT_OUT_MODE_1 0x00040000 /* Set output to 1 */ +#define IOC4_INT_OUT_MODE_1PULSE 0x00050000 /* Send 1 pulse */ +#define IOC4_INT_OUT_MODE_PULSES 0x00060000 /* Send 1 pulse every interval */ +#define IOC4_INT_OUT_MODE_SQW 0x00070000 /* Toggle output every interval */ +#define IOC4_INT_OUT_DIAG 0x40000000 /* Diag mode */ +#define IOC4_INT_OUT_INT_OUT 0x80000000 /* Current state of INT_OUT */ + +/* Time constants for IOC4_INT_OUT */ +#define IOC4_INT_OUT_NS_PER_TICK (15 * 520) /* 15 ns PCI clock, multi=520 */ +#define IOC4_INT_OUT_TICKS_PER_PULSE 3 /* Outgoing pulse lasts 3 + ticks */ +#define IOC4_INT_OUT_US_TO_COUNT(x) /* Convert uS to a count value */ \ + (((x) * 10 + IOC4_INT_OUT_NS_PER_TICK / 200) * \ + 100 / IOC4_INT_OUT_NS_PER_TICK - 1) +#define IOC4_INT_OUT_COUNT_TO_US(x) /* Convert count value to uS */ \ + (((x) + 1) * IOC4_INT_OUT_NS_PER_TICK / 1000) +#define IOC4_INT_OUT_MIN_TICKS 3 /* Min period is width of + pulse in "ticks" */ +#define IOC4_INT_OUT_MAX_TICKS IOC4_INT_OUT_COUNT /* Largest possible count */ + +/* Bitmasks for IOC4_GPCR */ +#define IOC4_GPCR_DIR 0x000000ff /* Tristate pin in or out */ +#define IOC4_GPCR_DIR_PIN(x) (1<<(x)) /* Access one of the DIR bits */ +#define IOC4_GPCR_EDGE 0x0000ff00 /* Extint edge or level + sensitive */ +#define IOC4_GPCR_EDGE_PIN(x) (1<<((x)+7 )) /* Access one of the EDGE bits */ + +/* Values for IOC4_GPCR */ +#define IOC4_GPCR_INT_OUT_EN 0x00100000 /* Enable INT_OUT to pin 0 */ +#define IOC4_GPCR_DIR_SER0_XCVR 0x00000010 /* Port 0 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER1_XCVR 0x00000020 /* Port 1 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER2_XCVR 0x00000040 /* Port 2 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER3_XCVR 0x00000080 /* Port 3 Transceiver select + enable */ + +/* Defs for some of the generic I/O pins */ +#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 + mode sel */ +#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 + mode sel */ +#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 + mode sel */ +#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 + mode sel */ + +#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling + uart 0 mode select */ +#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling + uart 1 mode select */ +#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling + uart 2 mode select */ +#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling + uart 3 mode select */ + +/* Bitmasks for IOC4_ATA_TIMING */ +#define IOC4_ATA_TIMING_ADR_SETUP 0x00000003 /* Clocks of addr set-up */ +#define IOC4_ATA_TIMING_PULSE_WIDTH 0x000001f8 /* Clocks of read or write + pulse width */ +#define IOC4_ATA_TIMING_RECOVERY 0x0000fe00 /* Clocks before next read + or write */ +#define IOC4_ATA_TIMING_USE_IORDY 0x00010000 /* PIO uses IORDY */ + +/* Bitmasks for address list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_ALE_DMA_ADDRESS 0xfffffffffffffffe + +/* Bitmasks for byte count list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_BCLE_BYTE_COUNT 0x000000000000fffe +#define IOC4_ATA_BCLE_LIST_END 0x0000000080000000 + +/* Bitmasks for IOC4_ATA_BC_ */ +#define IOC4_ATA_BC_BYTE_CNT 0x0001fffe /* Byte count */ + +/* Bitmasks for IOC4_ATA_DMA_CTRL */ +#define IOC4_ATA_DMA_CTRL_STRAT 0x00000001 /* 1 -> start DMA engine */ +#define IOC4_ATA_DMA_CTRL_STOP 0x00000002 /* 1 -> stop DMA engine */ +#define IOC4_ATA_DMA_CTRL_DIR 0x00000004 /* 1 -> ATA bus data copied + to memory */ +#define IOC4_ATA_DMA_CTRL_ACTIVE 0x00000008 /* DMA channel is active */ +#define IOC4_ATA_DMA_CTRL_MEM_ERROR 0x00000010 /* DMA engine encountered + a PCI error */ +/* Bitmasks for IOC4_KM_CSR */ +#define IOC4_KM_CSR_K_WRT_PEND 0x00000001 /* Kbd port xmitting or resetting */ +#define IOC4_KM_CSR_M_WRT_PEND 0x00000002 /* Mouse port xmitting or resetting */ +#define IOC4_KM_CSR_K_LCB 0x00000004 /* Line Cntrl Bit for last KBD write */ +#define IOC4_KM_CSR_M_LCB 0x00000008 /* Same for mouse */ +#define IOC4_KM_CSR_K_DATA 0x00000010 /* State of kbd data line */ +#define IOC4_KM_CSR_K_CLK 0x00000020 /* State of kbd clock line */ +#define IOC4_KM_CSR_K_PULL_DATA 0x00000040 /* Pull kbd data line low */ +#define IOC4_KM_CSR_K_PULL_CLK 0x00000080 /* Pull kbd clock line low */ +#define IOC4_KM_CSR_M_DATA 0x00000100 /* State of mouse data line */ +#define IOC4_KM_CSR_M_CLK 0x00000200 /* State of mouse clock line */ +#define IOC4_KM_CSR_M_PULL_DATA 0x00000400 /* Pull mouse data line low */ +#define IOC4_KM_CSR_M_PULL_CLK 0x00000800 /* Pull mouse clock line low */ +#define IOC4_KM_CSR_EMM_MODE 0x00001000 /* Emulation mode */ +#define IOC4_KM_CSR_SIM_MODE 0x00002000 /* Clock X8 */ +#define IOC4_KM_CSR_K_SM_IDLE 0x00004000 /* Keyboard is idle */ +#define IOC4_KM_CSR_M_SM_IDLE 0x00008000 /* Mouse is idle */ +#define IOC4_KM_CSR_K_TO 0x00010000 /* Keyboard trying to send/receive */ +#define IOC4_KM_CSR_M_TO 0x00020000 /* Mouse trying to send/receive */ +#define IOC4_KM_CSR_K_TO_EN 0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */ +#define IOC4_KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */ +#define IOC4_KM_CSR_K_CLAMP_THREE \ + 0x00400000 /* Pull K_CLK low after rec. three chars */ +#define IOC4_KM_CSR_M_CLAMP_THREE \ + 0x00800000 /* Pull M_CLK low after rec. three char */ + +/* Bitmasks for IOC4_K_RD and IOC4_M_RD */ +#define IOC4_KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ +#define IOC4_KM_RD_DATA_2_SHIFT 0 +#define IOC4_KM_RD_DATA_1 0x0000ff00 /* 2nd char recvd since last read */ +#define IOC4_KM_RD_DATA_1_SHIFT 8 +#define IOC4_KM_RD_DATA_0 0x00ff0000 /* 1st char recvd since last read */ +#define IOC4_KM_RD_DATA_0_SHIFT 16 +#define IOC4_KM_RD_FRAME_ERR_2 0x01000000 /* Framing or parity error in byte 2 */ +#define IOC4_KM_RD_FRAME_ERR_1 0x02000000 /* Same for byte 1 */ +#define IOC4_KM_RD_FRAME_ERR_0 0x04000000 /* Same for byte 0 */ + +#define IOC4_KM_RD_KBD_MSE 0x08000000 /* 0 if from kbd, 1 if from mouse */ +#define IOC4_KM_RD_OFLO 0x10000000 /* 4th char recvd before this read */ +#define IOC4_KM_RD_VALID_2 0x20000000 /* DATA_2 valid */ +#define IOC4_KM_RD_VALID_1 0x40000000 /* DATA_1 valid */ +#define IOC4_KM_RD_VALID_0 0x80000000 /* DATA_0 valid */ +#define IOC4_KM_RD_VALID_ALL (IOC4_KM_RD_VALID_0 | IOC4_KM_RD_VALID_1 | \ + IOC4_KM_RD_VALID_2) + +/* Bitmasks for IOC4_K_WD & IOC4_M_WD */ +#define IOC4_KM_WD_WRT_DATA 0x000000ff /* Write to keyboard/mouse port */ +#define IOC4_KM_WD_WRT_DATA_SHIFT 0 + +/* Bitmasks for serial RX status byte */ +#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */ +#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */ +#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */ +#define IOC4_RXSB_BREAK 0x08 /* Break character */ +#define IOC4_RXSB_CTS 0x10 /* State of CTS */ +#define IOC4_RXSB_DCD 0x20 /* State of DCD */ +#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */ +#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR & BREAK valid */ + +/* Bitmasks for serial TX control byte */ +#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */ +#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */ +#define IOC4_TXCB_VALID 0x40 /* Byte is valid */ +#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control register */ +#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */ + +/* Bitmasks for IOC4_SBBR_L */ +#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ +#define IOC4_SBBR_L_BASE 0xfffff000 /* Lower serial ring base addr */ + +/* Bitmasks for IOC4_SSCR_<3:0> */ +#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */ +#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ +#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */ +#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */ +#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */ +#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */ +#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */ +#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */ +#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */ +#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */ +#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */ + +/* All producer/comsumer pointers are the same bitfield */ +#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */ +#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */ +#define IOC4_PROD_CONS_PTR_OFF 3 + +/* Bitmasks for IOC4_STPIR_<3:0> */ +/* Reserved for future register definitions */ + +/* Bitmasks for IOC4_STCIR_<3:0> */ +#define IOC4_STCIR_BYTE_CNT 0x0f000000 /* Bytes in unpacker */ +#define IOC4_STCIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRPIR_<3:0> */ +#define IOC4_SRPIR_BYTE_CNT 0x0f000000 /* Bytes in packer */ +#define IOC4_SRPIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRCIR_<3:0> */ +#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */ + +/* Bitmasks for IOC4_SHADOW_<3:0> */ +#define IOC4_SHADOW_DR 0x00000001 /* Data ready */ +#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */ +#define IOC4_SHADOW_PE 0x00000004 /* Parity error */ +#define IOC4_SHADOW_FE 0x00000008 /* Framing error */ +#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */ +#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */ +#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */ +#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */ +#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */ +#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */ +#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */ +#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */ +#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */ +#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */ +#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ +#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ +#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */ + +/* Bitmasks for IOC4_SRTR_<3:0> */ +#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */ +#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */ +#define IOC4_SRTR_CNT_VAL_SHIFT 16 +#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */ + +/* Serial port register map used for DMA and PIO serial I/O */ +typedef volatile struct ioc4_serialregs { + ioc4reg_t sscr; + ioc4reg_t stpir; + ioc4reg_t stcir; + ioc4reg_t srpir; + ioc4reg_t srcir; + ioc4reg_t srtr; + ioc4reg_t shadow; +} ioc4_sregs_t; + +/* IOC4 UART register map */ +typedef volatile struct ioc4_uartregs { + union { + char rbr; /* read only, DLAB == 0 */ + char thr; /* write only, DLAB == 0 */ + char dll; /* DLAB == 1 */ + } u1; + union { + char ier; /* DLAB == 0 */ + char dlm; /* DLAB == 1 */ + } u2; + union { + char iir; /* read only */ + char fcr; /* write only */ + } u3; + char i4u_lcr; + char i4u_mcr; + char i4u_lsr; + char i4u_msr; + char i4u_scr; +} ioc4_uart_t; + +#define i4u_rbr u1.rbr +#define i4u_thr u1.thr +#define i4u_dll u1.dll +#define i4u_ier u2.ier +#define i4u_dlm u2.dlm +#define i4u_iir u3.iir +#define i4u_fcr u3.fcr + +/* PCI config space register map */ +typedef volatile struct ioc4_configregs { + ioc4reg_t pci_id; + ioc4reg_t pci_scr; + ioc4reg_t pci_rev; + ioc4reg_t pci_lat; + ioc4reg_t pci_bar0; + ioc4reg_t pci_bar1; + ioc4reg_t pci_bar2_not_implemented; + ioc4reg_t pci_cis_ptr_not_implemented; + ioc4reg_t pci_sidv; + ioc4reg_t pci_rom_bar_not_implemented; + ioc4reg_t pci_cap; + ioc4reg_t pci_rsv; + ioc4reg_t pci_latgntint; + + char pci_fill1[0x58 - 0x3c - 4]; + + ioc4reg_t pci_pcix; + ioc4reg_t pci_pcixstatus; +} ioc4_cfg_t; + +/* PCI memory space register map addressed using pci_bar0 */ +typedef volatile struct ioc4_memregs { + + /* Miscellaneous IOC4 registers */ + ioc4reg_t pci_err_addr_l; + ioc4reg_t pci_err_addr_h; + ioc4reg_t sio_ir; + ioc4reg_t other_ir; + + /* These registers are read-only for general kernel code. To + * modify them use the functions in ioc4.c. + */ + ioc4reg_t sio_ies_ro; + ioc4reg_t other_ies_ro; + ioc4reg_t sio_iec_ro; + ioc4reg_t other_iec_ro; + ioc4reg_t sio_cr; + ioc4reg_t misc_fill1; + ioc4reg_t int_out; + ioc4reg_t misc_fill2; + ioc4reg_t gpcr_s; + ioc4reg_t gpcr_c; + ioc4reg_t gpdr; + ioc4reg_t misc_fill3; + ioc4reg_t gppr_0; + ioc4reg_t gppr_1; + ioc4reg_t gppr_2; + ioc4reg_t gppr_3; + ioc4reg_t gppr_4; + ioc4reg_t gppr_5; + ioc4reg_t gppr_6; + ioc4reg_t gppr_7; + + char misc_fill4[0x100 - 0x5C - 4]; + + /* ATA/ATAP registers */ + ioc4reg_t ata_0; + ioc4reg_t ata_1; + ioc4reg_t ata_2; + ioc4reg_t ata_3; + ioc4reg_t ata_4; + ioc4reg_t ata_5; + ioc4reg_t ata_6; + ioc4reg_t ata_7; + ioc4reg_t ata_aux; + + char ata_fill1[0x140 - 0x120 - 4]; + + ioc4reg_t ata_timing; + ioc4reg_t ata_dma_ptr_l; + ioc4reg_t ata_dma_ptr_h; + ioc4reg_t ata_dma_addr_l; + ioc4reg_t ata_dma_addr_h; + ioc4reg_t ata_bc_dev; + ioc4reg_t ata_bc_mem; + ioc4reg_t ata_dma_ctrl; + + char ata_fill2[0x200 - 0x15C - 4]; + + /* Keyboard and mouse registers */ + ioc4reg_t km_csr; + ioc4reg_t k_rd; + ioc4reg_t m_rd; + ioc4reg_t k_wd; + ioc4reg_t m_wd; + + char km_fill1[0x300 - 0x210 - 4]; + + /* Serial port registers used for DMA serial I/O */ + ioc4reg_t sbbr01_l; + ioc4reg_t sbbr01_h; + ioc4reg_t sbbr23_l; + ioc4reg_t sbbr23_h; + + ioc4_sregs_t port_0; + ioc4_sregs_t port_1; + ioc4_sregs_t port_2; + ioc4_sregs_t port_3; + + ioc4_uart_t uart_0; + ioc4_uart_t uart_1; + ioc4_uart_t uart_2; + ioc4_uart_t uart_3; +} ioc4_mem_t; + +#endif /* 0 */ + +/* + * Bytebus device space + */ +#define IOC4_BYTEBUS_DEV0 0x80000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV1 0xA0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV2 0xC0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV3 0xE0000L /* Addressed using pci_bar0 */ + +#if 0 +/* UART clock speed */ +#define IOC4_SER_XIN_CLK 66000000 + +typedef enum ioc4_subdevs_e { + ioc4_subdev_generic, + ioc4_subdev_kbms, + ioc4_subdev_tty0, + ioc4_subdev_tty1, + ioc4_subdev_tty2, + ioc4_subdev_tty3, + ioc4_subdev_rt, + ioc4_nsubdevs +} ioc4_subdev_t; + +/* Subdevice disable bits, + * from the standard INFO_LBL_SUBDEVS + */ +#define IOC4_SDB_TTY0 (1 << ioc4_subdev_tty0) +#define IOC4_SDB_TTY1 (1 << ioc4_subdev_tty1) +#define IOC4_SDB_TTY2 (1 << ioc4_subdev_tty2) +#define IOC4_SDB_TTY3 (1 << ioc4_subdev_tty3) +#define IOC4_SDB_KBMS (1 << ioc4_subdev_kbms) +#define IOC4_SDB_RT (1 << ioc4_subdev_rt) +#define IOC4_SDB_GENERIC (1 << ioc4_subdev_generic) + +#define IOC4_ALL_SUBDEVS ((1 << ioc4_nsubdevs) - 1) + +#define IOC4_SDB_SERIAL (IOC4_SDB_TTY0 | IOC4_SDB_TTY1 | IOC4_SDB_TTY2 | IOC4_SDB_TTY3) + +#define IOC4_STD_SUBDEVS IOC4_ALL_SUBDEVS + +#define IOC4_INTA_SUBDEVS (IOC4_SDB_SERIAL | IOC4_SDB_KBMS | IOC4_SDB_RT | IOC4_SDB_GENERIC) + +extern int ioc4_subdev_enabled(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_enables(vertex_hdl_t, ulong_t); +extern void ioc4_subdev_enable(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_disable(vertex_hdl_t, ioc4_subdev_t); + +/* Macros to read and write the SIO_IEC and SIO_IES registers (see the + * comments in ioc4.c for details on why this is necessary + */ +#define IOC4_W_IES 0 +#define IOC4_W_IEC 1 +extern void ioc4_write_ireg(void *, ioc4reg_t, int, ioc4_intr_type_t); + +#define IOC4_WRITE_IES(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IES, type) +#define IOC4_WRITE_IEC(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IEC, type) + +typedef void +ioc4_intr_func_f (intr_arg_t, ioc4reg_t); + +typedef void +ioc4_intr_connect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl, + vertex_hdl_t intr_dev_vhdl, + int (*)(intr_arg_t)); + +typedef void +ioc4_intr_disconnect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl); + +ioc4_intr_disconnect_f ioc4_intr_disconnect; +ioc4_intr_connect_f ioc4_intr_connect; + +extern int ioc4_is_console(vertex_hdl_t conn_vhdl); + +extern void ioc4_mlreset(ioc4_cfg_t *, ioc4_mem_t *); + +extern intr_func_f ioc4_intr; + +extern ioc4_mem_t *ioc4_mem_ptr(void *ioc4_fastinfo); + +typedef ioc4_intr_func_f *ioc4_intr_func_t; + +#endif /* 0 */ +#endif /* _ASM_IA64_SN_IOC4_H */ diff --git a/include/asm-ia64/sn/ioerror.h b/include/asm-ia64/sn/ioerror.h index f8260c8ccec..f7e90b5cbc9 100644 --- a/include/asm-ia64/sn/ioerror.h +++ b/include/asm-ia64/sn/ioerror.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_H #define _ASM_IA64_SN_IOERROR_H @@ -108,7 +108,7 @@ * we have a single structure, and the appropriate fields get filled in * at each layer. * - This provides a way to dump all error related information in any layer - * of error handling (debugging aid). + * of erorr handling (debugging aid). * * A second possibility is to allow each layer to define its own error * data structure, and fill in the proper fields. This has the advantage diff --git a/include/asm-ia64/sn/ioerror_handling.h b/include/asm-ia64/sn/ioerror_handling.h index 401aaf36259..171b37dc64e 100644 --- a/include/asm-ia64/sn/ioerror_handling.h +++ b/include/asm-ia64/sn/ioerror_handling.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_HANDLING_H #define _ASM_IA64_SN_IOERROR_HANDLING_H @@ -207,26 +207,17 @@ typedef uint64_t error_priority_t; /* Error state interfaces */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -extern error_return_code_t error_state_set(devfs_handle_t,error_state_t); -extern error_state_t error_state_get(devfs_handle_t); +extern error_return_code_t error_state_set(vertex_hdl_t,error_state_t); +extern error_state_t error_state_get(vertex_hdl_t); #endif -/* System critical graph interfaces */ - -extern boolean_t is_sys_critical_vertex(devfs_handle_t); -extern devfs_handle_t sys_critical_first_child_get(devfs_handle_t); -extern devfs_handle_t sys_critical_next_child_get(devfs_handle_t); -extern devfs_handle_t sys_critical_parent_get(devfs_handle_t); -extern error_return_code_t sys_critical_graph_vertex_add(devfs_handle_t, - devfs_handle_t new); - /* Error action interfaces */ -extern error_return_code_t error_action_set(devfs_handle_t, +extern error_return_code_t error_action_set(vertex_hdl_t, error_action_f, error_context_t, error_priority_t); -extern error_return_code_t error_action_perform(devfs_handle_t); +extern error_return_code_t error_action_perform(vertex_hdl_t); #define INFO_LBL_ERROR_SKIP_ENV "error_skip_env" @@ -243,14 +234,14 @@ hwgraph_info_get_LBL(v, INFO_LBL_ERROR_SKIP_ENV, (arbitrary_info_t *)&l) hwgraph_info_remove_LBL(v, INFO_LBL_ERROR_SKIP_ENV, 0) /* Skip point interfaces */ -extern error_return_code_t error_skip_point_jump(devfs_handle_t, boolean_t); -extern error_return_code_t error_skip_point_clear(devfs_handle_t); +extern error_return_code_t error_skip_point_jump(vertex_hdl_t, boolean_t); +extern error_return_code_t error_skip_point_clear(vertex_hdl_t); /* REFERENCED */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) inline static int -error_skip_point_mark(devfs_handle_t v) +error_skip_point_mark(vertex_hdl_t v) { label_t *error_env = NULL; int code = 0; @@ -283,10 +274,10 @@ error_skip_point_mark(devfs_handle_t v) typedef uint64_t counter_t; -extern counter_t error_retry_count_get(devfs_handle_t); -extern error_return_code_t error_retry_count_set(devfs_handle_t,counter_t); -extern counter_t error_retry_count_increment(devfs_handle_t); -extern counter_t error_retry_count_decrement(devfs_handle_t); +extern counter_t error_retry_count_get(vertex_hdl_t); +extern error_return_code_t error_retry_count_set(vertex_hdl_t,counter_t); +extern counter_t error_retry_count_increment(vertex_hdl_t); +extern counter_t error_retry_count_decrement(vertex_hdl_t); /* Except for the PIO Read error typically the other errors are handled in * the context of an asynchronous error interrupt. @@ -298,7 +289,7 @@ extern counter_t error_retry_count_decrement(devfs_handle_t); * thru the calls the io error handling layer. */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -extern boolean_t is_device_shutdown(devfs_handle_t); +extern boolean_t is_device_shutdown(vertex_hdl_t); #define IS_DEVICE_SHUTDOWN(_d) (is_device_shutdown(_d)) #endif diff --git a/include/asm-ia64/sn/iograph.h b/include/asm-ia64/sn/iograph.h index d6a6f62ba34..f686631eb2d 100644 --- a/include/asm-ia64/sn/iograph.h +++ b/include/asm-ia64/sn/iograph.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOGRAPH_H #define _ASM_IA64_SN_IOGRAPH_H @@ -77,7 +77,7 @@ #define EDGE_LBL_IOC3 "ioc3" #define EDGE_LBL_LUN "lun" #define EDGE_LBL_LINUX "linux" -#define EDGE_LBL_LINUX_BUS EDGE_LBL_LINUX "/busnum" +#define EDGE_LBL_LINUX_BUS EDGE_LBL_LINUX "/bus/pci-x" #define EDGE_LBL_MACE "mace" /* O2 mace */ #define EDGE_LBL_MACHDEP "machdep" /* Platform depedent devices */ #define EDGE_LBL_MASTER ".master" @@ -127,8 +127,12 @@ #define EDGE_LBL_XBOX_RPS "xbox_rps" /* redundant power supply for xbox unit */ #define EDGE_LBL_IOBRICK "iobrick" #define EDGE_LBL_PBRICK "Pbrick" +#define EDGE_LBL_PEBRICK "PEbrick" +#define EDGE_LBL_PXBRICK "PXbrick" +#define EDGE_LBL_IXBRICK "IXbrick" #define EDGE_LBL_IBRICK "Ibrick" #define EDGE_LBL_XBRICK "Xbrick" +#define EDGE_LBL_CGBRICK "CGbrick" #define EDGE_LBL_CPUBUS "cpubus" /* CPU Interfaces (SysAd) */ /* vertex info labels in hwgraph */ @@ -211,7 +215,7 @@ void init_all_devices(void); #include /* For get MAX_PORT_NUM */ int io_brick_map_widget(int, int); -int io_path_map_widget(devfs_handle_t); +int io_path_map_widget(vertex_hdl_t); /* * Map a brick's widget number to a meaningful int diff --git a/include/asm-ia64/sn/klclock.h b/include/asm-ia64/sn/klclock.h index 702460435f6..a288d7fd0bb 100644 --- a/include/asm-ia64/sn/klclock.h +++ b/include/asm-ia64/sn/klclock.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1996, 2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 2001 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCLOCK_H diff --git a/include/asm-ia64/sn/klconfig.h b/include/asm-ia64/sn/klconfig.h index 2bfc1708ac1..dee79cd85b8 100644 --- a/include/asm-ia64/sn/klconfig.h +++ b/include/asm-ia64/sn/klconfig.h @@ -6,7 +6,7 @@ * * Derived from IRIX . * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCONFIG_H @@ -46,18 +46,8 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN1 -#include -#endif - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif #define KLCFGINFO_MAGIC 0xbeedbabe @@ -398,6 +388,12 @@ typedef struct kl_config_hdr { #define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) #define KLTYPE_PBRICK (KLCLASS_IOBRICK | 0x2) #define KLTYPE_XBRICK (KLCLASS_IOBRICK | 0x3) +#define KLTYPE_NBRICK (KLCLASS_IOBRICK | 0x4) +#define KLTYPE_PEBRICK (KLCLASS_IOBRICK | 0x5) +#define KLTYPE_PXBRICK (KLCLASS_IOBRICK | 0x6) +#define KLTYPE_IXBRICK (KLCLASS_IOBRICK | 0x7) +#define KLTYPE_CGBRICK (KLCLASS_IOBRICK | 0x8) + #define KLTYPE_PBRICK_BRIDGE KLTYPE_PBRICK @@ -437,11 +433,7 @@ typedef struct lboard_s { unsigned char brd_flags; /* Enabled, Disabled etc */ unsigned char brd_slot; /* slot number */ unsigned short brd_debugsw; /* Debug switches */ -#ifdef CONFIG_IA64_SGI_SN2 geoid_t brd_geoid; /* geo id */ -#else - moduleid_t brd_module; /* module to which it belongs */ -#endif partid_t brd_partition; /* Partition number */ unsigned short brd_diagval; /* diagnostic value */ unsigned short brd_diagparm; /* diagnostic parameter */ @@ -452,13 +444,11 @@ typedef struct lboard_s { klconf_off_t brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */ klconf_off_t brd_errinfo; /* Board's error information */ struct lboard_s *brd_parent; /* Logical parent for this brd */ - devfs_handle_t brd_graph_link; /* vertex hdl to connect extern compts */ + vertex_hdl_t brd_graph_link; /* vertex hdl to connect extern compts */ confidence_t brd_confidence; /* confidence that the board is bad */ nasid_t brd_owner; /* who owns this board */ unsigned char brd_nic_flags; /* To handle 8 more NICs */ -#ifdef CONFIG_IA64_SGI_SN2 char pad[32]; /* future expansion */ -#endif char brd_name[32]; } lboard_t; @@ -491,7 +481,8 @@ typedef struct lboard_s { ((_brd)->brd_next ? \ (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next)): NULL) #define KLCF_COMP(_brd, _ndx) \ - (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)])) + ((((_brd)->brd_compts[(_ndx)]) == 0) ? 0 : \ + (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)]))) #define KLCF_COMP_ERROR(_brd, _comp) \ (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) @@ -626,9 +617,7 @@ typedef struct klport_s { nasid_t port_nasid; unsigned char port_flag; klconf_off_t port_offset; -#ifdef CONFIG_IA64_SGI_SN2 short port_num; -#endif } klport_t; typedef struct klcpu_s { /* CPU */ @@ -638,9 +627,7 @@ typedef struct klcpu_s { /* CPU */ unsigned short cpu_speed; /* Speed in MHZ */ unsigned short cpu_scachesz; /* secondary cache size in MB */ unsigned short cpu_scachespeed;/* secondary cache speed in MHz */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klcpu_t ; #define CPU_STRUCT_VERSION 2 @@ -648,28 +635,20 @@ typedef struct klcpu_s { /* CPU */ typedef struct klhub_s { /* HUB */ klinfo_t hub_info; uint hub_flags; /* PCFG_HUB_xxx flags */ -#ifdef CONFIG_IA64_SGI_SN2 #define MAX_NI_PORTS 2 klport_t hub_port[MAX_NI_PORTS + 1];/* hub is connected to this */ -#else - klport_t hub_port; /* hub is connected to this */ -#endif nic_t hub_box_nic; /* nic of containing box */ klconf_off_t hub_mfg_nic; /* MFG NIC string */ u64 hub_speed; /* Speed of hub in HZ */ -#ifdef CONFIG_IA64_SGI_SN2 moduleid_t hub_io_module; /* attached io module */ unsigned long pad; -#endif } klhub_t ; typedef struct klhub_uart_s { /* HUB */ klinfo_t hubuart_info; uint hubuart_flags; /* PCFG_HUB_xxx flags */ nic_t hubuart_box_nic; /* nic of containing box */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klhub_uart_t ; #define MEMORY_STRUCT_VERSION 2 @@ -680,9 +659,7 @@ typedef struct klmembnk_s { /* MEMORY BANK */ short membnk_dimm_select; /* bank to physical addr mapping*/ short membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */ short membnk_attr; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmembnk_t ; #define KLCONFIG_MEMBNK_SIZE(_info, _bank) \ @@ -701,9 +678,7 @@ typedef struct klmod_serial_num_s { char snum_str[MAX_SERIAL_NUM_SIZE]; unsigned long long snum_int; } snum; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmod_serial_num_t; /* Macros needed to access serial number structure in lboard_t. @@ -721,9 +696,7 @@ typedef struct klxbow_s { /* XBOW */ klport_t xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */ int xbow_master_hub_link; /* type of brd connected+component struct ptr+flags */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klxbow_t ; #define MAX_PCI_SLOTS 8 @@ -742,9 +715,7 @@ typedef struct klbri_s { /* BRIDGE */ pci_t pci_specific ; /* PCI Board config info */ klpci_device_t bri_devices[MAX_PCI_DEVS] ; /* PCI IDs */ klconf_off_t bri_mfg_nic ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klbri_t ; #define MAX_IOC3_TTY 2 @@ -758,9 +729,7 @@ typedef struct klioc3_s { /* IOC3 */ klinfo_t ioc3_enet ; klconf_off_t ioc3_enet_off ; klconf_off_t ioc3_kbd_off ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klioc3_t ; #define MAX_VME_SLOTS 8 @@ -769,18 +738,14 @@ typedef struct klvmeb_s { /* VME BRIDGE - PCI CTLR */ klinfo_t vmeb_info ; vmeb_t vmeb_specific ; klconf_off_t vmeb_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klvmeb_t ; typedef struct klvmed_s { /* VME DEVICE - VME BOARD */ klinfo_t vmed_info ; vmed_t vmed_specific ; klconf_off_t vmed_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klvmed_t ; #define ROUTER_VECTOR_VERS 2 @@ -793,9 +758,7 @@ typedef struct klrou_s { /* ROUTER */ klport_t rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */ klconf_off_t rou_mfg_nic ; /* MFG NIC string */ u64 rou_vector; /* vector from master node */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klrou_t ; /* @@ -820,25 +783,19 @@ typedef struct klgfx_s { /* GRAPHICS Device */ graphics_t gfx_specific; klconf_off_t pad0; /* for compatibility with older proms */ klconf_off_t gfx_mfg_nic; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klgfx_t; typedef struct klxthd_s { klinfo_t xthd_info ; klconf_off_t xthd_mfg_nic ; /* MFG NIC string */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klxthd_t ; typedef struct kltpu_s { /* TPU board */ klinfo_t tpu_info ; klconf_off_t tpu_mfg_nic ; /* MFG NIC string */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } kltpu_t ; typedef struct klgsn_s { /* GSN board */ @@ -860,9 +817,7 @@ typedef struct klscsi_s { /* SCSI Bus */ scsi_t scsi_specific ; unsigned char scsi_numdevs ; klconf_off_t scsi_devinfo[MAX_SCSI_DEVS] ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscsi_t ; typedef struct klscctl_s { /* SCSI Controller */ @@ -870,49 +825,37 @@ typedef struct klscctl_s { /* SCSI Controller */ uint type; uint scsi_buscnt; /* # busses this cntlr */ void *scsi_bus[2]; /* Pointer to 2 klscsi_t's */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscctl_t ; typedef struct klscdev_s { /* SCSI device */ klinfo_t scdev_info ; struct scsidisk_data *scdev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscdev_t ; typedef struct klttydev_s { /* TTY device */ klinfo_t ttydev_info ; struct terminal_data *ttydev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klttydev_t ; typedef struct klenetdev_s { /* ENET device */ klinfo_t enetdev_info ; struct net_data *enetdev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klenetdev_t ; typedef struct klkbddev_s { /* KBD device */ klinfo_t kbddev_info ; struct keyboard_data *kbddev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klkbddev_t ; typedef struct klmsdev_s { /* mouse device */ klinfo_t msdev_info ; void *msdev_cfg ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmsdev_t ; #define MAX_FDDI_DEVS 10 /* XXX Is this true */ @@ -921,17 +864,13 @@ typedef struct klfddi_s { /* FDDI */ klinfo_t fddi_info ; fddi_t fddi_specific ; klconf_off_t fddi_devinfo[MAX_FDDI_DEVS] ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klfddi_t ; typedef struct klmio_s { /* MIO */ klinfo_t mio_info ; mio_t mio_specific ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmio_t ; /* @@ -942,9 +881,7 @@ typedef struct klusb_s { klinfo_t usb_info; /* controller info */ void *usb_bus; /* handle to usb_bus_t */ uint64_t usb_controller; /* ptr to controller info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klusb_t ; typedef union klcomp_s { @@ -1028,37 +965,18 @@ extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type); extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); -extern xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx); -extern devfs_handle_t nodevertex_xbow_peer_get(devfs_handle_t node_vtx); extern lboard_t *find_gfxpipe(int pipenum); -extern void setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum); extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class); -#ifdef CONFIG_IA64_SGI_SN2 -extern lboard_t *find_lboard_module_class(lboard_t *start, geoid_t geoid, - unsigned char brd_class); -#else -extern lboard_t *find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_class); -#endif extern lboard_t *find_nic_lboard(lboard_t *, nic_t); extern lboard_t *find_nic_type_lboard(nasid_t, unsigned char, nic_t); -#ifdef CONFIG_IA64_SGI_SN2 extern lboard_t *find_lboard_modslot(lboard_t *start, geoid_t geoid); extern lboard_t *find_lboard_module(lboard_t *start, geoid_t geoid); -extern lboard_t *get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name); -#else -extern lboard_t *find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot); -extern lboard_t *find_lboard_module(lboard_t *start, moduleid_t mod); -extern lboard_t *get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name); -#endif extern int config_find_nic_router(nasid_t, nic_t, lboard_t **, klrou_t**); extern int config_find_nic_hub(nasid_t, nic_t, lboard_t **, klhub_t**); extern int config_find_xbow(nasid_t, lboard_t **, klxbow_t**); extern int update_klcfg_cpuinfo(nasid_t, int); extern void board_to_path(lboard_t *brd, char *path); -#ifdef CONFIG_IA64_SGI_SN2 extern moduleid_t get_module_id(nasid_t nasid); -#endif extern void nic_name_convert(char *old_name, char *new_name); extern int module_brds(nasid_t nasid, lboard_t **module_brds, int n); extern lboard_t *brd_from_key(uint64_t key); diff --git a/include/asm-ia64/sn/kldir.h b/include/asm-ia64/sn/kldir.h index 2f6f644a209..c49174494ce 100644 --- a/include/asm-ia64/sn/kldir.h +++ b/include/asm-ia64/sn/kldir.h @@ -5,7 +5,7 @@ * * Derived from IRIX , revision 1.21. * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLDIR_H diff --git a/include/asm-ia64/sn/ksys/elsc.h b/include/asm-ia64/sn/ksys/elsc.h index 40ba043febb..aa8272ad858 100644 --- a/include/asm-ia64/sn/ksys/elsc.h +++ b/include/asm-ia64/sn/ksys/elsc.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_ELSC_H #define _ASM_SN_KSYS_ELSC_H @@ -12,82 +12,6 @@ #include #include -#ifdef CONFIG_IA64_SGI_SN1 - -#define ELSC_ACP_MAX 86 /* 84+cr+lf */ -#define ELSC_LINE_MAX (ELSC_ACP_MAX - 2) - -typedef sc_cq_t elsc_cq_t; - -/* - * ELSC structure passed around as handle - */ - -typedef l1sc_t elsc_t; - -void elsc_init(elsc_t *e, nasid_t nasid); - -int elsc_process(elsc_t *e); -int elsc_msg_check(elsc_t *e, char *msg, int msg_max); -int elsc_msg_callback(elsc_t *e, - void (*callback)(void *callback_data, char *msg), - void *callback_data); -char *elsc_errmsg(int code); - -int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len); -int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len); -int elsc_nvram_magic(elsc_t *e); -int elsc_command(elsc_t *e, int only_if_message); -int elsc_parse(elsc_t *e, char *p1, char *p2, char *p3); -int elsc_ust_write(elsc_t *e, uchar_t c); -int elsc_ust_read(elsc_t *e, char *c); - - - -/* - * System controller commands - */ - -int elsc_version(elsc_t *e, char *result); -int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2); -int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2); -int elsc_module_set(elsc_t *e, int module); -int elsc_module_get(elsc_t *e); -int elsc_partition_set(elsc_t *e, int partition); -int elsc_partition_get(elsc_t *e); -int elsc_domain_set(elsc_t *e, int domain); -int elsc_domain_get(elsc_t *e); -int elsc_cluster_set(elsc_t *e, int cluster); -int elsc_cluster_get(elsc_t *e); -int elsc_cell_set(elsc_t *e, int cell); -int elsc_cell_get(elsc_t *e); -int elsc_bist_set(elsc_t *e, char bist_status); -char elsc_bist_get(elsc_t *e); -int elsc_lock(elsc_t *e, int retry_interval_usec, int timeout_usec, u_char lock_val); -int elsc_unlock(elsc_t *e); -int elsc_display_char(elsc_t *e, int led, int chr); -int elsc_display_digit(elsc_t *e, int led, int num, int l_case); -int elsc_display_mesg(elsc_t *e, char *chr); /* 8-char input */ -int elsc_password_set(elsc_t *e, char *password); /* 4-char input */ -int elsc_password_get(elsc_t *e, char *password); /* 4-char output */ -int elsc_rpwr_query(elsc_t *e, int is_master); -int elsc_power_query(elsc_t *e); -int elsc_power_down(elsc_t *e, int sec); -int elsc_power_cycle(elsc_t *e); -int elsc_system_reset(elsc_t *e); -int elsc_dip_switches(elsc_t *e); - -int _elsc_hbt(elsc_t *e, int ival, int rdly); - -#define elsc_hbt_enable(e, ival, rdly) _elsc_hbt(e, ival, rdly) -#define elsc_hbt_disable(e) _elsc_hbt(e, 0, 0) -#define elsc_hbt_send(e) _elsc_hbt(e, 0, 1) - -elsc_t *get_elsc(void); - -#endif /* CONFIG_IA64_SGI_SN1 */ - - /* * Error codes * diff --git a/include/asm-ia64/sn/ksys/l1.h b/include/asm-ia64/sn/ksys/l1.h index d3f1be06554..6016bb73b86 100644 --- a/include/asm-ia64/sn/ksys/l1.h +++ b/include/asm-ia64/sn/ksys/l1.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_L1_H @@ -16,162 +16,6 @@ #include #include - -#ifdef CONFIG_IA64_SGI_SN1 - -#define BRL1_QSIZE 128 /* power of 2 is more efficient */ -#define BRL1_BUFSZ 264 /* needs to be large enough - * to hold 2 flags, escaped - * CRC, type/subchannel byte, - * and escaped payload - */ - -#define BRL1_IQS 32 -#define BRL1_OQS 4 - - -typedef struct sc_cq_s { - u_char buf[BRL1_QSIZE]; - int ipos, opos, tent_next; -} sc_cq_t; - -/* An l1sc_t struct can be associated with the local (C-brick) L1 or an L1 - * on an R-brick. In the R-brick case, the l1sc_t records a vector path - * to the R-brick's junk bus UART. In the C-brick case, we just use the - * following flag to denote the local uart. - * - * This value can't be confused with a network vector because the least- - * significant nibble of a network vector cannot be greater than 8. - */ -#define BRL1_LOCALHUB_UART ((net_vec_t)0xf) - -/* L1<->Bedrock reserved subchannels */ - -/* console channels */ -#define SC_CONS_CPU0 0x00 -#define SC_CONS_CPU1 0x01 -#define SC_CONS_CPU2 0x02 -#define SC_CONS_CPU3 0x03 - -#define L1_ELSCUART_SUBCH(p) (p) -#define L1_ELSCUART_CPU(ch) (ch) - -#define SC_CONS_SYSTEM CPUS_PER_NODE - -/* mapping subchannels to queues */ -#define MAP_IQ(s) (s) -#define MAP_OQ(s) (s) - -#define BRL1_NUM_SUBCHANS 32 -#define BRL1_CMD_SUBCH 16 -#define BRL1_EVENT_SUBCH (BRL1_NUM_SUBCHANS - 1) -#define BRL1_SUBCH_RSVD 0 -#define BRL1_SUBCH_FREE (-1) - -/* constants for L1 hwgraph vertex info */ -#define CBRICK_L1 (__psint_t)1 -#define IOBRICK_L1 (__psint_t)2 -#define RBRICK_L1 (__psint_t)3 - - -struct l1sc_s; -/* Saved off interrupt frame */ -typedef struct brl1_intr_frame { - int bf_irq; /* irq received */ - void *bf_dev_id; /* device information */ - struct pt_regs *bf_regs; /* register frame */ -} brl1_intr_frame_t; - -typedef void (*brl1_notif_t)(int, void *, struct pt_regs *, struct l1sc_s *, int); -typedef int (*brl1_uartf_t)(struct l1sc_s *); - -/* structure for controlling a subchannel */ -typedef struct brl1_sch_s { - int use; /* if this subchannel is free, - * use == BRL1_SUBCH_FREE */ - uint target; /* type, rack and slot of component to - * which this subchannel is directed */ - atomic_t packet_arrived; /* true if packet arrived on - * this subchannel */ - sc_cq_t * iqp; /* input queue for this subchannel */ - sv_t arrive_sv; /* used to wait for a packet */ - spinlock_t data_lock; /* synchronize access to input queues and - * other fields of the brl1_sch_s struct */ - brl1_notif_t tx_notify; /* notify higher layer that transmission may - * continue */ - brl1_notif_t rx_notify; /* notify higher layer that a packet has been - * received */ - brl1_intr_frame_t irq_frame; /* saved off irq information */ -} brl1_sch_t; - -/* br<->l1 protocol states */ -#define BRL1_IDLE 0 -#define BRL1_FLAG 1 -#define BRL1_HDR 2 -#define BRL1_BODY 3 -#define BRL1_ESC 4 -#define BRL1_RESET 7 - - -/* - * l1sc_t structure-- tracks protocol state, open subchannels, etc. - */ -typedef struct l1sc_s { - nasid_t nasid; /* nasid with which this instance - * of the structure is associated */ - moduleid_t modid; /* module id of this brick */ - u_char verbose; /* non-zero if elscuart routines should - * prefix output */ - net_vec_t uart; /* vector path to UART, or BRL1_LOCALUART */ - int sent; /* number of characters sent */ - int send_len; /* number of characters in send buf */ - brl1_uartf_t putc_f; /* pointer to UART putc function */ - brl1_uartf_t getc_f; /* pointer to UART getc function */ - - spinlock_t send_lock; /* arbitrates send synchronization */ - spinlock_t recv_lock; /* arbitrates uart receive access */ - spinlock_t subch_lock; /* arbitrates subchannel allocation */ - cpuid_t intr_cpu; /* cpu that receives L1 interrupts */ - - u_char send_in_use; /* non-zero if send buffer contains an - * unsent or partially-sent packet */ - u_char fifo_space; /* current depth of UART send FIFO */ - - u_char brl1_state; /* current state of the receive side */ - u_char brl1_last_hdr; /* last header byte received */ - - char send[BRL1_BUFSZ]; /* send buffer */ - - int sol; /* "start of line" (see elscuart routines) */ - int cons_listen; /* non-zero if the elscuart interface should - * also check the system console subchannel */ - brl1_sch_t subch[BRL1_NUM_SUBCHANS]; - /* subchannels provided by link */ - - sc_cq_t garbage_q; /* a place to put unsolicited packets */ - sc_cq_t oq[BRL1_OQS]; /* elscuart output queues */ -} l1sc_t; - - -/* error codes */ -#define BRL1_VALID 0 -#define BRL1_FULL_Q (-1) -#define BRL1_CRC (-2) -#define BRL1_PROTOCOL (-3) -#define BRL1_NO_MESSAGE (-4) -#define BRL1_LINK (-5) -#define BRL1_BUSY (-6) - -#define SC_SUCCESS BRL1_VALID -#define SC_NMSG BRL1_NO_MESSAGE -#define SC_BUSY BRL1_BUSY -#define SC_NOPEN (-7) -#define SC_BADSUBCH (-8) -#define SC_TIMEDOUT (-9) -#define SC_NSUBCH (-10) - -#endif /* CONFIG_IA64_SGI_SN1 */ - /* L1 Target Addresses */ /* * L1 commands and responses use source/target addresses that are @@ -181,39 +25,11 @@ typedef struct l1sc_s { * id (L1 functionality is divided into several independent "tasks" * that can each receive command requests and transmit responses) */ -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_TYPE_SHFT 28 -#define L1_ADDR_TYPE_MASK 0xF0000000 -#else -#define L1_ADDR_TYPE_SHFT 8 -#define L1_ADDR_TYPE_MASK 0xFF00 -#endif /* CONFIG_IA64_SGI_SN1 */ #define L1_ADDR_TYPE_L1 0x00 /* L1 system controller */ #define L1_ADDR_TYPE_L2 0x01 /* L2 system controller */ #define L1_ADDR_TYPE_L3 0x02 /* L3 system controller */ #define L1_ADDR_TYPE_CBRICK 0x03 /* attached C brick */ #define L1_ADDR_TYPE_IOBRICK 0x04 /* attached I/O brick */ - -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_RACK_SHFT 18 -#define L1_ADDR_RACK_MASK 0x0FFC0000 -#define L1_ADDR_RACK_LOCAL 0x3ff /* local brick's rack */ -#else -#define L1_ADDR_RACK_SHFT 16 -#define L1_ADDR_RACK_MASK 0xFFFF00 -#define L1_ADDR_RACK_LOCAL 0xffff /* local brick's rack */ -#endif /* CONFIG_IA64_SGI_SN1 */ - -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_BAY_SHFT 12 -#define L1_ADDR_BAY_MASK 0x0003F000 -#define L1_ADDR_BAY_LOCAL 0x3f /* local brick's bay */ -#else -#define L1_ADDR_BAY_SHFT 0 -#define L1_ADDR_BAY_MASK 0xFF -#define L1_ADDR_BAY_LOCAL 0xff /* local brick's bay */ -#endif /* CONFIG_IA64_SGI_SN1 */ - #define L1_ADDR_TASK_SHFT 0 #define L1_ADDR_TASK_MASK 0x0000001F #define L1_ADDR_TASK_INVALID 0x00 /* invalid task */ @@ -296,7 +112,9 @@ typedef struct l1sc_s { #define L1_BRICKTYPE_X 0x58 /* X */ #define L1_BRICKTYPE_X2 0x59 /* Y */ #define L1_BRICKTYPE_N 0x4e /* N */ +#define L1_BRICKTYPE_PE 0x25 /* % */ #define L1_BRICKTYPE_PX 0x23 /* # */ +#define L1_BRICKTYPE_IX 0x3d /* = */ /* EEPROM codes (for the "read EEPROM" request) */ /* c brick */ @@ -339,50 +157,10 @@ typedef uint32_t l1addr_t; #define bzero(d, n) memset((d), 0, (n)) -#ifdef CONFIG_IA64_SGI_SN1 - -#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00) - -/* public interfaces to L1 system controller */ - -int sc_open( l1sc_t *sc, uint target ); -int sc_close( l1sc_t *sc, int ch ); -int sc_construct_msg( l1sc_t *sc, int ch, - char *msg, int msg_len, - uint addr_task, short req_code, - int req_nargs, ... ); -int sc_interpret_resp( char *resp, int resp_nargs, ... ); -int sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ); -int sc_recv( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ); -int sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ); -int sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ); -int sc_poll( l1sc_t *sc, int ch ); -void sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ); -void sc_intr_enable( l1sc_t *sc ); - -int elsc_rack_bay_get(l1sc_t *e, uint *rack, uint *bay); -int elsc_rack_bay_type_get(l1sc_t *e, uint *rack, - uint *bay, uint *brick_type); -int elsc_cons_subch(l1sc_t *e, uint ch); -int elsc_cons_node(l1sc_t *e); -int elsc_display_line(l1sc_t *e, char *line, int lnum); - -extern l1sc_t *get_elsc( void ); -#define get_l1sc get_elsc -#define get_master_l1sc get_l1sc - -int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ); -int iobrick_module_get( l1sc_t *sc ); -int iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ); -int iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ); -int iobrick_sc_version( l1sc_t *sc, char *result ); -#else int elsc_display_line(nasid_t nasid, char *line, int lnum); int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, uint *bay, uint *brick_type ); int iobrick_module_get( nasid_t nasid ); -#endif /* CONFIG_IA64_SGI_SN1 */ #endif /* _ASM_SN_KSYS_L1_H */ diff --git a/include/asm-ia64/sn/labelcl.h b/include/asm-ia64/sn/labelcl.h index b08f52a4e62..488245f721b 100644 --- a/include/asm-ia64/sn/labelcl.h +++ b/include/asm-ia64/sn/labelcl.h @@ -4,13 +4,11 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_LABELCL_H #define _ASM_IA64_SN_LABELCL_H -#include - #define LABELCL_MAGIC 0x4857434c /* 'HWLC' */ #define LABEL_LENGTH_MAX 256 /* Includes NULL char */ #define INFO_DESC_PRIVATE (-1) /* default */ @@ -77,18 +75,18 @@ struct string_table { extern labelcl_info_t *labelcl_info_create(void); extern int labelcl_info_destroy(labelcl_info_t *); -extern int labelcl_info_add_LBL(struct devfs_entry *, char *, arb_info_desc_t, arbitrary_info_t); -extern int labelcl_info_remove_LBL(struct devfs_entry *, char *, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_replace_LBL(struct devfs_entry *, char *, arb_info_desc_t, +extern int labelcl_info_add_LBL(vertex_hdl_t, char *, arb_info_desc_t, arbitrary_info_t); +extern int labelcl_info_remove_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *); +extern int labelcl_info_replace_LBL(vertex_hdl_t, char *, arb_info_desc_t, arbitrary_info_t, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_get_LBL(struct devfs_entry *, char *, arb_info_desc_t *, +extern int labelcl_info_get_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_get_next_LBL(struct devfs_entry *, char *, arb_info_desc_t *, +extern int labelcl_info_get_next_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *, labelcl_info_place_t *); -extern int labelcl_info_replace_IDX(struct devfs_entry *, int, arbitrary_info_t, +extern int labelcl_info_replace_IDX(vertex_hdl_t, int, arbitrary_info_t, arbitrary_info_t *); -extern int labelcl_info_connectpt_set(struct devfs_entry *, struct devfs_entry *); -extern int labelcl_info_get_IDX(struct devfs_entry *, int, arbitrary_info_t *); -extern struct devfs_entry *device_info_connectpt_get(struct devfs_entry *); +extern int labelcl_info_connectpt_set(vertex_hdl_t, vertex_hdl_t); +extern int labelcl_info_get_IDX(vertex_hdl_t, int, arbitrary_info_t *); +extern struct devfs_handle_t device_info_connectpt_get(vertex_hdl_t); #endif /* _ASM_IA64_SN_LABELCL_H */ diff --git a/include/asm-ia64/sn/leds.h b/include/asm-ia64/sn/leds.h index 040b117f4b6..095d26106e9 100644 --- a/include/asm-ia64/sn/leds.h +++ b/include/asm-ia64/sn/leds.h @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -13,25 +13,14 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN1 -#define LED0 0xc0000b00100000c0LL -#define LED_CPU_SHIFT 3 -#else #include + #define LED0 (LOCAL_MMR_ADDR(SH_REAL_JUNK_BUS_LED0)) #define LED_CPU_SHIFT 16 -#endif #define LED_CPU_HEARTBEAT 0x01 #define LED_CPU_ACTIVITY 0x02 -#ifdef LED_WAR -#define LED_ALWAYS_SET 0x64 /* SN2 hw workaround: always set 0x60 */ -#define LED_MASK_AUTOTEST 0x9e -#else /* LED_WAR */ #define LED_ALWAYS_SET 0x00 -#define LED_MASK_AUTOTEST 0xfe -#endif /* LED_WAR */ /* * Basic macros for flashing the LEDS on an SGI, SN1. @@ -40,14 +29,8 @@ static __inline__ void set_led_bits(u8 value, u8 mask) { -#if 0 - pda.led_state = (pda.led_state & ~mask) | (value & mask); -#ifdef CONFIG_IA64_SGI_SN1 - *pda.led_address = (long) pda.led_state; -#else - *pda.led_address = (short) pda.led_state; -#endif -#endif + pda->led_state = (pda->led_state & ~mask) | (value & mask); + *pda->led_address = (short) pda->led_state; } #endif /* _ASM_IA64_SN_LEDS_H */ diff --git a/include/asm-ia64/sn/mca.h b/include/asm-ia64/sn/mca.h deleted file mode 100644 index 4c17af4701a..00000000000 --- a/include/asm-ia64/sn/mca.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * File: mca.h - * Purpose: Machine check handling specific to the SN platform defines - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include - -#ifdef CONFIG_IA64_SGI_SN - -typedef u64 __uint64_t; - -typedef struct { - __uint64_t sh_event_occurred; - __uint64_t sh_first_error; - __uint64_t sh_event_overflow; - __uint64_t sh_pi_first_error; - __uint64_t sh_pi_error_summary; - __uint64_t sh_pi_error_overflow; - __uint64_t sh_pi_error_detail_1; - __uint64_t sh_pi_error_detail_2; - __uint64_t sh_pi_hw_time_stamp; - __uint64_t sh_pi_uncorrected_detail_1; - __uint64_t sh_pi_uncorrected_detail_2; - __uint64_t sh_pi_uncorrected_detail_3; - __uint64_t sh_pi_uncorrected_detail_4; - __uint64_t sh_pi_uncor_time_stamp; - __uint64_t sh_pi_corrected_detail_1; - __uint64_t sh_pi_corrected_detail_2; - __uint64_t sh_pi_corrected_detail_3; - __uint64_t sh_pi_corrected_detail_4; - __uint64_t sh_pi_cor_time_stamp; - __uint64_t sh_mem_error_summary; - __uint64_t sh_mem_error_overflow; - __uint64_t sh_misc_err_hdr_lower; - __uint64_t sh_misc_err_hdr_upper; - __uint64_t sh_dir_uc_err_hdr_lower; - __uint64_t sh_dir_uc_err_hdr_upper; - __uint64_t sh_dir_cor_err_hdr_lower; - __uint64_t sh_dir_cor_err_hdr_upper; - __uint64_t sh_mem_error_mask; - __uint64_t sh_md_uncor_time_stamp; - __uint64_t sh_md_cor_time_stamp; - __uint64_t sh_md_hw_time_stamp; - __uint64_t sh_xn_error_summary; - __uint64_t sh_xn_first_error; - __uint64_t sh_xn_error_overflow; - __uint64_t sh_xniilb_error_summary; - __uint64_t sh_xniilb_first_error; - __uint64_t sh_xniilb_error_overflow; - __uint64_t sh_xniilb_error_detail_1; - __uint64_t sh_xniilb_error_detail_2; - __uint64_t sh_xniilb_error_detail_3; - __uint64_t sh_xnpi_error_summary; - __uint64_t sh_xnpi_first_error; - __uint64_t sh_xnpi_error_overflow; - __uint64_t sh_xnpi_error_detail_1; - __uint64_t sh_xnmd_error_summary; - __uint64_t sh_xnmd_first_error; - __uint64_t sh_xnmd_error_overflow; - __uint64_t sh_xnmd_ecc_err_report; - __uint64_t sh_xnmd_error_detail_1; - __uint64_t sh_lb_error_summary; - __uint64_t sh_lb_first_error; - __uint64_t sh_lb_error_overflow; - __uint64_t sh_lb_error_detail_1; - __uint64_t sh_lb_error_detail_2; - __uint64_t sh_lb_error_detail_3; - __uint64_t sh_lb_error_detail_4; - __uint64_t sh_lb_error_detail_5; -} sal_log_shub_state_t; - -typedef struct { -sal_log_section_hdr_t header; - struct - { - __uint64_t err_status : 1, - guid : 1, - oem_data : 1, - reserved : 61; - } valid; - __uint64_t err_status; - efi_guid_t guid; - __uint64_t shub_nic; - sal_log_shub_state_t shub_state; -} sal_log_plat_info_t; - - -extern void sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc); - -#ifdef platform_plat_specific_err_print -#undef platform_plat_specific_err_print -#endif -#define platform_plat_specific_err_print sal_log_plat_print - -#endif /* CONFIG_IA64_SGI_SN */ diff --git a/include/asm-ia64/sn/mmtimer_private.h b/include/asm-ia64/sn/mmtimer_private.h index 72ead52c7eb..e8ba8e0b40c 100644 --- a/include/asm-ia64/sn/mmtimer_private.h +++ b/include/asm-ia64/sn/mmtimer_private.h @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. * * Helper file for the SN implementation of mmtimers * diff --git a/include/asm-ia64/sn/module.h b/include/asm-ia64/sn/module.h index 9e3b73818a3..df95417bf33 100644 --- a/include/asm-ia64/sn/module.h +++ b/include/asm-ia64/sn/module.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_MODULE_H #define _ASM_IA64_SN_MODULE_H @@ -32,9 +32,6 @@ extern "C" { #define MODULE_FORMAT_BRIEF 1 #define MODULE_FORMAT_LONG 2 - -#ifdef CONFIG_IA64_SGI_SN2 - /* * Module id format * @@ -141,6 +138,7 @@ extern char brick_types[]; #define MODULE_NBRICK 7 #define MODULE_PEBRICK 8 #define MODULE_PXBRICK 9 +#define MODULE_IXBRICK 10 /* * Moduleid_t comparison macros @@ -150,118 +148,6 @@ extern char brick_types[]; ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK))) #define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#else -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - -/* - * Module id format - * - * 15-12 Brick type (enumerated) - * 11-6 Rack ID (encoded class, group, number) - * 5-0 Brick position in rack (0-63) - */ -/* - * Macros for getting the brick type - */ -#define MODULE_BTYPE_MASK 0xf000 -#define MODULE_BTYPE_SHFT 12 -#define MODULE_GET_BTYPE(_m) (((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT) -#define MODULE_BT_TO_CHAR(_b) (brick_types[(_b)]) -#define MODULE_GET_BTCHAR(_m) (MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m))) - -/* - * Macros for getting the rack ID. - */ -#define MODULE_RACK_MASK 0x0fc0 -#define MODULE_RACK_SHFT 6 -#define MODULE_GET_RACK(_m) (((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT) - -/* - * Macros for getting the brick position - */ -#define MODULE_BPOS_MASK 0x003f -#define MODULE_BPOS_SHFT 0 -#define MODULE_GET_BPOS(_m) (((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT) - -/* - * Macros for constructing moduleid_t's - */ -#define RBT_TO_MODULE(_r, _b, _t) ((_r) << MODULE_RACK_SHFT | \ - (_b) << MODULE_BPOS_SHFT | \ - (_t) << MODULE_BTYPE_SHFT) - -/* - * Macros for encoding and decoding rack IDs - * A rack number consists of three parts: - * class 1 bit, 0==CPU/mixed, 1==I/O - * group 2 bits for CPU/mixed, 3 bits for I/O - * number 3 bits for CPU/mixed, 2 bits for I/O (1 based) - */ -#define RACK_GROUP_BITS(_r) (RACK_GET_CLASS(_r) ? 3 : 2) -#define RACK_NUM_BITS(_r) (RACK_GET_CLASS(_r) ? 2 : 3) - -#define RACK_CLASS_MASK(_r) 0x20 -#define RACK_CLASS_SHFT(_r) 5 -#define RACK_GET_CLASS(_r) \ - (((_r) & RACK_CLASS_MASK(_r)) >> RACK_CLASS_SHFT(_r)) -#define RACK_ADD_CLASS(_r, _c) \ - ((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r)) - -#define RACK_GROUP_SHFT(_r) RACK_NUM_BITS(_r) -#define RACK_GROUP_MASK(_r) \ - ( (((unsigned)1<> RACK_GROUP_SHFT(_r)) -#define RACK_ADD_GROUP(_r, _g) \ - ((_r) |= (_g) << RACK_GROUP_SHFT(_r) & RACK_GROUP_MASK(_r)) - -#define RACK_NUM_SHFT(_r) 0 -#define RACK_NUM_MASK(_r) \ - ( (((unsigned)1<> RACK_NUM_SHFT(_r)) + 1 ) -#define RACK_ADD_NUM(_r, _n) \ - ((_r) |= ((_n) - 1) << RACK_NUM_SHFT(_r) & RACK_NUM_MASK(_r)) - -/* - * Brick type definitions - */ -#define MAX_BRICK_TYPES 16 /* 1 << (MODULE_RACK_SHFT - MODULE_BTYPE_SHFT */ - -extern char brick_types[]; - -#define MODULE_CBRICK 0 -#define MODULE_RBRICK 1 -#define MODULE_IBRICK 2 -#define MODULE_KBRICK 3 -#define MODULE_XBRICK 4 -#define MODULE_DBRICK 5 -#define MODULE_PBRICK 6 -#define MODULE_NBRICK 7 -#define MODULE_PEBRICK 8 -#define MODULE_PXBRICK 9 - -/* - * Moduleid_t comparison macros - */ -/* Don't compare the brick type: only the position is significant */ -#define MODULE_CMP(_m1, _m2) (((_m1)&(MODULE_RACK_MASK|MODULE_BPOS_MASK)) -\ - ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK))) -#define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#else - -/* - * Some code that uses this macro will not be conditionally compiled. - */ -#define MODULE_GET_BTCHAR(_m) ('?') -#define MODULE_CMP(_m1, _m2) ((_m1) - (_m2)) -#define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#endif /* SN1 */ -#endif /* SN2 */ - typedef struct module_s module_t; struct module_s { @@ -271,23 +157,15 @@ struct module_s { /* List of nodes in this module */ cnodeid_t nodes[MODULE_MAX_NODES]; -#ifdef CONFIG_IA64_SGI_SN2 geoid_t geoid[MODULE_MAX_NODES]; struct { char moduleid[8]; } io[MODULE_MAX_NODES]; -#endif int nodecnt; /* Number of nodes in array */ - /* Fields for Module System Controller */ int mesgpend; /* Message pending */ int shutdown; /* Shutdown in progress */ struct semaphore thdcnt; /* Threads finished counter */ - -#ifdef CONFIG_IA64_SGI_SN1 - elsc_t elsc; - spinlock_t elsclock; -#endif time_t intrhist[MODULE_HIST_CNT]; int histptr; @@ -315,10 +193,6 @@ extern int nummodules; extern module_t *module_lookup(moduleid_t id); -#if defined(CONFIG_IA64_SGI_SN1) -extern elsc_t *get_elsc(void); -#endif - extern int get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info); extern int get_kmod_sys_snum(cmoduleid_t cmod, diff --git a/include/asm-ia64/sn/nag.h b/include/asm-ia64/sn/nag.h index f1380f7c787..10a15a8a261 100644 --- a/include/asm-ia64/sn/nag.h +++ b/include/asm-ia64/sn/nag.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff --git a/include/asm-ia64/sn/nic.h b/include/asm-ia64/sn/nic.h deleted file mode 100644 index 44eedb02f7d..00000000000 --- a/include/asm-ia64/sn/nic.h +++ /dev/null @@ -1,129 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_NIC_H -#define _ASM_IA64_SN_NIC_H - -#include -#include -#include - -#define MCR_DATA(x) ((int) ((x) & 1)) -#define MCR_DONE(x) ((x) & 2) -#define MCR_PACK(pulse, sample) ((pulse) << 10 | (sample) << 2) - -typedef __psunsigned_t nic_data_t; - -typedef int -nic_access_f(nic_data_t data, - int pulse, int sample, int delay); - -typedef nic_access_f *nic_access_t; - -typedef struct nic_vmce_s *nic_vmce_t; -typedef void nic_vmc_func(devfs_handle_t v); - -/* - * PRIVATE data for Dallas NIC - */ - -typedef struct nic_state_t { - nic_access_t access; - nic_data_t data; - int last_disc; - int done; - int bit_index; - int disc_marker; - uchar_t bits[64]; -} nic_state_t; - -/* - * Public interface for Dallas NIC - * - * - * Access Routine - * - * nic_setup requires an access routine that pulses the NIC line for a - * specified duration, samples the NIC line after a specified duration, - * then delays for a third specified duration (for precharge). - * - * This general scheme allows us to access NICs through any medium - * (e.g. hub regs, bridge regs, vector writes, system ctlr commands). - * - * The access routine should return the sample value 0 or 1, or if an - * error occurs, return a negative error code. Negative error codes from - * the access routine will abort the NIC operation and be propagated - * through out of the top-level NIC call. - */ - -#define NIC_OK 0 -#define NIC_DONE 1 -#define NIC_FAIL 2 -#define NIC_BAD_CRC 3 -#define NIC_NOT_PRESENT 4 -#define NIC_REDIR_LOOP 5 -#define NIC_PARAM 6 -#define NIC_NOMEM 7 - -uint64_t nic_get_phase_bits(void); - -extern int nic_setup(nic_state_t *ns, - nic_access_t access, - nic_data_t data); - -extern int nic_next(nic_state_t *ns, - char *serial, - char *family, - char *crc); - -extern int nic_read_one_page(nic_state_t *ns, - char *family, - char *serial, - char *crc, - int start, - uchar_t *redirect, - uchar_t *byte); - -extern int nic_read_mfg(nic_state_t *ns, - char *family, - char *serial, - char *crc, - uchar_t *pageA, - uchar_t *pageB); - -extern int nic_info_get(nic_access_t access, - nic_data_t data, - char *info); - -extern int nic_item_info_get(char *buf, char *item, char **item_info); - -nic_access_f nic_access_mcr32; - -extern char *nic_vertex_info_get(devfs_handle_t v); - -extern char *nic_vertex_info_set(nic_access_t access, - nic_data_t data, - devfs_handle_t v); - -extern int nic_vertex_info_match(devfs_handle_t vertex, - char *name); - -extern char *nic_bridge_vertex_info(devfs_handle_t vertex, - nic_data_t data); -extern char *nic_hq4_vertex_info(devfs_handle_t vertex, - nic_data_t data); -extern char *nic_ioc3_vertex_info(devfs_handle_t vertex, - nic_data_t data, - int32_t *gpcr_s); - -extern char *nic_hub_vertex_info(devfs_handle_t vertex); - -extern nic_vmce_t nic_vmc_add(char *, nic_vmc_func *); -extern void nic_vmc_del(nic_vmce_t); - -#endif /* _ASM_IA64_SN_NIC_H */ diff --git a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h index f9aa614ddb1..a53b50cae4b 100644 --- a/include/asm-ia64/sn/nodepda.h +++ b/include/asm-ia64/sn/nodepda.h @@ -3,27 +3,21 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_NODEPDA_H #define _ASM_IA64_SN_NODEPDA_H #include +#include #include #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#endif #include #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#endif - /* * NUMA Node-Specific Data structures are defined in this file. * In particular, this is the location of the node PDA. @@ -31,23 +25,6 @@ */ /* - * Subnode PDA structures. Each node needs a few data structures that - * correspond to the PIs on the HUB chip that supports the node. - */ -#if defined(CONFIG_IA64_SGI_SN1) -struct subnodepda_s { - intr_vecblk_t intr_dispatch0; - intr_vecblk_t intr_dispatch1; -}; - -typedef struct subnodepda_s subnode_pda_t; - - -struct synergy_perf_s; -#endif - - -/* * Node-specific data structure. * * One of these structures is allocated on each node of a NUMA system. @@ -66,24 +43,20 @@ struct nodepda_s { /* the second cpu on a node is */ /* node_first_cpu+1. */ - devfs_handle_t xbow_vhdl; + vertex_hdl_t xbow_vhdl; nasid_t xbow_peer; /* NASID of our peer hub on xbow */ struct semaphore xbow_sema; /* Sema for xbow synchronization */ slotid_t slotdesc; -#ifdef CONFIG_IA64_SGI_SN2 geoid_t geoid; -#else - moduleid_t module_id; /* Module ID (redundant local copy) */ -#endif module_t *module; /* Pointer to containing module */ xwidgetnum_t basew_id; - devfs_handle_t basew_xc; + vertex_hdl_t basew_xc; int hubticks; int num_routers; /* XXX not setup! Total routers in the system */ char *hwg_node_name; /* hwgraph node name */ - devfs_handle_t node_vertex; /* Hwgraph vertex for this node */ + vertex_hdl_t node_vertex; /* Hwgraph vertex for this node */ void *pdinfo; /* Platform-dependent per-node info */ @@ -95,27 +68,9 @@ struct nodepda_s { /* * The BTEs on this node are shared by the local cpus */ - bteinfo_t bte_if[BTES_PER_NODE]; /* Virtual Interface */ - char bte_cleanup[5 * L1_CACHE_BYTES] ____cacheline_aligned; - -#if defined(CONFIG_IA64_SGI_SN1) - subnode_pda_t snpda[NUM_SUBNODES]; - /* - * New extended memory reference counters - */ - void *migr_refcnt_counterbase; - void *migr_refcnt_counterbuffer; - size_t migr_refcnt_cbsize; - int migr_refcnt_numsets; - hubstat_t hubstats; - int synergy_perf_enabled; - int synergy_perf_freq; - spinlock_t synergy_perf_lock; - uint64_t synergy_inactive_intervals; - uint64_t synergy_active_intervals; - struct synergy_perf_s *synergy_perf_data; - struct synergy_perf_s *synergy_perf_first; /* reporting consistency .. */ -#endif /* CONFIG_IA64_SGI_SN1 */ + struct bteinfo_s bte_if[BTES_PER_NODE]; /* Virtual Interface */ + struct timer_list bte_recovery_timer; + spinlock_t bte_recovery_lock; /* * Array of pointers to the nodepdas for each node. @@ -126,18 +81,16 @@ struct nodepda_s { typedef struct nodepda_s nodepda_t; -#ifdef CONFIG_IA64_SGI_SN2 -#define NR_IVECS 256 struct irqpda_s { int num_irq_used; - char irq_flags[NR_IVECS]; + char irq_flags[NR_IRQS]; + struct pci_dev *device_dev[NR_IRQS]; + char share_count[NR_IRQS]; + struct pci_dev *current; }; typedef struct irqpda_s irqpda_t; -#endif /* CONFIG_IA64_SGI_SN2 */ - - /* * Access Functions for node PDA. @@ -156,21 +109,11 @@ typedef struct irqpda_s irqpda_t; #define nodepda pda->p_nodepda /* Ptr to this node's PDA */ #define NODEPDA(cnode) (nodepda->pernode_pdaindr[cnode]) -#if defined(CONFIG_IA64_SGI_SN1) -#define subnodepda pda.p_subnodepda /* Ptr to this node's subnode PDA */ -#define SUBNODEPDA(cnode,sn) (&(NODEPDA(cnode)->snpda[sn])) -#define SNPDA(npda,sn) (&(npda)->snpda[sn]) -#endif - /* * Macros to access data structures inside nodepda */ -#ifdef CONFIG_IA64_SGI_SN2 #define NODE_MODULEID(cnode) geo_module((NODEPDA(cnode)->geoid)) -#else -#define NODE_MODULEID(cnode) (NODEPDA(cnode)->module_id) -#endif #define NODE_SLOTID(cnode) (NODEPDA(cnode)->slotdesc) @@ -184,8 +127,8 @@ typedef struct irqpda_s irqpda_t; * Check if given a compact node id the corresponding node has all the * cpus disabled. */ -#define is_headless_node(cnode) 0 /*((cnode == CNODEID_NONE) || \ - (node_data(cnode)->active_cpu_count == 0)) */ +#define is_headless_node(cnode) ((cnode == CNODEID_NONE) || \ + (node_data(cnode)->active_cpu_count == 0)) /* * Check if given a node vertex handle the corresponding node has all the diff --git a/include/asm-ia64/sn/pci/bridge.h b/include/asm-ia64/sn/pci/bridge.h index ebbc59ad0d1..bc021e657f7 100644 --- a/include/asm-ia64/sn/pci/bridge.h +++ b/include/asm-ia64/sn/pci/bridge.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_BRIDGE_H #define _ASM_SN_PCI_BRIDGE_H @@ -36,7 +36,6 @@ #include #include -#ifndef CONFIG_IA64_SGI_SN1 #include extern int io_get_sh_swapper(nasid_t); @@ -45,7 +44,6 @@ extern int io_get_sh_swapper(nasid_t); #define BRIDGE_REG_SET32(reg) \ *(volatile uint32_t *) (((uint64_t)reg)^4) -#endif /* CONFIG_IA64_SGI_SN1 */ /* I/O page size */ @@ -111,7 +109,6 @@ typedef volatile bridge_ate_t *bridge_ate_p; * Generated from Bridge spec dated 04oct95 */ -#ifndef CONFIG_IA64_SGI_SN1 /* * pic_widget_cfg_s is a local definition of widget_cfg_t but with @@ -605,292 +602,6 @@ typedef volatile struct bridge_s { } b_external_flash; } bridge_t; -#else /* CONFIG_IA64_SGI_SN1 */ - - -typedef volatile struct bridge_s { - - /* Local Registers 0x000000-0x00FFFF */ - - /* standard widget configuration 0x000000-0x000057 */ - widget_cfg_t b_widget; /* 0x000000 */ - - /* helper fieldnames for accessing bridge widget */ - -#define b_wid_id b_widget.w_id -#define b_wid_stat b_widget.w_status -#define b_wid_err_upper b_widget.w_err_upper_addr -#define b_wid_err_lower b_widget.w_err_lower_addr -#define b_wid_control b_widget.w_control -#define b_wid_req_timeout b_widget.w_req_timeout -#define b_wid_int_upper b_widget.w_intdest_upper_addr -#define b_wid_int_lower b_widget.w_intdest_lower_addr -#define b_wid_err_cmdword b_widget.w_err_cmd_word -#define b_wid_llp b_widget.w_llp_cfg -#define b_wid_tflush b_widget.w_tflush - - /* - * we access these through synergy unswizzled space, so the address - * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.) - * That's why we put the register first and filler second. - */ - /* bridge-specific widget configuration 0x000058-0x00007F */ - bridgereg_t b_wid_aux_err; /* 0x00005C */ - bridgereg_t _pad_000058; - - bridgereg_t b_wid_resp_upper; /* 0x000064 */ - bridgereg_t _pad_000060; - - bridgereg_t b_wid_resp_lower; /* 0x00006C */ - bridgereg_t _pad_000068; - - bridgereg_t b_wid_tst_pin_ctrl; /* 0x000074 */ - bridgereg_t _pad_000070; - - bridgereg_t _pad_000078[2]; - - /* PMU & Map 0x000080-0x00008F */ - bridgereg_t b_dir_map; /* 0x000084 */ - bridgereg_t _pad_000080; - bridgereg_t _pad_000088[2]; - - /* SSRAM 0x000090-0x00009F */ - bridgereg_t b_ram_perr_or_map_fault;/* 0x000094 */ - bridgereg_t _pad_000090; -#define b_ram_perr b_ram_perr_or_map_fault /* Bridge */ -#define b_map_fault b_ram_perr_or_map_fault /* Xbridge */ - bridgereg_t _pad_000098[2]; - - /* Arbitration 0x0000A0-0x0000AF */ - bridgereg_t b_arb; /* 0x0000A4 */ - bridgereg_t _pad_0000A0; - bridgereg_t _pad_0000A8[2]; - - /* Number In A Can 0x0000B0-0x0000BF */ - bridgereg_t b_nic; /* 0x0000B4 */ - bridgereg_t _pad_0000B0; - bridgereg_t _pad_0000B8[2]; - - /* PCI/GIO 0x0000C0-0x0000FF */ - bridgereg_t b_bus_timeout; /* 0x0000C4 */ - bridgereg_t _pad_0000C0; -#define b_pci_bus_timeout b_bus_timeout - - bridgereg_t b_pci_cfg; /* 0x0000CC */ - bridgereg_t _pad_0000C8; - - bridgereg_t b_pci_err_upper; /* 0x0000D4 */ - bridgereg_t _pad_0000D0; - - bridgereg_t b_pci_err_lower; /* 0x0000DC */ - bridgereg_t _pad_0000D8; - bridgereg_t _pad_0000E0[8]; -#define b_gio_err_lower b_pci_err_lower -#define b_gio_err_upper b_pci_err_upper - - /* Interrupt 0x000100-0x0001FF */ - bridgereg_t b_int_status; /* 0x000104 */ - bridgereg_t _pad_000100; - - bridgereg_t b_int_enable; /* 0x00010C */ - bridgereg_t _pad_000108; - - bridgereg_t b_int_rst_stat; /* 0x000114 */ - bridgereg_t _pad_000110; - - bridgereg_t b_int_mode; /* 0x00011C */ - bridgereg_t _pad_000118; - - bridgereg_t b_int_device; /* 0x000124 */ - bridgereg_t _pad_000120; - - bridgereg_t b_int_host_err; /* 0x00012C */ - bridgereg_t _pad_000128; - - struct { - bridgereg_t addr; /* 0x0001{34,,,6C} */ - bridgereg_t __pad; /* 0x0001{30,,,68} */ - } b_int_addr[8]; /* 0x000130 */ - - bridgereg_t b_err_int_view; /* 0x000174 */ - bridgereg_t _pad_000170; - - bridgereg_t b_mult_int; /* 0x00017c */ - bridgereg_t _pad_000178; - - struct { - bridgereg_t intr; /* 0x0001{84,,,BC} */ - bridgereg_t __pad; /* 0x0001{80,,,B8} */ - } b_force_always[8]; /* 0x000180 */ - - struct { - bridgereg_t intr; /* 0x0001{C4,,,FC} */ - bridgereg_t __pad; /* 0x0001{C0,,,F8} */ - } b_force_pin[8]; /* 0x0001C0 */ - - /* Device 0x000200-0x0003FF */ - struct { - bridgereg_t reg; /* 0x0002{04,,,3C} */ - bridgereg_t __pad; /* 0x0002{00,,,38} */ - } b_device[8]; /* 0x000200 */ - - struct { - bridgereg_t reg; /* 0x0002{44,,,7C} */ - bridgereg_t __pad; /* 0x0002{40,,,78} */ - } b_wr_req_buf[8]; /* 0x000240 */ - - struct { - bridgereg_t reg; /* 0x0002{84,,,8C} */ - bridgereg_t __pad; /* 0x0002{80,,,88} */ - } b_rrb_map[2]; /* 0x000280 */ -#define b_even_resp b_rrb_map[0].reg /* 0x000284 */ -#define b_odd_resp b_rrb_map[1].reg /* 0x00028C */ - - bridgereg_t b_resp_status; /* 0x000294 */ - bridgereg_t _pad_000290; - - bridgereg_t b_resp_clear; /* 0x00029C */ - bridgereg_t _pad_000298; - - bridgereg_t _pad_0002A0[24]; - - /* Xbridge only */ - struct { - bridgereg_t upper; /* 0x0003{04,,,F4} */ - bridgereg_t __pad1; /* 0x0003{00,,,F0} */ - bridgereg_t lower; /* 0x0003{0C,,,FC} */ - bridgereg_t __pad2; /* 0x0003{08,,,F8} */ - } b_buf_addr_match[16]; - - /* Performance Monitor Registers (even only) */ - struct { - bridgereg_t flush_w_touch; /* 0x000404,,,5C4 */ - bridgereg_t __pad1; /* 0x000400,,,5C0 */ - - bridgereg_t flush_wo_touch; /* 0x00040C,,,5CC */ - bridgereg_t __pad2; /* 0x000408,,,5C8 */ - - bridgereg_t inflight; /* 0x000414,,,5D4 */ - bridgereg_t __pad3; /* 0x000410,,,5D0 */ - - bridgereg_t prefetch; /* 0x00041C,,,5DC */ - bridgereg_t __pad4; /* 0x000418,,,5D8 */ - - bridgereg_t total_pci_retry; /* 0x000424,,,5E4 */ - bridgereg_t __pad5; /* 0x000420,,,5E0 */ - - bridgereg_t max_pci_retry; /* 0x00042C,,,5EC */ - bridgereg_t __pad6; /* 0x000428,,,5E8 */ - - bridgereg_t max_latency; /* 0x000434,,,5F4 */ - bridgereg_t __pad7; /* 0x000430,,,5F0 */ - - bridgereg_t clear_all; /* 0x00043C,,,5FC */ - bridgereg_t __pad8; /* 0x000438,,,5F8 */ - } b_buf_count[8]; - - char _pad_000600[0x010000 - 0x000600]; - - /* - * The Xbridge has 1024 internal ATE's and the Bridge has 128. - * Make enough room for the Xbridge ATE's and depend on runtime - * checks to limit access to bridge ATE's. - */ - - /* Internal Address Translation Entry RAM 0x010000-0x011fff */ - union { - bridge_ate_t wr; /* write-only */ - struct { - bridgereg_t rd; /* read-only */ - bridgereg_t _p_pad; - } hi; - } b_int_ate_ram[XBRIDGE_INTERNAL_ATES]; - -#define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd - - /* the xbridge read path for internal ates starts at 0x12000. - * I don't believe we ever try to read the ates. - */ - /* Internal Address Translation Entry RAM LOW 0x012000-0x013fff */ - struct { - bridgereg_t rd; - bridgereg_t _p_pad; - } xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES]; - - char _pad_014000[0x20000 - 0x014000]; - - /* PCI Device Configuration Spaces 0x020000-0x027FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - union { - uchar_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } b_type0_cfg_dev[8]; /* 0x020000 */ - - /* PCI Type 1 Configuration Space 0x028000-0x028FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - union { - uchar_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } b_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x007000]; /* 0x029000-0x030000 */ - - /* PCI Interrupt Acknowledge Cycle 0x030000 */ - union { - uchar_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } b_pci_iack; /* 0x030000 */ - - uchar_t _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ - - /* External Address Translation Entry RAM 0x080000-0x0FFFFF */ - bridge_ate_t b_ext_ate_ram[0x10000]; - - /* Reserved 0x100000-0x1FFFFF */ - char _pad_100000[0x200000-0x100000]; - - /* PCI/GIO Device Spaces 0x200000-0xBFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x100000 / 1]; - uint16_t s[0x100000 / 2]; - uint32_t l[0x100000 / 4]; - uint64_t d[0x100000 / 8]; - } b_devio_raw[10]; /* 0x200000 */ - - /* b_devio macro is a bit strange; it reflects the - * fact that the Bridge ASIC provides 2M for the - * first two DevIO windows and 1M for the other six. - */ -#define b_devio(n) b_devio_raw[((n)<2)?(n*2):(n+2)] - - /* External Flash Proms 1,0 0xC00000-0xFFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x400000 / 1]; /* read-only */ - uint16_t s[0x400000 / 2]; /* read-write */ - uint32_t l[0x400000 / 4]; /* read-only */ - uint64_t d[0x400000 / 8]; /* read-only */ - } b_external_flash; /* 0xC00000 */ -} bridge_t; - -#endif /* CONFIG_IA64_SGI_SN1 */ - - #define berr_field berr_un.berr_st #endif /* __ASSEMBLY__ */ @@ -1428,8 +1139,7 @@ typedef volatile struct bridge_s { #define BRIDGE_ISR_ERRORS \ (BRIDGE_ISR_LINK_ERROR|BRIDGE_ISR_PCIBUS_ERROR| \ BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR| \ - BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_PCIX_ARB_ERR| \ - PIC_ISR_INT_RAM_PERR) + BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_INT_RAM_PERR) /* * List of Errors which are fatal and kill the sytem @@ -1598,22 +1308,6 @@ typedef volatile struct bridge_s { #define BRIDGE_TMO_PCI_RETRY_CNT_MAX 0x3ff -#ifdef SN0 -/* - * The NASID should be shifted by this amount and stored into the - * interrupt(x) register. - */ -#define BRIDGE_INT_ADDR_NASID_SHFT 8 - -/* - * The BRIDGE_INT_ADDR_DEST_IO bit should be set to send an interrupt to - * memory. - */ -#define BRIDGE_INT_ADDR_DEST_IO (1 << 17) -#define BRIDGE_INT_ADDR_DEST_MEM 0 -#define BRIDGE_INT_ADDR_MASK (1 << 17) -#endif - /* Bridge device(x) register bits definition */ #define BRIDGE_DEV_ERR_LOCK_EN (1ull << 28) #define BRIDGE_DEV_PAGE_CHK_DIS (1ull << 27) @@ -1728,6 +1422,38 @@ typedef volatile struct bridge_s { #define BRIDGE_PCI_IO_LIMIT BRIDGE_PCIIO_XTALK_ALIAS_LIMIT /* + * Macros for Xtalk to Bridge bus (PCI) PIO + * refer to section 5.2.1 Figure 4 of the "PCI Interface Chip (PIC) Volume II + * Programmer's Reference" (Revision 0.8 as of this writing). + * + * These are PIC bridge specific. A separate set of macros was defined + * because PIC deviates from Bridge/Xbridge by not supporting a big-window + * alias for PCI I/O space, and also redefines XTALK addresses + * 0x0000C0000000L and 0x000100000000L to be PCI MEM aliases for the second + * bus. + */ + +/* XTALK addresses that map into PIC Bridge Bus addr space */ +#define PICBRIDGE0_PIO32_XTALK_ALIAS_BASE 0x000040000000L +#define PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT 0x00007FFFFFFFL +#define PICBRIDGE0_PIO64_XTALK_ALIAS_BASE 0x000080000000L +#define PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT 0x0000BFFFFFFFL +#define PICBRIDGE1_PIO32_XTALK_ALIAS_BASE 0x0000C0000000L +#define PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT 0x0000FFFFFFFFL +#define PICBRIDGE1_PIO64_XTALK_ALIAS_BASE 0x000100000000L +#define PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT 0x00013FFFFFFFL + +/* XTALK addresses that map into PCI addresses */ +#define PICBRIDGE0_PCI_MEM32_BASE PICBRIDGE0_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM32_LIMIT PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE0_PCI_MEM64_BASE PICBRIDGE0_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM64_LIMIT PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM32_BASE PICBRIDGE1_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM32_LIMIT PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM64_BASE PICBRIDGE1_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM64_LIMIT PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT + +/* * Macros for Bridge bus (PCI/GIO) to Xtalk DMA */ /* Bridge Bus DMA addresses */ @@ -1845,9 +1571,6 @@ typedef union ate_u { #define ATE_SWAP_ON(x) ((x) |= (1 << ATE_SWAPSHIFT)) #define ATE_SWAP_OFF(x) ((x) &= ~(1 << ATE_SWAPSHIFT)) -#define is_xbridge(bridge) IS_XBRIDGE(bridge->b_wid_id) -#define is_pic(bridge) IS_PIC_BRIDGE(bridge->b_wid_id) - /* extern declarations */ #ifndef __ASSEMBLY__ diff --git a/include/asm-ia64/sn/pci/pci_bus_cvlink.h b/include/asm-ia64/sn/pci/pci_bus_cvlink.h index 6c4e2dfc215..517acefde8b 100644 --- a/include/asm-ia64/sn/pci/pci_bus_cvlink.h +++ b/include/asm-ia64/sn/pci/pci_bus_cvlink.h @@ -4,13 +4,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_CVLINK_H #define _ASM_SN_PCI_CVLINK_H #include -#include #include #include #include @@ -50,11 +49,11 @@ (((struct sn_widget_sysdata *)((pci_bus)->sysdata))->vhdl) struct sn_widget_sysdata { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; }; struct sn_device_sysdata { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; int isa64; int isPIC; volatile unsigned int *dma_buf_sync; diff --git a/include/asm-ia64/sn/pci/pci_defs.h b/include/asm-ia64/sn/pci/pci_defs.h index 2df7888e561..73dbb4b81a0 100644 --- a/include/asm-ia64/sn/pci/pci_defs.h +++ b/include/asm-ia64/sn/pci/pci_defs.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCI_DEFS_H #define _ASM_SN_PCI_PCI_DEFS_H @@ -321,6 +321,112 @@ extern void pci_write(void * address, int data, int type); #ifndef __ASSEMBLY__ +#ifdef LITTLE_ENDIAN + +/* + * PCI config space definition + */ +typedef volatile struct pci_cfg_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[6]; + uint32_t cardbus; + uint16_t subsys_vendor_id; + uint16_t subsys_dev_id; + uint32_t exp_rom; + uint32_t res[2]; + uchar_t int_line; + uchar_t int_pin; + uchar_t min_gnt; + uchar_t max_lat; +} pci_cfg_t; + +/* + * PCI Type 1 config space definition for PCI to PCI Bridges (PPBs) + */ +typedef volatile struct pci_cfg1_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[2]; + uchar_t pri_bus_num; + uchar_t snd_bus_num; + uchar_t sub_bus_num; + uchar_t slt; + uchar_t io_base; + uchar_t io_limit; + uint16_t snd_status; + uint16_t mem_base; + uint16_t mem_limit; + uint16_t pmem_base; + uint16_t pmem_limit; + uint32_t pmem_base_upper; + uint32_t pmem_limit_upper; + uint16_t io_base_upper; + uint16_t io_limit_upper; + uint32_t res; + uint32_t exp_rom; + uchar_t int_line; + uchar_t int_pin; + uint16_t ppb_control; + +} pci_cfg1_t; + +/* + * PCI-X Capability + */ +typedef volatile struct cap_pcix_cmd_reg_s { + uint16_t data_parity_enable: 1, + enable_relaxed_order: 1, + max_mem_read_cnt: 2, + max_split: 3, + reserved1: 9; +} cap_pcix_cmd_reg_t; + +typedef volatile struct cap_pcix_stat_reg_s { + uint32_t func_num: 3, + dev_num: 5, + bus_num: 8, + bit64_device: 1, + mhz133_capable: 1, + split_complt_discard: 1, + unexpect_split_complt: 1, + device_complex: 1, + max_mem_read_cnt: 2, + max_out_split: 3, + max_cum_read: 3, + split_complt_err: 1, + reserved1: 2; +} cap_pcix_stat_reg_t; + +typedef volatile struct cap_pcix_type0_s { + uchar_t pcix_cap_id; + uchar_t pcix_cap_nxt; + cap_pcix_cmd_reg_t pcix_type0_command; + cap_pcix_stat_reg_t pcix_type0_status; +} cap_pcix_type0_t; + +#else + /* * PCI config space definition */ @@ -388,6 +494,8 @@ typedef volatile struct pci_cfg1_s { uchar_t int_line; } pci_cfg1_t; + + /* * PCI-X Capability */ @@ -422,5 +530,6 @@ typedef volatile struct cap_pcix_type0_s { cap_pcix_stat_reg_t pcix_type0_status; } cap_pcix_type0_t; +#endif #endif /* __ASSEMBLY__ */ #endif /* _ASM_SN_PCI_PCI_DEFS_H */ diff --git a/include/asm-ia64/sn/pci/pciba.h b/include/asm-ia64/sn/pci/pciba.h deleted file mode 100644 index f8b16a2033e..00000000000 --- a/include/asm-ia64/sn/pci/pciba.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of - * this archive for more details. - * - * Copyright (C) 1997, 2001 Silicon Graphics, Inc. All rights reserved. - * - */ - -#ifndef _ASM_SN_PCI_PCIBA_H -#define _ASM_SN_PCI_PCIBA_H - -#include -#include -#include - -/* for application compatibility with IRIX (why do I bother?) */ - -#ifndef __KERNEL__ -typedef u_int8_t uint8_t; -typedef u_int16_t uint16_t; -typedef u_int32_t uint32_t; -#endif - -#define PCI_CFG_VENDOR_ID PCI_VENDOR_ID -#define PCI_CFG_COMMAND PCI_COMMAND -#define PCI_CFG_REV_ID PCI_REVISION_ID -#define PCI_CFG_HEADER_TYPE PCI_HEADER_TYPE -#define PCI_CFG_BASE_ADDR(n) PCI_BASE_ADDRESS_##n - - -/* /hw/.../pci/[slot]/config accepts ioctls to read - * and write specific registers as follows: - * - * "t" is the native type (char, short, uint32, uint64) - * to read from CFG space; results will be arranged in - * byte significance (ie. first byte from PCI is lowest - * or last byte in result). - * - * "r" is the byte offset in PCI CFG space of the first - * byte of the register (it's least significant byte, - * in the little-endian PCI numbering). This can actually - * be as much as 16 bits wide, and is intended to match - * the layout of a "Type 1 Configuration Space" address: - * the register number in the low eight bits, then three - * bits for the function number and five bits for the - * slot number. - */ -#define PCIIOCCFGRD(t,r) _IOR(0,(r),t) -#define PCIIOCCFGWR(t,r) _IOW(0,(r),t) - -/* Some common config register access commands. - * Use these as examples of how to construct - * values for other registers you want to access. - */ - -/* PCIIOCGETID: arg is ptr to 32-bit int, - * returns the 32-bit ID value with VENDOR - * in the bottom 16 bits and DEVICE in the top. - */ -#define PCIIOCGETID PCIIOCCFGRD(uint32_t,PCI_CFG_VENDOR_ID) - -/* PCIIOCSETCMD: arg is ptr to a 16-bit short, - * which will be written to the CMD register. - */ -#define PCIIOCSETCMD PCIIOCCFGWR(uint16_t,PCI_CFG_COMMAND) - -/* PCIIOCGETREV: arg is ptr to an 8-bit char, - * which will get the 8-bit revision number. - */ -#define PCIIOCGETREV PCIIOCCFGRD(uint8_t,PCI_CFG_REV_ID) - -/* PCIIOCGETHTYPE: arg is ptr to an 8-bit char, - * which will get the 8-bit header type. - */ -#define PCIIOCGETHTYPE PCIIOCCFGRD(uint8_t,PCI_CFG_HEADER_TYPE) - -/* PCIIOCGETBASE(n): arg is ptr to a 32-bit int, - * which will get the value of the BASE register. - */ - -/* FIXME chadt: this doesn't tell me whether or not this will work - with non-constant 'n.' */ -#define PCIIOCGETBASE(n) PCIIOCCFGRD(uint32_t,PCI_CFG_BASE_ADDR(n)) - - -/* /hw/.../pci/[slot]/dma accepts ioctls to allocate - * and free physical memory for use in user-triggered - * DMA operations. - */ -#define PCIIOCDMAALLOC _IOWR(0,1,uint64_t) -#define PCIIOCDMAFREE _IOW(0,1,uint64_t) - -/* pio cache-mode ioctl defines. current only uncached accelerated */ -#define PCIBA_CACHE_MODE_SET 1 -#define PCIBA_CACHE_MODE_CLEAR 2 -#ifdef PIOMAP_UNC_ACC -#define PCIBA_UNCACHED_ACCEL PIOMAP_UNC_ACC -#endif - -/* The parameter for PCIIOCDMAALLOC needs to contain - * both the size of the request and the flag values - * to be used in setting up the DMA. - * - -FIXME chadt: gonna have to revisit this: what flags would an IRIXer like to - have available? - - * Any flags normally useful in pciio_dmamap - * or pciio_dmatrans function calls can6 be used here. */ -#define PCIIOCDMAALLOC_REQUEST_PACK(flags,size) \ - ((((uint64_t)(flags))<<32)| \ - (((uint64_t)(size))&0xFFFFFFFF)) - - -#ifdef __KERNEL__ -extern int pciba_init(void); -#endif - - -#endif /* _ASM_SN_PCI_PCIBA_H */ diff --git a/include/asm-ia64/sn/pci/pcibr.h b/include/asm-ia64/sn/pci/pcibr.h index c29d13c49fb..c9153ea71e9 100644 --- a/include/asm-ia64/sn/pci/pcibr.h +++ b/include/asm-ia64/sn/pci/pcibr.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_H #define _ASM_SN_PCI_PCIBR_H @@ -59,9 +59,7 @@ typedef struct pcibr_intr_s *pcibr_intr_t; * code and part number registered by pcibr_init(). */ -extern void pcibr_init(void); - -extern int pcibr_attach(devfs_handle_t); +extern int pcibr_attach(vertex_hdl_t); /* ===================================================================== * bus provider function table @@ -94,7 +92,7 @@ extern pciio_provider_t pci_pic_provider; * smarts on the part of the compilation system). */ -extern pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t dev, +extern pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -110,24 +108,24 @@ extern caddr_t pcibr_piomap_addr(pcibr_piomap_t piomap, extern void pcibr_piomap_done(pcibr_piomap_t piomap); -extern caddr_t pcibr_piotrans_addr(devfs_handle_t dev, +extern caddr_t pcibr_piotrans_addr(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, size_t byte_count, unsigned flags); -extern iopaddr_t pcibr_piospace_alloc(devfs_handle_t dev, +extern iopaddr_t pcibr_piospace_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, size_t byte_count, size_t alignment); -extern void pcibr_piospace_free(devfs_handle_t dev, +extern void pcibr_piospace_free(vertex_hdl_t dev, pciio_space_t space, iopaddr_t pciaddr, size_t byte_count); -extern pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t dev, +extern pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t dev, device_desc_t dev_desc, size_t byte_count_max, unsigned flags); @@ -150,109 +148,97 @@ extern void pcibr_dmamap_done(pcibr_dmamap_t dmamap); * (This node id can be different for each PCI bus.) */ -extern cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl); +extern cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t pconn_vhdl); -extern iopaddr_t pcibr_dmatrans_addr(devfs_handle_t dev, +extern iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t dev, device_desc_t dev_desc, paddr_t paddr, size_t byte_count, unsigned flags); -extern alenlist_t pcibr_dmatrans_list(devfs_handle_t dev, +extern alenlist_t pcibr_dmatrans_list(vertex_hdl_t dev, device_desc_t dev_desc, alenlist_t palenlist, unsigned flags); extern void pcibr_dmamap_drain(pcibr_dmamap_t map); -extern void pcibr_dmaaddr_drain(devfs_handle_t vhdl, +extern void pcibr_dmaaddr_drain(vertex_hdl_t vhdl, paddr_t addr, size_t bytes); -extern void pcibr_dmalist_drain(devfs_handle_t vhdl, +extern void pcibr_dmalist_drain(vertex_hdl_t vhdl, alenlist_t list); typedef unsigned pcibr_intr_ibit_f(pciio_info_t info, pciio_intr_line_t lines); -extern void pcibr_intr_ibit_set(devfs_handle_t, pcibr_intr_ibit_f *); +extern void pcibr_intr_ibit_set(vertex_hdl_t, pcibr_intr_ibit_f *); -extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t dev, +extern pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_intr_line_t lines, - devfs_handle_t owner_dev); + vertex_hdl_t owner_dev); extern void pcibr_intr_free(pcibr_intr_t intr); -#ifdef CONFIG_IA64_SGI_SN1 -extern int pcibr_intr_connect(pcibr_intr_t intr); -#else extern int pcibr_intr_connect(pcibr_intr_t intr, intr_func_t, intr_arg_t); -#endif extern void pcibr_intr_disconnect(pcibr_intr_t intr); -extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t intr); +extern vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t intr); -extern void pcibr_provider_startup(devfs_handle_t pcibr); +extern void pcibr_provider_startup(vertex_hdl_t pcibr); -extern void pcibr_provider_shutdown(devfs_handle_t pcibr); +extern void pcibr_provider_shutdown(vertex_hdl_t pcibr); -extern int pcibr_reset(devfs_handle_t dev); +extern int pcibr_reset(vertex_hdl_t dev); -extern int pcibr_write_gather_flush(devfs_handle_t dev); +extern int pcibr_write_gather_flush(vertex_hdl_t dev); -extern pciio_endian_t pcibr_endian_set(devfs_handle_t dev, +extern pciio_endian_t pcibr_endian_set(vertex_hdl_t dev, pciio_endian_t device_end, pciio_endian_t desired_end); -extern pciio_priority_t pcibr_priority_set(devfs_handle_t dev, +extern pciio_priority_t pcibr_priority_set(vertex_hdl_t dev, pciio_priority_t device_prio); -extern uint64_t pcibr_config_get(devfs_handle_t conn, +extern uint64_t pcibr_config_get(vertex_hdl_t conn, unsigned reg, unsigned size); -extern void pcibr_config_set(devfs_handle_t conn, +extern void pcibr_config_set(vertex_hdl_t conn, unsigned reg, unsigned size, uint64_t value); -extern int pcibr_error_devenable(devfs_handle_t pconn_vhdl, +extern int pcibr_error_devenable(vertex_hdl_t pconn_vhdl, int error_code); -#ifdef PIC_LATER -extern pciio_slot_t pcibr_error_extract(devfs_handle_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *addrp); -#endif - -extern int pcibr_wrb_flush(devfs_handle_t pconn_vhdl); -extern int pcibr_rrb_check(devfs_handle_t pconn_vhdl, +extern int pcibr_wrb_flush(vertex_hdl_t pconn_vhdl); +extern int pcibr_rrb_check(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1, int *count_reserved, int *count_pool); -#ifndef CONFIG_IA64_SGI_SN1 -extern int pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, +extern int pcibr_alloc_all_rrbs(vertex_hdl_t vhdl, int even_odd, int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4); -#endif typedef void -rrb_alloc_funct_f (devfs_handle_t xconn_vhdl, +rrb_alloc_funct_f (vertex_hdl_t xconn_vhdl, int *vendor_list); typedef rrb_alloc_funct_f *rrb_alloc_funct_t; -void pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, +void pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_f *func); -extern int pcibr_device_unregister(devfs_handle_t); -extern int pcibr_dma_enabled(devfs_handle_t); +extern int pcibr_device_unregister(vertex_hdl_t); +extern int pcibr_dma_enabled(vertex_hdl_t); /* * Bridge-specific flags that can be set via pcibr_device_flags_set * and cleared via pcibr_device_flags_clear. Other flags are @@ -320,7 +306,7 @@ typedef int pcibr_device_flags_t; * "flags" are defined above. NOTE: this includes turning * things *OFF* as well as turning them *ON* ... */ -extern int pcibr_device_flags_set(devfs_handle_t dev, +extern int pcibr_device_flags_set(vertex_hdl_t dev, pcibr_device_flags_t flags); /* @@ -331,7 +317,7 @@ extern int pcibr_device_flags_set(devfs_handle_t dev, * <0 on failure, which occurs when we're unable to allocate any * buffers to a channel that desires at least one buffer. */ -extern int pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, +extern int pcibr_rrb_alloc(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1); @@ -345,19 +331,15 @@ extern iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); extern xwidget_intr_preset_f pcibr_xintr_preset; -extern void pcibr_hints_fix_rrbs(devfs_handle_t); -extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); -extern void pcibr_hints_handsoff(devfs_handle_t); +extern void pcibr_hints_fix_rrbs(vertex_hdl_t); +extern void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +extern void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, ulong); +extern void pcibr_hints_handsoff(vertex_hdl_t); -#ifdef CONFIG_IA64_SGI_SN1 -typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t); -#else typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t, int); -#endif -extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); +extern void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); -extern int pcibr_asic_rev(devfs_handle_t); +extern int pcibr_asic_rev(vertex_hdl_t); #endif /* __ASSEMBLY__ */ #endif /* #if defined(__KERNEL__) */ @@ -433,7 +415,7 @@ struct pcibr_slot_info_resp_s { short resp_bs_bridge_mode; int resp_has_host; char resp_host_slot; - devfs_handle_t resp_slot_conn; + vertex_hdl_t resp_slot_conn; char resp_slot_conn_name[MAXDEVNAME]; int resp_slot_status; int resp_l1_bus_num; @@ -460,10 +442,8 @@ struct pcibr_slot_info_resp_s { bridgereg_t resp_b_int_device; bridgereg_t resp_b_int_enable; bridgereg_t resp_b_int_host; -#ifndef CONFIG_IA64_SGI_SN1 picreg_t resp_p_int_enable; picreg_t resp_p_int_host; -#endif struct pcibr_slot_func_info_resp_s { int resp_f_status; char resp_f_slot_name[MAXDEVNAME]; diff --git a/include/asm-ia64/sn/pci/pcibr_private.h b/include/asm-ia64/sn/pci/pcibr_private.h index 569aba5e2b3..86c7ba69184 100644 --- a/include/asm-ia64/sn/pci/pcibr_private.h +++ b/include/asm-ia64/sn/pci/pcibr_private.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_PRIVATE_H #define _ASM_SN_PCI_PCIBR_PRIVATE_H @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -45,7 +46,7 @@ cfg_p pcibr_slot_config_addr(bridge_t *, pciio_slot_t, int); cfg_p pcibr_func_config_addr(bridge_t *, pciio_bus_t bus, pciio_slot_t, pciio_function_t, int); unsigned pcibr_slot_config_get(bridge_t *, pciio_slot_t, int); unsigned pcibr_func_config_get(bridge_t *, pciio_slot_t, pciio_function_t, int); -void pcibr_debug(uint32_t, devfs_handle_t, char *, ...); +void pcibr_debug(uint32_t, vertex_hdl_t, char *, ...); void pcibr_slot_config_set(bridge_t *, pciio_slot_t, int, unsigned); void pcibr_func_config_set(bridge_t *, pciio_slot_t, pciio_function_t, int, unsigned); @@ -171,6 +172,7 @@ struct pcibr_intr_s { unsigned bi_ibits; /* which Bridge interrupt bit(s) */ pcibr_soft_t bi_soft; /* shortcut to soft info */ struct pcibr_intr_cbuf_s bi_ibuf; /* circular buffer of wrap ptrs */ + unsigned bi_last_intr; /* For Shub lb lost intr. bug */ }; @@ -254,11 +256,7 @@ struct pcibr_intr_list_s { struct pcibr_intr_wrap_s { pcibr_soft_t iw_soft; /* which bridge */ volatile bridgereg_t *iw_stat; /* ptr to b_int_status */ -#ifdef CONFIG_IA64_SGI_SN1 - bridgereg_t iw_intr; /* bit in b_int_status */ -#else bridgereg_t iw_ibit; /* bit in b_int_status */ -#endif pcibr_intr_list_t iw_list; /* ghostbusters! */ int iw_hdlrcnt; /* running handler count */ int iw_shared; /* if Bridge bit is shared */ @@ -293,6 +291,8 @@ struct pcibr_intr_wrap_s { #define PCIBR_BRIDGETYPE_PIC 2 #define IS_XBRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_XBRIDGE) #define IS_PIC_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_PIC) +#define IS_PIC_BUSNUM_SOFT(ps, bus) \ + (IS_PIC_SOFT(ps) && ((ps)->bs_busnum == (bus))) #define IS_BRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_BRIDGE) #define IS_XBRIDGE_OR_PIC_SOFT(ps) (IS_XBRIDGE_SOFT(ps) || IS_PIC_SOFT(ps)) @@ -348,13 +348,13 @@ struct pcibr_intr_wrap_s { */ struct pcibr_soft_s { - devfs_handle_t bs_conn; /* xtalk connection point */ - devfs_handle_t bs_vhdl; /* vertex owned by pcibr */ + vertex_hdl_t bs_conn; /* xtalk connection point */ + vertex_hdl_t bs_vhdl; /* vertex owned by pcibr */ uint64_t bs_int_enable; /* Mask of enabled intrs */ bridge_t *bs_base; /* PIO pointer to Bridge chip */ char *bs_name; /* hw graph name */ xwidgetnum_t bs_xid; /* Bridge's xtalk ID number */ - devfs_handle_t bs_master; /* xtalk master vertex */ + vertex_hdl_t bs_master; /* xtalk master vertex */ xwidgetnum_t bs_mxid; /* master's xtalk ID number */ pciio_slot_t bs_first_slot; /* first existing slot */ pciio_slot_t bs_last_slot; /* last existing slot */ @@ -372,9 +372,6 @@ struct pcibr_soft_s { short bs_int_ate_size; /* number of internal ates */ short bs_bridge_type; /* see defines above */ short bs_bridge_mode; /* see defines above */ -#ifdef CONFIG_IA64_SGI_SN1 -#define bs_xbridge bs_bridge_type -#endif int bs_rev_num; /* revision number of Bridge */ /* bs_dma_flags are the forced dma flags used on all DMAs. Used for @@ -382,9 +379,6 @@ struct pcibr_soft_s { */ unsigned bs_dma_flags; /* forced DMA flags */ -#ifdef CONFIG_IA64_SGI_SN1 - l1sc_t *bs_l1sc; /* io brick l1 system cntr */ -#endif moduleid_t bs_moduleid; /* io brick moduleid */ short bs_bricktype; /* io brick type */ @@ -394,7 +388,7 @@ struct pcibr_soft_s { */ spinlock_t bs_lock; - devfs_handle_t bs_noslot_conn; /* NO-SLOT connection point */ + vertex_hdl_t bs_noslot_conn; /* NO-SLOT connection point */ pcibr_info_t bs_noslot_info; struct pcibr_soft_slot_s { /* information we keep about each CFG slot */ @@ -411,7 +405,7 @@ struct pcibr_soft_s { */ int has_host; pciio_slot_t host_slot; - devfs_handle_t slot_conn; + vertex_hdl_t slot_conn; /* PCI Hot-Plug status word */ int slot_status; @@ -531,13 +525,8 @@ struct pcibr_soft_s { int bs_rrb_avail[2]; int bs_rrb_res[8]; int bs_rrb_res_dflt[8]; -#ifdef CONFIG_IA64_SGI_SN1 - int bs_rrb_valid[16]; - int bs_rrb_valid_dflt[16]; -#else int bs_rrb_valid[8][4]; int bs_rrb_valid_dflt[8][4]; -#endif struct { /* Each Bridge interrupt bit has a single XIO * interrupt channel allocated. @@ -578,7 +567,7 @@ struct pcibr_soft_s { #ifdef LATER toid_t bserr_toutid; /* Timeout started by errintr */ #endif /* LATER */ - iopaddr_t bserr_addr; /* Address where error occurred */ + iopaddr_t bserr_addr; /* Address where error occured */ uint64_t bserr_intstat; /* interrupts active at error dump */ } bs_errinfo; @@ -599,16 +588,6 @@ struct pcibr_soft_s { * in Megabytes), and they generally tend to take once and never * release. */ -#ifdef CONFIG_IA64_SGI_SN1 - struct br_pcisp_info { - iopaddr_t pci_io_base; - iopaddr_t pci_io_last; - iopaddr_t pci_swin_base; - iopaddr_t pci_swin_last; - iopaddr_t pci_mem_base; - iopaddr_t pci_mem_last; - } bs_spinfo; -#endif /* CONFIG_IA64_SGI_SN1 */ struct pciio_win_map_s bs_io_win_map; /* I/O addr space */ struct pciio_win_map_s bs_swin_map; /* Small window addr space */ struct pciio_win_map_s bs_mem_win_map; /* Memory addr space */ @@ -655,8 +634,6 @@ struct pcibr_hints_s { pcibr_intr_bits_f *ph_intr_bits; /* map PCI INT[ABCD] to Bridge Int(n) */ }; -extern int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; - /* * Number of bridge non-fatal error interrupts we can see before * we decide to disable that interrupt. @@ -689,7 +666,6 @@ extern int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; #define NEW(ptr) NEWA(ptr,1) #define DEL(ptr) DELA(ptr,1) -#ifndef CONFIG_IA64_SGI_SN1 /* * Additional PIO spaces per slot are * recorded in this structure. @@ -701,7 +677,6 @@ struct pciio_piospace_s { iopaddr_t start; /* Starting address of the PIO space */ size_t count; /* size of PIO space */ }; -#endif /* CONFIG_IA64_SGI_SN1 */ /* Use io spin locks. This ensures that all the PIO writes from a particular * CPU to a particular IO device are synched before the start of the next @@ -715,11 +690,9 @@ struct pciio_piospace_s { #define pcibr_unlock(pcibr_soft, s) #endif /* PCI_LATER */ -#ifndef CONFIG_IA64_SGI_SN1 #define PCIBR_VALID_SLOT(ps, s) (s < PCIBR_NUM_SLOTS(ps)) #define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) #define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) -#endif #define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" #define PCIBR_SOFT_LIST 1 @@ -728,8 +701,35 @@ typedef struct pcibr_list_s *pcibr_list_p; struct pcibr_list_s { pcibr_list_p bl_next; pcibr_soft_t bl_soft; - devfs_handle_t bl_vhdl; + vertex_hdl_t bl_vhdl; }; #endif /* PCIBR_SOFT_LIST */ + +// Devices per widget: 2 buses, 2 slots per bus, 8 functions per slot. +#define DEV_PER_WIDGET (2*2*8) + +struct sn_flush_device_list { + int bus; + int pin; + struct bar_list { + unsigned long start; + unsigned long end; + } bar_list[PCI_ROM_RESOURCE]; + unsigned long force_int_addr; + volatile unsigned long flush_addr; + spinlock_t flush_lock; +}; + +struct sn_flush_nasid_entry { + struct sn_flush_device_list **widget_p; + unsigned long iio_itte1; + unsigned long iio_itte2; + unsigned long iio_itte3; + unsigned long iio_itte4; + unsigned long iio_itte5; + unsigned long iio_itte6; + unsigned long iio_itte7; +}; + #endif /* _ASM_SN_PCI_PCIBR_PRIVATE_H */ diff --git a/include/asm-ia64/sn/pci/pciio.h b/include/asm-ia64/sn/pci/pciio.h index b48737b2800..e7f47d3240b 100644 --- a/include/asm-ia64/sn/pci/pciio.h +++ b/include/asm-ia64/sn/pci/pciio.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_H #define _ASM_SN_PCI_PCIIO_H @@ -277,7 +277,7 @@ typedef struct pciio_win_alloc_s *pciio_win_alloc_t; #define PCIIO_PIOMAP_WIN(n) (0x8+(n)) typedef pciio_piomap_t -pciio_piomap_alloc_f (devfs_handle_t dev, /* set up mapping for this device */ +pciio_piomap_alloc_f (vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pcipio_addr, /* starting address */ @@ -297,7 +297,7 @@ typedef void pciio_piomap_done_f (pciio_piomap_t pciio_piomap); typedef caddr_t -pciio_piotrans_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_piotrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pciio_addr, /* starting address */ @@ -305,7 +305,7 @@ pciio_piotrans_addr_f (devfs_handle_t dev, /* translate for this device */ unsigned flags); typedef caddr_t -pciio_pio_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_pio_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pciio_addr, /* starting address */ @@ -314,14 +314,14 @@ pciio_pio_addr_f (devfs_handle_t dev, /* translate for this device */ unsigned flags); typedef iopaddr_t -pciio_piospace_alloc_f (devfs_handle_t dev, /* PIO space for this device */ +pciio_piospace_alloc_f (vertex_hdl_t dev, /* PIO space for this device */ device_desc_t dev_desc, /* Device descriptor */ pciio_space_t space, /* which address space */ size_t byte_count, /* Number of bytes of space */ size_t alignment); /* Alignment of allocation */ typedef void -pciio_piospace_free_f (devfs_handle_t dev, /* Device freeing space */ +pciio_piospace_free_f (vertex_hdl_t dev, /* Device freeing space */ pciio_space_t space, /* Which space is freed */ iopaddr_t pci_addr, /* Address being freed */ size_t size); /* Size freed */ @@ -329,7 +329,7 @@ pciio_piospace_free_f (devfs_handle_t dev, /* Device freeing space */ /* DMA MANAGEMENT */ typedef pciio_dmamap_t -pciio_dmamap_alloc_f (devfs_handle_t dev, /* set up mappings for this device */ +pciio_dmamap_alloc_f (vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -342,123 +342,107 @@ pciio_dmamap_addr_f (pciio_dmamap_t dmamap, /* use these mapping resources paddr_t paddr, /* map for this address */ size_t byte_count); /* map this many bytes */ -typedef alenlist_t -pciio_dmamap_list_f (pciio_dmamap_t dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this address/length list */ - unsigned flags); - typedef void pciio_dmamap_done_f (pciio_dmamap_t dmamap); typedef iopaddr_t -pciio_dmatrans_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_dmatrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); /* defined in dma.h */ -typedef alenlist_t -pciio_dmatrans_list_f (devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags); /* defined in dma.h */ - typedef void pciio_dmamap_drain_f (pciio_dmamap_t map); typedef void -pciio_dmaaddr_drain_f (devfs_handle_t vhdl, +pciio_dmaaddr_drain_f (vertex_hdl_t vhdl, paddr_t addr, size_t bytes); typedef void -pciio_dmalist_drain_f (devfs_handle_t vhdl, +pciio_dmalist_drain_f (vertex_hdl_t vhdl, alenlist_t list); /* INTERRUPT MANAGEMENT */ typedef pciio_intr_t -pciio_intr_alloc_f (devfs_handle_t dev, /* which PCI device */ +pciio_intr_alloc_f (vertex_hdl_t dev, /* which PCI device */ device_desc_t dev_desc, /* device descriptor */ pciio_intr_line_t lines, /* which line(s) will be used */ - devfs_handle_t owner_dev); /* owner of this intr */ + vertex_hdl_t owner_dev); /* owner of this intr */ typedef void pciio_intr_free_f (pciio_intr_t intr_hdl); -#ifdef CONFIG_IA64_SGI_SN1 -typedef int -pciio_intr_connect_f (pciio_intr_t intr_hdl); /* pciio intr resource handle */ -#else typedef int pciio_intr_connect_f (pciio_intr_t intr_hdl, intr_func_t intr_func, intr_arg_t intr_arg); /* pciio intr resource handle */ -#endif typedef void pciio_intr_disconnect_f (pciio_intr_t intr_hdl); -typedef devfs_handle_t +typedef vertex_hdl_t pciio_intr_cpu_get_f (pciio_intr_t intr_hdl); /* pciio intr resource handle */ /* CONFIGURATION MANAGEMENT */ typedef void -pciio_provider_startup_f (devfs_handle_t pciio_provider); +pciio_provider_startup_f (vertex_hdl_t pciio_provider); typedef void -pciio_provider_shutdown_f (devfs_handle_t pciio_provider); +pciio_provider_shutdown_f (vertex_hdl_t pciio_provider); typedef int -pciio_reset_f (devfs_handle_t conn); /* pci connection point */ +pciio_reset_f (vertex_hdl_t conn); /* pci connection point */ typedef int -pciio_write_gather_flush_f (devfs_handle_t dev); /* Device flushing buffers */ +pciio_write_gather_flush_f (vertex_hdl_t dev); /* Device flushing buffers */ typedef pciio_endian_t /* actual endianness */ -pciio_endian_set_f (devfs_handle_t dev, /* specify endianness for this device */ +pciio_endian_set_f (vertex_hdl_t dev, /* specify endianness for this device */ pciio_endian_t device_end, /* endianness of device */ pciio_endian_t desired_end); /* desired endianness */ typedef pciio_priority_t -pciio_priority_set_f (devfs_handle_t pcicard, +pciio_priority_set_f (vertex_hdl_t pcicard, pciio_priority_t device_prio); typedef uint64_t -pciio_config_get_f (devfs_handle_t conn, /* pci connection point */ +pciio_config_get_f (vertex_hdl_t conn, /* pci connection point */ unsigned reg, /* register byte offset */ unsigned size); /* width in bytes (1..4) */ typedef void -pciio_config_set_f (devfs_handle_t conn, /* pci connection point */ +pciio_config_set_f (vertex_hdl_t conn, /* pci connection point */ unsigned reg, /* register byte offset */ unsigned size, /* width in bytes (1..4) */ uint64_t value); /* value to store */ typedef int -pciio_error_devenable_f (devfs_handle_t pconn_vhdl, int error_code); +pciio_error_devenable_f (vertex_hdl_t pconn_vhdl, int error_code); typedef pciio_slot_t -pciio_error_extract_f (devfs_handle_t vhdl, +pciio_error_extract_f (vertex_hdl_t vhdl, pciio_space_t *spacep, iopaddr_t *addrp); typedef void -pciio_driver_reg_callback_f (devfs_handle_t conn, +pciio_driver_reg_callback_f (vertex_hdl_t conn, int key1, int key2, int error); typedef void -pciio_driver_unreg_callback_f (devfs_handle_t conn, /* pci connection point */ +pciio_driver_unreg_callback_f (vertex_hdl_t conn, /* pci connection point */ int key1, int key2, int error); typedef int -pciio_device_unregister_f (devfs_handle_t conn); +pciio_device_unregister_f (vertex_hdl_t conn); typedef int -pciio_dma_enabled_f (devfs_handle_t conn); +pciio_dma_enabled_f (vertex_hdl_t conn); /* * Adapters that provide a PCI interface adhere to this software interface. @@ -477,10 +461,8 @@ typedef struct pciio_provider_s { pciio_dmamap_alloc_f *dmamap_alloc; pciio_dmamap_free_f *dmamap_free; pciio_dmamap_addr_f *dmamap_addr; - pciio_dmamap_list_f *dmamap_list; pciio_dmamap_done_f *dmamap_done; pciio_dmatrans_addr_f *dmatrans_addr; - pciio_dmatrans_list_f *dmatrans_list; pciio_dmamap_drain_f *dmamap_drain; pciio_dmaaddr_drain_f *dmaaddr_drain; pciio_dmalist_drain_f *dmalist_drain; @@ -525,10 +507,8 @@ extern pciio_piospace_free_f pciio_piospace_free; extern pciio_dmamap_alloc_f pciio_dmamap_alloc; extern pciio_dmamap_free_f pciio_dmamap_free; extern pciio_dmamap_addr_f pciio_dmamap_addr; -extern pciio_dmamap_list_f pciio_dmamap_list; extern pciio_dmamap_done_f pciio_dmamap_done; extern pciio_dmatrans_addr_f pciio_dmatrans_addr; -extern pciio_dmatrans_list_f pciio_dmatrans_list; extern pciio_dmamap_drain_f pciio_dmamap_drain; extern pciio_dmaaddr_drain_f pciio_dmaaddr_drain; extern pciio_dmalist_drain_f pciio_dmalist_drain; @@ -580,34 +560,31 @@ pciio_driver_register (pciio_vendor_id_t vendor_id, /* card's vendor number */ unsigned flags); extern void -pciio_error_register (devfs_handle_t pconn, /* which slot */ +pciio_error_register (vertex_hdl_t pconn, /* which slot */ error_handler_f *efunc, /* function to call */ error_handler_arg_t einfo); /* first parameter */ extern void pciio_driver_unregister(char *driver_prefix); -typedef void pciio_iter_f(devfs_handle_t pconn); /* a connect point */ - -extern void pciio_iterate(char *driver_prefix, - pciio_iter_f *func); +typedef void pciio_iter_f(vertex_hdl_t pconn); /* a connect point */ /* Interfaces used by PCI Bus Providers to talk to * the Generic PCI layer. */ -extern devfs_handle_t -pciio_device_register (devfs_handle_t connectpt, /* vertex at center of bus */ - devfs_handle_t master, /* card's master ASIC (pci provider) */ +extern vertex_hdl_t +pciio_device_register (vertex_hdl_t connectpt, /* vertex at center of bus */ + vertex_hdl_t master, /* card's master ASIC (pci provider) */ pciio_slot_t slot, /* card's slot (0..?) */ pciio_function_t func, /* card's func (0..?) */ pciio_vendor_id_t vendor, /* card's vendor number */ pciio_device_id_t device); /* card's device number */ extern void -pciio_device_unregister(devfs_handle_t connectpt); +pciio_device_unregister(vertex_hdl_t connectpt); extern pciio_info_t pciio_device_info_new (pciio_info_t pciio_info, /* preallocated info struct */ - devfs_handle_t master, /* card's master ASIC (pci provider) */ + vertex_hdl_t master, /* card's master ASIC (pci provider) */ pciio_slot_t slot, /* card's slot (0..?) */ pciio_function_t func, /* card's func (0..?) */ pciio_vendor_id_t vendor, /* card's vendor number */ @@ -616,24 +593,24 @@ pciio_device_info_new (pciio_info_t pciio_info, /* preallocated info struct */ extern void pciio_device_info_free(pciio_info_t pciio_info); -extern devfs_handle_t +extern vertex_hdl_t pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info); /* details about conn point */ extern void pciio_device_info_unregister( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info); /* details about conn point */ extern int pciio_device_attach( - devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + vertex_hdl_t pcicard, /* vertex created by pciio_device_register */ int drv_flags); extern int pciio_device_detach( - devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + vertex_hdl_t pcicard, /* vertex created by pciio_device_register */ int drv_flags); @@ -654,20 +631,12 @@ pciio_device_win_populate(pciio_win_map_t win_map, /* win map */ size_t size); /* size of free range */ /* allocate window from mapping resource */ -#ifdef CONFIG_IA64_SGI_SN1 -extern iopaddr_t -pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ - pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ - size_t size, /* size of allocation */ - size_t align); /* alignment of allocation */ -#else extern iopaddr_t pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ size_t start, /* start unit, or 0 */ size_t size, /* size of allocation */ size_t align); /* alignment of allocation */ -#endif /* free previously allocated window */ extern void @@ -680,11 +649,11 @@ pciio_device_win_free(pciio_win_alloc_t win_alloc); /* opaque allocation cookie */ /* Generic PCI interrupt interfaces */ -extern devfs_handle_t pciio_intr_dev_get(pciio_intr_t pciio_intr); -extern devfs_handle_t pciio_intr_cpu_get(pciio_intr_t pciio_intr); +extern vertex_hdl_t pciio_intr_dev_get(pciio_intr_t pciio_intr); +extern vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t pciio_intr); /* Generic PCI pio interfaces */ -extern devfs_handle_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap); +extern vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap); extern pciio_slot_t pciio_pio_slot_get(pciio_piomap_t pciio_piomap); extern pciio_space_t pciio_pio_space_get(pciio_piomap_t pciio_piomap); extern iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap); @@ -692,26 +661,26 @@ extern ulong pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap); extern caddr_t pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap); /* Generic PCI dma interfaces */ -extern devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); +extern vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); /* Register/unregister PCI providers and get implementation handle */ -extern void pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns); -extern void pciio_provider_unregister(devfs_handle_t provider); -extern pciio_provider_t *pciio_provider_fns_get(devfs_handle_t provider); +extern void pciio_provider_register(vertex_hdl_t provider, pciio_provider_t *pciio_fns); +extern void pciio_provider_unregister(vertex_hdl_t provider); +extern pciio_provider_t *pciio_provider_fns_get(vertex_hdl_t provider); /* Generic pci slot information access interface */ -extern pciio_info_t pciio_info_chk(devfs_handle_t vhdl); -extern pciio_info_t pciio_info_get(devfs_handle_t vhdl); -extern pciio_info_t pciio_hostinfo_get(devfs_handle_t vhdl); -extern void pciio_info_set(devfs_handle_t vhdl, pciio_info_t widget_info); -extern devfs_handle_t pciio_info_dev_get(pciio_info_t pciio_info); -extern devfs_handle_t pciio_info_hostdev_get(pciio_info_t pciio_info); +extern pciio_info_t pciio_info_chk(vertex_hdl_t vhdl); +extern pciio_info_t pciio_info_get(vertex_hdl_t vhdl); +extern pciio_info_t pciio_hostinfo_get(vertex_hdl_t vhdl); +extern void pciio_info_set(vertex_hdl_t vhdl, pciio_info_t widget_info); +extern vertex_hdl_t pciio_info_dev_get(pciio_info_t pciio_info); +extern vertex_hdl_t pciio_info_hostdev_get(pciio_info_t pciio_info); extern pciio_bus_t pciio_info_bus_get(pciio_info_t pciio_info); extern pciio_slot_t pciio_info_slot_get(pciio_info_t pciio_info); extern pciio_function_t pciio_info_function_get(pciio_info_t pciio_info); extern pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t pciio_info); extern pciio_device_id_t pciio_info_device_id_get(pciio_info_t pciio_info); -extern devfs_handle_t pciio_info_master_get(pciio_info_t pciio_info); +extern vertex_hdl_t pciio_info_master_get(pciio_info_t pciio_info); extern arbitrary_info_t pciio_info_mfast_get(pciio_info_t pciio_info); extern pciio_provider_t *pciio_info_pops_get(pciio_info_t pciio_info); extern error_handler_f *pciio_info_efunc_get(pciio_info_t); @@ -722,8 +691,8 @@ extern size_t pciio_info_bar_size_get(pciio_info_t, int); extern iopaddr_t pciio_info_rom_base_get(pciio_info_t); extern size_t pciio_info_rom_size_get(pciio_info_t); extern int pciio_info_type1_get(pciio_info_t); -extern int pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -extern int pciio_dma_enabled(devfs_handle_t); +extern int pciio_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); +extern int pciio_dma_enabled(vertex_hdl_t); #endif /* C or C++ */ #endif /* _ASM_SN_PCI_PCIIO_H */ diff --git a/include/asm-ia64/sn/pci/pciio_private.h b/include/asm-ia64/sn/pci/pciio_private.h index 57fbd978715..4ae63322d60 100644 --- a/include/asm-ia64/sn/pci/pciio_private.h +++ b/include/asm-ia64/sn/pci/pciio_private.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H #define _ASM_SN_PCI_PCIIO_PRIVATE_H @@ -24,7 +24,7 @@ */ struct pciio_piomap_s { unsigned pp_flags; /* PCIIO_PIOMAP flags */ - devfs_handle_t pp_dev; /* associated pci card */ + vertex_hdl_t pp_dev; /* associated pci card */ pciio_slot_t pp_slot; /* which slot the card is in */ pciio_space_t pp_space; /* which address space */ iopaddr_t pp_pciaddr; /* starting offset of mapping */ @@ -37,7 +37,7 @@ struct pciio_piomap_s { */ struct pciio_dmamap_s { unsigned pd_flags; /* PCIIO_DMAMAP flags */ - devfs_handle_t pd_dev; /* associated pci card */ + vertex_hdl_t pd_dev; /* associated pci card */ pciio_slot_t pd_slot; /* which slot the card is in */ }; @@ -47,7 +47,7 @@ struct pciio_dmamap_s { struct pciio_intr_s { unsigned pi_flags; /* PCIIO_INTR flags */ - devfs_handle_t pi_dev; /* associated pci card */ + vertex_hdl_t pi_dev; /* associated pci card */ device_desc_t pi_dev_desc; /* override device descriptor */ pciio_intr_line_t pi_lines; /* which interrupt line(s) */ intr_func_t pi_func; /* handler function (when connected) */ @@ -100,13 +100,13 @@ struct pciio_win_alloc_s { struct pciio_info_s { char *c_fingerprint; - devfs_handle_t c_vertex; /* back pointer to vertex */ + vertex_hdl_t c_vertex; /* back pointer to vertex */ pciio_bus_t c_bus; /* which bus the card is in */ pciio_slot_t c_slot; /* which slot the card is in */ pciio_function_t c_func; /* which func (on multi-func cards) */ pciio_vendor_id_t c_vendor; /* PCI card "vendor" code */ pciio_device_id_t c_device; /* PCI card "device" code */ - devfs_handle_t c_master; /* PCI bus provider */ + vertex_hdl_t c_master; /* PCI bus provider */ arbitrary_info_t c_mfast; /* cached fastinfo from c_master */ pciio_provider_t *c_pops; /* cached provider from c_master */ error_handler_f *c_efunc; /* error handling function */ diff --git a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h index a6e5c304613..6c605727ea2 100644 --- a/include/asm-ia64/sn/pda.h +++ b/include/asm-ia64/sn/pda.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PDA_H #define _ASM_IA64_SN_PDA_H @@ -26,15 +26,6 @@ * all SN per-cpu data structures. */ -#ifdef BUS_INT_WAR -#define POLL_ENTRIES 50 -typedef struct { - int irq; - int interval; - short tick; -} sn_poll_entry_t; -#endif - typedef struct pda_s { /* Having a pointer in the begining of PDA tends to increase @@ -48,31 +39,27 @@ typedef struct pda_s { /* * Support for SN LEDs */ -#ifdef CONFIG_IA64_SGI_SN1 - volatile long *led_address; -#else volatile short *led_address; -#endif u8 led_state; u8 hb_state; /* supports blinking heartbeat leds */ + u8 shub_1_1_found; unsigned int hb_count; unsigned int idle_flag; -#ifdef CONFIG_IA64_SGI_SN2 - struct irqpda_s *p_irqpda; /* Pointer to CPU irq data */ -#endif volatile unsigned long *bedrock_rev_id; volatile unsigned long *pio_write_status_addr; volatile unsigned long *pio_shub_war_cam_addr; volatile unsigned long *mem_write_status_addr; - bteinfo_t *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ + struct bteinfo_s *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ -#ifdef BUS_INT_WAR - sn_poll_entry_t pda_poll_entries[POLL_ENTRIES]; - int pda_poll_entry_count; -#endif + unsigned long sn_soft_irr[4]; + unsigned long sn_in_service_ivecs[4]; + short cnodeid_to_nasid_table[NR_NODES]; + int sn_lb_int_war_ticks; + int sn_last_irq; + int sn_first_irq; } pda_t; @@ -96,5 +83,9 @@ DECLARE_PER_CPU(struct pda_s, pda_percpu); #define pdacpu(cpu) (&per_cpu(pda_percpu, cpu)) +/* + * Use this macro to test if shub 1.1 wars should be enabled + */ +#define enable_shub_wars_1_1() (pda->shub_1_1_found) #endif /* _ASM_IA64_SN_PDA_H */ diff --git a/include/asm-ia64/sn/pio.h b/include/asm-ia64/sn/pio.h index b1a0402972c..3db61abb950 100644 --- a/include/asm-ia64/sn/pio.h +++ b/include/asm-ia64/sn/pio.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PIO_H #define _ASM_IA64_SN_PIO_H @@ -32,19 +32,11 @@ typedef volatile ulong* pioaddr_t; typedef struct piomap { uint pio_bus; uint pio_adap; -#ifdef LATER - iospace_t pio_iospace; -#endif int pio_flag; int pio_reg; char pio_name[7]; /* to identify the mapped device */ struct piomap *pio_next; /* dlist to link active piomap's */ struct piomap *pio_prev; /* for debug and error reporting */ -#ifdef LATER - void (*pio_errfunc)(); /* Pointer to an error function */ - /* Used only for piomaps allocated - * in user level vme driver */ -#endif iopaddr_t pio_iopmask; /* valid iop address bit mask */ iobush_t pio_bushandle; /* bus-level handle */ } piomap_t; @@ -60,54 +52,6 @@ typedef struct piomap { /* - * pio_mapalloc() - allocates a handle that specifies a mapping from kernel - * virtual to io space. The returned handle piomap is used - * with the access functions to make sure that the mapping - * to the iospace exists. - * pio_mapfree() - frees the mapping as specified in the piomap handle. - * pio_mapaddr() - returns the kv address that maps to piomap'ed io address. - */ -#ifdef LATER -extern piomap_t *pio_mapalloc(uint,uint,iospace_t*,int,char*); -extern void pio_mapfree(piomap_t*); -extern caddr_t pio_mapaddr(piomap_t*,iopaddr_t); -extern piomap_t *pio_ioaddr(int, iobush_t, iopaddr_t, piomap_t *); - -/* - * PIO access functions. - */ -extern int pio_badaddr(piomap_t*,iopaddr_t,int); -extern int pio_badaddr_val(piomap_t*,iopaddr_t,int,void*); -extern int pio_wbadaddr(piomap_t*,iopaddr_t,int); -extern int pio_wbadaddr_val(piomap_t*,iopaddr_t,int,int); -extern int pio_bcopyin(piomap_t*,iopaddr_t,void *,int, int, int); -extern int pio_bcopyout(piomap_t*,iopaddr_t,void *,int, int, int); - - -/* - * PIO RMW functions using piomap. - */ -extern void pio_orb_rmw(piomap_t*, iopaddr_t, unsigned char); -extern void pio_orh_rmw(piomap_t*, iopaddr_t, unsigned short); -extern void pio_orw_rmw(piomap_t*, iopaddr_t, unsigned long); -extern void pio_andb_rmw(piomap_t*, iopaddr_t, unsigned char); -extern void pio_andh_rmw(piomap_t*, iopaddr_t, unsigned short); -extern void pio_andw_rmw(piomap_t*, iopaddr_t, unsigned long); - - -/* - * Old RMW function interface - */ -extern void orb_rmw(volatile void*, unsigned int); -extern void orh_rmw(volatile void*, unsigned int); -extern void orw_rmw(volatile void*, unsigned int); -extern void andb_rmw(volatile void*, unsigned int); -extern void andh_rmw(volatile void*, unsigned int); -extern void andw_rmw(volatile void*, unsigned int); -#endif /* LATER */ - - -/* * piomap_t type defines */ diff --git a/include/asm-ia64/sn/pio_flush.h b/include/asm-ia64/sn/pio_flush.h deleted file mode 100644 index 194348c75c3..00000000000 --- a/include/asm-ia64/sn/pio_flush.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include - -#ifndef _ASM_IA64_PIO_FLUSH_H -#define _ASM_IA64_PIO_FLUSH_H - -/* - * This macro flushes all outstanding PIOs performed by this cpu to the - * intended destination SHUB. This in essence ensures that all PIO's - * issues by this cpu has landed at it's destination. - * - * This macro expects the caller: - * 1. The thread is locked. - * 2. All prior PIO operations has been fenced. - * - */ - -#if defined (CONFIG_IA64_SGI_SN) - -#include - -#if defined (CONFIG_IA64_SGI_SN2) - -#define PIO_FLUSH() \ - { \ - while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000) { \ - udelay(5); \ - } \ - __ia64_mf_a(); \ - } - -#elif defined (CONFIG_IA64_SGI_SN1) - -/* - * For SN1 we need to first read any local Bedrock's MMR and then poll on the - * Synergy MMR. - */ -#define PIO_FLUSH() \ - { \ - (volatile unsigned long) (*pda.bedrock_rev_id); \ - while (!(volatile unsigned long) (*pda.pio_write_status_addr)) { \ - udelay(5); \ - } \ - __ia64_mf_a(); \ - } -#endif -#else -/* - * For all ARCHITECTURE type, this is a NOOP. - */ - -#define PIO_FLUSH() - -#endif - -#endif /* _ASM_IA64_PIO_FLUSH_H */ diff --git a/include/asm-ia64/sn/prio.h b/include/asm-ia64/sn/prio.h index d1f24449e67..76b8037e5c1 100644 --- a/include/asm-ia64/sn/prio.h +++ b/include/asm-ia64/sn/prio.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PRIO_H #define _ASM_IA64_SN_PRIO_H diff --git a/include/asm-ia64/sn/router.h b/include/asm-ia64/sn/router.h index 689ec31a007..1c280988539 100644 --- a/include/asm-ia64/sn/router.h +++ b/include/asm-ia64/sn/router.h @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ROUTER_H @@ -494,7 +494,7 @@ typedef struct router_info_s { slotid_t ri_slotnum; /* Which slot are we in? */ router_reg_t ri_glbl_parms[GLBL_PARMS_REGS]; /* Global parms0&1 register contents*/ - devfs_handle_t ri_vertex; /* hardware graph vertex */ + vertex_hdl_t ri_vertex; /* hardware graph vertex */ router_reg_t ri_prot_conf; /* protection config. register */ int64_t ri_per_minute; /* Ticks per minute */ @@ -506,7 +506,7 @@ typedef struct router_info_s { * the bottom of the structure, below the user stuff. */ char ri_hist_type; /* histogram type */ - devfs_handle_t ri_guardian; /* guardian node for the router */ + vertex_hdl_t ri_guardian; /* guardian node for the router */ int64_t ri_last_print; /* When did we last print */ char ri_print; /* Should we print */ char ri_just_blink; /* Should we blink the LEDs */ @@ -549,7 +549,7 @@ typedef struct router_info_s { * Router info hanging in the nodepda */ typedef struct nodepda_router_info_s { - devfs_handle_t router_vhdl; /* vertex handle of the router */ + vertex_hdl_t router_vhdl; /* vertex handle of the router */ short router_port; /* port thru which we entered */ short router_portmask; moduleid_t router_module; /* module in which router is there */ @@ -593,9 +593,9 @@ typedef struct router_elt_s { */ struct { /* vertex handle for the router */ - devfs_handle_t vhdl; + vertex_hdl_t vhdl; /* guardian for this router */ - devfs_handle_t guard; + vertex_hdl_t guard; /* vector router from the guardian to the router */ net_vec_t vec; } k_elt; @@ -648,8 +648,7 @@ typedef struct router_queue_s { int router_reg_read(router_info_t *rip, int regno, router_reg_t *val); int router_reg_write(router_info_t *rip, int regno, router_reg_t val); -int router_get_info(devfs_handle_t routerv, router_info_t *, int); -int router_init(cnodeid_t cnode,int writeid, nodepda_router_info_t *npda_rip); +int router_get_info(vertex_hdl_t routerv, router_info_t *, int); int router_set_leds(router_info_t *rip); void router_print_state(router_info_t *rip, int level, void (*pf)(int, char *, ...),int print_where); @@ -658,7 +657,7 @@ void capture_router_stats(router_info_t *rip); int probe_routers(void); void get_routername(unsigned char brd_type,char *rtrname); -void router_guardians_set(devfs_handle_t hwgraph_root); +void router_guardians_set(vertex_hdl_t hwgraph_root); int router_hist_reselect(router_info_t *, int64_t); #endif /* __ASSEMBLY__ */ diff --git a/include/asm-ia64/sn/sgi.h b/include/asm-ia64/sn/sgi.h index cb716f0c6d2..77cd3bf944e 100644 --- a/include/asm-ia64/sn/sgi.h +++ b/include/asm-ia64/sn/sgi.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -17,14 +17,15 @@ #include /* for copy_??_user */ #include #include +#include +#include + +typedef hwgfs_handle_t vertex_hdl_t; typedef int64_t __psint_t; /* needed by klgraph.c */ typedef enum { B_FALSE, B_TRUE } boolean_t; -#define ctob(x) ((uint64_t)(x)*NBPC) -#define btoc(x) (((uint64_t)(x)+(NBPC-1))/NBPC) - /* ** Possible return values from graph routines. @@ -50,28 +51,13 @@ typedef enum graph_error_e { typedef uint64_t vhandl_t; -#ifndef NBPP -#define NBPP 4096 -#endif - -#ifndef D_MP -#define D_MP 1 -#endif +#define NBPP PAGE_SIZE +#define _PAGESZ PAGE_SIZE #ifndef MAXDEVNAME #define MAXDEVNAME 256 #endif -#ifndef NBPC -#define NBPC 0 -#endif - -#ifndef _PAGESZ -#define _PAGESZ 4096 -#endif - -typedef uint64_t mrlock_t; /* needed by devsupport.c */ - #define HUB_PIO_CONVEYOR 0x1 #define CNODEID_NONE ((cnodeid_t)-1) #define XTALK_PCI_PART_NUM "030-1275-" @@ -81,10 +67,6 @@ typedef uint64_t mrlock_t; /* needed by devsupport.c */ #define COPYIN(a, b, c) copy_from_user(b,a,c) #define COPYOUT(a, b, c) copy_to_user(b,a,c) -#define kvtophys(x) (alenaddr_t) (x) -#define POFFMASK (NBPP - 1) -#define poff(X) ((__psunsigned_t)(X) & POFFMASK) - #define BZERO(a,b) memset(a, 0, b) #define kern_malloc(x) kmalloc(x, GFP_KERNEL) @@ -141,12 +123,6 @@ mutex_spinlock(spinlock_t *sem) { #define PRINT_PANIC panic -#ifdef CONFIG_SMP -#define cpu_enabled(cpu) (test_bit(cpu, &cpu_online_map)) -#else -#define cpu_enabled(cpu) (1) -#endif - /* print_register() defs */ /* @@ -172,6 +148,31 @@ struct reg_desc { extern void print_register(unsigned long long, struct reg_desc *); -#include /* for now */ +/****************************************** + * Definitions that do not exist in linux * + ******************************************/ + +#define DELAY(a) + +/************************************************ + * Routines redefined to use linux equivalents. * + ************************************************/ + +/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ + +#define FIXME(s) + +/* move to stubs.c yet */ +#define dev_to_vhdl(dev) 0 +#define get_timestamp() 0 +#define us_delay(a) +#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); +#define splhi() 0 +#define splx(s) + +extern void * snia_kmem_alloc_node(register size_t, register int, cnodeid_t); +extern void * snia_kmem_zalloc(size_t, int); +extern void * snia_kmem_zalloc_node(register size_t, register int, cnodeid_t ); +extern int is_specified(char *); #endif /* _ASM_IA64_SN_SGI_H */ diff --git a/include/asm-ia64/sn/simulator.h b/include/asm-ia64/sn/simulator.h index b66624df649..82bc2cb2035 100644 --- a/include/asm-ia64/sn/simulator.h +++ b/include/asm-ia64/sn/simulator.h @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff --git a/include/asm-ia64/sn/slotnum.h b/include/asm-ia64/sn/slotnum.h index 680ae79fb94..dff21f3fb6b 100644 --- a/include/asm-ia64/sn/slotnum.h +++ b/include/asm-ia64/sn/slotnum.h @@ -4,23 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SLOTNUM_H #define _ASM_IA64_SN_SLOTNUM_H -#include typedef unsigned char slotid_t; -#if defined (CONFIG_IA64_SGI_SN1) -#include -#elif defined (CONFIG_IA64_SGI_SN2) #include -#else - -#error <> - -#endif /* !CONFIG_IA64_SGI_SN1 */ #endif /* _ASM_IA64_SN_SLOTNUM_H */ diff --git a/include/asm-ia64/sn/sn1/addrs.h b/include/asm-ia64/sn/sn1/addrs.h deleted file mode 100644 index 3f12cb5da8e..00000000000 --- a/include/asm-ia64/sn/sn1/addrs.h +++ /dev/null @@ -1,275 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_ADDRS_H -#define _ASM_IA64_SN_SN1_ADDRS_H - -#include - -#ifdef CONFIG_IA64_SGI_SN1 -/* - * SN1 (on a TRex) Address map - * - * This file contains a set of definitions and macros which are used - * to reference into the major address spaces (CAC, HSPEC, IO, MSPEC, - * and UNCAC) used by the SN1 architecture. It also contains addresses - * for "major" statically locatable PROM/Kernel data structures, such as - * the partition table, the configuration data structure, etc. - * We make an implicit assumption that the processor using this file - * follows the R12K's provisions for specifying uncached attributes; - * should this change, the base registers may very well become processor- - * dependent. - * - * For more information on the address spaces, see the "Local Resources" - * chapter of the Hub specification. - * - * NOTE: This header file is included both by C and by assembler source - * files. Please bracket any language-dependent definitions - * appropriately. - */ - - -/* - * Some of the macros here need to be casted to appropriate types when used - * from C. They definitely must not be casted from assembly language so we - * use some new ANSI preprocessor stuff to paste these on where needed. - */ - -#define CACHEABLE_MEM_SPACE 0xe000000000000000 -#define CAC_BASE CACHEABLE_MEM_SPACE -#define HSPEC_BASE 0xc0000b0000000000 -#define HSPEC_SWIZ_BASE 0xc000030000000000 -#define IO_BASE 0xc0000a0000000000 -#define IO_SWIZ_BASE 0xc000020000000000 -#define MSPEC_BASE 0xc000090000000000 -#define UNCAC_BASE 0xc000000000000000 -#define TO_PHYS_MASK 0x000000ffffffffff - -#define TO_PHYS(x) ( ((x) & TO_PHYS_MASK)) -#define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_UNCAC(x) (UNCAC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_MSPEC(x) (MSPEC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_HSPEC(x) (HSPEC_BASE | ((x) & TO_PHYS_MASK)) - - -/* - * The following couple of definitions will eventually need to be variables, - * since the amount of address space assigned to each node depends on - * whether the system is running in N-mode (more nodes with less memory) - * or M-mode (fewer nodes with more memory). We expect that it will - * be a while before we need to make this decision dynamically, though, - * so for now we just use defines bracketed by an ifdef. - */ - -#if defined(N_MODE) - -#define NODE_SIZE_BITS 32 -#define BWIN_SIZE_BITS 28 - -#define NASID_BITS 8 -#define NASID_BITMASK (0xffLL) -#define NASID_SHFT 32 -#define NASID_META_BITS 1 -#define NASID_LOCAL_BITS 7 - -#define BDDIR_UPPER_MASK (UINT64_CAST 0x1ffffff << 4) -#define BDECC_UPPER_MASK (UINT64_CAST 0x1fffffff ) - -#else /* !defined(N_MODE), assume that M-mode is desired */ - -#define NODE_SIZE_BITS 33 -#define BWIN_SIZE_BITS 29 - -#define NASID_BITMASK (0x7fLL) -#define NASID_BITS 7 -#define NASID_SHFT 33 -#define NASID_META_BITS 0 -#define NASID_LOCAL_BITS 7 - -#define BDDIR_UPPER_MASK (UINT64_CAST 0x3ffffff << 4) -#define BDECC_UPPER_MASK (UINT64_CAST 0x3fffffff) - -#endif /* defined(N_MODE) */ - -#define NODE_ADDRSPACE_SIZE (UINT64_CAST 1 << NODE_SIZE_BITS) - -#define NASID_MASK (UINT64_CAST NASID_BITMASK << NASID_SHFT) -#define NASID_GET(_pa) (int) ((UINT64_CAST (_pa) >> \ - NASID_SHFT) & NASID_BITMASK) - -#ifndef __ASSEMBLY__ -#define NODE_SWIN_BASE(nasid, widget) \ - ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN) \ - : RAW_NODE_SWIN_BASE(nasid, widget)) -#else -#define NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + (UINT64_CAST (widget) << SWIN_SIZE_BITS)) -#endif /* __ASSEMBLY__ */ - -/* - * The following definitions pertain to the IO special address - * space. They define the location of the big and little windows - * of any given node. - */ - -#define BWIN_INDEX_BITS 3 -#define BWIN_SIZE (UINT64_CAST 1 << BWIN_SIZE_BITS) -#define BWIN_SIZEMASK (BWIN_SIZE - 1) -#define BWIN_WIDGET_MASK 0x7 -#define NODE_BWIN_BASE0(nasid) (NODE_IO_BASE(nasid) + BWIN_SIZE) -#define NODE_BWIN_BASE(nasid, bigwin) (NODE_BWIN_BASE0(nasid) + \ - (UINT64_CAST (bigwin) << BWIN_SIZE_BITS)) - -#define BWIN_WIDGETADDR(addr) ((addr) & BWIN_SIZEMASK) -#define BWIN_WINDOWNUM(addr) (((addr) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) -/* - * Verify if addr belongs to large window address of node with "nasid" - * - * - * NOTE: "addr" is expected to be XKPHYS address, and NOT physical - * address - * - * - */ - -#define NODE_BWIN_ADDR(nasid, addr) \ - (((addr) >= NODE_BWIN_BASE0(nasid)) && \ - ((addr) < (NODE_BWIN_BASE(nasid, HUB_NUM_BIG_WINDOW) + \ - BWIN_SIZE))) - -/* - * The following define the major position-independent aliases used - * in SN1. - * CALIAS -- Varies in size, points to the first n bytes of memory - * on the reader's node. - */ - -#define CALIAS_BASE CAC_BASE - - - -#define BRIDGE_REG_PTR(_base, _off) ((volatile bridgereg_t *) \ - ((__psunsigned_t)(_base) + (__psunsigned_t)(_off))) - -#define SN0_WIDGET_BASE(_nasid, _wid) (NODE_SWIN_BASE((_nasid), (_wid))) - - - -/* - * needed by symmon so it needs to be outside #if PROM - * (see also POD_ELSCSIZE) - */ -#define IP27PROM_ELSC_BASE_A PHYS_TO_K0(0x020e0000) -#define IP27PROM_ELSC_BASE_B PHYS_TO_K0(0x020e0800) -#define IP27PROM_ELSC_BASE_C PHYS_TO_K0(0x020e1000) -#define IP27PROM_ELSC_BASE_D PHYS_TO_K0(0x020e1800) -#define IP27PROM_ELSC_SHFT 11 -#define IP27PROM_ELSC_SIZE (1 << IP27PROM_ELSC_SHFT) - -#define FREEMEM_BASE PHYS_TO_K0(0x4000000) - -#define IO6PROM_STACK_SHFT 14 /* stack per cpu */ -#define IO6PROM_STACK_SIZE (1 << IO6PROM_STACK_SHFT) - - -#define KL_UART_BASE LOCAL_HSPEC(HSPEC_UART_0) /* base of UART regs */ -#define KL_UART_CMD LOCAL_HSPEC(HSPEC_UART_0) /* UART command reg */ -#define KL_UART_DATA LOCAL_HSPEC(HSPEC_UART_1) /* UART data reg */ - -#if !__ASSEMBLY__ -/* Address 0x400 to 0x1000 ualias points to cache error eframe + misc - * CACHE_ERR_SP_PTR could either contain an address to the stack, or - * the stack could start at CACHE_ERR_SP_PTR - */ -#define CACHE_ERR_EFRAME 0x400 - -#define CACHE_ERR_ECCFRAME (CACHE_ERR_EFRAME + EF_SIZE) -#define CACHE_ERR_SP_PTR (0x1000 - 32) /* why -32? TBD */ -#define CACHE_ERR_IBASE_PTR (0x1000 - 40) -#define CACHE_ERR_SP (CACHE_ERR_SP_PTR - 16) -#define CACHE_ERR_AREA_SIZE (ARCS_SPB_OFFSET - CACHE_ERR_EFRAME) - -#endif /* !__ASSEMBLY__ */ - - - -#define _ARCSPROM - -#ifdef _STANDALONE - -/* - * The PROM needs to pass the device base address and the - * device pci cfg space address to the device drivers during - * install. The COMPONENT->Key field is used for this purpose. - * Macros needed by SN1 device drivers to convert the - * COMPONENT->Key field to the respective base address. - * Key field looks as follows: - * - * +----------------------------------------------------+ - * |devnasid | widget |pciid |hubwidid|hstnasid | adap | - * | 2 | 1 | 1 | 1 | 2 | 1 | - * +----------------------------------------------------+ - * | | | | | | | - * 64 48 40 32 24 8 0 - * - * These are used by standalone drivers till the io infrastructure - * is in place. - */ - -#ifndef __ASSEMBLY__ - -#define uchar unsigned char - -#define KEY_DEVNASID_SHFT 48 -#define KEY_WIDID_SHFT 40 -#define KEY_PCIID_SHFT 32 -#define KEY_HUBWID_SHFT 24 -#define KEY_HSTNASID_SHFT 8 - -#define MK_SN0_KEY(nasid, widid, pciid) \ - ((((__psunsigned_t)nasid)<< KEY_DEVNASID_SHFT |\ - ((__psunsigned_t)widid) << KEY_WIDID_SHFT) |\ - ((__psunsigned_t)pciid) << KEY_PCIID_SHFT) - -#define ADD_HUBWID_KEY(key,hubwid)\ - (key|=((__psunsigned_t)hubwid << KEY_HUBWID_SHFT)) - -#define ADD_HSTNASID_KEY(key,hstnasid)\ - (key|=((__psunsigned_t)hstnasid << KEY_HSTNASID_SHFT)) - -#define GET_DEVNASID_FROM_KEY(key) ((short)(key >> KEY_DEVNASID_SHFT)) -#define GET_WIDID_FROM_KEY(key) ((uchar)(key >> KEY_WIDID_SHFT)) -#define GET_PCIID_FROM_KEY(key) ((uchar)(key >> KEY_PCIID_SHFT)) -#define GET_HUBWID_FROM_KEY(key) ((uchar)(key >> KEY_HUBWID_SHFT)) -#define GET_HSTNASID_FROM_KEY(key) ((short)(key >> KEY_HSTNASID_SHFT)) - -#define PCI_64_TARGID_SHFT 60 - -#define GET_PCIBASE_FROM_KEY(key) (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_DEVIO(GET_PCIID_FROM_KEY(key))) - -#define GET_PCICFGBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_TYPE0_CFG_DEV(GET_PCIID_FROM_KEY(key))) - -#define GET_WIDBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))) - -#define PUT_INSTALL_STATUS(c,s) c->Revision = s -#define GET_INSTALL_STATUS(c) c->Revision - -#endif /* __ASSEMBLY__ */ - -#endif /* _STANDALONE */ -#endif /* CONFIG_IA64_SGI_SN1 */ - -#endif /* _ASM_IA64_SN_SN1_ADDRS_H */ diff --git a/include/asm-ia64/sn/sn1/arch.h b/include/asm-ia64/sn/sn1/arch.h deleted file mode 100644 index a91b4bcbee1..00000000000 --- a/include/asm-ia64/sn/sn1/arch.h +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_ARCH_H -#define _ASM_IA64_SN_SN1_ARCH_H - -#if defined(N_MODE) -#error "ERROR constants defined only for M-mode" -#endif - -#include -#include - -#define CPUS_PER_NODE 4 /* CPUs on a single hub */ -#define CPUS_PER_SUBNODE 2 /* CPUs on a single hub PI */ - -/* - * This is the maximum number of NASIDS that can be present in a system. - * This include ALL nodes in ALL partitions connected via NUMALINK. - * (Highest NASID plus one.) - */ -#define MAX_NASIDS 128 - -/* - * This is the maximum number of nodes that can be part of a kernel. - * Effectively, it's the maximum number of compact node ids (cnodeid_t). - * This is not necessarily the same as MAX_NASIDS. - */ -#define MAX_COMPACT_NODES 128 - -/* - * MAX_REGIONS refers to the maximum number of hardware partitioned regions. - */ -#define MAX_REGIONS 64 -#define MAX_NONPREMIUM_REGIONS 16 -#define MAX_PREMIUM_REGIONS MAX_REGIONS - -/* - * Slot constants for IP35 - */ - -#define MAX_MEM_SLOTS 8 /* max slots per node */ - -#if defined(N_MODE) -#error "N-mode not supported" -#endif - -#define SLOT_SHIFT (30) -#define SLOT_MIN_MEM_SIZE (64*1024*1024) - - -/* - * MAX_PARITIONS refers to the maximum number of logically defined - * partitions the system can support. - */ -#define MAX_PARTITIONS MAX_REGIONS - - -#define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) - -/* - * New stuff in here from Irix sys/pfdat.h. - */ -#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) -#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) -#define slot_getbasepfn(node,slot) (mkpfn(COMPACT_TO_NASID_NODEID(node), slot<> SUBNODE_SHFT) -#define LOCALCPU(slice) (((slice) & LOCALCPU_MASK) >> LOCALCPU_SHFT) -#define TO_SLICE(subn, local) (((subn) << SUBNODE_SHFT) | \ - ((local) << LOCALCPU_SHFT)) - -#endif /* _ASM_IA64_SN_SN1_ARCH_H */ diff --git a/include/asm-ia64/sn/sn1/bedrock.h b/include/asm-ia64/sn/sn1/bedrock.h deleted file mode 100644 index d2e8e040796..00000000000 --- a/include/asm-ia64/sn/sn1/bedrock.h +++ /dev/null @@ -1,74 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_BEDROCK_H -#define _ASM_IA64_SN_SN1_BEDROCK_H - - -/* The secret password; used to release protection */ -#define HUB_PASSWORD 0x53474972756c6573ull - -#define CHIPID_HUB 0x3012 -#define CHIPID_ROUTER 0x3017 - -#define BEDROCK_REV_1_0 1 -#define BEDROCK_REV_1_1 2 - -#define MAX_HUB_PATH 80 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Translation of uncached attributes */ -#define UATTR_HSPEC 0 -#define UATTR_IO 1 -#define UATTR_MSPEC 2 -#define UATTR_UNCAC 3 - -#if __ASSEMBLY__ - -/* - * Get nasid into register, r (uses at) - */ -#define GET_NASID_ASM(r) \ - dli r, LOCAL_HUB_ADDR(LB_REV_ID); \ - ld r, (r); \ - and r, LRI_NODEID_MASK; \ - dsrl r, LRI_NODEID_SHFT - -#endif /* __ASSEMBLY__ */ - -#ifndef __ASSEMBLY__ - -#include - -/* hub-as-widget iograph info, labelled by INFO_LBL_XWIDGET */ -typedef struct v_hub_s *v_hub_t; -typedef uint64_t rtc_time_t; - -struct nodepda_s; -int hub_check_pci_equiv(void *addra, void *addrb); -void capture_hub_stats(cnodeid_t, struct nodepda_s *); -void init_hub_stats(cnodeid_t, struct nodepda_s *); - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_IA64_SN_SN1_BEDROCK_H */ diff --git a/include/asm-ia64/sn/sn1/hubdev.h b/include/asm-ia64/sn/sn1/hubdev.h deleted file mode 100644 index d2108402ea9..00000000000 --- a/include/asm-ia64/sn/sn1/hubdev.h +++ /dev/null @@ -1,21 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_HUBDEV_H -#define _ASM_IA64_SN_SN1_HUBDEV_H - -extern void hubdev_init(void); -extern void hubdev_register(int (*attach_method)(devfs_handle_t)); -extern int hubdev_unregister(int (*attach_method)(devfs_handle_t)); -extern int hubdev_docallouts(devfs_handle_t hub); - -extern caddr_t hubdev_prombase_get(devfs_handle_t hub); -extern cnodeid_t hubdev_cnodeid_get(devfs_handle_t hub); - -#endif /* _ASM_IA64_SN_SN1_HUBDEV_H */ diff --git a/include/asm-ia64/sn/sn1/hubio.h b/include/asm-ia64/sn/sn1/hubio.h deleted file mode 100644 index 7851fe4f7aa..00000000000 --- a/include/asm-ia64/sn/sn1/hubio.h +++ /dev/null @@ -1,5016 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#ifndef _ASM_IA64_SN_SN1_HUBIO_H -#define _ASM_IA64_SN_SN1_HUBIO_H - - -#define IIO_WID 0x00400000 /* - * Crosstalk Widget - * Identification This - * register is also - * accessible from - * Crosstalk at - * address 0x0. - */ - - - -#define IIO_WSTAT 0x00400008 /* - * Crosstalk Widget - * Status - */ - - - -#define IIO_WCR 0x00400020 /* - * Crosstalk Widget - * Control Register - */ - - - -#define IIO_ILAPR 0x00400100 /* - * IO Local Access - * Protection Register - */ - - - -#define IIO_ILAPO 0x00400108 /* - * IO Local Access - * Protection Override - */ - - - -#define IIO_IOWA 0x00400110 /* - * IO Outbound Widget - * Access - */ - - - -#define IIO_IIWA 0x00400118 /* - * IO Inbound Widget - * Access - */ - - - -#define IIO_IIDEM 0x00400120 /* - * IO Inbound Device - * Error Mask - */ - - - -#define IIO_ILCSR 0x00400128 /* - * IO LLP Control and - * Status Register - */ - - - -#define IIO_ILLR 0x00400130 /* IO LLP Log Register */ - - - -#define IIO_IIDSR 0x00400138 /* - * IO Interrupt - * Destination - */ - - - -#define IIO_IGFX0 0x00400140 /* - * IO Graphics - * Node-Widget Map 0 - */ - - - -#define IIO_IGFX1 0x00400148 /* - * IO Graphics - * Node-Widget Map 1 - */ - - - -#define IIO_ISCR0 0x00400150 /* - * IO Scratch Register - * 0 - */ - - - -#define IIO_ISCR1 0x00400158 /* - * IO Scratch Register - * 1 - */ - - - -#define IIO_ITTE1 0x00400160 /* - * IO Translation - * Table Entry 1 - */ - - - -#define IIO_ITTE2 0x00400168 /* - * IO Translation - * Table Entry 2 - */ - - - -#define IIO_ITTE3 0x00400170 /* - * IO Translation - * Table Entry 3 - */ - - - -#define IIO_ITTE4 0x00400178 /* - * IO Translation - * Table Entry 4 - */ - - - -#define IIO_ITTE5 0x00400180 /* - * IO Translation - * Table Entry 5 - */ - - - -#define IIO_ITTE6 0x00400188 /* - * IO Translation - * Table Entry 6 - */ - - - -#define IIO_ITTE7 0x00400190 /* - * IO Translation - * Table Entry 7 - */ - - - -#define IIO_IPRB0 0x00400198 /* IO PRB Entry 0 */ - - - -#define IIO_IPRB8 0x004001A0 /* IO PRB Entry 8 */ - - - -#define IIO_IPRB9 0x004001A8 /* IO PRB Entry 9 */ - - - -#define IIO_IPRBA 0x004001B0 /* IO PRB Entry A */ - - - -#define IIO_IPRBB 0x004001B8 /* IO PRB Entry B */ - - - -#define IIO_IPRBC 0x004001C0 /* IO PRB Entry C */ - - - -#define IIO_IPRBD 0x004001C8 /* IO PRB Entry D */ - - - -#define IIO_IPRBE 0x004001D0 /* IO PRB Entry E */ - - - -#define IIO_IPRBF 0x004001D8 /* IO PRB Entry F */ - - - -#define IIO_IXCC 0x004001E0 /* - * IO Crosstalk Credit - * Count Timeout - */ - - - -#define IIO_IMEM 0x004001E8 /* - * IO Miscellaneous - * Error Mask - */ - - - -#define IIO_IXTT 0x004001F0 /* - * IO Crosstalk - * Timeout Threshold - */ - - - -#define IIO_IECLR 0x004001F8 /* - * IO Error Clear - * Register - */ - - - -#define IIO_IBCR 0x00400200 /* - * IO BTE Control - * Register - */ - - - -#define IIO_IXSM 0x00400208 /* - * IO Crosstalk - * Spurious Message - */ - - - -#define IIO_IXSS 0x00400210 /* - * IO Crosstalk - * Spurious Sideband - */ - - - -#define IIO_ILCT 0x00400218 /* IO LLP Channel Test */ - - - -#define IIO_IIEPH1 0x00400220 /* - * IO Incoming Error - * Packet Header, Part - * 1 - */ - - - -#define IIO_IIEPH2 0x00400228 /* - * IO Incoming Error - * Packet Header, Part - * 2 - */ - - - -#define IIO_IPCA 0x00400300 /* - * IO PRB Counter - * Adjust - */ - - - -#define IIO_IPRTE0 0x00400308 /* - * IO PIO Read Address - * Table Entry 0 - */ - - - -#define IIO_IPRTE1 0x00400310 /* - * IO PIO Read Address - * Table Entry 1 - */ - - - -#define IIO_IPRTE2 0x00400318 /* - * IO PIO Read Address - * Table Entry 2 - */ - - - -#define IIO_IPRTE3 0x00400320 /* - * IO PIO Read Address - * Table Entry 3 - */ - - - -#define IIO_IPRTE4 0x00400328 /* - * IO PIO Read Address - * Table Entry 4 - */ - - - -#define IIO_IPRTE5 0x00400330 /* - * IO PIO Read Address - * Table Entry 5 - */ - - - -#define IIO_IPRTE6 0x00400338 /* - * IO PIO Read Address - * Table Entry 6 - */ - - - -#define IIO_IPRTE7 0x00400340 /* - * IO PIO Read Address - * Table Entry 7 - */ - - - -#define IIO_IPDR 0x00400388 /* - * IO PIO Deallocation - * Register - */ - - - -#define IIO_ICDR 0x00400390 /* - * IO CRB Entry - * Deallocation - * Register - */ - - - -#define IIO_IFDR 0x00400398 /* - * IO IOQ FIFO Depth - * Register - */ - - - -#define IIO_IIAP 0x004003A0 /* - * IO IIQ Arbitration - * Parameters - */ - - - -#define IIO_ICMR 0x004003A8 /* - * IO CRB Management - * Register - */ - - - -#define IIO_ICCR 0x004003B0 /* - * IO CRB Control - * Register - */ - - - -#define IIO_ICTO 0x004003B8 /* IO CRB Timeout */ - - - -#define IIO_ICTP 0x004003C0 /* - * IO CRB Timeout - * Prescalar - */ - - - -#define IIO_ICRB0_A 0x00400400 /* IO CRB Entry 0_A */ - - - -#define IIO_ICRB0_B 0x00400408 /* IO CRB Entry 0_B */ - - - -#define IIO_ICRB0_C 0x00400410 /* IO CRB Entry 0_C */ - - - -#define IIO_ICRB0_D 0x00400418 /* IO CRB Entry 0_D */ - - - -#define IIO_ICRB1_A 0x00400420 /* IO CRB Entry 1_A */ - - - -#define IIO_ICRB1_B 0x00400428 /* IO CRB Entry 1_B */ - - - -#define IIO_ICRB1_C 0x00400430 /* IO CRB Entry 1_C */ - - - -#define IIO_ICRB1_D 0x00400438 /* IO CRB Entry 1_D */ - - - -#define IIO_ICRB2_A 0x00400440 /* IO CRB Entry 2_A */ - - - -#define IIO_ICRB2_B 0x00400448 /* IO CRB Entry 2_B */ - - - -#define IIO_ICRB2_C 0x00400450 /* IO CRB Entry 2_C */ - - - -#define IIO_ICRB2_D 0x00400458 /* IO CRB Entry 2_D */ - - - -#define IIO_ICRB3_A 0x00400460 /* IO CRB Entry 3_A */ - - - -#define IIO_ICRB3_B 0x00400468 /* IO CRB Entry 3_B */ - - - -#define IIO_ICRB3_C 0x00400470 /* IO CRB Entry 3_C */ - - - -#define IIO_ICRB3_D 0x00400478 /* IO CRB Entry 3_D */ - - - -#define IIO_ICRB4_A 0x00400480 /* IO CRB Entry 4_A */ - - - -#define IIO_ICRB4_B 0x00400488 /* IO CRB Entry 4_B */ - - - -#define IIO_ICRB4_C 0x00400490 /* IO CRB Entry 4_C */ - - - -#define IIO_ICRB4_D 0x00400498 /* IO CRB Entry 4_D */ - - - -#define IIO_ICRB5_A 0x004004A0 /* IO CRB Entry 5_A */ - - - -#define IIO_ICRB5_B 0x004004A8 /* IO CRB Entry 5_B */ - - - -#define IIO_ICRB5_C 0x004004B0 /* IO CRB Entry 5_C */ - - - -#define IIO_ICRB5_D 0x004004B8 /* IO CRB Entry 5_D */ - - - -#define IIO_ICRB6_A 0x004004C0 /* IO CRB Entry 6_A */ - - - -#define IIO_ICRB6_B 0x004004C8 /* IO CRB Entry 6_B */ - - - -#define IIO_ICRB6_C 0x004004D0 /* IO CRB Entry 6_C */ - - - -#define IIO_ICRB6_D 0x004004D8 /* IO CRB Entry 6_D */ - - - -#define IIO_ICRB7_A 0x004004E0 /* IO CRB Entry 7_A */ - - - -#define IIO_ICRB7_B 0x004004E8 /* IO CRB Entry 7_B */ - - - -#define IIO_ICRB7_C 0x004004F0 /* IO CRB Entry 7_C */ - - - -#define IIO_ICRB7_D 0x004004F8 /* IO CRB Entry 7_D */ - - - -#define IIO_ICRB8_A 0x00400500 /* IO CRB Entry 8_A */ - - - -#define IIO_ICRB8_B 0x00400508 /* IO CRB Entry 8_B */ - - - -#define IIO_ICRB8_C 0x00400510 /* IO CRB Entry 8_C */ - - - -#define IIO_ICRB8_D 0x00400518 /* IO CRB Entry 8_D */ - - - -#define IIO_ICRB9_A 0x00400520 /* IO CRB Entry 9_A */ - - - -#define IIO_ICRB9_B 0x00400528 /* IO CRB Entry 9_B */ - - - -#define IIO_ICRB9_C 0x00400530 /* IO CRB Entry 9_C */ - - - -#define IIO_ICRB9_D 0x00400538 /* IO CRB Entry 9_D */ - - - -#define IIO_ICRBA_A 0x00400540 /* IO CRB Entry A_A */ - - - -#define IIO_ICRBA_B 0x00400548 /* IO CRB Entry A_B */ - - - -#define IIO_ICRBA_C 0x00400550 /* IO CRB Entry A_C */ - - - -#define IIO_ICRBA_D 0x00400558 /* IO CRB Entry A_D */ - - - -#define IIO_ICRBB_A 0x00400560 /* IO CRB Entry B_A */ - - - -#define IIO_ICRBB_B 0x00400568 /* IO CRB Entry B_B */ - - - -#define IIO_ICRBB_C 0x00400570 /* IO CRB Entry B_C */ - - - -#define IIO_ICRBB_D 0x00400578 /* IO CRB Entry B_D */ - - - -#define IIO_ICRBC_A 0x00400580 /* IO CRB Entry C_A */ - - - -#define IIO_ICRBC_B 0x00400588 /* IO CRB Entry C_B */ - - - -#define IIO_ICRBC_C 0x00400590 /* IO CRB Entry C_C */ - - - -#define IIO_ICRBC_D 0x00400598 /* IO CRB Entry C_D */ - - - -#define IIO_ICRBD_A 0x004005A0 /* IO CRB Entry D_A */ - - - -#define IIO_ICRBD_B 0x004005A8 /* IO CRB Entry D_B */ - - - -#define IIO_ICRBD_C 0x004005B0 /* IO CRB Entry D_C */ - - - -#define IIO_ICRBD_D 0x004005B8 /* IO CRB Entry D_D */ - - - -#define IIO_ICRBE_A 0x004005C0 /* IO CRB Entry E_A */ - - - -#define IIO_ICRBE_B 0x004005C8 /* IO CRB Entry E_B */ - - - -#define IIO_ICRBE_C 0x004005D0 /* IO CRB Entry E_C */ - - - -#define IIO_ICRBE_D 0x004005D8 /* IO CRB Entry E_D */ - - - -#define IIO_ICSML 0x00400600 /* - * IO CRB Spurious - * Message Low - */ - - - -#define IIO_ICSMH 0x00400608 /* - * IO CRB Spurious - * Message High - */ - - - -#define IIO_IDBSS 0x00400610 /* - * IO Debug Submenu - * Select - */ - - - -#define IIO_IBLS0 0x00410000 /* - * IO BTE Length - * Status 0 - */ - - - -#define IIO_IBSA0 0x00410008 /* - * IO BTE Source - * Address 0 - */ - - - -#define IIO_IBDA0 0x00410010 /* - * IO BTE Destination - * Address 0 - */ - - - -#define IIO_IBCT0 0x00410018 /* - * IO BTE Control - * Terminate 0 - */ - - - -#define IIO_IBNA0 0x00410020 /* - * IO BTE Notification - * Address 0 - */ - - - -#define IIO_IBIA0 0x00410028 /* - * IO BTE Interrupt - * Address 0 - */ - - - -#define IIO_IBLS1 0x00420000 /* - * IO BTE Length - * Status 1 - */ - - - -#define IIO_IBSA1 0x00420008 /* - * IO BTE Source - * Address 1 - */ - - - -#define IIO_IBDA1 0x00420010 /* - * IO BTE Destination - * Address 1 - */ - - - -#define IIO_IBCT1 0x00420018 /* - * IO BTE Control - * Terminate 1 - */ - - - -#define IIO_IBNA1 0x00420020 /* - * IO BTE Notification - * Address 1 - */ - - - -#define IIO_IBIA1 0x00420028 /* - * IO BTE Interrupt - * Address 1 - */ - - - -#define IIO_IPCR 0x00430000 /* - * IO Performance - * Control - */ - - - -#define IIO_IPPR 0x00430008 /* - * IO Performance - * Profiling - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register echoes some information from the * - * LB_REV_ID register. It is available through Crosstalk as described * - * above. The REV_NUM and MFG_NUM fields receive their values from * - * the REVISION and MANUFACTURER fields in the LB_REV_ID register. * - * The PART_NUM field's value is the Crosstalk device ID number that * - * Steve Miller assigned to the Bedrock chip. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wid_u { - bdrkreg_t ii_wid_regval; - struct { - bdrkreg_t w_rsvd_1 : 1; - bdrkreg_t w_mfg_num : 11; - bdrkreg_t w_part_num : 16; - bdrkreg_t w_rev_num : 4; - bdrkreg_t w_rsvd : 32; - } ii_wid_fld_s; -} ii_wid_u_t; - -#else - -typedef union ii_wid_u { - bdrkreg_t ii_wid_regval; - struct { - bdrkreg_t w_rsvd : 32; - bdrkreg_t w_rev_num : 4; - bdrkreg_t w_part_num : 16; - bdrkreg_t w_mfg_num : 11; - bdrkreg_t w_rsvd_1 : 1; - } ii_wid_fld_s; -} ii_wid_u_t; - -#endif - - - - -/************************************************************************ - * * - * The fields in this register are set upon detection of an error * - * and cleared by various mechanisms, as explained in the * - * description. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wstat_u { - bdrkreg_t ii_wstat_regval; - struct { - bdrkreg_t w_pending : 4; - bdrkreg_t w_xt_crd_to : 1; - bdrkreg_t w_xt_tail_to : 1; - bdrkreg_t w_rsvd_3 : 3; - bdrkreg_t w_tx_mx_rty : 1; - bdrkreg_t w_rsvd_2 : 6; - bdrkreg_t w_llp_tx_cnt : 8; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_crazy : 1; - bdrkreg_t w_rsvd : 31; - } ii_wstat_fld_s; -} ii_wstat_u_t; - -#else - -typedef union ii_wstat_u { - bdrkreg_t ii_wstat_regval; - struct { - bdrkreg_t w_rsvd : 31; - bdrkreg_t w_crazy : 1; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_llp_tx_cnt : 8; - bdrkreg_t w_rsvd_2 : 6; - bdrkreg_t w_tx_mx_rty : 1; - bdrkreg_t w_rsvd_3 : 3; - bdrkreg_t w_xt_tail_to : 1; - bdrkreg_t w_xt_crd_to : 1; - bdrkreg_t w_pending : 4; - } ii_wstat_fld_s; -} ii_wstat_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This is a read-write enabled register. It controls * - * various aspects of the Crosstalk flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wcr_u { - bdrkreg_t ii_wcr_regval; - struct { - bdrkreg_t w_wid : 4; - bdrkreg_t w_tag : 1; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_dst_crd : 3; - bdrkreg_t w_f_bad_pkt : 1; - bdrkreg_t w_dir_con : 1; - bdrkreg_t w_e_thresh : 5; - bdrkreg_t w_rsvd : 41; - } ii_wcr_fld_s; -} ii_wcr_u_t; - -#else - -typedef union ii_wcr_u { - bdrkreg_t ii_wcr_regval; - struct { - bdrkreg_t w_rsvd : 41; - bdrkreg_t w_e_thresh : 5; - bdrkreg_t w_dir_con : 1; - bdrkreg_t w_f_bad_pkt : 1; - bdrkreg_t w_dst_crd : 3; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_tag : 1; - bdrkreg_t w_wid : 4; - } ii_wcr_fld_s; -} ii_wcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register's value is a bit vector that guards * - * access to local registers within the II as well as to external * - * Crosstalk widgets. Each bit in the register corresponds to a * - * particular region in the system; a region consists of one, two or * - * four nodes (depending on the value of the REGION_SIZE field in the * - * LB_REV_ID register, which is documented in Section 8.3.1.1). The * - * protection provided by this register applies to PIO read * - * operations as well as PIO write operations. The II will perform a * - * PIO read or write request only if the bit for the requestor's * - * region is set; otherwise, the II will not perform the requested * - * operation and will return an error response. When a PIO read or * - * write request targets an external Crosstalk widget, then not only * - * must the bit for the requestor's region be set in the ILAPR, but * - * also the target widget's bit in the IOWA register must be set in * - * order for the II to perform the requested operation; otherwise, * - * the II will return an error response. Hence, the protection * - * provided by the IOWA register supplements the protection provided * - * by the ILAPR for requests that target external Crosstalk widgets. * - * This register itself can be accessed only by the nodes whose * - * region ID bits are enabled in this same register. It can also be * - * accessed through the IAlias space by the local processors. * - * The reset value of this register allows access by all nodes. * - * * - ************************************************************************/ - - - - -typedef union ii_ilapr_u { - bdrkreg_t ii_ilapr_regval; - struct { - bdrkreg_t i_region : 64; - } ii_ilapr_fld_s; -} ii_ilapr_u_t; - - - - -/************************************************************************ - * * - * Description: A write to this register of the 64-bit value * - * "SGIrules" in ASCII, will cause the bit in the ILAPR register * - * corresponding to the region of the requestor to be set (allow * - * access). A write of any other value will be ignored. Access * - * protection for this register is "SGIrules". * - * This register can also be accessed through the IAlias space. * - * However, this access will not change the access permissions in the * - * ILAPR. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilapo_u { - bdrkreg_t ii_ilapo_regval; - struct { - bdrkreg_t i_io_ovrride : 9; - bdrkreg_t i_rsvd : 55; - } ii_ilapo_fld_s; -} ii_ilapo_u_t; - -#else - -typedef union ii_ilapo_u { - bdrkreg_t ii_ilapo_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_io_ovrride : 9; - } ii_ilapo_fld_s; -} ii_ilapo_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register qualifies all the PIO and Graphics writes launched * - * from the Bedrock towards a widget. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iowa_u { - bdrkreg_t ii_iowa_regval; - struct { - bdrkreg_t i_w0_oac : 1; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_wx_oac : 8; - bdrkreg_t i_rsvd : 48; - } ii_iowa_fld_s; -} ii_iowa_u_t; - -#else - -typedef union ii_iowa_u { - bdrkreg_t ii_iowa_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_wx_oac : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_w0_oac : 1; - } ii_iowa_fld_s; -} ii_iowa_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register qualifies all the requests launched * - * from a widget towards the Bedrock. This register is intended to be * - * used by software in case of misbehaving widgets. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iiwa_u { - bdrkreg_t ii_iiwa_regval; - struct { - bdrkreg_t i_w0_iac : 1; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_wx_iac : 8; - bdrkreg_t i_rsvd : 48; - } ii_iiwa_fld_s; -} ii_iiwa_u_t; - -#else - -typedef union ii_iiwa_u { - bdrkreg_t ii_iiwa_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_wx_iac : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_w0_iac : 1; - } ii_iiwa_fld_s; -} ii_iiwa_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register qualifies all the operations launched * - * from a widget towards the Bedrock. It allows individual access * - * control for up to 8 devices per widget. A device refers to * - * individual DMA master hosted by a widget. * - * The bits in each field of this register are cleared by the Bedrock * - * upon detection of an error which requires the device to be * - * disabled. These fields assume that 0=TNUM=7 (i.e., Bridge-centric * - * Crosstalk). Whether or not a device has access rights to this * - * Bedrock is determined by an AND of the device enable bit in the * - * appropriate field of this register and the corresponding bit in * - * the Wx_IAC field (for the widget which this device belongs to). * - * The bits in this field are set by writing a 1 to them. Incoming * - * replies from Crosstalk are not subject to this access control * - * mechanism. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iidem_u { - bdrkreg_t ii_iidem_regval; - struct { - bdrkreg_t i_w8_dxs : 8; - bdrkreg_t i_w9_dxs : 8; - bdrkreg_t i_wa_dxs : 8; - bdrkreg_t i_wb_dxs : 8; - bdrkreg_t i_wc_dxs : 8; - bdrkreg_t i_wd_dxs : 8; - bdrkreg_t i_we_dxs : 8; - bdrkreg_t i_wf_dxs : 8; - } ii_iidem_fld_s; -} ii_iidem_u_t; - -#else - -typedef union ii_iidem_u { - bdrkreg_t ii_iidem_regval; - struct { - bdrkreg_t i_wf_dxs : 8; - bdrkreg_t i_we_dxs : 8; - bdrkreg_t i_wd_dxs : 8; - bdrkreg_t i_wc_dxs : 8; - bdrkreg_t i_wb_dxs : 8; - bdrkreg_t i_wa_dxs : 8; - bdrkreg_t i_w9_dxs : 8; - bdrkreg_t i_w8_dxs : 8; - } ii_iidem_fld_s; -} ii_iidem_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the various programmable fields necessary * - * for controlling and observing the LLP signals. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilcsr_u { - bdrkreg_t ii_ilcsr_regval; - struct { - bdrkreg_t i_nullto : 6; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_wrmrst : 1; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_llp_en : 1; - bdrkreg_t i_bm8 : 1; - bdrkreg_t i_llp_stat : 2; - bdrkreg_t i_remote_power : 1; - bdrkreg_t i_rsvd_2 : 1; - bdrkreg_t i_maxrtry : 10; - bdrkreg_t i_d_avail_sel : 2; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_maxbrst : 10; - bdrkreg_t i_rsvd : 22; - - } ii_ilcsr_fld_s; -} ii_ilcsr_u_t; - -#else - -typedef union ii_ilcsr_u { - bdrkreg_t ii_ilcsr_regval; - struct { - bdrkreg_t i_rsvd : 22; - bdrkreg_t i_maxbrst : 10; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_d_avail_sel : 2; - bdrkreg_t i_maxrtry : 10; - bdrkreg_t i_rsvd_2 : 1; - bdrkreg_t i_remote_power : 1; - bdrkreg_t i_llp_stat : 2; - bdrkreg_t i_bm8 : 1; - bdrkreg_t i_llp_en : 1; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_wrmrst : 1; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_nullto : 6; - } ii_ilcsr_fld_s; -} ii_ilcsr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This is simply a status registers that monitors the LLP error * - * rate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_illr_u { - bdrkreg_t ii_illr_regval; - struct { - bdrkreg_t i_sn_cnt : 16; - bdrkreg_t i_cb_cnt : 16; - bdrkreg_t i_rsvd : 32; - } ii_illr_fld_s; -} ii_illr_u_t; - -#else - -typedef union ii_illr_u { - bdrkreg_t ii_illr_regval; - struct { - bdrkreg_t i_rsvd : 32; - bdrkreg_t i_cb_cnt : 16; - bdrkreg_t i_sn_cnt : 16; - } ii_illr_fld_s; -} ii_illr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: All II-detected non-BTE error interrupts are * - * specified via this register. * - * NOTE: The PI interrupt register address is hardcoded in the II. If * - * PI_ID==0, then the II sends an interrupt request (Duplonet PWRI * - * packet) to address offset 0x0180_0090 within the local register * - * address space of PI0 on the node specified by the NODE field. If * - * PI_ID==1, then the II sends the interrupt request to address * - * offset 0x01A0_0090 within the local register address space of PI1 * - * on the node specified by the NODE field. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iidsr_u { - bdrkreg_t ii_iidsr_regval; - struct { - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node : 8; - bdrkreg_t i_rsvd_3 : 7; - bdrkreg_t i_enable : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_int_sent : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_rsvd : 30; - } ii_iidsr_fld_s; -} ii_iidsr_u_t; - -#else - -typedef union ii_iidsr_u { - bdrkreg_t ii_iidsr_regval; - struct { - bdrkreg_t i_rsvd : 30; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_int_sent : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_enable : 1; - bdrkreg_t i_rsvd_3 : 7; - bdrkreg_t i_node : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_level : 7; - } ii_iidsr_fld_s; -} ii_iidsr_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_igfx0_u { - bdrkreg_t ii_igfx0_regval; - struct { - bdrkreg_t i_w_num : 4; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd : 47; - } ii_igfx0_fld_s; -} ii_igfx0_u_t; - -#else - -typedef union ii_igfx0_u { - bdrkreg_t ii_igfx0_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_w_num : 4; - } ii_igfx0_fld_s; -} ii_igfx0_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_igfx1_u { - bdrkreg_t ii_igfx1_regval; - struct { - bdrkreg_t i_w_num : 4; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd : 47; - } ii_igfx1_fld_s; -} ii_igfx1_u_t; - -#else - -typedef union ii_igfx1_u { - bdrkreg_t ii_igfx1_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_w_num : 4; - } ii_igfx1_fld_s; -} ii_igfx1_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - - - - -typedef union ii_iscr0_u { - bdrkreg_t ii_iscr0_regval; - struct { - bdrkreg_t i_scratch : 64; - } ii_iscr0_fld_s; -} ii_iscr0_u_t; - - - - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - - - - -typedef union ii_iscr1_u { - bdrkreg_t ii_iscr1_regval; - struct { - bdrkreg_t i_scratch : 64; - } ii_iscr1_fld_s; -} ii_iscr1_u_t; - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte1_u { - bdrkreg_t ii_itte1_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte1_fld_s; -} ii_itte1_u_t; - -#else - -typedef union ii_itte1_u { - bdrkreg_t ii_itte1_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte1_fld_s; -} ii_itte1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte2_u { - bdrkreg_t ii_itte2_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte2_fld_s; -} ii_itte2_u_t; - -#else -typedef union ii_itte2_u { - bdrkreg_t ii_itte2_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte2_fld_s; -} ii_itte2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte3_u { - bdrkreg_t ii_itte3_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte3_fld_s; -} ii_itte3_u_t; - -#else - -typedef union ii_itte3_u { - bdrkreg_t ii_itte3_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte3_fld_s; -} ii_itte3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte4_u { - bdrkreg_t ii_itte4_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte4_fld_s; -} ii_itte4_u_t; - -#else - -typedef union ii_itte4_u { - bdrkreg_t ii_itte4_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte4_fld_s; -} ii_itte4_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte5_u { - bdrkreg_t ii_itte5_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte5_fld_s; -} ii_itte5_u_t; - -#else - -typedef union ii_itte5_u { - bdrkreg_t ii_itte5_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte5_fld_s; -} ii_itte5_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte6_u { - bdrkreg_t ii_itte6_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte6_fld_s; -} ii_itte6_u_t; - -#else - -typedef union ii_itte6_u { - bdrkreg_t ii_itte6_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte6_fld_s; -} ii_itte6_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte7_u { - bdrkreg_t ii_itte7_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte7_fld_s; -} ii_itte7_u_t; - -#else - -typedef union ii_itte7_u { - bdrkreg_t ii_itte7_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte7_fld_s; -} ii_itte7_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb0_u { - bdrkreg_t ii_iprb0_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb0_fld_s; -} ii_iprb0_u_t; - -#else - -typedef union ii_iprb0_u { - bdrkreg_t ii_iprb0_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb0_fld_s; -} ii_iprb0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb8_u { - bdrkreg_t ii_iprb8_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb8_fld_s; -} ii_iprb8_u_t; - -#else - - -typedef union ii_iprb8_u { - bdrkreg_t ii_iprb8_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb8_fld_s; -} ii_iprb8_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb9_u { - bdrkreg_t ii_iprb9_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb9_fld_s; -} ii_iprb9_u_t; - -#else - -typedef union ii_iprb9_u { - bdrkreg_t ii_iprb9_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb9_fld_s; -} ii_iprb9_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprba_u { - bdrkreg_t ii_iprba_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprba_fld_s; -} ii_iprba_u_t; - -#else - -typedef union ii_iprba_u { - bdrkreg_t ii_iprba_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprba_fld_s; -} ii_iprba_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbb_u { - bdrkreg_t ii_iprbb_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbb_fld_s; -} ii_iprbb_u_t; - -#else - -typedef union ii_iprbb_u { - bdrkreg_t ii_iprbb_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbb_fld_s; -} ii_iprbb_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbc_u { - bdrkreg_t ii_iprbc_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbc_fld_s; -} ii_iprbc_u_t; - -#else - -typedef union ii_iprbc_u { - bdrkreg_t ii_iprbc_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbc_fld_s; -} ii_iprbc_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbd_u { - bdrkreg_t ii_iprbd_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbd_fld_s; -} ii_iprbd_u_t; - -#else - -typedef union ii_iprbd_u { - bdrkreg_t ii_iprbd_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbd_fld_s; -} ii_iprbd_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbe_u { - bdrkreg_t ii_iprbe_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbe_fld_s; -} ii_iprbe_u_t; - -#else - -typedef union ii_iprbe_u { - bdrkreg_t ii_iprbe_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbe_fld_s; -} ii_iprbe_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbf_u { - bdrkreg_t ii_iprbf_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbe_fld_s; -} ii_iprbf_u_t; - -#else - -typedef union ii_iprbf_u { - bdrkreg_t ii_iprbf_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbf_fld_s; -} ii_iprbf_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register specifies the timeout value to use for monitoring * - * Crosstalk credits which are used outbound to Crosstalk. An * - * internal counter called the Crosstalk Credit Timeout Counter * - * increments every 128 II clocks. The counter starts counting * - * anytime the credit count drops below a threshold, and resets to * - * zero (stops counting) anytime the credit count is at or above the * - * threshold. The threshold is 1 credit in direct connect mode and 2 * - * in Crossbow connect mode. When the internal Crosstalk Credit * - * Timeout Counter reaches the value programmed in this register, a * - * Crosstalk Credit Timeout has occurred. The internal counter is not * - * readable from software, and stops counting at its maximum value, * - * so it cannot cause more than one interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixcc_u { - bdrkreg_t ii_ixcc_regval; - struct { - bdrkreg_t i_time_out : 26; - bdrkreg_t i_rsvd : 38; - } ii_ixcc_fld_s; -} ii_ixcc_u_t; - -#else - -typedef union ii_ixcc_u { - bdrkreg_t ii_ixcc_regval; - struct { - bdrkreg_t i_rsvd : 38; - bdrkreg_t i_time_out : 26; - } ii_ixcc_fld_s; -} ii_ixcc_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: This register qualifies all the PIO and DMA * - * operations launched from widget 0 towards the Bedrock. In * - * addition, it also qualifies accesses by the BTE streams. * - * The bits in each field of this register are cleared by the Bedrock * - * upon detection of an error which requires widget 0 or the BTE * - * streams to be terminated. Whether or not widget x has access * - * rights to this Bedrock is determined by an AND of the device * - * enable bit in the appropriate field of this register and bit 0 in * - * the Wx_IAC field. The bits in this field are set by writing a 1 to * - * them. Incoming replies from Crosstalk are not subject to this * - * access control mechanism. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_imem_u { - bdrkreg_t ii_imem_regval; - struct { - bdrkreg_t i_w0_esd : 1; - bdrkreg_t i_rsvd_3 : 3; - bdrkreg_t i_b0_esd : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_b1_esd : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_clr_precise : 1; - bdrkreg_t i_rsvd : 51; - } ii_imem_fld_s; -} ii_imem_u_t; - -#else - -typedef union ii_imem_u { - bdrkreg_t ii_imem_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_clr_precise : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_b1_esd : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_b0_esd : 1; - bdrkreg_t i_rsvd_3 : 3; - bdrkreg_t i_w0_esd : 1; - } ii_imem_fld_s; -} ii_imem_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register specifies the timeout value to use for * - * monitoring Crosstalk tail flits coming into the Bedrock in the * - * TAIL_TO field. An internal counter associated with this register * - * is incremented every 128 II internal clocks (7 bits). The counter * - * starts counting anytime a header micropacket is received and stops * - * counting (and resets to zero) any time a micropacket with a Tail * - * bit is received. Once the counter reaches the threshold value * - * programmed in this register, it generates an interrupt to the * - * processor that is programmed into the IIDSR. The counter saturates * - * (does not roll over) at its maximum value, so it cannot cause * - * another interrupt until after it is cleared. * - * The register also contains the Read Response Timeout values. The * - * Prescalar is 23 bits, and counts II clocks. An internal counter * - * increments on every II clock and when it reaches the value in the * - * Prescalar field, all IPRTE registers with their valid bits set * - * have their Read Response timers bumped. Whenever any of them match * - * the value in the RRSP_TO field, a Read Response Timeout has * - * occurred, and error handling occurs as described in the Error * - * Handling section of this document. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixtt_u { - bdrkreg_t ii_ixtt_regval; - struct { - bdrkreg_t i_tail_to : 26; - bdrkreg_t i_rsvd_1 : 6; - bdrkreg_t i_rrsp_ps : 23; - bdrkreg_t i_rrsp_to : 5; - bdrkreg_t i_rsvd : 4; - } ii_ixtt_fld_s; -} ii_ixtt_u_t; - -#else - -typedef union ii_ixtt_u { - bdrkreg_t ii_ixtt_regval; - struct { - bdrkreg_t i_rsvd : 4; - bdrkreg_t i_rrsp_to : 5; - bdrkreg_t i_rrsp_ps : 23; - bdrkreg_t i_rsvd_1 : 6; - bdrkreg_t i_tail_to : 26; - } ii_ixtt_fld_s; -} ii_ixtt_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing a 1 to the fields of this register clears the appropriate * - * error bits in other areas of Bedrock_II. Note that when the * - * E_PRB_x bits are used to clear error bits in PRB registers, * - * SPUR_RD and SPUR_WR may persist, because they require additional * - * action to clear them. See the IPRBx and IXSS Register * - * specifications. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ieclr_u { - bdrkreg_t ii_ieclr_regval; - struct { - bdrkreg_t i_e_prb_0 : 1; - bdrkreg_t i_rsvd : 7; - bdrkreg_t i_e_prb_8 : 1; - bdrkreg_t i_e_prb_9 : 1; - bdrkreg_t i_e_prb_a : 1; - bdrkreg_t i_e_prb_b : 1; - bdrkreg_t i_e_prb_c : 1; - bdrkreg_t i_e_prb_d : 1; - bdrkreg_t i_e_prb_e : 1; - bdrkreg_t i_e_prb_f : 1; - bdrkreg_t i_e_crazy : 1; - bdrkreg_t i_e_bte_0 : 1; - bdrkreg_t i_e_bte_1 : 1; - bdrkreg_t i_reserved_1 : 9; - bdrkreg_t i_ii_internal : 1; - bdrkreg_t i_spur_rd_hdr : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_reserved : 32; - } ii_ieclr_fld_s; -} ii_ieclr_u_t; - -#else - -typedef union ii_ieclr_u { - bdrkreg_t ii_ieclr_regval; - struct { - bdrkreg_t i_reserved : 32; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_spur_rd_hdr : 1; - bdrkreg_t i_ii_internal : 1; - bdrkreg_t i_reserved_1 : 9; - bdrkreg_t i_e_bte_1 : 1; - bdrkreg_t i_e_bte_0 : 1; - bdrkreg_t i_e_crazy : 1; - bdrkreg_t i_e_prb_f : 1; - bdrkreg_t i_e_prb_e : 1; - bdrkreg_t i_e_prb_d : 1; - bdrkreg_t i_e_prb_c : 1; - bdrkreg_t i_e_prb_b : 1; - bdrkreg_t i_e_prb_a : 1; - bdrkreg_t i_e_prb_9 : 1; - bdrkreg_t i_e_prb_8 : 1; - bdrkreg_t i_rsvd : 7; - bdrkreg_t i_e_prb_0 : 1; - } ii_ieclr_fld_s; -} ii_ieclr_u_t; - -#endif - - - - - -/************************************************************************ - * * - * This register controls both BTEs. SOFT_RESET is intended for * - * recovery after an error. COUNT controls the total number of CRBs * - * that both BTEs (combined) can use, which affects total BTE * - * bandwidth. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibcr_u { - bdrkreg_t ii_ibcr_regval; - struct { - bdrkreg_t i_count : 4; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_soft_reset : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibcr_fld_s; -} ii_ibcr_u_t; - -#else - -typedef union ii_ibcr_u { - bdrkreg_t ii_ibcr_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_soft_reset : 1; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_count : 4; - } ii_ibcr_fld_s; -} ii_ibcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the header of a spurious read response * - * received from Crosstalk. A spurious read response is defined as a * - * read response received by II from a widget for which (1) the SIDN * - * has a value between 1 and 7, inclusive (II never sends requests to * - * these widgets (2) there is no valid IPRTE register which * - * corresponds to the TNUM, or (3) the widget indicated in SIDN is * - * not the same as the widget recorded in the IPRTE register * - * referenced by the TNUM. If this condition is true, and if the * - * IXSS[VALID] bit is clear, then the header of the spurious read * - * response is capture in IXSM and IXSS, and IXSS[VALID] is set. The * - * errant header is thereby captured, and no further spurious read * - * respones are captured until IXSS[VALID] is cleared by setting the * - * appropriate bit in IECLR.Everytime a spurious read response is * - * detected, the SPUR_RD bit of the PRB corresponding to the incoming * - * message's SIDN field is set. This always happens, regarless of * - * whether a header is captured. The programmer should check * - * IXSM[SIDN] to determine which widget sent the spurious response, * - * because there may be more than one SPUR_RD bit set in the PRB * - * registers. The widget indicated by IXSM[SIDN] was the first * - * spurious read response to be received since the last time * - * IXSS[VALID] was clear. The SPUR_RD bit of the corresponding PRB * - * will be set. Any SPUR_RD bits in any other PRB registers indicate * - * spurious messages from other widets which were detected after the * - * header was captured.. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixsm_u { - bdrkreg_t ii_ixsm_regval; - struct { - bdrkreg_t i_byte_en : 32; - bdrkreg_t i_reserved : 1; - bdrkreg_t i_tag : 3; - bdrkreg_t i_alt_pactyp : 4; - bdrkreg_t i_bo : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_vbpm : 1; - bdrkreg_t i_gbr : 1; - bdrkreg_t i_ds : 2; - bdrkreg_t i_ct : 1; - bdrkreg_t i_tnum : 5; - bdrkreg_t i_pactyp : 4; - bdrkreg_t i_sidn : 4; - bdrkreg_t i_didn : 4; - } ii_ixsm_fld_s; -} ii_ixsm_u_t; - -#else - -typedef union ii_ixsm_u { - bdrkreg_t ii_ixsm_regval; - struct { - bdrkreg_t i_didn : 4; - bdrkreg_t i_sidn : 4; - bdrkreg_t i_pactyp : 4; - bdrkreg_t i_tnum : 5; - bdrkreg_t i_ct : 1; - bdrkreg_t i_ds : 2; - bdrkreg_t i_gbr : 1; - bdrkreg_t i_vbpm : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_bo : 1; - bdrkreg_t i_alt_pactyp : 4; - bdrkreg_t i_tag : 3; - bdrkreg_t i_reserved : 1; - bdrkreg_t i_byte_en : 32; - } ii_ixsm_fld_s; -} ii_ixsm_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the sideband bits of a spurious read * - * response received from Crosstalk. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixss_u { - bdrkreg_t ii_ixss_regval; - struct { - bdrkreg_t i_sideband : 8; - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_valid : 1; - } ii_ixss_fld_s; -} ii_ixss_u_t; - -#else - -typedef union ii_ixss_u { - bdrkreg_t ii_ixss_regval; - struct { - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_sideband : 8; - } ii_ixss_fld_s; -} ii_ixss_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register enables software to access the II LLP's test port. * - * Refer to the LLP 2.5 documentation for an explanation of the test * - * port. Software can write to this register to program the values * - * for the control fields (TestErrCapture, TestClear, TestFlit, * - * TestMask and TestSeed). Similarly, software can read from this * - * register to obtain the values of the test port's status outputs * - * (TestCBerr, TestValid and TestData). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilct_u { - bdrkreg_t ii_ilct_regval; - struct { - bdrkreg_t i_test_seed : 20; - bdrkreg_t i_test_mask : 8; - bdrkreg_t i_test_data : 20; - bdrkreg_t i_test_valid : 1; - bdrkreg_t i_test_cberr : 1; - bdrkreg_t i_test_flit : 3; - bdrkreg_t i_test_clear : 1; - bdrkreg_t i_test_err_capture : 1; - bdrkreg_t i_rsvd : 9; - } ii_ilct_fld_s; -} ii_ilct_u_t; - -#else - -typedef union ii_ilct_u { - bdrkreg_t ii_ilct_regval; - struct { - bdrkreg_t i_rsvd : 9; - bdrkreg_t i_test_err_capture : 1; - bdrkreg_t i_test_clear : 1; - bdrkreg_t i_test_flit : 3; - bdrkreg_t i_test_cberr : 1; - bdrkreg_t i_test_valid : 1; - bdrkreg_t i_test_data : 20; - bdrkreg_t i_test_mask : 8; - bdrkreg_t i_test_seed : 20; - } ii_ilct_fld_s; -} ii_ilct_u_t; - -#endif - - - - -/************************************************************************ - * * - * If the II detects an illegal incoming Duplonet packet (request or * - * reply) when VALID==0 in the IIEPH1 register, then it saves the * - * contents of the packet's header flit in the IIEPH1 and IIEPH2 * - * registers, sets the VALID bit in IIEPH1, clears the OVERRUN bit, * - * and assigns a value to the ERR_TYPE field which indicates the * - * specific nature of the error. The II recognizes four different * - * types of errors: short request packets (ERR_TYPE==2), short reply * - * packets (ERR_TYPE==3), long request packets (ERR_TYPE==4) and long * - * reply packets (ERR_TYPE==5). The encodings for these types of * - * errors were chosen to be consistent with the same types of errors * - * indicated by the ERR_TYPE field in the LB_ERROR_HDR1 register (in * - * the LB unit). If the II detects an illegal incoming Duplonet * - * packet when VALID==1 in the IIEPH1 register, then it merely sets * - * the OVERRUN bit to indicate that a subsequent error has happened, * - * and does nothing further. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iieph1_u { - bdrkreg_t ii_iieph1_regval; - struct { - bdrkreg_t i_command : 7; - bdrkreg_t i_rsvd_5 : 1; - bdrkreg_t i_suppl : 11; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_source : 11; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_err_type : 4; - bdrkreg_t i_rsvd_2 : 4; - bdrkreg_t i_overrun : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd : 19; - } ii_iieph1_fld_s; -} ii_iieph1_u_t; - -#else - -typedef union ii_iieph1_u { - bdrkreg_t ii_iieph1_regval; - struct { - bdrkreg_t i_rsvd : 19; - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_overrun : 1; - bdrkreg_t i_rsvd_2 : 4; - bdrkreg_t i_err_type : 4; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_source : 11; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_suppl : 11; - bdrkreg_t i_rsvd_5 : 1; - bdrkreg_t i_command : 7; - } ii_iieph1_fld_s; -} ii_iieph1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register holds the Address field from the header flit of an * - * incoming erroneous Duplonet packet, along with the tail bit which * - * accompanied this header flit. This register is essentially an * - * extension of IIEPH1. Two registers were necessary because the 64 * - * bits available in only a single register were insufficient to * - * capture the entire header flit of an erroneous packet. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iieph2_u { - bdrkreg_t ii_iieph2_regval; - struct { - bdrkreg_t i_address : 38; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_tail : 1; - bdrkreg_t i_rsvd : 23; - } ii_iieph2_fld_s; -} ii_iieph2_u_t; - -#else - -typedef union ii_iieph2_u { - bdrkreg_t ii_iieph2_regval; - struct { - bdrkreg_t i_rsvd : 23; - bdrkreg_t i_tail : 1; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_address : 38; - } ii_iieph2_fld_s; -} ii_iieph2_u_t; - -#endif - - - - -/************************************************************************ - * * - * A write to this register causes a particular field in the * - * corresponding widget's PRB entry to be adjusted up or down by 1. * - * This counter should be used when recovering from error and reset * - * conditions. Note that software would be capable of causing * - * inadvertent overflow or underflow of these counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipca_u { - bdrkreg_t ii_ipca_regval; - struct { - bdrkreg_t i_wid : 4; - bdrkreg_t i_adjust : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_field : 2; - bdrkreg_t i_rsvd : 54; - } ii_ipca_fld_s; -} ii_ipca_u_t; - -#else - -typedef union ii_ipca_u { - bdrkreg_t ii_ipca_regval; - struct { - bdrkreg_t i_rsvd : 54; - bdrkreg_t i_field : 2; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_adjust : 1; - bdrkreg_t i_wid : 4; - } ii_ipca_fld_s; -} ii_ipca_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte0_u { - bdrkreg_t ii_iprte0_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte0_fld_s; -} ii_iprte0_u_t; - -#else - -typedef union ii_iprte0_u { - bdrkreg_t ii_iprte0_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte0_fld_s; -} ii_iprte0_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte1_u { - bdrkreg_t ii_iprte1_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte1_fld_s; -} ii_iprte1_u_t; - -#else - -typedef union ii_iprte1_u { - bdrkreg_t ii_iprte1_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte1_fld_s; -} ii_iprte1_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte2_u { - bdrkreg_t ii_iprte2_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte2_fld_s; -} ii_iprte2_u_t; - -#else - -typedef union ii_iprte2_u { - bdrkreg_t ii_iprte2_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte2_fld_s; -} ii_iprte2_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte3_u { - bdrkreg_t ii_iprte3_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte3_fld_s; -} ii_iprte3_u_t; - -#else - -typedef union ii_iprte3_u { - bdrkreg_t ii_iprte3_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte3_fld_s; -} ii_iprte3_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte4_u { - bdrkreg_t ii_iprte4_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte4_fld_s; -} ii_iprte4_u_t; - -#else - -typedef union ii_iprte4_u { - bdrkreg_t ii_iprte4_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte4_fld_s; -} ii_iprte4_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte5_u { - bdrkreg_t ii_iprte5_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte5_fld_s; -} ii_iprte5_u_t; - -#else - -typedef union ii_iprte5_u { - bdrkreg_t ii_iprte5_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte5_fld_s; -} ii_iprte5_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte6_u { - bdrkreg_t ii_iprte6_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte6_fld_s; -} ii_iprte6_u_t; - -#else - -typedef union ii_iprte6_u { - bdrkreg_t ii_iprte6_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte6_fld_s; -} ii_iprte6_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte7_u { - bdrkreg_t ii_iprte7_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte7_fld_s; -} ii_iprte7_u_t; - -#else - -typedef union ii_iprte7_u { - bdrkreg_t ii_iprte7_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte7_fld_s; -} ii_iprte7_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Bedrock_II contains a feature which did not exist in * - * the Hub which automatically cleans up after a Read Response * - * timeout, including deallocation of the IPRTE and recovery of IBuf * - * space. The inclusion of this register in Bedrock is for backward * - * compatibility * - * A write to this register causes an entry from the table of * - * outstanding PIO Read Requests to be freed and returned to the * - * stack of free entries. This register is used in handling the * - * timeout errors that result in a PIO Reply never returning from * - * Crosstalk. * - * Note that this register does not affect the contents of the IPRTE * - * registers. The Valid bits in those registers have to be * - * specifically turned off by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipdr_u { - bdrkreg_t ii_ipdr_regval; - struct { - bdrkreg_t i_te : 3; - bdrkreg_t i_rsvd_1 : 1; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_init_rpcnt : 1; - bdrkreg_t i_rsvd : 58; - } ii_ipdr_fld_s; -} ii_ipdr_u_t; - -#else - -typedef union ii_ipdr_u { - bdrkreg_t ii_ipdr_regval; - struct { - bdrkreg_t i_rsvd : 58; - bdrkreg_t i_init_rpcnt : 1; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_rsvd_1 : 1; - bdrkreg_t i_te : 3; - } ii_ipdr_fld_s; -} ii_ipdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * A write to this register causes a CRB entry to be returned to the * - * queue of free CRBs. The entry should have previously been cleared * - * (mark bit) via backdoor access to the pertinent CRB entry. This * - * register is used in the last step of handling the errors that are * - * captured and marked in CRB entries. Briefly: 1) first error for * - * DMA write from a particular device, and first error for a * - * particular BTE stream, lead to a marked CRB entry, and processor * - * interrupt, 2) software reads the error information captured in the * - * CRB entry, and presumably takes some corrective action, 3) * - * software clears the mark bit, and finally 4) software writes to * - * the ICDR register to return the CRB entry to the list of free CRB * - * entries. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icdr_u { - bdrkreg_t ii_icdr_regval; - struct { - bdrkreg_t i_crb_num : 4; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_rsvd : 59; - } ii_icdr_fld_s; -} ii_icdr_u_t; - -#else - -typedef union ii_icdr_u { - bdrkreg_t ii_icdr_regval; - struct { - bdrkreg_t i_rsvd : 59; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_crb_num : 4; - } ii_icdr_fld_s; -} ii_icdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides debug access to two FIFOs inside of II. * - * Both IOQ_MAX* fields of this register contain the instantaneous * - * depth (in units of the number of available entries) of the * - * associated IOQ FIFO. A read of this register will return the * - * number of free entries on each FIFO at the time of the read. So * - * when a FIFO is idle, the associated field contains the maximum * - * depth of the FIFO. This register is writable for debug reasons * - * and is intended to be written with the maximum desired FIFO depth * - * while the FIFO is idle. Software must assure that II is idle when * - * this register is written. If there are any active entries in any * - * of these FIFOs when this register is written, the results are * - * undefined. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ifdr_u { - bdrkreg_t ii_ifdr_regval; - struct { - bdrkreg_t i_ioq_max_rq : 7; - bdrkreg_t i_set_ioq_rq : 1; - bdrkreg_t i_ioq_max_rp : 7; - bdrkreg_t i_set_ioq_rp : 1; - bdrkreg_t i_rsvd : 48; - } ii_ifdr_fld_s; -} ii_ifdr_u_t; - -#else - -typedef union ii_ifdr_u { - bdrkreg_t ii_ifdr_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_set_ioq_rp : 1; - bdrkreg_t i_ioq_max_rp : 7; - bdrkreg_t i_set_ioq_rq : 1; - bdrkreg_t i_ioq_max_rq : 7; - } ii_ifdr_fld_s; -} ii_ifdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the II to become sluggish in removing * - * messages from its inbound queue (IIQ). This will cause messages to * - * back up in either virtual channel. Disabling the "molasses" mode * - * subsequently allows the II to be tested under stress. In the * - * sluggish ("Molasses") mode, the localized effects of congestion * - * can be observed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iiap_u { - bdrkreg_t ii_iiap_regval; - struct { - bdrkreg_t i_rq_mls : 6; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_rp_mls : 6; - bdrkreg_t i_rsvd : 50; - } ii_iiap_fld_s; -} ii_iiap_u_t; - -#else - -typedef union ii_iiap_u { - bdrkreg_t ii_iiap_regval; - struct { - bdrkreg_t i_rsvd : 50; - bdrkreg_t i_rp_mls : 6; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_rq_mls : 6; - } ii_iiap_fld_s; -} ii_iiap_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows several parameters of CRB operation to be * - * set. Note that writing to this register can have catastrophic side * - * effects, if the CRB is not quiescent, i.e. if the CRB is * - * processing protocol messages when the write occurs. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icmr_u { - bdrkreg_t ii_icmr_regval; - struct { - bdrkreg_t i_sp_msg : 1; - bdrkreg_t i_rd_hdr : 1; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_c_cnt : 4; - bdrkreg_t i_rsvd_3 : 4; - bdrkreg_t i_clr_rqpd : 1; - bdrkreg_t i_clr_rppd : 1; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_fc_cnt : 4; - bdrkreg_t i_crb_vld : 15; - bdrkreg_t i_crb_mark : 15; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_precise : 1; - bdrkreg_t i_rsvd : 11; - } ii_icmr_fld_s; -} ii_icmr_u_t; - -#else - -typedef union ii_icmr_u { - bdrkreg_t ii_icmr_regval; - struct { - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_precise : 1; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_crb_mark : 15; - bdrkreg_t i_crb_vld : 15; - bdrkreg_t i_fc_cnt : 4; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_clr_rppd : 1; - bdrkreg_t i_clr_rqpd : 1; - bdrkreg_t i_rsvd_3 : 4; - bdrkreg_t i_c_cnt : 4; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_rd_hdr : 1; - bdrkreg_t i_sp_msg : 1; - } ii_icmr_fld_s; -} ii_icmr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows control of the table portion of the CRB * - * logic via software. Control operations from this register have * - * priority over all incoming Crosstalk or BTE requests. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iccr_u { - bdrkreg_t ii_iccr_regval; - struct { - bdrkreg_t i_crb_num : 4; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_cmd : 8; - bdrkreg_t i_pending : 1; - bdrkreg_t i_rsvd : 47; - } ii_iccr_fld_s; -} ii_iccr_u_t; - -#else - -typedef union ii_iccr_u { - bdrkreg_t ii_iccr_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_pending : 1; - bdrkreg_t i_cmd : 8; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_crb_num : 4; - } ii_iccr_fld_s; -} ii_iccr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the maximum timeout value to be programmed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icto_u { - bdrkreg_t ii_icto_regval; - struct { - bdrkreg_t i_timeout : 8; - bdrkreg_t i_rsvd : 56; - } ii_icto_fld_s; -} ii_icto_u_t; - -#else - -typedef union ii_icto_u { - bdrkreg_t ii_icto_regval; - struct { - bdrkreg_t i_rsvd : 56; - bdrkreg_t i_timeout : 8; - } ii_icto_fld_s; -} ii_icto_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the timeout prescalar to be programmed. An * - * internal counter is associated with this register. When the * - * internal counter reaches the value of the PRESCALE field, the * - * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT] * - * field). The internal counter resets to zero, and then continues * - * counting. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ictp_u { - bdrkreg_t ii_ictp_regval; - struct { - bdrkreg_t i_prescale : 24; - bdrkreg_t i_rsvd : 40; - } ii_ictp_fld_s; -} ii_ictp_u_t; - -#else - -typedef union ii_ictp_u { - bdrkreg_t ii_ictp_regval; - struct { - bdrkreg_t i_rsvd : 40; - bdrkreg_t i_prescale : 24; - } ii_ictp_fld_s; -} ii_ictp_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * The CRB Entry registers can be conceptualized as rows and columns * - * (illustrated in the table above). Each row contains the 4 * - * registers required for a single CRB Entry. The first doubleword * - * (column) for each entry is labeled A, and the second doubleword * - * (higher address) is labeled B, the third doubleword is labeled C, * - * and the fourth doubleword is labeled D. All CRB entries have their * - * addresses on a quarter cacheline aligned boundary. * - * Upon reset, only the following fields are initialized: valid * - * (VLD), priority count, timeout, timeout valid, and context valid. * - * All other bits should be cleared by software before use (after * - * recovering any potential error state from before the reset). * - * The following four tables summarize the format for the four * - * registers that are used for each ICRB# Entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_a_u { - bdrkreg_t ii_icrb0_a_regval; - struct { - bdrkreg_t ia_iow : 1; - bdrkreg_t ia_vld : 1; - bdrkreg_t ia_addr : 38; - bdrkreg_t ia_tnum : 5; - bdrkreg_t ia_sidn : 4; - bdrkreg_t ia_xt_err : 1; - bdrkreg_t ia_mark : 1; - bdrkreg_t ia_ln_uce : 1; - bdrkreg_t ia_errcode : 3; - bdrkreg_t ia_error : 1; - bdrkreg_t ia_stall__bte_1 : 1; - bdrkreg_t ia_stall__bte_0 : 1; - bdrkreg_t ia_rsvd : 6; - } ii_icrb0_a_fld_s; -} ii_icrb0_a_u_t; - -#else - -typedef union ii_icrb0_a_u { - bdrkreg_t ii_icrb0_a_regval; - struct { - bdrkreg_t ia_rsvd : 6; - bdrkreg_t ia_stall__bte_0 : 1; - bdrkreg_t ia_stall__bte_1 : 1; - bdrkreg_t ia_error : 1; - bdrkreg_t ia_errcode : 3; - bdrkreg_t ia_ln_uce : 1; - bdrkreg_t ia_mark : 1; - bdrkreg_t ia_xt_err : 1; - bdrkreg_t ia_sidn : 4; - bdrkreg_t ia_tnum : 5; - bdrkreg_t ia_addr : 38; - bdrkreg_t ia_vld : 1; - bdrkreg_t ia_iow : 1; - } ii_icrb0_a_fld_s; -} ii_icrb0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_b_u { - bdrkreg_t ii_icrb0_b_regval; - struct { - bdrkreg_t ib_stall__intr : 1; - bdrkreg_t ib_stall_ib : 1; - bdrkreg_t ib_intvn : 1; - bdrkreg_t ib_wb : 1; - bdrkreg_t ib_hold : 1; - bdrkreg_t ib_ack : 1; - bdrkreg_t ib_resp : 1; - bdrkreg_t ib_ack_cnt : 11; - bdrkreg_t ib_rsvd_1 : 7; - bdrkreg_t ib_exc : 5; - bdrkreg_t ib_init : 3; - bdrkreg_t ib_imsg : 8; - bdrkreg_t ib_imsgtype : 2; - bdrkreg_t ib_use_old : 1; - bdrkreg_t ib_source : 12; - bdrkreg_t ib_size : 2; - bdrkreg_t ib_ct : 1; - bdrkreg_t ib_bte_num : 1; - bdrkreg_t ib_rsvd : 4; - } ii_icrb0_b_fld_s; -} ii_icrb0_b_u_t; - -#else - -typedef union ii_icrb0_b_u { - bdrkreg_t ii_icrb0_b_regval; - struct { - bdrkreg_t ib_rsvd : 4; - bdrkreg_t ib_bte_num : 1; - bdrkreg_t ib_ct : 1; - bdrkreg_t ib_size : 2; - bdrkreg_t ib_source : 12; - bdrkreg_t ib_use_old : 1; - bdrkreg_t ib_imsgtype : 2; - bdrkreg_t ib_imsg : 8; - bdrkreg_t ib_init : 3; - bdrkreg_t ib_exc : 5; - bdrkreg_t ib_rsvd_1 : 7; - bdrkreg_t ib_ack_cnt : 11; - bdrkreg_t ib_resp : 1; - bdrkreg_t ib_ack : 1; - bdrkreg_t ib_hold : 1; - bdrkreg_t ib_wb : 1; - bdrkreg_t ib_intvn : 1; - bdrkreg_t ib_stall_ib : 1; - bdrkreg_t ib_stall__intr : 1; - } ii_icrb0_b_fld_s; -} ii_icrb0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_c_u { - bdrkreg_t ii_icrb0_c_regval; - struct { - bdrkreg_t ic_gbr : 1; - bdrkreg_t ic_resprqd : 1; - bdrkreg_t ic_bo : 1; - bdrkreg_t ic_suppl : 12; - bdrkreg_t ic_pa_be : 34; - bdrkreg_t ic_bte_op : 1; - bdrkreg_t ic_pr_psc : 4; - bdrkreg_t ic_pr_cnt : 4; - bdrkreg_t ic_sleep : 1; - bdrkreg_t ic_rsvd : 5; - } ii_icrb0_c_fld_s; -} ii_icrb0_c_u_t; - -#else - -typedef union ii_icrb0_c_u { - bdrkreg_t ii_icrb0_c_regval; - struct { - bdrkreg_t ic_rsvd : 5; - bdrkreg_t ic_sleep : 1; - bdrkreg_t ic_pr_cnt : 4; - bdrkreg_t ic_pr_psc : 4; - bdrkreg_t ic_bte_op : 1; - bdrkreg_t ic_pa_be : 34; - bdrkreg_t ic_suppl : 12; - bdrkreg_t ic_bo : 1; - bdrkreg_t ic_resprqd : 1; - bdrkreg_t ic_gbr : 1; - } ii_icrb0_c_fld_s; -} ii_icrb0_c_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_d_u { - bdrkreg_t ii_icrb0_d_regval; - struct { - bdrkreg_t id_timeout : 8; - bdrkreg_t id_context : 15; - bdrkreg_t id_rsvd_1 : 1; - bdrkreg_t id_tvld : 1; - bdrkreg_t id_cvld : 1; - bdrkreg_t id_rsvd : 38; - } ii_icrb0_d_fld_s; -} ii_icrb0_d_u_t; - -#else - -typedef union ii_icrb0_d_u { - bdrkreg_t ii_icrb0_d_regval; - struct { - bdrkreg_t id_rsvd : 38; - bdrkreg_t id_cvld : 1; - bdrkreg_t id_tvld : 1; - bdrkreg_t id_rsvd_1 : 1; - bdrkreg_t id_context : 15; - bdrkreg_t id_timeout : 8; - } ii_icrb0_d_fld_s; -} ii_icrb0_d_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the lower 64 bits of the header of the * - * spurious message captured by II. Valid when the SP_MSG bit in ICMR * - * register is set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icsml_u { - bdrkreg_t ii_icsml_regval; - struct { - bdrkreg_t i_tt_addr : 38; - bdrkreg_t i_tt_ack_cnt : 11; - bdrkreg_t i_newsuppl_ex : 11; - bdrkreg_t i_reserved : 3; - bdrkreg_t i_overflow : 1; - } ii_icsml_fld_s; -} ii_icsml_u_t; - -#else - -typedef union ii_icsml_u { - bdrkreg_t ii_icsml_regval; - struct { - bdrkreg_t i_overflow : 1; - bdrkreg_t i_reserved : 3; - bdrkreg_t i_newsuppl_ex : 11; - bdrkreg_t i_tt_ack_cnt : 11; - bdrkreg_t i_tt_addr : 38; - } ii_icsml_fld_s; -} ii_icsml_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the microscopic state, all the inputs to * - * the protocol table, captured with the spurious message. Valid when * - * the SP_MSG bit in the ICMR register is set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icsmh_u { - bdrkreg_t ii_icsmh_regval; - struct { - bdrkreg_t i_tt_vld : 1; - bdrkreg_t i_xerr : 1; - bdrkreg_t i_ft_cwact_o : 1; - bdrkreg_t i_ft_wact_o : 1; - bdrkreg_t i_ft_active_o : 1; - bdrkreg_t i_sync : 1; - bdrkreg_t i_mnusg : 1; - bdrkreg_t i_mnusz : 1; - bdrkreg_t i_plusz : 1; - bdrkreg_t i_plusg : 1; - bdrkreg_t i_tt_exc : 5; - bdrkreg_t i_tt_wb : 1; - bdrkreg_t i_tt_hold : 1; - bdrkreg_t i_tt_ack : 1; - bdrkreg_t i_tt_resp : 1; - bdrkreg_t i_tt_intvn : 1; - bdrkreg_t i_g_stall_bte1 : 1; - bdrkreg_t i_g_stall_bte0 : 1; - bdrkreg_t i_g_stall_il : 1; - bdrkreg_t i_g_stall_ib : 1; - bdrkreg_t i_tt_imsg : 8; - bdrkreg_t i_tt_imsgtype : 2; - bdrkreg_t i_tt_use_old : 1; - bdrkreg_t i_tt_respreqd : 1; - bdrkreg_t i_tt_bte_num : 1; - bdrkreg_t i_cbn : 1; - bdrkreg_t i_match : 1; - bdrkreg_t i_rpcnt_lt_34 : 1; - bdrkreg_t i_rpcnt_ge_34 : 1; - bdrkreg_t i_rpcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_18 : 1; - bdrkreg_t i_rpcnt_lt_2 : 1; - bdrkreg_t i_rpcnt_ge_2 : 1; - bdrkreg_t i_rqcnt_lt_18 : 1; - bdrkreg_t i_rqcnt_ge_18 : 1; - bdrkreg_t i_rqcnt_lt_2 : 1; - bdrkreg_t i_rqcnt_ge_2 : 1; - bdrkreg_t i_tt_device : 7; - bdrkreg_t i_tt_init : 3; - bdrkreg_t i_reserved : 5; - } ii_icsmh_fld_s; -} ii_icsmh_u_t; - -#else - -typedef union ii_icsmh_u { - bdrkreg_t ii_icsmh_regval; - struct { - bdrkreg_t i_reserved : 5; - bdrkreg_t i_tt_init : 3; - bdrkreg_t i_tt_device : 7; - bdrkreg_t i_rqcnt_ge_2 : 1; - bdrkreg_t i_rqcnt_lt_2 : 1; - bdrkreg_t i_rqcnt_ge_18 : 1; - bdrkreg_t i_rqcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_2 : 1; - bdrkreg_t i_rpcnt_lt_2 : 1; - bdrkreg_t i_rpcnt_ge_18 : 1; - bdrkreg_t i_rpcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_34 : 1; - bdrkreg_t i_rpcnt_lt_34 : 1; - bdrkreg_t i_match : 1; - bdrkreg_t i_cbn : 1; - bdrkreg_t i_tt_bte_num : 1; - bdrkreg_t i_tt_respreqd : 1; - bdrkreg_t i_tt_use_old : 1; - bdrkreg_t i_tt_imsgtype : 2; - bdrkreg_t i_tt_imsg : 8; - bdrkreg_t i_g_stall_ib : 1; - bdrkreg_t i_g_stall_il : 1; - bdrkreg_t i_g_stall_bte0 : 1; - bdrkreg_t i_g_stall_bte1 : 1; - bdrkreg_t i_tt_intvn : 1; - bdrkreg_t i_tt_resp : 1; - bdrkreg_t i_tt_ack : 1; - bdrkreg_t i_tt_hold : 1; - bdrkreg_t i_tt_wb : 1; - bdrkreg_t i_tt_exc : 5; - bdrkreg_t i_plusg : 1; - bdrkreg_t i_plusz : 1; - bdrkreg_t i_mnusz : 1; - bdrkreg_t i_mnusg : 1; - bdrkreg_t i_sync : 1; - bdrkreg_t i_ft_active_o : 1; - bdrkreg_t i_ft_wact_o : 1; - bdrkreg_t i_ft_cwact_o : 1; - bdrkreg_t i_xerr : 1; - bdrkreg_t i_tt_vld : 1; - } ii_icsmh_fld_s; -} ii_icsmh_u_t; - -#endif - - -/************************************************************************ - * * - * The Bedrock DEBUG unit provides a 3-bit selection signal to the * - * II unit, thus allowing a choice of one set of debug signal outputs * - * from a menu of 8 options. Each option is limited to 32 bits in * - * size. There are more signals of interest than can be accommodated * - * in this 8*32 framework, so the IDBSS register has been defined to * - * extend the range of choices available. For each menu option * - * available to the DEBUG unit, the II provides a "submenu" of * - * several options. The value of the SUBMENU field in the IDBSS * - * register selects the desired submenu. Hence, the particular debug * - * signals provided by the II are determined by the 3-bit selection * - * signal from the DEBUG unit and the value of the SUBMENU field * - * within the IDBSS register. For a detailed description of the * - * available menus and submenus for II debug signals, refer to the * - * documentation in ii_interface.doc.. * - * * - ************************************************************************/ - - - - -#ifdef LIITLE_ENDIAN - -typedef union ii_idbss_u { - bdrkreg_t ii_idbss_regval; - struct { - bdrkreg_t i_submenu : 3; - bdrkreg_t i_rsvd : 61; - } ii_idbss_fld_s; -} ii_idbss_u_t; - -#else - -typedef union ii_idbss_u { - bdrkreg_t ii_idbss_regval; - struct { - bdrkreg_t i_rsvd : 61; - bdrkreg_t i_submenu : 3; - } ii_idbss_fld_s; -} ii_idbss_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - - - - -#ifdef LIITLE_ENDIAN - -typedef union ii_ibls0_u { - bdrkreg_t ii_ibls0_regval; - struct { - bdrkreg_t i_length : 16; - bdrkreg_t i_error : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd : 43; - } ii_ibls0_fld_s; -} ii_ibls0_u_t; - -#else - -typedef union ii_ibls0_u { - bdrkreg_t ii_ibls0_regval; - struct { - bdrkreg_t i_rsvd : 43; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_error : 1; - bdrkreg_t i_length : 16; - } ii_ibls0_fld_s; -} ii_ibls0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibsa0_u { - bdrkreg_t ii_ibsa0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibsa0_fld_s; -} ii_ibsa0_u_t; - -#else - -typedef union ii_ibsa0_u { - bdrkreg_t ii_ibsa0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibsa0_fld_s; -} ii_ibsa0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibda0_u { - bdrkreg_t ii_ibda0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibda0_fld_s; -} ii_ibda0_u_t; - -#else - -typedef union ii_ibda0_u { - bdrkreg_t ii_ibda0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibda0_fld_s; -} ii_ibda0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibct0_u { - bdrkreg_t ii_ibct0_regval; - struct { - bdrkreg_t i_zerofill : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibct0_fld_s; -} ii_ibct0_u_t; - -#else - -typedef union ii_ibct0_u { - bdrkreg_t ii_ibct0_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_zerofill : 1; - } ii_ibct0_fld_s; -} ii_ibct0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibna0_u { - bdrkreg_t ii_ibna0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibna0_fld_s; -} ii_ibna0_u_t; - -#else - -typedef union ii_ibna0_u { - bdrkreg_t ii_ibna0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibna0_fld_s; -} ii_ibna0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibia0_u { - bdrkreg_t ii_ibia0_regval; - struct { - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd : 41; - } ii_ibia0_fld_s; -} ii_ibia0_u_t; - -#else - -typedef union ii_ibia0_u { - bdrkreg_t ii_ibia0_regval; - struct { - bdrkreg_t i_rsvd : 41; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_pi_id : 1; - } ii_ibia0_fld_s; -} ii_ibia0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibls1_u { - bdrkreg_t ii_ibls1_regval; - struct { - bdrkreg_t i_length : 16; - bdrkreg_t i_error : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd : 43; - } ii_ibls1_fld_s; -} ii_ibls1_u_t; - -#else - -typedef union ii_ibls1_u { - bdrkreg_t ii_ibls1_regval; - struct { - bdrkreg_t i_rsvd : 43; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_error : 1; - bdrkreg_t i_length : 16; - } ii_ibls1_fld_s; -} ii_ibls1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibsa1_u { - bdrkreg_t ii_ibsa1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibsa1_fld_s; -} ii_ibsa1_u_t; - -#else - -typedef union ii_ibsa1_u { - bdrkreg_t ii_ibsa1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibsa1_fld_s; -} ii_ibsa1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibda1_u { - bdrkreg_t ii_ibda1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibda1_fld_s; -} ii_ibda1_u_t; - -#else - -typedef union ii_ibda1_u { - bdrkreg_t ii_ibda1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibda1_fld_s; -} ii_ibda1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibct1_u { - bdrkreg_t ii_ibct1_regval; - struct { - bdrkreg_t i_zerofill : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibct1_fld_s; -} ii_ibct1_u_t; - -#else - -typedef union ii_ibct1_u { - bdrkreg_t ii_ibct1_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_zerofill : 1; - } ii_ibct1_fld_s; -} ii_ibct1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibna1_u { - bdrkreg_t ii_ibna1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibna1_fld_s; -} ii_ibna1_u_t; - -#else - -typedef union ii_ibna1_u { - bdrkreg_t ii_ibna1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibna1_fld_s; -} ii_ibna1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibia1_u { - bdrkreg_t ii_ibia1_regval; - struct { - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd : 41; - } ii_ibia1_fld_s; -} ii_ibia1_u_t; - -#else - -typedef union ii_ibia1_u { - bdrkreg_t ii_ibia1_regval; - struct { - bdrkreg_t i_rsvd : 41; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_pi_id : 1; - } ii_ibia1_fld_s; -} ii_ibia1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register defines the resources that feed information into * - * the two performance counters located in the IO Performance * - * Profiling Register. There are 17 different quantities that can be * - * measured. Given these 17 different options, the two performance * - * counters have 15 of them in common; menu selections 0 through 0xE * - * are identical for each performance counter. As for the other two * - * options, one is available from one performance counter and the * - * other is available from the other performance counter. Hence, the * - * II supports all 17*16=272 possible combinations of quantities to * - * measure. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipcr_u { - bdrkreg_t ii_ipcr_regval; - struct { - bdrkreg_t i_ippr0_c : 4; - bdrkreg_t i_ippr1_c : 4; - bdrkreg_t i_icct : 8; - bdrkreg_t i_rsvd : 48; - } ii_ipcr_fld_s; -} ii_ipcr_u_t; - -#else - -typedef union ii_ipcr_u { - bdrkreg_t ii_ipcr_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_icct : 8; - bdrkreg_t i_ippr1_c : 4; - bdrkreg_t i_ippr0_c : 4; - } ii_ipcr_fld_s; -} ii_ipcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ippr_u { - bdrkreg_t ii_ippr_regval; - struct { - bdrkreg_t i_ippr0 : 32; - bdrkreg_t i_ippr1 : 32; - } ii_ippr_fld_s; -} ii_ippr_u_t; - -#else - -typedef union ii_ippr_u { - bdrkreg_t ii_ippr_regval; - struct { - bdrkreg_t i_ippr1 : 32; - bdrkreg_t i_ippr0 : 32; - } ii_ippr_fld_s; -} ii_ippr_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines which were not formed into structures are * - * probably indentical to another register, and the name of the * - * register is provided against each of these registers. This * - * information needs to be checked carefully * - * * - * IIO_ICRB1_A IIO_ICRB0_A * - * IIO_ICRB1_B IIO_ICRB0_B * - * IIO_ICRB1_C IIO_ICRB0_C * - * IIO_ICRB1_D IIO_ICRB0_D * - * IIO_ICRB2_A IIO_ICRB0_A * - * IIO_ICRB2_B IIO_ICRB0_B * - * IIO_ICRB2_C IIO_ICRB0_C * - * IIO_ICRB2_D IIO_ICRB0_D * - * IIO_ICRB3_A IIO_ICRB0_A * - * IIO_ICRB3_B IIO_ICRB0_B * - * IIO_ICRB3_C IIO_ICRB0_C * - * IIO_ICRB3_D IIO_ICRB0_D * - * IIO_ICRB4_A IIO_ICRB0_A * - * IIO_ICRB4_B IIO_ICRB0_B * - * IIO_ICRB4_C IIO_ICRB0_C * - * IIO_ICRB4_D IIO_ICRB0_D * - * IIO_ICRB5_A IIO_ICRB0_A * - * IIO_ICRB5_B IIO_ICRB0_B * - * IIO_ICRB5_C IIO_ICRB0_C * - * IIO_ICRB5_D IIO_ICRB0_D * - * IIO_ICRB6_A IIO_ICRB0_A * - * IIO_ICRB6_B IIO_ICRB0_B * - * IIO_ICRB6_C IIO_ICRB0_C * - * IIO_ICRB6_D IIO_ICRB0_D * - * IIO_ICRB7_A IIO_ICRB0_A * - * IIO_ICRB7_B IIO_ICRB0_B * - * IIO_ICRB7_C IIO_ICRB0_C * - * IIO_ICRB7_D IIO_ICRB0_D * - * IIO_ICRB8_A IIO_ICRB0_A * - * IIO_ICRB8_B IIO_ICRB0_B * - * IIO_ICRB8_C IIO_ICRB0_C * - * IIO_ICRB8_D IIO_ICRB0_D * - * IIO_ICRB9_A IIO_ICRB0_A * - * IIO_ICRB9_B IIO_ICRB0_B * - * IIO_ICRB9_C IIO_ICRB0_C * - * IIO_ICRB9_D IIO_ICRB0_D * - * IIO_ICRBA_A IIO_ICRB0_A * - * IIO_ICRBA_B IIO_ICRB0_B * - * IIO_ICRBA_C IIO_ICRB0_C * - * IIO_ICRBA_D IIO_ICRB0_D * - * IIO_ICRBB_A IIO_ICRB0_A * - * IIO_ICRBB_B IIO_ICRB0_B * - * IIO_ICRBB_C IIO_ICRB0_C * - * IIO_ICRBB_D IIO_ICRB0_D * - * IIO_ICRBC_A IIO_ICRB0_A * - * IIO_ICRBC_B IIO_ICRB0_B * - * IIO_ICRBC_C IIO_ICRB0_C * - * IIO_ICRBC_D IIO_ICRB0_D * - * IIO_ICRBD_A IIO_ICRB0_A * - * IIO_ICRBD_B IIO_ICRB0_B * - * IIO_ICRBD_C IIO_ICRB0_C * - * IIO_ICRBD_D IIO_ICRB0_D * - * IIO_ICRBE_A IIO_ICRB0_A * - * IIO_ICRBE_B IIO_ICRB0_B * - * IIO_ICRBE_C IIO_ICRB0_C * - * IIO_ICRBE_D IIO_ICRB0_D * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBIO_H */ diff --git a/include/asm-ia64/sn/sn1/hubio_next.h b/include/asm-ia64/sn/sn1/hubio_next.h deleted file mode 100644 index 037d3bae307..00000000000 --- a/include/asm-ia64/sn/sn1/hubio_next.h +++ /dev/null @@ -1,762 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBIO_NEXT_H -#define _ASM_IA64_SN_SN1_HUBIO_NEXT_H - -/* - * Slightly friendlier names for some common registers. - */ -#define IIO_WIDGET IIO_WID /* Widget identification */ -#define IIO_WIDGET_STAT IIO_WSTAT /* Widget status register */ -#define IIO_WIDGET_CTRL IIO_WCR /* Widget control register */ -#define IIO_PROTECT IIO_ILAPR /* IO interface protection */ -#define IIO_PROTECT_OVRRD IIO_ILAPO /* IO protect override */ -#define IIO_OUTWIDGET_ACCESS IIO_IOWA /* Outbound widget access */ -#define IIO_INWIDGET_ACCESS IIO_IIWA /* Inbound widget access */ -#define IIO_INDEV_ERR_MASK IIO_IIDEM /* Inbound device error mask */ -#define IIO_LLP_CSR IIO_ILCSR /* LLP control and status */ -#define IIO_LLP_LOG IIO_ILLR /* LLP log */ -#define IIO_XTALKCC_TOUT IIO_IXCC /* Xtalk credit count timeout*/ -#define IIO_XTALKTT_TOUT IIO_IXTT /* Xtalk tail timeout */ -#define IIO_IO_ERR_CLR IIO_IECLR /* IO error clear */ -#define IIO_IGFX_0 IIO_IGFX0 -#define IIO_IGFX_1 IIO_IGFX1 -#define IIO_IBCT_0 IIO_IBCT0 -#define IIO_IBCT_1 IIO_IBCT1 -#define IIO_IBLS_0 IIO_IBLS0 -#define IIO_IBLS_1 IIO_IBLS1 -#define IIO_IBSA_0 IIO_IBSA0 -#define IIO_IBSA_1 IIO_IBSA1 -#define IIO_IBDA_0 IIO_IBDA0 -#define IIO_IBDA_1 IIO_IBDA1 -#define IIO_IBNA_0 IIO_IBNA0 -#define IIO_IBNA_1 IIO_IBNA1 -#define IIO_IBIA_0 IIO_IBIA0 -#define IIO_IBIA_1 IIO_IBIA1 -#define IIO_IOPRB_0 IIO_IPRB0 -#define IIO_PRTE_0 IIO_IPRTE0 /* PIO Read address table entry 0 */ -#define IIO_PRTE(_x) (IIO_PRTE_0 + (8 * (_x))) -#define IIO_NUM_IPRBS (9) -#define IIO_WIDPRTE(x) IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */ - -#define IIO_LLP_CSR_IS_UP 0x00002000 -#define IIO_LLP_CSR_LLP_STAT_MASK 0x00003000 -#define IIO_LLP_CSR_LLP_STAT_SHFT 12 - -#define IIO_LLP_CB_MAX 0xffff /* in ILLR CB_CNT, Max Check Bit errors */ -#define IIO_LLP_SN_MAX 0xffff /* in ILLR SN_CNT, Max Sequence Number errors */ - -/* key to IIO_PROTECT_OVRRD */ -#define IIO_PROTECT_OVRRD_KEY 0x53474972756c6573ull /* "SGIrules" */ - -/* BTE register names */ -#define IIO_BTE_STAT_0 IIO_IBLS_0 /* Also BTE length/status 0 */ -#define IIO_BTE_SRC_0 IIO_IBSA_0 /* Also BTE source address 0 */ -#define IIO_BTE_DEST_0 IIO_IBDA_0 /* Also BTE dest. address 0 */ -#define IIO_BTE_CTRL_0 IIO_IBCT_0 /* Also BTE control/terminate 0 */ -#define IIO_BTE_NOTIFY_0 IIO_IBNA_0 /* Also BTE notification 0 */ -#define IIO_BTE_INT_0 IIO_IBIA_0 /* Also BTE interrupt 0 */ -#define IIO_BTE_OFF_0 0 /* Base offset from BTE 0 regs. */ -#define IIO_BTE_OFF_1 (IIO_IBLS_1 - IIO_IBLS_0) /* Offset from base to BTE 1 */ - -/* BTE register offsets from base */ -#define BTEOFF_STAT 0 -#define BTEOFF_SRC (IIO_BTE_SRC_0 - IIO_BTE_STAT_0) -#define BTEOFF_DEST (IIO_BTE_DEST_0 - IIO_BTE_STAT_0) -#define BTEOFF_CTRL (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0) -#define BTEOFF_NOTIFY (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0) -#define BTEOFF_INT (IIO_BTE_INT_0 - IIO_BTE_STAT_0) - - -/* names used in hub_diags.c; carried over from SN0 */ -#define IIO_BASE_BTE0 IIO_IBLS_0 -#define IIO_BASE_BTE1 IIO_IBLS_1 - -/* - * Macro which takes the widget number, and returns the - * IO PRB address of that widget. - * value _x is expected to be a widget number in the range - * 0, 8 - 0xF - */ -#define IIO_IOPRB(_x) (IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \ - (_x) : \ - (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) ) - - -/* GFX Flow Control Node/Widget Register */ -#define IIO_IGFX_W_NUM_BITS 4 /* size of widget num field */ -#define IIO_IGFX_W_NUM_MASK ((1<> IIO_WSTAT_TXRETRY_SHFT) & \ - IIO_WSTAT_TXRETRY_MASK) - -/* Number of II perf. counters we can multiplex at once */ - -#define IO_PERF_SETS 32 - -#if __KERNEL__ -#ifndef __ASSEMBLY__ -/* XXX moved over from SN/SN0/hubio.h -- each should be checked for SN1 */ -#include -#include -#include -#include - -/* Bit for the widget in inbound access register */ -#define IIO_IIWA_WIDGET(_w) ((uint64_t)(1ULL << _w)) -/* Bit for the widget in outbound access register */ -#define IIO_IOWA_WIDGET(_w) ((uint64_t)(1ULL << _w)) - -/* NOTE: The following define assumes that we are going to get - * widget numbers from 8 thru F and the device numbers within - * widget from 0 thru 7. - */ -#define IIO_IIDEM_WIDGETDEV_MASK(w, d) ((uint64_t)(1ULL << (8 * ((w) - 8) + (d)))) - -/* IO Interrupt Destination Register */ -#define IIO_IIDSR_SENT_SHIFT 28 -#define IIO_IIDSR_SENT_MASK 0x10000000 -#define IIO_IIDSR_ENB_SHIFT 24 -#define IIO_IIDSR_ENB_MASK 0x01000000 -#define IIO_IIDSR_NODE_SHIFT 8 -#define IIO_IIDSR_NODE_MASK 0x0000ff00 -#define IIO_IIDSR_PI_ID_SHIFT 8 -#define IIO_IIDSR_PI_ID_MASK 0x00000010 -#define IIO_IIDSR_LVL_SHIFT 0 -#define IIO_IIDSR_LVL_MASK 0x0000007f - -/* Xtalk timeout threshhold register (IIO_IXTT) */ -#define IXTT_RRSP_TO_SHFT 55 /* read response timeout */ -#define IXTT_RRSP_TO_MASK (0x1FULL << IXTT_RRSP_TO_SHFT) -#define IXTT_RRSP_PS_SHFT 32 /* read responsed TO prescalar */ -#define IXTT_RRSP_PS_MASK (0x7FFFFFULL << IXTT_RRSP_PS_SHFT) -#define IXTT_TAIL_TO_SHFT 0 /* tail timeout counter threshold */ -#define IXTT_TAIL_TO_MASK (0x3FFFFFFULL << IXTT_TAIL_TO_SHFT) - -/* - * The IO LLP control status register and widget control register - */ - -#ifdef LITTLE_ENDIAN - -typedef union hubii_wcr_u { - uint64_t wcr_reg_value; - struct { - uint64_t wcr_widget_id: 4, /* LLP crossbar credit */ - wcr_tag_mode: 1, /* Tag mode */ - wcr_rsvd1: 8, /* Reserved */ - wcr_xbar_crd: 3, /* LLP crossbar credit */ - wcr_f_bad_pkt: 1, /* Force bad llp pkt enable */ - wcr_dir_con: 1, /* widget direct connect */ - wcr_e_thresh: 5, /* elasticity threshold */ - wcr_rsvd: 41; /* unused */ - } wcr_fields_s; -} hubii_wcr_t; - -#else - -typedef union hubii_wcr_u { - uint64_t wcr_reg_value; - struct { - uint64_t wcr_rsvd: 41, /* unused */ - wcr_e_thresh: 5, /* elasticity threshold */ - wcr_dir_con: 1, /* widget direct connect */ - wcr_f_bad_pkt: 1, /* Force bad llp pkt enable */ - wcr_xbar_crd: 3, /* LLP crossbar credit */ - wcr_rsvd1: 8, /* Reserved */ - wcr_tag_mode: 1, /* Tag mode */ - wcr_widget_id: 4; /* LLP crossbar credit */ - } wcr_fields_s; -} hubii_wcr_t; - -#endif - -#define iwcr_dir_con wcr_fields_s.wcr_dir_con - -/* The structures below are defined to extract and modify the ii -performance registers */ - -/* io_perf_sel allows the caller to specify what tests will be - performed */ -#ifdef LITTLE_ENDIAN - -typedef union io_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_ippr0 : 4, - perf_ippr1 : 4, - perf_icct : 8, - perf_rsvd : 48; - } perf_sel_bits; -} io_perf_sel_t; - -#else - -typedef union io_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_rsvd : 48, - perf_icct : 8, - perf_ippr1 : 4, - perf_ippr0 : 4; - } perf_sel_bits; -} io_perf_sel_t; - -#endif - -/* io_perf_cnt is to extract the count from the hub registers. Due to - hardware problems there is only one counter, not two. */ - -#ifdef LITTLE_ENDIAN - -typedef union io_perf_cnt { - uint64_t perf_cnt; - struct { - uint64_t perf_cnt : 20, - perf_rsvd2 : 12, - perf_rsvd1 : 32; - } perf_cnt_bits; - -} io_perf_cnt_t; - -#else - -typedef union io_perf_cnt { - uint64_t perf_cnt; - struct { - uint64_t perf_rsvd1 : 32, - perf_rsvd2 : 12, - perf_cnt : 20; - } perf_cnt_bits; - -} io_perf_cnt_t; - -#endif - -#ifdef LITTLE_ENDIAN - -typedef union iprte_a { - bdrkreg_t entry; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } iprte_fields; -} iprte_a_t; - -#else - -typedef union iprte_a { - bdrkreg_t entry; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } iprte_fields; -} iprte_a_t; - -#endif - -/* PIO MANAGEMENT */ -typedef struct hub_piomap_s *hub_piomap_t; - -extern hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags); /* defined in sys/pio.h */ - -extern void hub_piomap_free(hub_piomap_t hub_piomap); - -extern caddr_t -hub_piomap_addr(hub_piomap_t hub_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk addr */ - size_t byte_count); /* map this many bytes */ - -extern void -hub_piomap_done(hub_piomap_t hub_piomap); - -extern caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags); /* (currently unused) */ - -/* DMA MANAGEMENT */ -typedef struct hub_dmamap_s *hub_dmamap_t; - -extern hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for dev */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags); /* defined in dma.h */ - -extern void -hub_dmamap_free(hub_dmamap_t dmamap); - -extern iopaddr_t -hub_dmamap_addr( hub_dmamap_t dmamap, /* use mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count); /* map this many bytes */ - -extern alenlist_t -hub_dmamap_list( hub_dmamap_t dmamap, /* use mapping resources */ - alenlist_t alenlist, /* map this Addr/Length List */ - unsigned flags); - -extern void -hub_dmamap_done( hub_dmamap_t dmamap); /* done w/ mapping resources */ - -extern iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags); /* defined in dma.h */ - -extern alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system addr/length list */ - unsigned flags); /* defined in dma.h */ - -extern void -hub_dmamap_drain( hub_dmamap_t map); - -extern void -hub_dmaaddr_drain( devfs_handle_t vhdl, - paddr_t addr, - size_t bytes); - -extern void -hub_dmalist_drain( devfs_handle_t vhdl, - alenlist_t list); - - -/* INTERRUPT MANAGEMENT */ -typedef struct hub_intr_s *hub_intr_t; - -extern hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ - -extern hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ - -extern void -hub_intr_free(hub_intr_t intr_hdl); - -extern int -hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource hndl */ - xtalk_intr_setfunc_t setfunc, - /* func to set intr hw */ - void *setfunc_arg); /* arg to setfunc */ - -extern void -hub_intr_disconnect(hub_intr_t intr_hdl); - -extern devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl); - -/* CONFIGURATION MANAGEMENT */ - -extern void -hub_provider_startup(devfs_handle_t hub); - -extern void -hub_provider_shutdown(devfs_handle_t hub); - -#define HUB_PIO_CONVEYOR 0x1 /* PIO in conveyor belt mode */ -#define HUB_PIO_FIRE_N_FORGET 0x2 /* PIO in fire-and-forget mode */ - -/* Flags that make sense to hub_widget_flags_set */ -#define HUB_WIDGET_FLAGS ( \ - HUB_PIO_CONVEYOR | \ - HUB_PIO_FIRE_N_FORGET \ - ) - - -typedef int hub_widget_flags_t; - -/* Set the PIO mode for a widget. These two functions perform the - * same operation, but hub_device_flags_set() takes a hardware graph - * vertex while hub_widget_flags_set() takes a nasid and widget - * number. In most cases, hub_device_flags_set() should be used. - */ -extern int hub_widget_flags_set(nasid_t nasid, - xwidgetnum_t widget_num, - hub_widget_flags_t flags); - -/* Depending on the flags set take the appropriate actions */ -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); - - -/* Error Handling. */ -extern int hub_ioerror_handler(devfs_handle_t, int, int, struct io_error_s *); -extern int kl_ioerror_handler(cnodeid_t, cnodeid_t, cpuid_t, - int, paddr_t, caddr_t, ioerror_mode_t); -extern void hub_widget_reset(devfs_handle_t, xwidgetnum_t); -extern int hub_error_devenable(devfs_handle_t, int, int); -extern void hub_widgetdev_enable(devfs_handle_t, int); -extern void hub_widgetdev_shutdown(devfs_handle_t, int); -extern int hub_dma_enabled(devfs_handle_t); - -#endif /* __ASSEMBLY__ */ -#endif /* _KERNEL */ -#endif /* _ASM_IA64_SN_SN1_HUBIO_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hublb.h b/include/asm-ia64/sn/sn1/hublb.h deleted file mode 100644 index 60082cafac5..00000000000 --- a/include/asm-ia64/sn/sn1/hublb.h +++ /dev/null @@ -1,1607 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#ifndef _ASM_IA64_SN_SN1_HUBLB_H -#define _ASM_IA64_SN_SN1_HUBLB_H - - -#define LB_REV_ID 0x00600000 /* - * Bedrock Revision - * and ID - */ - - - -#define LB_CPU_PERMISSION 0x00604000 /* - * CPU PIO access - * permission bits - */ - - - -#define LB_CPU_PERM_OVRRD 0x00604008 /* - * CPU PIO access - * permission bit - * override - */ - - - -#define LB_IO_PERMISSION 0x00604010 /* - * IO PIO access - * permission bits - */ - - - -#define LB_SOFT_RESET 0x00604018 /* - * Soft reset the - * Bedrock chip - */ - - - -#define LB_REGION_PRESENT 0x00604020 /* - * Regions Present for - * Invalidates - */ - - - -#define LB_NODES_ABSENT 0x00604028 /* - * Nodes Absent for - * Invalidates - */ - - - -#define LB_MICROLAN_CTL 0x00604030 /* - * Microlan Control - * (NIC) - */ - - - -#define LB_ERROR_BITS 0x00604040 /* - * Local Block error - * bits - */ - - - -#define LB_ERROR_MASK_CLR 0x00604048 /* - * Bit mask write to - * clear error bits - */ - - - -#define LB_ERROR_HDR1 0x00604050 /* - * Source, Suppl and - * Cmd fields - */ - - - -#define LB_ERROR_HDR2 0x00604058 /* - * Address field from - * first error - */ - - - -#define LB_ERROR_DATA 0x00604060 /* - * Data flit (if any) - * from first error - */ - - - -#define LB_DEBUG_SELECT 0x00604100 /* - * Choice of debug - * signals from chip - */ - - - -#define LB_DEBUG_PINS 0x00604108 /* - * Value on the chip's - * debug pins - */ - - - -#define LB_RT_LOCAL_CTRL 0x00604200 /* - * Local generation of - * real-time clock - */ - - - -#define LB_RT_FILTER_CTRL 0x00604208 /* - * Control of - * filtering of global - * clock - */ - - - -#define LB_SCRATCH_REG0 0x00608000 /* Scratch Register 0 */ - - - -#define LB_SCRATCH_REG1 0x00608008 /* Scratch Register 1 */ - - - -#define LB_SCRATCH_REG2 0x00608010 /* Scratch Register 2 */ - - - -#define LB_SCRATCH_REG3 0x00608018 /* Scratch Register 3 */ - - - -#define LB_SCRATCH_REG4 0x00608020 /* Scratch Register 4 */ - - - -#define LB_SCRATCH_REG0_WZ 0x00608040 /* - * Scratch Register 0 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG1_WZ 0x00608048 /* - * Scratch Register 1 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG2_WZ 0x00608050 /* - * Scratch Register 2 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG3_RZ 0x00608058 /* - * Scratch Register 3 - * (RZ alias) - */ - - - -#define LB_SCRATCH_REG4_RZ 0x00608060 /* - * Scratch Register 4 - * (RZ alias) - */ - - - -#define LB_VECTOR_PARMS 0x0060C000 /* - * Vector PIO - * parameters - */ - - - -#define LB_VECTOR_ROUTE 0x0060C008 /* - * Vector PIO Vector - * Route - */ - - - -#define LB_VECTOR_DATA 0x0060C010 /* - * Vector PIO Write - * Data - */ - - - -#define LB_VECTOR_STATUS 0x0060C020 /* - * Vector PIO Return - * Status - */ - - - -#define LB_VECTOR_RETURN 0x0060C028 /* - * Vector PIO Return - * Route - */ - - - -#define LB_VECTOR_READ_DATA 0x0060C030 /* - * Vector PIO Read - * Data - */ - - - -#define LB_VECTOR_STATUS_CLEAR 0x0060C038 /* - * Clear Vector PIO - * Return Status - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register contains information that allows * - * exploratory software to probe for chip type. This is also the * - * register that sets this node's ID and the size of each region * - * (which affects the maximum possible system size). IBM assigns the * - * values for the REVISION, PART_NUMBER and MANUFACTURER fields, in * - * accordance with the IEEE 1149.1 standard; SGI is not at liberty to * - * unilaterally change the values of these fields. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rev_id_u { - bdrkreg_t lb_rev_id_regval; - struct { - bdrkreg_t ri_reserved_2 : 1; - bdrkreg_t ri_manufacturer : 11; - bdrkreg_t ri_part_number : 16; - bdrkreg_t ri_revision : 4; - bdrkreg_t ri_node_id : 8; - bdrkreg_t ri_reserved_1 : 6; - bdrkreg_t ri_region_size : 2; - bdrkreg_t ri_reserved : 16; - } lb_rev_id_fld_s; -} lb_rev_id_u_t; - -#else - -typedef union lb_rev_id_u { - bdrkreg_t lb_rev_id_regval; - struct { - bdrkreg_t ri_reserved : 16; - bdrkreg_t ri_region_size : 2; - bdrkreg_t ri_reserved_1 : 6; - bdrkreg_t ri_node_id : 8; - bdrkreg_t ri_revision : 4; - bdrkreg_t ri_part_number : 16; - bdrkreg_t ri_manufacturer : 11; - bdrkreg_t ri_reserved_2 : 1; - } lb_rev_id_fld_s; -} lb_rev_id_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the PI-access-rights bit-vector for the * - * LB, NI, XB and MD portions of the Bedrock local register space. If * - * a bit in the bit-vector is set, the region corresponding to that * - * bit has read/write permission on the LB, NI, XB and MD local * - * registers. If the bit is clear, that region has no write access to * - * the local registers and no read access if the read will cause any * - * state change. If a write or a read with side effects is attempted * - * by a PI in a region for which access is restricted, the LB will * - * not perform the operation and will send back a reply which * - * indicates an error. * - * * - ************************************************************************/ - - - - -typedef union lb_cpu_permission_u { - bdrkreg_t lb_cpu_permission_regval; - struct { - bdrkreg_t cp_cpu_access : 64; - } lb_cpu_permission_fld_s; -} lb_cpu_permission_u_t; - - - - -/************************************************************************ - * * - * A write to this register of the 64-bit value "SGIrules" will * - * cause the bit in the LB_CPU_PROTECT register corresponding to the * - * region of the requester to be set. * - * * - ************************************************************************/ - - - - -typedef union lb_cpu_perm_ovrrd_u { - bdrkreg_t lb_cpu_perm_ovrrd_regval; - struct { - bdrkreg_t cpo_cpu_perm_ovr : 64; - } lb_cpu_perm_ovrrd_fld_s; -} lb_cpu_perm_ovrrd_u_t; - - - - -/************************************************************************ - * * - * This register contains the II-access-rights bit-vector for the * - * LB, NI, XB and MD portions of the Bedrock local register space. If * - * a bit in the bit-vector is set, the region corresponding to that * - * bit has read/write permission on the LB, NI, XB and MD local * - * registers. If the bit is clear, then that region has no write * - * access to the local registers and no read access if the read * - * results in any state change. If a write or a read with side * - * effects is attempted by an II in a region for which access is * - * restricted, the LB will not perform the operation and will send * - * back a reply which indicates an error. * - * * - ************************************************************************/ - - - - -typedef union lb_io_permission_u { - bdrkreg_t lb_io_permission_regval; - struct { - bdrkreg_t ip_io_permission : 64; - } lb_io_permission_fld_s; -} lb_io_permission_u_t; - - - - -/************************************************************************ - * * - * A write to this bit resets the Bedrock chip with a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_soft_reset_u { - bdrkreg_t lb_soft_reset_regval; - struct { - bdrkreg_t sr_soft_reset : 1; - bdrkreg_t sr_reserved : 63; - } lb_soft_reset_fld_s; -} lb_soft_reset_u_t; - -#else - -typedef union lb_soft_reset_u { - bdrkreg_t lb_soft_reset_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_soft_reset : 1; - } lb_soft_reset_fld_s; -} lb_soft_reset_u_t; - -#endif - - - -/************************************************************************ - * * - * This register indicates which regions are present and capable of * - * receiving an invalidate (INVAL) request. The LB samples this * - * register at the start of processing each LINVAL. When an LINVAL * - * indicates that a particular PI unit might hold a shared copy of a * - * cache block but this PI is in a region which is not present (i.e., * - * its bit in LB_REGION_PRESENT is clear), then the LB sends an IVACK * - * reply packet on behalf of this PI. The REGION_SIZE field in the * - * LB_REV_ID register determines the number of nodes per region (and * - * hence, the number of PI units which share a common bit in the * - * LB_REGION_PRESENT register). * - * * - ************************************************************************/ - - - - -typedef union lb_region_present_u { - bdrkreg_t lb_region_present_regval; - struct { - bdrkreg_t rp_present_bits : 64; - } lb_region_present_fld_s; -} lb_region_present_u_t; - - - - -/************************************************************************ - * * - * Description: This register indicates which nodes are absent and * - * not capable of receiving an invalidate (INVAL) request. The LB * - * samples this register at the start of processing each LINVAL. When * - * an LINVAL indicates that a particular PI unit might hold a shared * - * copy of a cache block but this PI unit's node is not present * - * (i.e., its node ID is listed in the LB_NODES_ABSENT register), * - * then the LB sends an IVACK reply packet on behalf of this PI. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_nodes_absent_u { - bdrkreg_t lb_nodes_absent_regval; - struct { - bdrkreg_t na_node_0 : 8; - bdrkreg_t na_reserved_3 : 7; - bdrkreg_t na_node_0_valid : 1; - bdrkreg_t na_node_1 : 8; - bdrkreg_t na_reserved_2 : 7; - bdrkreg_t na_node_1_valid : 1; - bdrkreg_t na_node_2 : 8; - bdrkreg_t na_reserved_1 : 7; - bdrkreg_t na_node_2_valid : 1; - bdrkreg_t na_node_3 : 8; - bdrkreg_t na_reserved : 7; - bdrkreg_t na_node_3_valid : 1; - } lb_nodes_absent_fld_s; -} lb_nodes_absent_u_t; - -#else - -typedef union lb_nodes_absent_u { - bdrkreg_t lb_nodes_absent_regval; - struct { - bdrkreg_t na_node_3_valid : 1; - bdrkreg_t na_reserved : 7; - bdrkreg_t na_node_3 : 8; - bdrkreg_t na_node_2_valid : 1; - bdrkreg_t na_reserved_1 : 7; - bdrkreg_t na_node_2 : 8; - bdrkreg_t na_node_1_valid : 1; - bdrkreg_t na_reserved_2 : 7; - bdrkreg_t na_node_1 : 8; - bdrkreg_t na_node_0_valid : 1; - bdrkreg_t na_reserved_3 : 7; - bdrkreg_t na_node_0 : 8; - } lb_nodes_absent_fld_s; -} lb_nodes_absent_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides access to the Number-In-a-Can add-only * - * serial PROM that is used to store node board serial number and * - * configuration information. (Refer to NIC datasheet Dallas 1990A * - * that is viewable at * - * URL::http://www.dalsemi.com/DocControl/PDFs/pdfindex.html). Data * - * comes from this interface LSB first. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_microlan_ctl_u { - bdrkreg_t lb_microlan_ctl_regval; - struct { - bdrkreg_t mc_rd_data : 1; - bdrkreg_t mc_done : 1; - bdrkreg_t mc_sample : 8; - bdrkreg_t mc_pulse : 10; - bdrkreg_t mc_clkdiv_phi0 : 7; - bdrkreg_t mc_clkdiv_phi1 : 7; - bdrkreg_t mc_reserved : 30; - } lb_microlan_ctl_fld_s; -} lb_microlan_ctl_u_t; - -#else - -typedef union lb_microlan_ctl_u { - bdrkreg_t lb_microlan_ctl_regval; - struct { - bdrkreg_t mc_reserved : 30; - bdrkreg_t mc_clkdiv_phi1 : 7; - bdrkreg_t mc_clkdiv_phi0 : 7; - bdrkreg_t mc_pulse : 10; - bdrkreg_t mc_sample : 8; - bdrkreg_t mc_done : 1; - bdrkreg_t mc_rd_data : 1; - } lb_microlan_ctl_fld_s; -} lb_microlan_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains the LB error status bits. * - * Whenever a particular type of error occurs, the LB sets its bit in * - * this register so that software will be aware that such an event * - * has happened. Reads from this register are non-destructive and the * - * contents of this register remain intact across reset operations. * - * Whenever any of these bits is set, the LB will assert its * - * interrupt request output signals that go to the PI units. * - * Software can simulate the occurrence of an error by first writing * - * appropriate values into the LB_ERROR_HDR1, LB_ERROR_HDR2 and * - * LB_ERROR_DATA registers, and then writing to the LB_ERROR_BITS * - * register to set the error bits in a particular way. Setting one or * - * more error bits will cause the LB to interrupt a processor and * - * invoke error-handling software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_bits_u { - bdrkreg_t lb_error_bits_regval; - struct { - bdrkreg_t eb_rq_bad_cmd : 1; - bdrkreg_t eb_rp_bad_cmd : 1; - bdrkreg_t eb_rq_short : 1; - bdrkreg_t eb_rp_short : 1; - bdrkreg_t eb_rq_long : 1; - bdrkreg_t eb_rp_long : 1; - bdrkreg_t eb_rq_bad_data : 1; - bdrkreg_t eb_rp_bad_data : 1; - bdrkreg_t eb_rq_bad_addr : 1; - bdrkreg_t eb_rq_bad_linval : 1; - bdrkreg_t eb_gclk_drop : 1; - bdrkreg_t eb_reserved : 53; - } lb_error_bits_fld_s; -} lb_error_bits_u_t; - -#else - -typedef union lb_error_bits_u { - bdrkreg_t lb_error_bits_regval; - struct { - bdrkreg_t eb_reserved : 53; - bdrkreg_t eb_gclk_drop : 1; - bdrkreg_t eb_rq_bad_linval : 1; - bdrkreg_t eb_rq_bad_addr : 1; - bdrkreg_t eb_rp_bad_data : 1; - bdrkreg_t eb_rq_bad_data : 1; - bdrkreg_t eb_rp_long : 1; - bdrkreg_t eb_rq_long : 1; - bdrkreg_t eb_rp_short : 1; - bdrkreg_t eb_rq_short : 1; - bdrkreg_t eb_rp_bad_cmd : 1; - bdrkreg_t eb_rq_bad_cmd : 1; - } lb_error_bits_fld_s; -} lb_error_bits_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register lets software clear some of the bits in the * - * LB_ERROR_BITS register without affecting other bits. Essentially, * - * it provides bit mask functionality. When software writes to the * - * LB_ERROR_MASK_CLR register, the bits which are set in the data * - * value indicate which bits are to be cleared in LB_ERROR_BITS. If a * - * bit is clear in the data value written to the LB_ERROR_MASK_CLR * - * register, then its corresponding bit in the LB_ERROR_BITS register * - * is not affected. Hence, software can atomically clear any subset * - * of the error bits in the LB_ERROR_BITS register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_mask_clr_u { - bdrkreg_t lb_error_mask_clr_regval; - struct { - bdrkreg_t emc_clr_rq_bad_cmd : 1; - bdrkreg_t emc_clr_rp_bad_cmd : 1; - bdrkreg_t emc_clr_rq_short : 1; - bdrkreg_t emc_clr_rp_short : 1; - bdrkreg_t emc_clr_rq_long : 1; - bdrkreg_t emc_clr_rp_long : 1; - bdrkreg_t emc_clr_rq_bad_data : 1; - bdrkreg_t emc_clr_rp_bad_data : 1; - bdrkreg_t emc_clr_rq_bad_addr : 1; - bdrkreg_t emc_clr_rq_bad_linval : 1; - bdrkreg_t emc_clr_gclk_drop : 1; - bdrkreg_t emc_reserved : 53; - } lb_error_mask_clr_fld_s; -} lb_error_mask_clr_u_t; - -#else - -typedef union lb_error_mask_clr_u { - bdrkreg_t lb_error_mask_clr_regval; - struct { - bdrkreg_t emc_reserved : 53; - bdrkreg_t emc_clr_gclk_drop : 1; - bdrkreg_t emc_clr_rq_bad_linval : 1; - bdrkreg_t emc_clr_rq_bad_addr : 1; - bdrkreg_t emc_clr_rp_bad_data : 1; - bdrkreg_t emc_clr_rq_bad_data : 1; - bdrkreg_t emc_clr_rp_long : 1; - bdrkreg_t emc_clr_rq_long : 1; - bdrkreg_t emc_clr_rp_short : 1; - bdrkreg_t emc_clr_rq_short : 1; - bdrkreg_t emc_clr_rp_bad_cmd : 1; - bdrkreg_t emc_clr_rq_bad_cmd : 1; - } lb_error_mask_clr_fld_s; -} lb_error_mask_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * If the LB detects an error when VALID==0 in the LB_ERROR_HDR1 * - * register, then it saves the contents of the offending packet's * - * header flit in the LB_ERROR_HDR1 and LB_ERROR_HDR2 registers, sets * - * the VALID bit in LB_ERROR_HDR1 and clears the OVERRUN bit in * - * LB_ERROR_HDR1 (and it will also set the corresponding bit in the * - * LB_ERROR_BITS register). The ERR_TYPE field indicates specifically * - * what kind of error occurred. Its encoding corresponds to the bit * - * positions in the LB_ERROR_BITS register (e.g., ERR_TYPE==5 * - * indicates a RP_LONG error). If an error (of any type except * - * GCLK_DROP) subsequently happens while VALID==1, then the LB sets * - * the OVERRUN bit in LB_ERROR_HDR1. This register is not relevant * - * when a GCLK_DROP error occurs; the LB does not even attempt to * - * change the ERR_TYPE, VALID or OVERRUN field when a GCLK_DROP error * - * happens. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_hdr1_u { - bdrkreg_t lb_error_hdr1_regval; - struct { - bdrkreg_t eh_command : 7; - bdrkreg_t eh_reserved_5 : 1; - bdrkreg_t eh_suppl : 11; - bdrkreg_t eh_reserved_4 : 1; - bdrkreg_t eh_source : 11; - bdrkreg_t eh_reserved_3 : 1; - bdrkreg_t eh_err_type : 4; - bdrkreg_t eh_reserved_2 : 4; - bdrkreg_t eh_overrun : 1; - bdrkreg_t eh_reserved_1 : 3; - bdrkreg_t eh_valid : 1; - bdrkreg_t eh_reserved : 19; - } lb_error_hdr1_fld_s; -} lb_error_hdr1_u_t; - -#else - -typedef union lb_error_hdr1_u { - bdrkreg_t lb_error_hdr1_regval; - struct { - bdrkreg_t eh_reserved : 19; - bdrkreg_t eh_valid : 1; - bdrkreg_t eh_reserved_1 : 3; - bdrkreg_t eh_overrun : 1; - bdrkreg_t eh_reserved_2 : 4; - bdrkreg_t eh_err_type : 4; - bdrkreg_t eh_reserved_3 : 1; - bdrkreg_t eh_source : 11; - bdrkreg_t eh_reserved_4 : 1; - bdrkreg_t eh_suppl : 11; - bdrkreg_t eh_reserved_5 : 1; - bdrkreg_t eh_command : 7; - } lb_error_hdr1_fld_s; -} lb_error_hdr1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contents of the Address field from header flit of first packet * - * that causes an error. This register is not relevant when a * - * GCLK_DROP error occurs. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_hdr2_u { - bdrkreg_t lb_error_hdr2_regval; - struct { - bdrkreg_t eh_address : 38; - bdrkreg_t eh_reserved : 26; - } lb_error_hdr2_fld_s; -} lb_error_hdr2_u_t; - -#else - -typedef union lb_error_hdr2_u { - bdrkreg_t lb_error_hdr2_regval; - struct { - bdrkreg_t eh_reserved : 26; - bdrkreg_t eh_address : 38; - } lb_error_hdr2_fld_s; -} lb_error_hdr2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register accompanies the LB_ERROR_HDR1 and * - * LB_ERROR_HDR2 registers. The LB updates the value in this * - * register when an incoming packet with a data flit causes an error * - * while VALID==0 in the LB_ERROR_HDR1 register. This register * - * retains the contents of the data flit from the incoming packet * - * that caused the error. This register is relevant for the following * - * types of errors: * - *
    * - *
      * - *
        * - *
          * - *
            * - *
          • RQ_BAD_LINVAL for a LINVAL request. * - *
          • RQ_BAD_ADDR for a normal or vector PIO request. * - *
          • RP_BAD_DATA for a vector PIO reply. * - *
          • RQ_BAD DATA for an incoming request with data. * - *
          • RP_LONG for a vector PIO reply. * - *
          • RQ_LONG for an incoming request with expected data. * - *
            * - * In the case of RQ_BAD_LINVAL, the register retains the 64-bit data * - * value that followed the header flit. In the case of RQ_BAD_ADDR * - * or RQ_BAD_DATA, the register retains the incoming packet's 64-bit * - * data value (i.e., 2nd flit in the packet for a normal PIO write or * - * an LINVAL, 3rd flit for a vector PIO read or write). In the case * - * of RP_BAD_DATA, the register retains the 64-bit data value in the * - * 3rd flit of the packet. When a RP_LONG or RQ_LONG error occurs, * - * the LB loads the LB_ERROR_DATA register with the contents of the * - * expected data flit (i.e., the 3rd flit in the packet for a vector * - * PIO request or reply, the 2nd flit for other packets), if any. The * - * contents of the LB_ERROR_DATA register are undefined after a * - * RP_SHORT, RQ_SHORT, RP_BAD_CMD or RQ_BAD_CMD error. The contents * - * of the LB_ERROR_DATA register are also undefined after an incoming * - * normal PIO read request which encounters a RQ_LONG error. * - * * - ************************************************************************/ - - - - -typedef union lb_error_data_u { - bdrkreg_t lb_error_data_regval; - struct { - bdrkreg_t ed_data : 64; - } lb_error_data_fld_s; -} lb_error_data_u_t; - - - - -/************************************************************************ - * * - * This register enables software to control what internal Bedrock * - * signals are visible on the chip's debug pins. The LB provides the * - * 6-bit value in this register to Bedrock's DEBUG unit. The JTAG * - * unit provides a similar 6-bit selection input to the DEBUG unit, * - * along with another signal that tells the DEBUG unit whether to use * - * the selection signal from the LB or the JTAG unit. For a * - * description of the menu of choices for debug signals, refer to the * - * documentation for the DEBUG unit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_debug_select_u { - bdrkreg_t lb_debug_select_regval; - struct { - bdrkreg_t ds_debug_sel : 6; - bdrkreg_t ds_reserved : 58; - } lb_debug_select_fld_s; -} lb_debug_select_u_t; - -#else - -typedef union lb_debug_select_u { - bdrkreg_t lb_debug_select_regval; - struct { - bdrkreg_t ds_reserved : 58; - bdrkreg_t ds_debug_sel : 6; - } lb_debug_select_fld_s; -} lb_debug_select_u_t; - -#endif - - - - -/************************************************************************ - * * - * A PIO read from this register returns the 32-bit value that is * - * currently on the Bedrock chip's debug pins. This register allows * - * software to observe debug pin output values which do not change * - * frequently (i.e., they remain constant over a period of many * - * cycles). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_debug_pins_u { - bdrkreg_t lb_debug_pins_regval; - struct { - bdrkreg_t dp_debug_pins : 32; - bdrkreg_t dp_reserved : 32; - } lb_debug_pins_fld_s; -} lb_debug_pins_u_t; - -#else - -typedef union lb_debug_pins_u { - bdrkreg_t lb_debug_pins_regval; - struct { - bdrkreg_t dp_reserved : 32; - bdrkreg_t dp_debug_pins : 32; - } lb_debug_pins_fld_s; -} lb_debug_pins_u_t; - -#endif - - - - -/************************************************************************ - * * - * The LB unit provides the PI0 and PI1 units with a real-time clock * - * signal. The LB can generate this signal itself, based on the * - * Bedrock chip's system clock which the LB receives as an input. * - * Alternatively, the LB can filter a global clock signal which it * - * receives as an input and provide the filtered version to PI0 and * - * PI1. The user can program the LB_RT_LOCAL_CTRL register to choose * - * the source of the real-time clock. If the user chooses to generate * - * the real-time clock internally within the LB, then the user can * - * specify the period for the real-time clock signal. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rt_local_ctrl_u { - bdrkreg_t lb_rt_local_ctrl_regval; - struct { - bdrkreg_t rlc_gclk_enable : 1; - bdrkreg_t rlc_reserved_4 : 3; - bdrkreg_t rlc_max_count : 10; - bdrkreg_t rlc_reserved_3 : 2; - bdrkreg_t rlc_gclk_counter : 10; - bdrkreg_t rlc_reserved_2 : 2; - bdrkreg_t rlc_gclk : 1; - bdrkreg_t rlc_reserved_1 : 3; - bdrkreg_t rlc_use_internal : 1; - bdrkreg_t rlc_reserved : 31; - } lb_rt_local_ctrl_fld_s; -} lb_rt_local_ctrl_u_t; - -#else - -typedef union lb_rt_local_ctrl_u { - bdrkreg_t lb_rt_local_ctrl_regval; - struct { - bdrkreg_t rlc_reserved : 31; - bdrkreg_t rlc_use_internal : 1; - bdrkreg_t rlc_reserved_1 : 3; - bdrkreg_t rlc_gclk : 1; - bdrkreg_t rlc_reserved_2 : 2; - bdrkreg_t rlc_gclk_counter : 10; - bdrkreg_t rlc_reserved_3 : 2; - bdrkreg_t rlc_max_count : 10; - bdrkreg_t rlc_reserved_4 : 3; - bdrkreg_t rlc_gclk_enable : 1; - } lb_rt_local_ctrl_fld_s; -} lb_rt_local_ctrl_u_t; - -#endif - - - - -/************************************************************************ - * * - * When the value of the USE_INTERNAL field in the LB_RT_LOCAL_CTRL * - * register is 0, the LB filters an incoming global clock signal and * - * provides the result to PI0 and PI1 for their real-time clock * - * inputs. The LB can perform either simple filtering or complex * - * filtering, depending on the value of the MASK_ENABLE bit. For the * - * simple filtering option, the LB merely removes glitches from the * - * incoming global clock; if the global clock goes high (or low) for * - * only a single cycle, the LB considers it to be a glitch and does * - * not pass it through to PI0 and PI1. For the complex filtering * - * option, the LB expects positive edges on the incoming global clock * - * to be spaced at fairly regular intervals and it looks for them at * - * these times; the LB keeps track of unexpected or missing positive * - * edges, and it generates an edge itself whenever the incoming * - * global clock apparently misses an edge. For each filtering option, * - * the real-time clock which the LB provides to PI0 and PI1 is not * - * necessarily a square wave; when a positive edge happens, the * - * real-time clock stays high for (2*MAX_COUNT+1-OFFSET)/2 cycles of * - * the LB's system clock, and then is low until the next positive * - * edge. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rt_filter_ctrl_u { - bdrkreg_t lb_rt_filter_ctrl_regval; - struct { - bdrkreg_t rfc_offset : 5; - bdrkreg_t rfc_reserved_4 : 3; - bdrkreg_t rfc_mask_counter : 12; - bdrkreg_t rfc_mask_enable : 1; - bdrkreg_t rfc_reserved_3 : 3; - bdrkreg_t rfc_dropout_counter : 10; - bdrkreg_t rfc_reserved_2 : 2; - bdrkreg_t rfc_dropout_thresh : 10; - bdrkreg_t rfc_reserved_1 : 2; - bdrkreg_t rfc_error_counter : 10; - bdrkreg_t rfc_reserved : 6; - } lb_rt_filter_ctrl_fld_s; -} lb_rt_filter_ctrl_u_t; - -#else - -typedef union lb_rt_filter_ctrl_u { - bdrkreg_t lb_rt_filter_ctrl_regval; - struct { - bdrkreg_t rfc_reserved : 6; - bdrkreg_t rfc_error_counter : 10; - bdrkreg_t rfc_reserved_1 : 2; - bdrkreg_t rfc_dropout_thresh : 10; - bdrkreg_t rfc_reserved_2 : 2; - bdrkreg_t rfc_dropout_counter : 10; - bdrkreg_t rfc_reserved_3 : 3; - bdrkreg_t rfc_mask_enable : 1; - bdrkreg_t rfc_mask_counter : 12; - bdrkreg_t rfc_reserved_4 : 3; - bdrkreg_t rfc_offset : 5; - } lb_rt_filter_ctrl_fld_s; -} lb_rt_filter_ctrl_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is a scratch register that is reset to 0x0. At the * - * normal address, the register is a simple storage location. At the * - * Write-If-Zero address, the register accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg0_u { - bdrkreg_t lb_scratch_reg0_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg0_fld_s; -} lb_scratch_reg0_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg1_u { - bdrkreg_t lb_scratch_reg1_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg1_fld_s; -} lb_scratch_reg1_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg2_u { - bdrkreg_t lb_scratch_reg2_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg2_fld_s; -} lb_scratch_reg2_u_t; - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg3_u { - bdrkreg_t lb_scratch_reg3_regval; - struct { - bdrkreg_t sr_scratch_bit : 1; - bdrkreg_t sr_reserved : 63; - } lb_scratch_reg3_fld_s; -} lb_scratch_reg3_u_t; - -#else - -typedef union lb_scratch_reg3_u { - bdrkreg_t lb_scratch_reg3_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_scratch_bit : 1; - } lb_scratch_reg3_fld_s; -} lb_scratch_reg3_u_t; - -#endif - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg4_u { - bdrkreg_t lb_scratch_reg4_regval; - struct { - bdrkreg_t sr_scratch_bit : 1; - bdrkreg_t sr_reserved : 63; - } lb_scratch_reg4_fld_s; -} lb_scratch_reg4_u_t; - -#else - -typedef union lb_scratch_reg4_u { - bdrkreg_t lb_scratch_reg4_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_scratch_bit : 1; - } lb_scratch_reg4_fld_s; -} lb_scratch_reg4_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is a scratch register that is reset to 0x0. At the * - * normal address, the register is a simple storage location. At the * - * Write-If-Zero address, the register accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg0_wz_u { - bdrkreg_t lb_scratch_reg0_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg0_wz_fld_s; -} lb_scratch_reg0_wz_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg1_wz_u { - bdrkreg_t lb_scratch_reg1_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg1_wz_fld_s; -} lb_scratch_reg1_wz_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg2_wz_u { - bdrkreg_t lb_scratch_reg2_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg2_wz_fld_s; -} lb_scratch_reg2_wz_u_t; - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg3_rz_u { - bdrkreg_t lb_scratch_reg3_rz_regval; - struct { - bdrkreg_t srr_scratch_bit : 1; - bdrkreg_t srr_reserved : 63; - } lb_scratch_reg3_rz_fld_s; -} lb_scratch_reg3_rz_u_t; - -#else - -typedef union lb_scratch_reg3_rz_u { - bdrkreg_t lb_scratch_reg3_rz_regval; - struct { - bdrkreg_t srr_reserved : 63; - bdrkreg_t srr_scratch_bit : 1; - } lb_scratch_reg3_rz_fld_s; -} lb_scratch_reg3_rz_u_t; - -#endif - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg4_rz_u { - bdrkreg_t lb_scratch_reg4_rz_regval; - struct { - bdrkreg_t srr_scratch_bit : 1; - bdrkreg_t srr_reserved : 63; - } lb_scratch_reg4_rz_fld_s; -} lb_scratch_reg4_rz_u_t; - -#else - -typedef union lb_scratch_reg4_rz_u { - bdrkreg_t lb_scratch_reg4_rz_regval; - struct { - bdrkreg_t srr_reserved : 63; - bdrkreg_t srr_scratch_bit : 1; - } lb_scratch_reg4_rz_fld_s; -} lb_scratch_reg4_rz_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains vector PIO parameters. A * - * write to this register triggers the LB to send out a vector PIO * - * request packet. Immediately after servicing a write request to the * - * LB_VECTOR_PARMS register, the LB sends back a reply (i.e., the LB * - * doesn't wait for the vector PIO operation to finish first). Three * - * LB registers provide the contents for an outgoing vector PIO * - * request packet. Software should wait until the BUSY bit in * - * LB_VECTOR_PARMS is clear and then initialize all three of these * - * registers before initiating a vector PIO operation. The three * - * vector PIO registers are: * - * LB_VECTOR_ROUTE * - * LB_VECTOR_DATA * - * LB_VECTOR_PARMS (should be written last) * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_parms_u { - bdrkreg_t lb_vector_parms_regval; - struct { - bdrkreg_t vp_type : 1; - bdrkreg_t vp_reserved_2 : 2; - bdrkreg_t vp_address : 21; - bdrkreg_t vp_reserved_1 : 8; - bdrkreg_t vp_write_id : 8; - bdrkreg_t vp_pio_id : 11; - bdrkreg_t vp_reserved : 12; - bdrkreg_t vp_busy : 1; - } lb_vector_parms_fld_s; -} lb_vector_parms_u_t; - -#else - -typedef union lb_vector_parms_u { - bdrkreg_t lb_vector_parms_regval; - struct { - bdrkreg_t vp_busy : 1; - bdrkreg_t vp_reserved : 12; - bdrkreg_t vp_pio_id : 11; - bdrkreg_t vp_write_id : 8; - bdrkreg_t vp_reserved_1 : 8; - bdrkreg_t vp_address : 21; - bdrkreg_t vp_reserved_2 : 2; - bdrkreg_t vp_type : 1; - } lb_vector_parms_fld_s; -} lb_vector_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the vector PIO route. This is one of the 3 * - * vector PIO control registers. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_route_u { - bdrkreg_t lb_vector_route_regval; - struct { - bdrkreg_t vr_vector : 64; - } lb_vector_route_fld_s; -} lb_vector_route_u_t; - - - - -/************************************************************************ - * * - * This register contains the vector PIO write data. This is one of * - * the 3 vector PIO control registers. The contents of this register * - * also provide the data value to be sent in outgoing vector PIO read * - * requests and vector PIO write replies. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_data_u { - bdrkreg_t lb_vector_data_regval; - struct { - bdrkreg_t vd_write_data : 64; - } lb_vector_data_fld_s; -} lb_vector_data_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains the vector PIO return status. * - * Software should clear this register before launching a vector PIO * - * request from the LB. The LB will not modify this register's value * - * if an incoming reply packet encounters any kind of error. If an * - * incoming reply packet does not encounter an error but the * - * STATUS_VALID bit is already set, then the LB sets the OVERRUN bit * - * and leaves the other fields unchanged. The LB updates the values * - * of the SOURCE, PIO_ID, WRITE_ID, ADDRESS and TYPE fields only if * - * an incoming vector PIO reply packet does not encounter an error * - * and the STATUS_VALID bit is clear; at the same time, the LB sets * - * the STATUS_VALID bit and will also update the LB_VECTOR_RETURN and * - * LB_VECTOR_READ_DATA registers. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_status_u { - bdrkreg_t lb_vector_status_regval; - struct { - bdrkreg_t vs_type : 3; - bdrkreg_t vs_address : 21; - bdrkreg_t vs_reserved : 8; - bdrkreg_t vs_write_id : 8; - bdrkreg_t vs_pio_id : 11; - bdrkreg_t vs_source : 11; - bdrkreg_t vs_overrun : 1; - bdrkreg_t vs_status_valid : 1; - } lb_vector_status_fld_s; -} lb_vector_status_u_t; - -#else - -typedef union lb_vector_status_u { - bdrkreg_t lb_vector_status_regval; - struct { - bdrkreg_t vs_status_valid : 1; - bdrkreg_t vs_overrun : 1; - bdrkreg_t vs_source : 11; - bdrkreg_t vs_pio_id : 11; - bdrkreg_t vs_write_id : 8; - bdrkreg_t vs_reserved : 8; - bdrkreg_t vs_address : 21; - bdrkreg_t vs_type : 3; - } lb_vector_status_fld_s; -} lb_vector_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the return vector PIO route. The LB will * - * not modify this register's value if an incoming reply packet * - * encounters any kind of error. The LB also will not modify this * - * register's value if the STATUS_VALID bit in the LB_VECTOR_STATUS * - * register is set when it receives an incoming vector PIO reply. The * - * LB stores an incoming vector PIO reply packet's vector route flit * - * in this register only if the packet does not encounter an error * - * and the STATUS_VALID bit is clear. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_return_u { - bdrkreg_t lb_vector_return_regval; - struct { - bdrkreg_t vr_return_vector : 64; - } lb_vector_return_fld_s; -} lb_vector_return_u_t; - - - - -/************************************************************************ - * * - * This register contains the vector PIO read data, if any. The LB * - * will not modify this register's value if an incoming reply packet * - * encounters any kind of error. The LB also will not modify this * - * register's value if the STATUS_VALID bit in the LB_VECTOR_STATUS * - * register is set when it receives an incoming vector PIO reply. The * - * LB stores an incoming vector PIO reply packet's data flit in this * - * register only if the packet does not encounter an error and the * - * STATUS_VALID bit is clear. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_read_data_u { - bdrkreg_t lb_vector_read_data_regval; - struct { - bdrkreg_t vrd_read_data : 64; - } lb_vector_read_data_fld_s; -} lb_vector_read_data_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains the vector PIO return status. * - * Software should clear this register before launching a vector PIO * - * request from the LB. The LB will not modify this register's value * - * if an incoming reply packet encounters any kind of error. If an * - * incoming reply packet does not encounter an error but the * - * STATUS_VALID bit is already set, then the LB sets the OVERRUN bit * - * and leaves the other fields unchanged. The LB updates the values * - * of the SOURCE, PIO_ID, WRITE_ID, ADDRESS and TYPE fields only if * - * an incoming vector PIO reply packet does not encounter an error * - * and the STATUS_VALID bit is clear; at the same time, the LB sets * - * the STATUS_VALID bit and will also update the LB_VECTOR_RETURN and * - * LB_VECTOR_READ_DATA registers. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_status_clear_u { - bdrkreg_t lb_vector_status_clear_regval; - struct { - bdrkreg_t vsc_type : 3; - bdrkreg_t vsc_address : 21; - bdrkreg_t vsc_reserved : 8; - bdrkreg_t vsc_write_id : 8; - bdrkreg_t vsc_pio_id : 11; - bdrkreg_t vsc_source : 11; - bdrkreg_t vsc_overrun : 1; - bdrkreg_t vsc_status_valid : 1; - } lb_vector_status_clear_fld_s; -} lb_vector_status_clear_u_t; - -#else - -typedef union lb_vector_status_clear_u { - bdrkreg_t lb_vector_status_clear_regval; - struct { - bdrkreg_t vsc_status_valid : 1; - bdrkreg_t vsc_overrun : 1; - bdrkreg_t vsc_source : 11; - bdrkreg_t vsc_pio_id : 11; - bdrkreg_t vsc_write_id : 8; - bdrkreg_t vsc_reserved : 8; - bdrkreg_t vsc_address : 21; - bdrkreg_t vsc_type : 3; - } lb_vector_status_clear_fld_s; -} lb_vector_status_clear_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBLB_H */ diff --git a/include/asm-ia64/sn/sn1/hublb_next.h b/include/asm-ia64/sn/sn1/hublb_next.h deleted file mode 100644 index 5b14992fc6d..00000000000 --- a/include/asm-ia64/sn/sn1/hublb_next.h +++ /dev/null @@ -1,109 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBLB_NEXT_H -#define _ASM_IA64_SN_SN1_HUBLB_NEXT_H - -/********************************************************************** - - This contains some mask and shift values for LB defined as required - for compatibility. - - **********************************************************************/ - -#define LRI_SYSTEM_SIZE_SHFT 46 -#define LRI_SYSTEM_SIZE_MASK (UINT64_CAST 0x3 << LRI_SYSTEM_SIZE_SHFT) -#define LRI_NODEID_SHFT 32 -#define LRI_NODEID_MASK (UINT64_CAST 0xff << LRI_NODEID_SHFT)/* Node ID */ -#define LRI_CHIPID_SHFT 12 -#define LRI_CHIPID_MASK (UINT64_CAST 0xffff << LRI_CHIPID_SHFT) /* should be 0x3012 */ -#define LRI_REV_SHFT 28 -#define LRI_REV_MASK (UINT64_CAST 0xf << LRI_REV_SHFT)/* Chip revision */ - -/* Values for LRI_SYSTEM_SIZE */ -#define SYSTEM_SIZE_INVALID 0x3 -#define SYSTEM_SIZE_NMODE 0x2 -#define SYSTEM_SIZE_COARSE 0x1 -#define SYSTEM_SIZE_SMALL 0x0 - -/* In fine mode, each node is a region. In coarse mode, there are - * 2 nodes per region. In N-mode, there are 4 nodes per region. */ -#define NASID_TO_FINEREG_SHFT 0 -#define NASID_TO_COARSEREG_SHFT 1 -#define NASID_TO_NMODEREG_SHFT 2 - -#define LR_LOCALRESET (UINT64_CAST 1) -/* - * LB_VECTOR_PARMS mask and shift definitions. - * TYPE may be any of the first four PIOTYPEs defined under NI_VECTOR_STATUS. - */ - -#define LVP_BUSY (UINT64_CAST 1 << 63) -#define LVP_PIOID_SHFT 40 -#define LVP_PIOID_MASK (UINT64_CAST 0x7ff << 40) -#define LVP_WRITEID_SHFT 32 -#define LVP_WRITEID_MASK (UINT64_CAST 0xff << 32) -#define LVP_ADDRESS_MASK (UINT64_CAST 0xfffff8) /* Bits 23:3 */ -#define LVP_TYPE_SHFT 0 -#define LVP_TYPE_MASK (UINT64_CAST 0x3) - -/* LB_VECTOR_STATUS mask and shift definitions */ - -#define LVS_VALID (UINT64_CAST 1 << 63) -#define LVS_OVERRUN (UINT64_CAST 1 << 62) -#define LVS_TARGET_SHFT 51 -#define LVS_TARGET_MASK (UINT64_CAST 0x7ff << 51) -#define LVS_PIOID_SHFT 40 -#define LVS_PIOID_MASK (UINT64_CAST 0x7ff << 40) -#define LVS_WRITEID_SHFT 32 -#define LVS_WRITEID_MASK (UINT64_CAST 0xff << 32) -#define LVS_ADDRESS_MASK (UINT64_CAST 0xfffff8) /* Bits 23:3 */ -#define LVS_TYPE_SHFT 0 -#define LVS_TYPE_MASK (UINT64_CAST 0x7) -#define LVS_ERROR_MASK (UINT64_CAST 0x4) /* bit set means error */ - -/* LB_RT_LOCAL_CTRL mask and shift definitions */ - -#define LRLC_USE_INT_SHFT 32 -#define LRLC_USE_INT_MASK (UINT64_CAST 1 << 32) -#define LRLC_USE_INT (UINT64_CAST 1 << 32) -#define LRLC_GCLK_SHFT 28 -#define LRLC_GCLK_MASK (UINT64_CAST 1 << 28) -#define LRLC_GCLK (UINT64_CAST 1 << 28) -#define LRLC_GCLK_COUNT_SHFT 16 -#define LRLC_GCLK_COUNT_MASK (UINT64_CAST 0x3ff << 16) -#define LRLC_MAX_COUNT_SHFT 4 -#define LRLC_MAX_COUNT_MASK (UINT64_CAST 0x3ff << 4) -#define LRLC_GCLK_EN_SHFT 0 -#define LRLC_GCLK_EN_MASK (UINT64_CAST 1) -#define LRLC_GCLK_EN (UINT64_CAST 1) - -/* LB_NODES_ABSENT mask and shift definitions */ -#define LNA_VALID_SHFT 15 -#define LNA_VALID_MASK (UINT64_CAST 1 << LNA_VALID_SHFT) -#define LNA_VALID (UINT64_CAST 1 << LNA_VALID_SHFT) -#define LNA_NODE_SHFT 0 -#define LNA_NODE_MASK (UINT64_CAST 0xff << LNA_NODE_SHFT) - -/* LB_NODES_ABSENT has 4 identical sub-registers, on 16-bit boundaries */ -#define LNA_ENTRY_SHFT 16 -#define LNA_MAX_ENTRIES 4 -#define LNA_ADD(_reg, _n) ((_reg) = (_reg) << LNA_ENTRY_SHFT | \ - LNA_VALID | (_n) << LNA_NODE_SHFT) - -#define PIOTYPE_READ 0 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_WRITE 1 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_UNDEFINED 2 /* VECTOR_PARMS and VECTOR_STATUS */ -/* XXX IP35 doesn't support vector exchange: scr. regs. do locks directly */ -#define PIOTYPE_EXCHANGE 3 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_ADDR_ERR 4 /* VECTOR_STATUS only */ -#define PIOTYPE_CMD_ERR 5 /* VECTOR_STATUS only */ -#define PIOTYPE_PROT_ERR 6 /* VECTOR_STATUS only */ -#define PIOTYPE_UNKNOWN 7 /* VECTOR_STATUS only */ - -#endif /* _ASM_IA64_SN_SN1_HUBLB_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hubmd.h b/include/asm-ia64/sn/sn1/hubmd.h deleted file mode 100644 index 09001472d71..00000000000 --- a/include/asm-ia64/sn/sn1/hubmd.h +++ /dev/null @@ -1,2476 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBMD_H -#define _ASM_IA64_SN_SN1_HUBMD_H - - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define MD_CURRENT_CELL 0x00780000 /* - * BDDIR, LREG, LBOOT, - * RREG, RBOOT - * protection and mask - * for using Local - * Access protection. - */ - - - -#define MD_MEMORY_CONFIG 0x00780008 /* - * Memory/Directory - * DIMM control - */ - - - -#define MD_ARBITRATION_CONTROL 0x00780010 /* - * Arbitration - * Parameters - */ - - - -#define MD_MIG_CONFIG 0x00780018 /* - * Page Migration - * control - */ - - - -#define MD_FANDOP_CAC_STAT0 0x00780020 /* - * Fetch-and-op cache - * 0 status - */ - - - -#define MD_FANDOP_CAC_STAT1 0x00780028 /* - * Fetch-and-op cache - * 1 status - */ - - - -#define MD_MISC0_ERROR 0x00780040 /* - * Miscellaneous MD - * error - */ - - - -#define MD_MISC1_ERROR 0x00780048 /* - * Miscellaneous MD - * error - */ - - - -#define MD_MISC1_ERROR_CLR 0x00780058 /* - * Miscellaneous MD - * error clear - */ - - - -#define MD_OUTGOING_RP_QUEUE_SIZE 0x00780060 /* - * MD outgoing reply - * queues sizing - */ - - - -#define MD_PERF_SEL0 0x00790000 /* - * Selects events - * monitored by - * MD_PERF_CNT0 - */ - - - -#define MD_PERF_SEL1 0x00790008 /* - * Selects events - * monitored by - * MD_PERF_CNT1 - */ - - - -#define MD_PERF_CNT0 0x00790010 /* - * Performance counter - * 0 - */ - - - -#define MD_PERF_CNT1 0x00790018 /* - * Performance counter - * 1 - */ - - - -#define MD_REFRESH_CONTROL 0x007A0000 /* - * Memory/Directory - * refresh control - */ - - - -#define MD_JUNK_BUS_TIMING 0x007A0008 /* Junk Bus Timing */ - - - -#define MD_LED0 0x007A0010 /* Reads of 8-bit LED0 */ - - - -#define MD_LED1 0x007A0018 /* Reads of 8-bit LED1 */ - - - -#define MD_LED2 0x007A0020 /* Reads of 8-bit LED2 */ - - - -#define MD_LED3 0x007A0028 /* Reads of 8-bit LED3 */ - - - -#define MD_BIST_CTL 0x007A0030 /* - * BIST general - * control - */ - - - -#define MD_BIST_DATA 0x007A0038 /* - * BIST initial data - * pattern and - * variation control - */ - - - -#define MD_BIST_AB_ERR_ADDR 0x007A0040 /* BIST error address */ - - - -#define MD_BIST_STATUS 0x007A0048 /* BIST status */ - - - -#define MD_IB_DEBUG 0x007A0060 /* IB debug select */ - - - -#define MD_DIR_CONFIG 0x007C0000 /* - * Directory mode - * control - */ - - - -#define MD_DIR_ERROR 0x007C0010 /* - * Directory DIMM - * error - */ - - - -#define MD_DIR_ERROR_CLR 0x007C0018 /* - * Directory DIMM - * error clear - */ - - - -#define MD_PROTOCOL_ERROR 0x007C0020 /* - * Directory protocol - * error - */ - - - -#define MD_PROTOCOL_ERR_CLR 0x007C0028 /* - * Directory protocol - * error clear - */ - - - -#define MD_MIG_CANDIDATE 0x007C0030 /* - * Page migration - * candidate - */ - - - -#define MD_MIG_CANDIDATE_CLR 0x007C0038 /* - * Page migration - * candidate clear - */ - - - -#define MD_MIG_DIFF_THRESH 0x007C0040 /* - * Page migration - * count difference - * threshold - */ - - - -#define MD_MIG_VALUE_THRESH 0x007C0048 /* - * Page migration - * count absolute - * threshold - */ - - - -#define MD_OUTGOING_RQ_QUEUE_SIZE 0x007C0050 /* - * MD outgoing request - * queues sizing - */ - - - -#define MD_BIST_DB_ERR_DATA 0x007C0058 /* - * BIST directory - * error data - */ - - - -#define MD_DB_DEBUG 0x007C0060 /* DB debug select */ - - - -#define MD_MB_ECC_CONFIG 0x007E0000 /* - * Data ECC - * Configuration - */ - - - -#define MD_MEM_ERROR 0x007E0010 /* Memory DIMM error */ - - - -#define MD_MEM_ERROR_CLR 0x007E0018 /* - * Memory DIMM error - * clear - */ - - - -#define MD_BIST_MB_ERR_DATA_0 0x007E0020 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_1 0x007E0028 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_2 0x007E0030 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_3 0x007E0038 /* - * BIST memory error - * data - */ - - - -#define MD_MB_DEBUG 0x007E0040 /* MB debug select */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register shows which regions are in the current * - * cell. If a region has its bit set in this register, then it uses * - * the Local Access protection in the directory instead of the * - * separate per-region protection (which would cause a small * - * performance penalty). In addition, writeback and write reply * - * commands from outside the current cell will always check the * - * directory protection before writing data to memory. Writeback and * - * write reply commands from inside the current cell will write * - * memory regardless of the protection value. * - * This register is also used as the access-rights bit-vector for * - * most of the ASIC-special (HSpec) portion of the address space. It * - * covers the BDDIR, LREG, LBOOT, RREG, and RBOOT spaces. It does not * - * cover the UALIAS and BDECC spaces, as they are covered by the * - * protection in the directory. If a bit in the bit-vector is set, * - * the region corresponding to that bit has read/write permission on * - * these spaces. If the bit is clear, then that region has read-only * - * access to these spaces (except for LREG/RREG which have no access * - * when the bit is clear). * - * The granularity of a region is set by the REGION_SIZE register in * - * the NI local register space. * - * NOTE: This means that no processor outside the current cell can * - * write into the BDDIR, LREG, LBOOT, RREG, or RBOOT spaces. * - * * - ************************************************************************/ - - - - -typedef union md_current_cell_u { - bdrkreg_t md_current_cell_regval; - struct { - bdrkreg_t cc_hspec_prot : 64; - } md_current_cell_fld_s; -} md_current_cell_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains three sets of information. * - * The first set describes the size and configuration of DIMMs that * - * are plugged into a system, the second set controls which set of * - * protection checks are performed on each access and the third set * - * controls various DDR SDRAM timing parameters. * - * In order to config a DIMM bank, three fields must be initialized: * - * BANK_SIZE, DRAM_WIDTH, and BANK_ENABLE. The BANK_SIZE field sets * - * the address range that the MD unit will accept for that DIMM bank. * - * All addresses larger than the specified size will return errors on * - * access. In order to read from a DIMM bank, Bedrock must know * - * whether or not the bank contains x4 or x8/x16 DRAM. The operating * - * system must query the System Controller for this information and * - * then set the DRAM_WIDTH field accordingly. The BANK_ENABLE field * - * can be used to individually enable the two physical banks located * - * on each DIMM bank. * - * The contents of this register are preserved through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_memory_config_u { - bdrkreg_t md_memory_config_regval; - struct { - bdrkreg_t mc_dimm0_bank_enable : 2; - bdrkreg_t mc_reserved_7 : 1; - bdrkreg_t mc_dimm0_dram_width : 1; - bdrkreg_t mc_dimm0_bank_size : 4; - bdrkreg_t mc_dimm1_bank_enable : 2; - bdrkreg_t mc_reserved_6 : 1; - bdrkreg_t mc_dimm1_dram_width : 1; - bdrkreg_t mc_dimm1_bank_size : 4; - bdrkreg_t mc_dimm2_bank_enable : 2; - bdrkreg_t mc_reserved_5 : 1; - bdrkreg_t mc_dimm2_dram_width : 1; - bdrkreg_t mc_dimm2_bank_size : 4; - bdrkreg_t mc_dimm3_bank_enable : 2; - bdrkreg_t mc_reserved_4 : 1; - bdrkreg_t mc_dimm3_dram_width : 1; - bdrkreg_t mc_dimm3_bank_size : 4; - bdrkreg_t mc_dimm0_sel : 2; - bdrkreg_t mc_reserved_3 : 10; - bdrkreg_t mc_cc_enable : 1; - bdrkreg_t mc_io_prot_en : 1; - bdrkreg_t mc_io_prot_ignore : 1; - bdrkreg_t mc_cpu_prot_ignore : 1; - bdrkreg_t mc_db_neg_edge : 1; - bdrkreg_t mc_phase_delay : 1; - bdrkreg_t mc_delay_mux_sel : 2; - bdrkreg_t mc_sample_time : 2; - bdrkreg_t mc_reserved_2 : 2; - bdrkreg_t mc_mb_neg_edge : 3; - bdrkreg_t mc_reserved_1 : 1; - bdrkreg_t mc_rcd_config : 1; - bdrkreg_t mc_rp_config : 1; - bdrkreg_t mc_reserved : 2; - } md_memory_config_fld_s; -} md_memory_config_u_t; - -#else - -typedef union md_memory_config_u { - bdrkreg_t md_memory_config_regval; - struct { - bdrkreg_t mc_reserved : 2; - bdrkreg_t mc_rp_config : 1; - bdrkreg_t mc_rcd_config : 1; - bdrkreg_t mc_reserved_1 : 1; - bdrkreg_t mc_mb_neg_edge : 3; - bdrkreg_t mc_reserved_2 : 2; - bdrkreg_t mc_sample_time : 2; - bdrkreg_t mc_delay_mux_sel : 2; - bdrkreg_t mc_phase_delay : 1; - bdrkreg_t mc_db_neg_edge : 1; - bdrkreg_t mc_cpu_prot_ignore : 1; - bdrkreg_t mc_io_prot_ignore : 1; - bdrkreg_t mc_io_prot_en : 1; - bdrkreg_t mc_cc_enable : 1; - bdrkreg_t mc_reserved_3 : 10; - bdrkreg_t mc_dimm0_sel : 2; - bdrkreg_t mc_dimm3_bank_size : 4; - bdrkreg_t mc_dimm3_dram_width : 1; - bdrkreg_t mc_reserved_4 : 1; - bdrkreg_t mc_dimm3_bank_enable : 2; - bdrkreg_t mc_dimm2_bank_size : 4; - bdrkreg_t mc_dimm2_dram_width : 1; - bdrkreg_t mc_reserved_5 : 1; - bdrkreg_t mc_dimm2_bank_enable : 2; - bdrkreg_t mc_dimm1_bank_size : 4; - bdrkreg_t mc_dimm1_dram_width : 1; - bdrkreg_t mc_reserved_6 : 1; - bdrkreg_t mc_dimm1_bank_enable : 2; - bdrkreg_t mc_dimm0_bank_size : 4; - bdrkreg_t mc_dimm0_dram_width : 1; - bdrkreg_t mc_reserved_7 : 1; - bdrkreg_t mc_dimm0_bank_enable : 2; - } md_memory_config_fld_s; -} md_memory_config_u_t; - -#endif - - - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_arbitration_control_u { - bdrkreg_t md_arbitration_control_regval; - struct { - bdrkreg_t ac_reply_guar : 4; - bdrkreg_t ac_write_guar : 4; - bdrkreg_t ac_reserved : 56; - } md_arbitration_control_fld_s; -} md_arbitration_control_u_t; - -#else - -typedef union md_arbitration_control_u { - bdrkreg_t md_arbitration_control_regval; - struct { - bdrkreg_t ac_reserved : 56; - bdrkreg_t ac_write_guar : 4; - bdrkreg_t ac_reply_guar : 4; - } md_arbitration_control_fld_s; -} md_arbitration_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains page migration control fields. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_config_u { - bdrkreg_t md_mig_config_regval; - struct { - bdrkreg_t mc_mig_interval : 10; - bdrkreg_t mc_reserved_2 : 6; - bdrkreg_t mc_mig_node_mask : 8; - bdrkreg_t mc_reserved_1 : 8; - bdrkreg_t mc_mig_enable : 1; - bdrkreg_t mc_reserved : 31; - } md_mig_config_fld_s; -} md_mig_config_u_t; - -#else - -typedef union md_mig_config_u { - bdrkreg_t md_mig_config_regval; - struct { - bdrkreg_t mc_reserved : 31; - bdrkreg_t mc_mig_enable : 1; - bdrkreg_t mc_reserved_1 : 8; - bdrkreg_t mc_mig_node_mask : 8; - bdrkreg_t mc_reserved_2 : 6; - bdrkreg_t mc_mig_interval : 10; - } md_mig_config_fld_s; -} md_mig_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each register contains the valid bit and address of the entry in * - * the fetch-and-op for cache 0 (or 1). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_fandop_cac_stat0_u { - bdrkreg_t md_fandop_cac_stat0_regval; - struct { - bdrkreg_t fcs_reserved_1 : 6; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_valid : 1; - } md_fandop_cac_stat0_fld_s; -} md_fandop_cac_stat0_u_t; - -#else - -typedef union md_fandop_cac_stat0_u { - bdrkreg_t md_fandop_cac_stat0_regval; - struct { - bdrkreg_t fcs_valid : 1; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved_1 : 6; - } md_fandop_cac_stat0_fld_s; -} md_fandop_cac_stat0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each register contains the valid bit and address of the entry in * - * the fetch-and-op for cache 0 (or 1). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_fandop_cac_stat1_u { - bdrkreg_t md_fandop_cac_stat1_regval; - struct { - bdrkreg_t fcs_reserved_1 : 6; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_valid : 1; - } md_fandop_cac_stat1_fld_s; -} md_fandop_cac_stat1_u_t; - -#else - -typedef union md_fandop_cac_stat1_u { - bdrkreg_t md_fandop_cac_stat1_regval; - struct { - bdrkreg_t fcs_valid : 1; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved_1 : 6; - } md_fandop_cac_stat1_fld_s; -} md_fandop_cac_stat1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains a number of fields to capture various * - * random memory/directory errors. For each 2-bit field, the LSB * - * indicates that additional information has been captured for the * - * error and the MSB indicates overrun, thus: * - * x1: bits 51...0 of this register contain additional information * - * for the message that caused this error * - * 1x: overrun occurred * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc0_error_u { - bdrkreg_t md_misc0_error_regval; - struct { - bdrkreg_t me_command : 7; - bdrkreg_t me_reserved_4 : 1; - bdrkreg_t me_source : 11; - bdrkreg_t me_reserved_3 : 1; - bdrkreg_t me_suppl : 11; - bdrkreg_t me_reserved_2 : 1; - bdrkreg_t me_virtual_channel : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_tail : 1; - bdrkreg_t me_reserved : 11; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_ill_revision : 2; - } md_misc0_error_fld_s; -} md_misc0_error_u_t; - -#else - -typedef union md_misc0_error_u { - bdrkreg_t md_misc0_error_regval; - struct { - bdrkreg_t me_ill_revision : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_reserved : 11; - bdrkreg_t me_tail : 1; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_virtual_channel : 2; - bdrkreg_t me_reserved_2 : 1; - bdrkreg_t me_suppl : 11; - bdrkreg_t me_reserved_3 : 1; - bdrkreg_t me_source : 11; - bdrkreg_t me_reserved_4 : 1; - bdrkreg_t me_command : 7; - } md_misc0_error_fld_s; -} md_misc0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Address for error captured in MISC0_ERROR. Error valid bits are * - * repeated in both MISC0_ERROR and MISC1_ERROR (allowing them to be * - * read sequentially without missing any errors). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc1_error_u { - bdrkreg_t md_misc1_error_regval; - struct { - bdrkreg_t me_reserved_1 : 3; - bdrkreg_t me_address : 38; - bdrkreg_t me_reserved : 7; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_ill_revision : 2; - } md_misc1_error_fld_s; -} md_misc1_error_u_t; - -#else - -typedef union md_misc1_error_u { - bdrkreg_t md_misc1_error_regval; - struct { - bdrkreg_t me_ill_revision : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_reserved : 7; - bdrkreg_t me_address : 38; - bdrkreg_t me_reserved_1 : 3; - } md_misc1_error_fld_s; -} md_misc1_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Address for error captured in MISC0_ERROR. Error valid bits are * - * repeated in both MISC0_ERROR and MISC1_ERROR (allowing them to be * - * read sequentially without missing any errors). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc1_error_clr_u { - bdrkreg_t md_misc1_error_clr_regval; - struct { - bdrkreg_t mec_reserved_1 : 3; - bdrkreg_t mec_address : 38; - bdrkreg_t mec_reserved : 7; - bdrkreg_t mec_xb_error : 4; - bdrkreg_t mec_bad_partial_data : 2; - bdrkreg_t mec_missing_dv : 2; - bdrkreg_t mec_short_pack : 2; - bdrkreg_t mec_long_pack : 2; - bdrkreg_t mec_ill_msg : 2; - bdrkreg_t mec_ill_revision : 2; - } md_misc1_error_clr_fld_s; -} md_misc1_error_clr_u_t; - -#else - -typedef union md_misc1_error_clr_u { - bdrkreg_t md_misc1_error_clr_regval; - struct { - bdrkreg_t mec_ill_revision : 2; - bdrkreg_t mec_ill_msg : 2; - bdrkreg_t mec_long_pack : 2; - bdrkreg_t mec_short_pack : 2; - bdrkreg_t mec_missing_dv : 2; - bdrkreg_t mec_bad_partial_data : 2; - bdrkreg_t mec_xb_error : 4; - bdrkreg_t mec_reserved : 7; - bdrkreg_t mec_address : 38; - bdrkreg_t mec_reserved_1 : 3; - } md_misc1_error_clr_fld_s; -} md_misc1_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: The MD no longer allows for arbitrarily sizing the * - * reply queues, so all of the fields in this register are read-only * - * and contain the reset default value of 12 for the MOQHs (for * - * headers) and 24 for the MOQDs (for data). * - * Reading from this register returns the values currently held in * - * the MD's credit counters. Writing to the register resets the * - * counters to the default reset values specified in the table below. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_outgoing_rp_queue_size_u { - bdrkreg_t md_outgoing_rp_queue_size_regval; - struct { - bdrkreg_t orqs_reserved_6 : 8; - bdrkreg_t orqs_moqh_p0_rp_size : 4; - bdrkreg_t orqs_reserved_5 : 4; - bdrkreg_t orqs_moqh_p1_rp_size : 4; - bdrkreg_t orqs_reserved_4 : 4; - bdrkreg_t orqs_moqh_np_rp_size : 4; - bdrkreg_t orqs_reserved_3 : 4; - bdrkreg_t orqs_moqd_pi0_rp_size : 5; - bdrkreg_t orqs_reserved_2 : 3; - bdrkreg_t orqs_moqd_pi1_rp_size : 5; - bdrkreg_t orqs_reserved_1 : 3; - bdrkreg_t orqs_moqd_np_rp_size : 5; - bdrkreg_t orqs_reserved : 11; - } md_outgoing_rp_queue_size_fld_s; -} md_outgoing_rp_queue_size_u_t; - -#else - -typedef union md_outgoing_rp_queue_size_u { - bdrkreg_t md_outgoing_rp_queue_size_regval; - struct { - bdrkreg_t orqs_reserved : 11; - bdrkreg_t orqs_moqd_np_rp_size : 5; - bdrkreg_t orqs_reserved_1 : 3; - bdrkreg_t orqs_moqd_pi1_rp_size : 5; - bdrkreg_t orqs_reserved_2 : 3; - bdrkreg_t orqs_moqd_pi0_rp_size : 5; - bdrkreg_t orqs_reserved_3 : 4; - bdrkreg_t orqs_moqh_np_rp_size : 4; - bdrkreg_t orqs_reserved_4 : 4; - bdrkreg_t orqs_moqh_p1_rp_size : 4; - bdrkreg_t orqs_reserved_5 : 4; - bdrkreg_t orqs_moqh_p0_rp_size : 4; - bdrkreg_t orqs_reserved_6 : 8; - } md_outgoing_rp_queue_size_fld_s; -} md_outgoing_rp_queue_size_u_t; - -#endif - - - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel0_u { - bdrkreg_t md_perf_sel0_regval; - struct { - bdrkreg_t ps_cnt_mode : 2; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_interrupt : 1; - } md_perf_sel0_fld_s; -} md_perf_sel0_u_t; - -#else - -typedef union md_perf_sel0_u { - bdrkreg_t md_perf_sel0_regval; - struct { - bdrkreg_t ps_interrupt : 1; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_cnt_mode : 2; - } md_perf_sel0_fld_s; -} md_perf_sel0_u_t; - -#endif - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel1_u { - bdrkreg_t md_perf_sel1_regval; - struct { - bdrkreg_t ps_cnt_mode : 2; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_interrupt : 1; - } md_perf_sel1_fld_s; -} md_perf_sel1_u_t; - -#else - -typedef union md_perf_sel1_u { - bdrkreg_t md_perf_sel1_regval; - struct { - bdrkreg_t ps_interrupt : 1; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_cnt_mode : 2; - } md_perf_sel1_fld_s; -} md_perf_sel1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Performance counter. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_cnt0_u { - bdrkreg_t md_perf_cnt0_regval; - struct { - bdrkreg_t pc_perf_cnt : 41; - bdrkreg_t pc_reserved : 23; - } md_perf_cnt0_fld_s; -} md_perf_cnt0_u_t; - -#else - -typedef union md_perf_cnt0_u { - bdrkreg_t md_perf_cnt0_regval; - struct { - bdrkreg_t pc_reserved : 23; - bdrkreg_t pc_perf_cnt : 41; - } md_perf_cnt0_fld_s; -} md_perf_cnt0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Performance counter. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_cnt1_u { - bdrkreg_t md_perf_cnt1_regval; - struct { - bdrkreg_t pc_perf_cnt : 41; - bdrkreg_t pc_reserved : 23; - } md_perf_cnt1_fld_s; -} md_perf_cnt1_u_t; - -#else - -typedef union md_perf_cnt1_u { - bdrkreg_t md_perf_cnt1_regval; - struct { - bdrkreg_t pc_reserved : 23; - bdrkreg_t pc_perf_cnt : 41; - } md_perf_cnt1_fld_s; -} md_perf_cnt1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains the control for * - * memory/directory refresh. Once the MEMORY_CONFIG register contains * - * the correct DIMM information, the hardware takes care of * - * refreshing all the banks in the system. Therefore, the value in * - * the counter threshold is corresponds exactly to the refresh value * - * required by the SDRAM parts (expressed in Bedrock clock cycles). * - * The refresh will execute whenever there is a free cycle and there * - * are still banks that have not been refreshed in the current * - * window. If the window expires with banks still waiting to be * - * refreshed, all other transactions are halted until the banks are * - * refreshed. * - * The upper order bit contains an enable, which may be needed for * - * correct initialization of the DIMMs (according to the specs, the * - * first operation to the DIMMs should be a mode register write, not * - * a refresh, so this bit is cleared on reset) and is also useful for * - * diagnostic purposes. * - * For the SDRAM parts used by Bedrock, 4096 refreshes need to be * - * issued during every 64 ms window, resulting in a refresh threshold * - * of 3125 Bedrock cycles. * - * The ENABLE and CNT_THRESH fields of this register are preserved * - * through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_refresh_control_u { - bdrkreg_t md_refresh_control_regval; - struct { - bdrkreg_t rc_cnt_thresh : 12; - bdrkreg_t rc_counter : 12; - bdrkreg_t rc_reserved : 39; - bdrkreg_t rc_enable : 1; - } md_refresh_control_fld_s; -} md_refresh_control_u_t; - -#else - -typedef union md_refresh_control_u { - bdrkreg_t md_refresh_control_regval; - struct { - bdrkreg_t rc_enable : 1; - bdrkreg_t rc_reserved : 39; - bdrkreg_t rc_counter : 12; - bdrkreg_t rc_cnt_thresh : 12; - } md_refresh_control_fld_s; -} md_refresh_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls the read and write timing for Flash PROM, * - * UART and Synergy junk bus devices. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_junk_bus_timing_u { - bdrkreg_t md_junk_bus_timing_regval; - struct { - bdrkreg_t jbt_fprom_setup_hold : 8; - bdrkreg_t jbt_fprom_enable : 8; - bdrkreg_t jbt_uart_setup_hold : 8; - bdrkreg_t jbt_uart_enable : 8; - bdrkreg_t jbt_synergy_setup_hold : 8; - bdrkreg_t jbt_synergy_enable : 8; - bdrkreg_t jbt_reserved : 16; - } md_junk_bus_timing_fld_s; -} md_junk_bus_timing_u_t; - -#else - -typedef union md_junk_bus_timing_u { - bdrkreg_t md_junk_bus_timing_regval; - struct { - bdrkreg_t jbt_reserved : 16; - bdrkreg_t jbt_synergy_enable : 8; - bdrkreg_t jbt_synergy_setup_hold : 8; - bdrkreg_t jbt_uart_enable : 8; - bdrkreg_t jbt_uart_setup_hold : 8; - bdrkreg_t jbt_fprom_enable : 8; - bdrkreg_t jbt_fprom_setup_hold : 8; - } md_junk_bus_timing_fld_s; -} md_junk_bus_timing_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led0_u { - bdrkreg_t md_led0_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led0_fld_s; -} md_led0_u_t; - -#else - -typedef union md_led0_u { - bdrkreg_t md_led0_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led0_fld_s; -} md_led0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led1_u { - bdrkreg_t md_led1_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led1_fld_s; -} md_led1_u_t; - -#else - -typedef union md_led1_u { - bdrkreg_t md_led1_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led1_fld_s; -} md_led1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led2_u { - bdrkreg_t md_led2_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led2_fld_s; -} md_led2_u_t; - -#else - -typedef union md_led2_u { - bdrkreg_t md_led2_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led2_fld_s; -} md_led2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led3_u { - bdrkreg_t md_led3_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led3_fld_s; -} md_led3_u_t; - -#else - -typedef union md_led3_u { - bdrkreg_t md_led3_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led3_fld_s; -} md_led3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Core control for the BIST function. Start and stop BIST at any * - * time. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_ctl_u { - bdrkreg_t md_bist_ctl_regval; - struct { - bdrkreg_t bc_bist_start : 1; - bdrkreg_t bc_bist_stop : 1; - bdrkreg_t bc_bist_reset : 1; - bdrkreg_t bc_reserved_1 : 1; - bdrkreg_t bc_bank_num : 1; - bdrkreg_t bc_dimm_num : 2; - bdrkreg_t bc_reserved : 57; - } md_bist_ctl_fld_s; -} md_bist_ctl_u_t; - -#else - -typedef union md_bist_ctl_u { - bdrkreg_t md_bist_ctl_regval; - struct { - bdrkreg_t bc_reserved : 57; - bdrkreg_t bc_dimm_num : 2; - bdrkreg_t bc_bank_num : 1; - bdrkreg_t bc_reserved_1 : 1; - bdrkreg_t bc_bist_reset : 1; - bdrkreg_t bc_bist_stop : 1; - bdrkreg_t bc_bist_start : 1; - } md_bist_ctl_fld_s; -} md_bist_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contain the initial BIST data nibble and the 4-bit data control * - * field.. * - * * - ************************************************************************/ - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_data_u { - bdrkreg_t md_bist_data_regval; - struct { - bdrkreg_t bd_bist_data : 4; - bdrkreg_t bd_bist_nibble : 1; - bdrkreg_t bd_bist_byte : 1; - bdrkreg_t bd_bist_cycle : 1; - bdrkreg_t bd_bist_write : 1; - bdrkreg_t bd_reserved : 56; - } md_bist_data_fld_s; -} md_bist_data_u_t; - -#else - -typedef union md_bist_data_u { - bdrkreg_t md_bist_data_regval; - struct { - bdrkreg_t bd_reserved : 56; - bdrkreg_t bd_bist_write : 1; - bdrkreg_t bd_bist_cycle : 1; - bdrkreg_t bd_bist_byte : 1; - bdrkreg_t bd_bist_nibble : 1; - bdrkreg_t bd_bist_data : 4; - } md_bist_data_fld_s; -} md_bist_data_u_t; - -#endif - - - - -/************************************************************************ - * * - * Captures the BIST error address and indicates whether it is an MB * - * error or DB error. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_ab_err_addr_u { - bdrkreg_t md_bist_ab_err_addr_regval; - struct { - bdrkreg_t baea_be_db_cas_addr : 15; - bdrkreg_t baea_reserved_3 : 1; - bdrkreg_t baea_be_mb_cas_addr : 15; - bdrkreg_t baea_reserved_2 : 1; - bdrkreg_t baea_be_ras_addr : 15; - bdrkreg_t baea_reserved_1 : 1; - bdrkreg_t baea_bist_mb_error : 1; - bdrkreg_t baea_bist_db_error : 1; - bdrkreg_t baea_reserved : 14; - } md_bist_ab_err_addr_fld_s; -} md_bist_ab_err_addr_u_t; - -#else - -typedef union md_bist_ab_err_addr_u { - bdrkreg_t md_bist_ab_err_addr_regval; - struct { - bdrkreg_t baea_reserved : 14; - bdrkreg_t baea_bist_db_error : 1; - bdrkreg_t baea_bist_mb_error : 1; - bdrkreg_t baea_reserved_1 : 1; - bdrkreg_t baea_be_ras_addr : 15; - bdrkreg_t baea_reserved_2 : 1; - bdrkreg_t baea_be_mb_cas_addr : 15; - bdrkreg_t baea_reserved_3 : 1; - bdrkreg_t baea_be_db_cas_addr : 15; - } md_bist_ab_err_addr_fld_s; -} md_bist_ab_err_addr_u_t; - -#endif - - - -/************************************************************************ - * * - * Contains information on BIST progress and memory bank currently * - * under BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_status_u { - bdrkreg_t md_bist_status_regval; - struct { - bdrkreg_t bs_bist_passed : 1; - bdrkreg_t bs_bist_done : 1; - bdrkreg_t bs_reserved : 62; - } md_bist_status_fld_s; -} md_bist_status_u_t; - -#else - -typedef union md_bist_status_u { - bdrkreg_t md_bist_status_regval; - struct { - bdrkreg_t bs_reserved : 62; - bdrkreg_t bs_bist_done : 1; - bdrkreg_t bs_bist_passed : 1; - } md_bist_status_fld_s; -} md_bist_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains 3 bits that allow the selection of IB debug information * - * at the debug port (see design specification for available debug * - * information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_ib_debug_u { - bdrkreg_t md_ib_debug_regval; - struct { - bdrkreg_t id_ib_debug_sel : 2; - bdrkreg_t id_reserved : 62; - } md_ib_debug_fld_s; -} md_ib_debug_u_t; - -#else - -typedef union md_ib_debug_u { - bdrkreg_t md_ib_debug_regval; - struct { - bdrkreg_t id_reserved : 62; - bdrkreg_t id_ib_debug_sel : 2; - } md_ib_debug_fld_s; -} md_ib_debug_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the directory specific mode bits. The contents of this * - * register are preserved through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_config_u { - bdrkreg_t md_dir_config_regval; - struct { - bdrkreg_t dc_dir_flavor : 1; - bdrkreg_t dc_ignore_dir_ecc : 1; - bdrkreg_t dc_reserved : 62; - } md_dir_config_fld_s; -} md_dir_config_u_t; - -#else - -typedef union md_dir_config_u { - bdrkreg_t md_dir_config_regval; - struct { - bdrkreg_t dc_reserved : 62; - bdrkreg_t dc_ignore_dir_ecc : 1; - bdrkreg_t dc_dir_flavor : 1; - } md_dir_config_fld_s; -} md_dir_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on uncorrectable and * - * correctable directory ECC errors, along with protection ECC * - * errors. The priority of ECC errors latched is: uncorrectable * - * directory, protection error, correctable directory. Thus the valid * - * bits signal: * - * 1xxx: uncorrectable directory ECC error (UCE) * - * 01xx: access protection double bit error (AE) * - * 001x: correctable directory ECC error (CE) * - * 0001: access protection correctable error (ACE) * - * If the UCE valid bit is set, the address field contains a pointer * - * to the Hspec address of the offending directory entry, the * - * syndrome field contains the bad syndrome, and the UCE overrun bit * - * indicates whether multiple double-bit errors were received. * - * If the UCE valid bit is clear but the AE valid bit is set, the * - * address field contains a pointer to the Hspec address of the * - * offending protection entry, the Bad Protection field contains the * - * 4-bit bad protection value, the PROT_INDEX field shows which of * - * the 8 protection values in the word was bad and the AE overrun bit * - * indicates whether multiple AE errors were received. * - * If the UCE and AE valid bits are clear, but the CE valid bit is * - * set, the address field contains a pointer to the Hspec address of * - * the offending directory entry, the syndrome field contains the bad * - * syndrome, and the CE overrun bit indicates whether multiple * - * single-bit errors were received. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_error_u { - bdrkreg_t md_dir_error_regval; - struct { - bdrkreg_t de_reserved_3 : 3; - bdrkreg_t de_hspec_addr : 30; - bdrkreg_t de_reserved_2 : 7; - bdrkreg_t de_bad_syn : 7; - bdrkreg_t de_reserved_1 : 1; - bdrkreg_t de_bad_protect : 4; - bdrkreg_t de_prot_index : 3; - bdrkreg_t de_reserved : 1; - bdrkreg_t de_ace_overrun : 1; - bdrkreg_t de_ce_overrun : 1; - bdrkreg_t de_ae_overrun : 1; - bdrkreg_t de_uce_overrun : 1; - bdrkreg_t de_ace_valid : 1; - bdrkreg_t de_ce_valid : 1; - bdrkreg_t de_ae_valid : 1; - bdrkreg_t de_uce_valid : 1; - } md_dir_error_fld_s; -} md_dir_error_u_t; - -#else - -typedef union md_dir_error_u { - bdrkreg_t md_dir_error_regval; - struct { - bdrkreg_t de_uce_valid : 1; - bdrkreg_t de_ae_valid : 1; - bdrkreg_t de_ce_valid : 1; - bdrkreg_t de_ace_valid : 1; - bdrkreg_t de_uce_overrun : 1; - bdrkreg_t de_ae_overrun : 1; - bdrkreg_t de_ce_overrun : 1; - bdrkreg_t de_ace_overrun : 1; - bdrkreg_t de_reserved : 1; - bdrkreg_t de_prot_index : 3; - bdrkreg_t de_bad_protect : 4; - bdrkreg_t de_reserved_1 : 1; - bdrkreg_t de_bad_syn : 7; - bdrkreg_t de_reserved_2 : 7; - bdrkreg_t de_hspec_addr : 30; - bdrkreg_t de_reserved_3 : 3; - } md_dir_error_fld_s; -} md_dir_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on uncorrectable and * - * correctable directory ECC errors, along with protection ECC * - * errors. The priority of ECC errors latched is: uncorrectable * - * directory, protection error, correctable directory. Thus the valid * - * bits signal: * - * 1xxx: uncorrectable directory ECC error (UCE) * - * 01xx: access protection double bit error (AE) * - * 001x: correctable directory ECC error (CE) * - * 0001: access protection correctable error (ACE) * - * If the UCE valid bit is set, the address field contains a pointer * - * to the Hspec address of the offending directory entry, the * - * syndrome field contains the bad syndrome, and the UCE overrun bit * - * indicates whether multiple double-bit errors were received. * - * If the UCE valid bit is clear but the AE valid bit is set, the * - * address field contains a pointer to the Hspec address of the * - * offending protection entry, the Bad Protection field contains the * - * 4-bit bad protection value, the PROT_INDEX field shows which of * - * the 8 protection values in the word was bad and the AE overrun bit * - * indicates whether multiple AE errors were received. * - * If the UCE and AE valid bits are clear, but the CE valid bit is * - * set, the address field contains a pointer to the Hspec address of * - * the offending directory entry, the syndrome field contains the bad * - * syndrome, and the CE overrun bit indicates whether multiple * - * single-bit errors were received. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_error_clr_u { - bdrkreg_t md_dir_error_clr_regval; - struct { - bdrkreg_t dec_reserved_3 : 3; - bdrkreg_t dec_hspec_addr : 30; - bdrkreg_t dec_reserved_2 : 7; - bdrkreg_t dec_bad_syn : 7; - bdrkreg_t dec_reserved_1 : 1; - bdrkreg_t dec_bad_protect : 4; - bdrkreg_t dec_prot_index : 3; - bdrkreg_t dec_reserved : 1; - bdrkreg_t dec_ace_overrun : 1; - bdrkreg_t dec_ce_overrun : 1; - bdrkreg_t dec_ae_overrun : 1; - bdrkreg_t dec_uce_overrun : 1; - bdrkreg_t dec_ace_valid : 1; - bdrkreg_t dec_ce_valid : 1; - bdrkreg_t dec_ae_valid : 1; - bdrkreg_t dec_uce_valid : 1; - } md_dir_error_clr_fld_s; -} md_dir_error_clr_u_t; - -#else - -typedef union md_dir_error_clr_u { - bdrkreg_t md_dir_error_clr_regval; - struct { - bdrkreg_t dec_uce_valid : 1; - bdrkreg_t dec_ae_valid : 1; - bdrkreg_t dec_ce_valid : 1; - bdrkreg_t dec_ace_valid : 1; - bdrkreg_t dec_uce_overrun : 1; - bdrkreg_t dec_ae_overrun : 1; - bdrkreg_t dec_ce_overrun : 1; - bdrkreg_t dec_ace_overrun : 1; - bdrkreg_t dec_reserved : 1; - bdrkreg_t dec_prot_index : 3; - bdrkreg_t dec_bad_protect : 4; - bdrkreg_t dec_reserved_1 : 1; - bdrkreg_t dec_bad_syn : 7; - bdrkreg_t dec_reserved_2 : 7; - bdrkreg_t dec_hspec_addr : 30; - bdrkreg_t dec_reserved_3 : 3; - } md_dir_error_clr_fld_s; -} md_dir_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains information on requests that encounter no valid protocol * - * table entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_protocol_error_u { - bdrkreg_t md_protocol_error_regval; - struct { - bdrkreg_t pe_overrun : 1; - bdrkreg_t pe_pointer_me : 1; - bdrkreg_t pe_reserved_1 : 1; - bdrkreg_t pe_address : 30; - bdrkreg_t pe_reserved : 1; - bdrkreg_t pe_ptr1_btmbits : 3; - bdrkreg_t pe_dir_format : 2; - bdrkreg_t pe_dir_state : 3; - bdrkreg_t pe_priority : 1; - bdrkreg_t pe_access : 1; - bdrkreg_t pe_msg_type : 8; - bdrkreg_t pe_initiator : 11; - bdrkreg_t pe_valid : 1; - } md_protocol_error_fld_s; -} md_protocol_error_u_t; - -#else - -typedef union md_protocol_error_u { - bdrkreg_t md_protocol_error_regval; - struct { - bdrkreg_t pe_valid : 1; - bdrkreg_t pe_initiator : 11; - bdrkreg_t pe_msg_type : 8; - bdrkreg_t pe_access : 1; - bdrkreg_t pe_priority : 1; - bdrkreg_t pe_dir_state : 3; - bdrkreg_t pe_dir_format : 2; - bdrkreg_t pe_ptr1_btmbits : 3; - bdrkreg_t pe_reserved : 1; - bdrkreg_t pe_address : 30; - bdrkreg_t pe_reserved_1 : 1; - bdrkreg_t pe_pointer_me : 1; - bdrkreg_t pe_overrun : 1; - } md_protocol_error_fld_s; -} md_protocol_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains information on requests that encounter no valid protocol * - * table entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_protocol_err_clr_u { - bdrkreg_t md_protocol_err_clr_regval; - struct { - bdrkreg_t pec_overrun : 1; - bdrkreg_t pec_pointer_me : 1; - bdrkreg_t pec_reserved_1 : 1; - bdrkreg_t pec_address : 30; - bdrkreg_t pec_reserved : 1; - bdrkreg_t pec_ptr1_btmbits : 3; - bdrkreg_t pec_dir_format : 2; - bdrkreg_t pec_dir_state : 3; - bdrkreg_t pec_priority : 1; - bdrkreg_t pec_access : 1; - bdrkreg_t pec_msg_type : 8; - bdrkreg_t pec_initiator : 11; - bdrkreg_t pec_valid : 1; - } md_protocol_err_clr_fld_s; -} md_protocol_err_clr_u_t; - -#else - -typedef union md_protocol_err_clr_u { - bdrkreg_t md_protocol_err_clr_regval; - struct { - bdrkreg_t pec_valid : 1; - bdrkreg_t pec_initiator : 11; - bdrkreg_t pec_msg_type : 8; - bdrkreg_t pec_access : 1; - bdrkreg_t pec_priority : 1; - bdrkreg_t pec_dir_state : 3; - bdrkreg_t pec_dir_format : 2; - bdrkreg_t pec_ptr1_btmbits : 3; - bdrkreg_t pec_reserved : 1; - bdrkreg_t pec_address : 30; - bdrkreg_t pec_reserved_1 : 1; - bdrkreg_t pec_pointer_me : 1; - bdrkreg_t pec_overrun : 1; - } md_protocol_err_clr_fld_s; -} md_protocol_err_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the address of the page and the requestor which caused a * - * migration threshold to be exceeded. Also contains the type of * - * threshold exceeded and an overrun bit. For Value mode type * - * interrupts, it indicates whether the local or the remote counter * - * triggered the interrupt. Unlike most registers, when the overrun * - * bit is set the register contains information on the most recent * - * (the last) migration candidate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_candidate_u { - bdrkreg_t md_mig_candidate_regval; - struct { - bdrkreg_t mc_address : 21; - bdrkreg_t mc_initiator : 11; - bdrkreg_t mc_overrun : 1; - bdrkreg_t mc_type : 1; - bdrkreg_t mc_local : 1; - bdrkreg_t mc_reserved : 28; - bdrkreg_t mc_valid : 1; - } md_mig_candidate_fld_s; -} md_mig_candidate_u_t; - -#else - -typedef union md_mig_candidate_u { - bdrkreg_t md_mig_candidate_regval; - struct { - bdrkreg_t mc_valid : 1; - bdrkreg_t mc_reserved : 28; - bdrkreg_t mc_local : 1; - bdrkreg_t mc_type : 1; - bdrkreg_t mc_overrun : 1; - bdrkreg_t mc_initiator : 11; - bdrkreg_t mc_address : 21; - } md_mig_candidate_fld_s; -} md_mig_candidate_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the address of the page and the requestor which caused a * - * migration threshold to be exceeded. Also contains the type of * - * threshold exceeded and an overrun bit. For Value mode type * - * interrupts, it indicates whether the local or the remote counter * - * triggered the interrupt. Unlike most registers, when the overrun * - * bit is set the register contains information on the most recent * - * (the last) migration candidate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_candidate_clr_u { - bdrkreg_t md_mig_candidate_clr_regval; - struct { - bdrkreg_t mcc_address : 21; - bdrkreg_t mcc_initiator : 11; - bdrkreg_t mcc_overrun : 1; - bdrkreg_t mcc_type : 1; - bdrkreg_t mcc_local : 1; - bdrkreg_t mcc_reserved : 28; - bdrkreg_t mcc_valid : 1; - } md_mig_candidate_clr_fld_s; -} md_mig_candidate_clr_u_t; - -#else - -typedef union md_mig_candidate_clr_u { - bdrkreg_t md_mig_candidate_clr_regval; - struct { - bdrkreg_t mcc_valid : 1; - bdrkreg_t mcc_reserved : 28; - bdrkreg_t mcc_local : 1; - bdrkreg_t mcc_type : 1; - bdrkreg_t mcc_overrun : 1; - bdrkreg_t mcc_initiator : 11; - bdrkreg_t mcc_address : 21; - } md_mig_candidate_clr_fld_s; -} md_mig_candidate_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls the generation of page-migration interrupts and loading * - * of the MIGRATION_CANDIDATE register for pages which are using the * - * difference between the requestor and home counts. If the * - * difference is greater-than or equal to than the threshold * - * contained in the register, and the valid bit is set, the migration * - * candidate is loaded (and an interrupt generated if enabled by the * - * page migration mode). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_diff_thresh_u { - bdrkreg_t md_mig_diff_thresh_regval; - struct { - bdrkreg_t mdt_threshold : 15; - bdrkreg_t mdt_reserved_1 : 17; - bdrkreg_t mdt_th_action : 3; - bdrkreg_t mdt_sat_action : 3; - bdrkreg_t mdt_reserved : 25; - bdrkreg_t mdt_valid : 1; - } md_mig_diff_thresh_fld_s; -} md_mig_diff_thresh_u_t; - -#else - -typedef union md_mig_diff_thresh_u { - bdrkreg_t md_mig_diff_thresh_regval; - struct { - bdrkreg_t mdt_valid : 1; - bdrkreg_t mdt_reserved : 25; - bdrkreg_t mdt_sat_action : 3; - bdrkreg_t mdt_th_action : 3; - bdrkreg_t mdt_reserved_1 : 17; - bdrkreg_t mdt_threshold : 15; - } md_mig_diff_thresh_fld_s; -} md_mig_diff_thresh_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls the generation of page-migration interrupts and loading * - * of the MIGRATION_CANDIDATE register for pages that are using the * - * absolute value of the requestor count. If the value is * - * greater-than or equal to the threshold contained in the register, * - * and the register valid bit is set, the migration candidate is * - * loaded and an interrupt generated. For the value mode of page * - * migration, there are two variations. In the first variation, * - * interrupts are only generated when the remote counter reaches the * - * threshold, not when the local counter reaches the threshold. In * - * the second mode, both the local counter and the remote counter * - * generate interrupts if they reach the threshold. This second mode * - * is useful for performance monitoring, to track the number of local * - * and remote references to a page. LOCAL_INT determines whether we * - * will generate interrupts when the local counter reaches the * - * threshold. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_value_thresh_u { - bdrkreg_t md_mig_value_thresh_regval; - struct { - bdrkreg_t mvt_threshold : 15; - bdrkreg_t mvt_reserved_1 : 17; - bdrkreg_t mvt_th_action : 3; - bdrkreg_t mvt_sat_action : 3; - bdrkreg_t mvt_reserved : 24; - bdrkreg_t mvt_local_int : 1; - bdrkreg_t mvt_valid : 1; - } md_mig_value_thresh_fld_s; -} md_mig_value_thresh_u_t; - -#else - -typedef union md_mig_value_thresh_u { - bdrkreg_t md_mig_value_thresh_regval; - struct { - bdrkreg_t mvt_valid : 1; - bdrkreg_t mvt_local_int : 1; - bdrkreg_t mvt_reserved : 24; - bdrkreg_t mvt_sat_action : 3; - bdrkreg_t mvt_th_action : 3; - bdrkreg_t mvt_reserved_1 : 17; - bdrkreg_t mvt_threshold : 15; - } md_mig_value_thresh_fld_s; -} md_mig_value_thresh_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the controls for the sizing of the three MOQH request * - * queues. The maximum (and default) value is 4. Queue sizes are in * - * flits. One header equals one flit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_outgoing_rq_queue_size_u { - bdrkreg_t md_outgoing_rq_queue_size_regval; - struct { - bdrkreg_t orqs_reserved_3 : 8; - bdrkreg_t orqs_moqh_p0_rq_size : 3; - bdrkreg_t orqs_reserved_2 : 5; - bdrkreg_t orqs_moqh_p1_rq_size : 3; - bdrkreg_t orqs_reserved_1 : 5; - bdrkreg_t orqs_moqh_np_rq_size : 3; - bdrkreg_t orqs_reserved : 37; - } md_outgoing_rq_queue_size_fld_s; -} md_outgoing_rq_queue_size_u_t; - -#else - -typedef union md_outgoing_rq_queue_size_u { - bdrkreg_t md_outgoing_rq_queue_size_regval; - struct { - bdrkreg_t orqs_reserved : 37; - bdrkreg_t orqs_moqh_np_rq_size : 3; - bdrkreg_t orqs_reserved_1 : 5; - bdrkreg_t orqs_moqh_p1_rq_size : 3; - bdrkreg_t orqs_reserved_2 : 5; - bdrkreg_t orqs_moqh_p0_rq_size : 3; - bdrkreg_t orqs_reserved_3 : 8; - } md_outgoing_rq_queue_size_fld_s; -} md_outgoing_rq_queue_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the 32-bit directory word failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_db_err_data_u { - bdrkreg_t md_bist_db_err_data_regval; - struct { - bdrkreg_t bded_db_er_d : 32; - bdrkreg_t bded_reserved : 32; - } md_bist_db_err_data_fld_s; -} md_bist_db_err_data_u_t; - -#else - -typedef union md_bist_db_err_data_u { - bdrkreg_t md_bist_db_err_data_regval; - struct { - bdrkreg_t bded_reserved : 32; - bdrkreg_t bded_db_er_d : 32; - } md_bist_db_err_data_fld_s; -} md_bist_db_err_data_u_t; - -#endif - - - -/************************************************************************ - * * - * Contains 2 bits that allow the selection of DB debug information * - * at the debug port (see the design specification for descrition of * - * the available debug information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_db_debug_u { - bdrkreg_t md_db_debug_regval; - struct { - bdrkreg_t dd_db_debug_sel : 2; - bdrkreg_t dd_reserved : 62; - } md_db_debug_fld_s; -} md_db_debug_u_t; - -#else - -typedef union md_db_debug_u { - bdrkreg_t md_db_debug_regval; - struct { - bdrkreg_t dd_reserved : 62; - bdrkreg_t dd_db_debug_sel : 2; - } md_db_debug_fld_s; -} md_db_debug_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the IgnoreECC bit. When this bit is set, all ECC errors * - * are ignored. ECC bits will still be generated on writebacks. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mb_ecc_config_u { - bdrkreg_t md_mb_ecc_config_regval; - struct { - bdrkreg_t mec_ignore_dataecc : 1; - bdrkreg_t mec_reserved : 63; - } md_mb_ecc_config_fld_s; -} md_mb_ecc_config_u_t; - -#else - -typedef union md_mb_ecc_config_u { - bdrkreg_t md_mb_ecc_config_regval; - struct { - bdrkreg_t mec_reserved : 63; - bdrkreg_t mec_ignore_dataecc : 1; - } md_mb_ecc_config_fld_s; -} md_mb_ecc_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on read memory errors (both * - * correctable and uncorrectable) and write memory errors (always * - * uncorrectable). The errors are prioritized as follows: * - * highest: uncorrectable read error (READ_UCE) * - * middle: write error (WRITE_UCE) * - * lowest: correctable read error (READ_CE) * - * Each type of error maintains a two-bit valid/overrun field * - * (READ_UCE, WRITE_UCE, or READ_CE). Bit 0 of each two-bit field * - * corresponds to the valid bit, and bit 1 of each two-bit field * - * corresponds to the overrun bit. * - * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occurred. * - * The rule for the overrun bit is that it gets set whenever we are * - * unable to record the address information for this particular * - * error, due to a previous error of the same or higher priority. * - * Note that the syndrome and address information always corresponds * - * to the earliest, highest priority error. * - * Finally, the UCE_DIFF_ADDR bit is set whenever there have been * - * several uncorrectable errors, to different cache line addresses. * - * If all the UCEs were to the same cache line address, then * - * UCE_DIFF_ADDR will be 0. This allows the operating system to * - * detect the case where a UCE error is read exclusively, and then * - * written back by the processor. If the bit is 0, it indicates that * - * no information has been lost about UCEs on other cache lines. In * - * particular, partial writes do a read modify write of the cache * - * line. A UCE read error will be set when the cache line is read, * - * and a UCE write error will occur when the cache line is written * - * back, but the UCE_DIFF_ADDR will not be set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mem_error_u { - bdrkreg_t md_mem_error_regval; - struct { - bdrkreg_t me_reserved_5 : 3; - bdrkreg_t me_address : 30; - bdrkreg_t me_reserved_4 : 7; - bdrkreg_t me_bad_syn : 8; - bdrkreg_t me_reserved_3 : 4; - bdrkreg_t me_read_ce : 2; - bdrkreg_t me_reserved_2 : 2; - bdrkreg_t me_write_uce : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_read_uce : 2; - bdrkreg_t me_reserved : 1; - bdrkreg_t me_uce_diff_addr : 1; - } md_mem_error_fld_s; -} md_mem_error_u_t; - -#else - -typedef union md_mem_error_u { - bdrkreg_t md_mem_error_regval; - struct { - bdrkreg_t me_uce_diff_addr : 1; - bdrkreg_t me_reserved : 1; - bdrkreg_t me_read_uce : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_write_uce : 2; - bdrkreg_t me_reserved_2 : 2; - bdrkreg_t me_read_ce : 2; - bdrkreg_t me_reserved_3 : 4; - bdrkreg_t me_bad_syn : 8; - bdrkreg_t me_reserved_4 : 7; - bdrkreg_t me_address : 30; - bdrkreg_t me_reserved_5 : 3; - } md_mem_error_fld_s; -} md_mem_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on read memory errors (both * - * correctable and uncorrectable) and write memory errors (always * - * uncorrectable). The errors are prioritized as follows: * - * highest: uncorrectable read error (READ_UCE) * - * middle: write error (WRITE_UCE) * - * lowest: correctable read error (READ_CE) * - * Each type of error maintains a two-bit valid/overrun field * - * (READ_UCE, WRITE_UCE, or READ_CE). Bit 0 of each two-bit field * - * corresponds to the valid bit, and bit 1 of each two-bit field * - * corresponds to the overrun bit. * - * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occurred. * - * The rule for the overrun bit is that it gets set whenever we are * - * unable to record the address information for this particular * - * error, due to a previous error of the same or higher priority. * - * Note that the syndrome and address information always corresponds * - * to the earliest, highest priority error. * - * Finally, the UCE_DIFF_ADDR bit is set whenever there have been * - * several uncorrectable errors, to different cache line addresses. * - * If all the UCEs were to the same cache line address, then * - * UCE_DIFF_ADDR will be 0. This allows the operating system to * - * detect the case where a UCE error is read exclusively, and then * - * written back by the processor. If the bit is 0, it indicates that * - * no information has been lost about UCEs on other cache lines. In * - * particular, partial writes do a read modify write of the cache * - * line. A UCE read error will be set when the cache line is read, * - * and a UCE write error will occur when the cache line is written * - * back, but the UCE_DIFF_ADDR will not be set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mem_error_clr_u { - bdrkreg_t md_mem_error_clr_regval; - struct { - bdrkreg_t mec_reserved_5 : 3; - bdrkreg_t mec_address : 30; - bdrkreg_t mec_reserved_4 : 7; - bdrkreg_t mec_bad_syn : 8; - bdrkreg_t mec_reserved_3 : 4; - bdrkreg_t mec_read_ce : 2; - bdrkreg_t mec_reserved_2 : 2; - bdrkreg_t mec_write_uce : 2; - bdrkreg_t mec_reserved_1 : 2; - bdrkreg_t mec_read_uce : 2; - bdrkreg_t mec_reserved : 1; - bdrkreg_t mec_uce_diff_addr : 1; - } md_mem_error_clr_fld_s; -} md_mem_error_clr_u_t; - -#else - -typedef union md_mem_error_clr_u { - bdrkreg_t md_mem_error_clr_regval; - struct { - bdrkreg_t mec_uce_diff_addr : 1; - bdrkreg_t mec_reserved : 1; - bdrkreg_t mec_read_uce : 2; - bdrkreg_t mec_reserved_1 : 2; - bdrkreg_t mec_write_uce : 2; - bdrkreg_t mec_reserved_2 : 2; - bdrkreg_t mec_read_ce : 2; - bdrkreg_t mec_reserved_3 : 4; - bdrkreg_t mec_bad_syn : 8; - bdrkreg_t mec_reserved_4 : 7; - bdrkreg_t mec_address : 30; - bdrkreg_t mec_reserved_5 : 3; - } md_mem_error_clr_fld_s; -} md_mem_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_0_u { - bdrkreg_t md_bist_mb_err_data_0_regval; - struct { - bdrkreg_t bmed0_mb_er_d : 36; - bdrkreg_t bmed0_reserved : 28; - } md_bist_mb_err_data_0_fld_s; -} md_bist_mb_err_data_0_u_t; - -#else - -typedef union md_bist_mb_err_data_0_u { - bdrkreg_t md_bist_mb_err_data_0_regval; - struct { - bdrkreg_t bmed0_reserved : 28; - bdrkreg_t bmed0_mb_er_d : 36; - } md_bist_mb_err_data_0_fld_s; -} md_bist_mb_err_data_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_1_u { - bdrkreg_t md_bist_mb_err_data_1_regval; - struct { - bdrkreg_t bmed1_mb_er_d : 36; - bdrkreg_t bmed1_reserved : 28; - } md_bist_mb_err_data_1_fld_s; -} md_bist_mb_err_data_1_u_t; - -#else - -typedef union md_bist_mb_err_data_1_u { - bdrkreg_t md_bist_mb_err_data_1_regval; - struct { - bdrkreg_t bmed1_reserved : 28; - bdrkreg_t bmed1_mb_er_d : 36; - } md_bist_mb_err_data_1_fld_s; -} md_bist_mb_err_data_1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_2_u { - bdrkreg_t md_bist_mb_err_data_2_regval; - struct { - bdrkreg_t bmed2_mb_er_d : 36; - bdrkreg_t bmed2_reserved : 28; - } md_bist_mb_err_data_2_fld_s; -} md_bist_mb_err_data_2_u_t; - -#else - -typedef union md_bist_mb_err_data_2_u { - bdrkreg_t md_bist_mb_err_data_2_regval; - struct { - bdrkreg_t bmed2_reserved : 28; - bdrkreg_t bmed2_mb_er_d : 36; - } md_bist_mb_err_data_2_fld_s; -} md_bist_mb_err_data_2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_3_u { - bdrkreg_t md_bist_mb_err_data_3_regval; - struct { - bdrkreg_t bmed3_mb_er_d : 36; - bdrkreg_t bmed3_reserved : 28; - } md_bist_mb_err_data_3_fld_s; -} md_bist_mb_err_data_3_u_t; - -#else - -typedef union md_bist_mb_err_data_3_u { - bdrkreg_t md_bist_mb_err_data_3_regval; - struct { - bdrkreg_t bmed3_reserved : 28; - bdrkreg_t bmed3_mb_er_d : 36; - } md_bist_mb_err_data_3_fld_s; -} md_bist_mb_err_data_3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains 1 bit that allow the selection of MB debug information * - * at the debug port (see the design specification for the available * - * debug information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mb_debug_u { - bdrkreg_t md_mb_debug_regval; - struct { - bdrkreg_t md_mb_debug_sel : 1; - bdrkreg_t md_reserved : 63; - } md_mb_debug_fld_s; -} md_mb_debug_u_t; - -#else - -typedef union md_mb_debug_u { - bdrkreg_t md_mb_debug_regval; - struct { - bdrkreg_t md_reserved : 63; - bdrkreg_t md_mb_debug_sel : 1; - } md_mb_debug_fld_s; -} md_mb_debug_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - -#endif /* _ASM_IA64_SN_SN1_HUBMD_H */ diff --git a/include/asm-ia64/sn/sn1/hubmd_next.h b/include/asm-ia64/sn/sn1/hubmd_next.h deleted file mode 100644 index 263dc66e78f..00000000000 --- a/include/asm-ia64/sn/sn1/hubmd_next.h +++ /dev/null @@ -1,812 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBMD_NEXT_H -#define _ASM_IA64_SN_SN1_HUBMD_NEXT_H - -/* XXX moved over from SN/SN0/hubmd.h -- each should be checked for SN1 */ -/* In fact, most of this stuff is wrong. Some is correct, such as - * MD_PAGE_SIZE and MD_PAGE_NUM_SHFT. - */ - -#define MD_PERF_COUNTERS 6 -#define MD_PERF_SETS 6 - -#define MD_SIZE_EMPTY 0 -#define MD_SIZE_64MB 1 -#define MD_SIZE_128MB 2 -#define MD_SIZE_256MB 3 -#define MD_SIZE_512MB 4 -#define MD_SIZE_1GB 5 - -#define MD_SIZE_BYTES(size) ((size) == 0 ? 0 : 0x2000000L << (size)) -#define MD_SIZE_MBYTES(size) ((size) == 0 ? 0 : 0x20 << (size)) -#define MD_NUM_ENABLED(_x) ((_x & 0x1) + ((_x >> 1) & 0x1) + \ - ((_x >> 2) & 0x1) + ((_x >> 3) & 0x1)) - - -/* Hardware page size and shift */ - -#define MD_PAGE_SIZE 16384 /* Page size in bytes */ -#define MD_PAGE_NUM_SHFT 14 /* Address to page number shift */ - -#define MMC_IO_PROT (UINT64_CAST 1 << 45) - -/* Register offsets from LOCAL_HUB or REMOTE_HUB */ -#define MD_PERF_SEL 0x210000 /* Select perf monitor events */ - -/* MD_MIG_VALUE_THRESH bit definitions */ - -#define MD_MIG_VALUE_THRES_VALID_MASK (UINT64_CAST 0x1 << 63) -#define MD_MIG_VALUE_THRES_VALUE_MASK (UINT64_CAST 0xfffff) - -/* MD_MIG_CANDIDATE bit definitions */ - -#define MD_MIG_CANDIDATE_VALID_MASK (UINT64_CAST 0x1 << 63) -#define MD_MIG_CANDIDATE_VALID_SHFT 63 -#define MD_MIG_CANDIDATE_TYPE_MASK (UINT64_CAST 0x1 << 30) -#define MD_MIG_CANDIDATE_TYPE_SHFT 30 -#define MD_MIG_CANDIDATE_OVERRUN_MASK (UINT64_CAST 0x1 << 29) -#define MD_MIG_CANDIDATE_OVERRUN_SHFT 29 -#define MD_MIG_CANDIDATE_NODEID_MASK (UINT64_CAST 0x1ff << 20) -#define MD_MIG_CANDIDATE_NODEID_SHFT 20 -#define MD_MIG_CANDIDATE_ADDR_MASK (UINT64_CAST 0x3ffff) - - -/* XXX protection and migration are completely revised on SN1. On - SN0, the reference count and protection fields were accessed in the - same word, but on SN1 they reside at different addresses. The - users of these macros will need to be rewritten. Also, the MD page - size is 16K on SN1 but 4K on SN0. */ - -/* Premium SIMM protection entry shifts and masks. */ - -#define MD_PPROT_SHFT 0 /* Prot. field */ -#define MD_PPROT_MASK 0xf -#define MD_PPROT_REFCNT_SHFT 5 /* Reference count */ -#define MD_PPROT_REFCNT_WIDTH 0x7ffff -#define MD_PPROT_REFCNT_MASK (MD_PPROT_REFCNT_WIDTH << 5) - -#define MD_PPROT_IO_SHFT 8 /* I/O Prot field */ - -/* Standard SIMM protection entry shifts and masks. */ - -#define MD_SPROT_SHFT 0 /* Prot. field */ -#define MD_SPROT_MASK 0xf -#define MD_SPROT_IO_SHFT 8 -#define MD_SPROT_REFCNT_SHFT 5 /* Reference count */ -#define MD_SPROT_REFCNT_WIDTH 0x7ff -#define MD_SPROT_REFCNT_MASK (MD_SPROT_REFCNT_WIDTH << 5) - -/* Migration modes used in protection entries */ - -#define MD_PROT_MIGMD_IREL (UINT64_CAST 0x3 << 3) -#define MD_PROT_MIGMD_IABS (UINT64_CAST 0x2 << 3) -#define MD_PROT_MIGMD_PREL (UINT64_CAST 0x1 << 3) -#define MD_PROT_MIGMD_OFF (UINT64_CAST 0x0 << 3) - -/* - * Operations on Memory/Directory DIMM control register - */ - -#define DIRTYPE_PREMIUM 1 -#define DIRTYPE_STANDARD 0 - -/* - * Operations on page migration count difference and absolute threshold - * registers - */ - -#define MD_MIG_VALUE_THRESH_GET(region) ( \ - REMOTE_HUB_L((region), MD_MIG_VALUE_THRESH) & \ - MD_MIG_VALUE_THRES_VALUE_MASK) - -#define MD_MIG_VALUE_THRESH_SET(region, value) ( \ - REMOTE_HUB_S((region), MD_MIG_VALUE_THRESH, \ - MD_MIG_VALUE_THRES_VALID_MASK | (value))) - -#define MD_MIG_VALUE_THRESH_ENABLE(region) ( \ - REMOTE_HUB_S((region), MD_MIG_VALUE_THRESH, \ - REMOTE_HUB_L((region), MD_MIG_VALUE_THRESH) \ - | MD_MIG_VALUE_THRES_VALID_MASK)) - -/* - * Operations on page migration candidate register - */ - -#define MD_MIG_CANDIDATE_GET(my_region_id) ( \ - REMOTE_HUB_L((my_region_id), MD_MIG_CANDIDATE_CLR)) - -#define MD_MIG_CANDIDATE_HWPFN(value) ((value) & MD_MIG_CANDIDATE_ADDR_MASK) - -#define MD_MIG_CANDIDATE_NODEID(value) ( \ - ((value) & MD_MIG_CANDIDATE_NODEID_MASK) >> MD_MIG_CANDIDATE_NODEID_SHFT) - -#define MD_MIG_CANDIDATE_TYPE(value) ( \ - ((value) & MD_MIG_CANDIDATE_TYPE_MASK) >> MD_MIG_CANDIDATE_TYPE_SHFT) - -#define MD_MIG_CANDIDATE_VALID(value) ( \ - ((value) & MD_MIG_CANDIDATE_VALID_MASK) >> MD_MIG_CANDIDATE_VALID_SHFT) - -/* - * Macros to retrieve fields in the protection entry - */ - -/* for Premium SIMM */ -#define MD_PPROT_REFCNT_GET(value) ( \ - ((value) & MD_PPROT_REFCNT_MASK) >> MD_PPROT_REFCNT_SHFT) - -/* for Standard SIMM */ -#define MD_SPROT_REFCNT_GET(value) ( \ - ((value) & MD_SPROT_REFCNT_MASK) >> MD_SPROT_REFCNT_SHFT) - -#ifndef __ASSEMBLY__ -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_sel : 3, - perf_en : 1, - perf_rsvd : 60; - } perf_sel_bits; -} md_perf_sel_t; - -#else - -typedef union md_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_rsvd : 60, - perf_en : 1, - perf_sel : 3; - } perf_sel_bits; -} md_perf_sel_t; - -#endif -#endif /* __ASSEMBLY__ */ - - -/* Like SN0, SN1 supports a mostly-flat address space with 8 - CPU-visible, evenly spaced, contiguous regions, or "software - banks". On SN1, software bank n begins at addresses n * 1GB, - 0 <= n < 8. - - Physically (and very unlike SN0), each SN1 node board contains 8 - dimm sockets, arranged as 4 "DIMM banks" of 2 dimms each. DIMM - size and width (x4/x8) is assigned per dimm bank. Each DIMM bank - consists of 2 "physical banks", one on the front sides of the 2 - DIMMs and the other on the back sides. Therefore a node has a - total of 8 ( = 4 * 2) physical banks. They are collectively - referred to as "locational banks", since the locational bank number - depends on the physical location of the DIMMs on the board. - - Dimm bank 0, Phys bank 0a (locational bank 0a) - Slot D0 ---------------------------------------------- - Dimm bank 0, Phys bank 1a (locational bank 1a) - - Dimm bank 1, Phys bank 0a (locational bank 2a) - Slot D1 ---------------------------------------------- - Dimm bank 1, Phys bank 1a (locational bank 3a) - - Dimm bank 2, Phys bank 0a (locational bank 4a) - Slot D2 ---------------------------------------------- - Dimm bank 2, Phys bank 1a (locational bank 5a) - - Dimm bank 3, Phys bank 0a (locational bank 6a) - Slot D3 ---------------------------------------------- - Dimm bank 3, Phys bank 1a (locational bank 7a) - - Dimm bank 0, Phys bank 0b (locational bank 0b) - Slot D4 ---------------------------------------------- - Dimm bank 0, Phys bank 1b (locational bank 1b) - - Dimm bank 1, Phys bank 0b (locational bank 2b) - Slot D5 ---------------------------------------------- - Dimm bank 1, Phys bank 1b (locational bank 3b) - - Dimm bank 2, Phys bank 0b (locational bank 4b) - Slot D6 ---------------------------------------------- - Dimm bank 2, Phys bank 1b (locational bank 5b) - - Dimm bank 3, Phys bank 0b (locational bank 6b) - Slot D7 ---------------------------------------------- - Dimm bank 3, Phys bank 1b (locational bank 7b) - - Since bank size is assigned per DIMM bank, each pair of locational - banks must have the same size. However, they may be - enabled/disabled individually. - - The locational banks map to the software banks via the dimm0_sel - field in MD_MEMORY_CONFIG. When the field is 0 (the usual case), - the mapping is direct: eg. locational bank 1 (dimm bank 0, - physical bank 1, which is the back side of the first DIMM pair) - corresponds to software bank 1, at node offset 1GB. More - generally, locational bank = software bank XOR dimm0_sel. - - All the PROM's data structures (promlog variables, klconfig, etc.) - track memory by the locational bank number. The kernel usually - tracks memory by the software bank number. - memsupport.c:slot_psize_compute() performs the mapping. - - (Note: the terms "locational bank" and "software bank" are not - offical in any way, but I've tried to make the PROM use them - consistently -- bjj.) - */ - -#define MD_MEM_BANKS 8 -#define MD_MEM_DIMM_BANKS 4 -#define MD_BANK_SHFT 30 /* log2(1 GB) */ -#define MD_BANK_MASK (UINT64_CAST 0x7 << 30) -#define MD_BANK_SIZE (UINT64_CAST 1 << MD_BANK_SHFT) /* 1 GB */ -#define MD_BANK_OFFSET(_b) (UINT64_CAST (_b) << MD_BANK_SHFT) -#define MD_BANK_GET(addr) (((addr) & MD_BANK_MASK) >> MD_BANK_SHFT) -#define MD_BANK_TO_DIMM_BANK(_b) (( (_b) >> 1) & 0x3) -#define MD_BANK_TO_PHYS_BANK(_b) (( (_b) >> 0) & 0x1) -#define MD_DIMM_BANK_GET(addr) MD_BANK_TO_DIMM_BANK(MD_BANK_GET(addr)) -#define MD_PHYS_BANK_GET(addr) MD_BANK_TO_PHYS_BANK(MD_BANK_GET(addr)) - - -/* Split an MD pointer (or message source & suppl. fields) into node, device */ - -#define MD_PTR_NODE_SHFT 3 -#define MD_PTR_DEVICE_MASK 0x7 -#define MD_PTR_SUBNODE0_MASK 0x1 -#define MD_PTR_SUBNODE1_MASK 0x4 - - -/********************************************************************** - - Backdoor protection and page counter structures - -**********************************************************************/ - -/* Protection entries and page counters are interleaved at 4 separate - addresses, 0x10 apart. Software must read/write all four. */ - -#define BD_ITLV_COUNT 4 -#define BD_ITLV_STRIDE 0x10 - -/* Protection entries */ - -/* (these macros work for standard (_rgn < 32) or premium DIMMs) */ -#define MD_PROT_SHFT(_rgn, _io) ((((_rgn) & 0x20) >> 2 | \ - ((_rgn) & 0x01) << 2 | \ - ((_io) & 0x1) << 1) * 8) -#define MD_PROT_MASK(_rgn, _io) (0xff << MD_PROT_SHFT(_rgn, _io)) -#define MD_PROT_GET(_val, _rgn, _io) \ - (((_val) & MD_PROT_MASK(_rgn, _io)) >> MD_PROT_SHFT(_rgn, _io)) - -/* Protection field values */ - -#define MD_PROT_RW (UINT64_CAST 0xff) -#define MD_PROT_RO (UINT64_CAST 0x0f) -#define MD_PROT_NO (UINT64_CAST 0x00) - - - - -/********************************************************************** - - Directory format structures - -***********************************************************************/ - -#ifndef __ASSEMBLY__ - -/* Standard Directory Entries */ - -#ifdef LITTLE_ENDIAN - -struct md_sdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t sdp_format : 2; - bdrkreg_t sdp_state : 3; - bdrkreg_t sdp_priority : 3; - bdrkreg_t sdp_pointer1 : 8; - bdrkreg_t sdp_ecc : 6; - bdrkreg_t sdp_locprot : 1; - bdrkreg_t sdp_reserved : 1; - bdrkreg_t sdp_crit_word_off : 3; - bdrkreg_t sdp_pointer2 : 5; - bdrkreg_t sdp_fill : 32; -}; - -#else - -struct md_sdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t sdp_fill : 32; - bdrkreg_t sdp_pointer2 : 5; - bdrkreg_t sdp_crit_word_off : 3; - bdrkreg_t sdp_reserved : 1; - bdrkreg_t sdp_locprot : 1; - bdrkreg_t sdp_ecc : 6; - bdrkreg_t sdp_pointer1 : 8; - bdrkreg_t sdp_priority : 3; - bdrkreg_t sdp_state : 3; - bdrkreg_t sdp_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_sdir_fine_fmt { /* shared (fine) */ - bdrkreg_t sdf_format : 2; - bdrkreg_t sdf_tag1 : 3; - bdrkreg_t sdf_tag2 : 3; - bdrkreg_t sdf_vector1 : 8; - bdrkreg_t sdf_ecc : 6; - bdrkreg_t sdf_locprot : 1; - bdrkreg_t sdf_tag2valid : 1; - bdrkreg_t sdf_vector2 : 8; - bdrkreg_t sdf_fill : 32; -}; - -#else - -struct md_sdir_fine_fmt { /* shared (fine) */ - bdrkreg_t sdf_fill : 32; - bdrkreg_t sdf_vector2 : 8; - bdrkreg_t sdf_tag2valid : 1; - bdrkreg_t sdf_locprot : 1; - bdrkreg_t sdf_ecc : 6; - bdrkreg_t sdf_vector1 : 8; - bdrkreg_t sdf_tag2 : 3; - bdrkreg_t sdf_tag1 : 3; - bdrkreg_t sdf_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_sdir_coarse_fmt { /* shared (coarse) */ - bdrkreg_t sdc_format : 2; - bdrkreg_t sdc_reserved_1 : 6; - bdrkreg_t sdc_vector_a : 8; - bdrkreg_t sdc_ecc : 6; - bdrkreg_t sdc_locprot : 1; - bdrkreg_t sdc_reserved : 1; - bdrkreg_t sdc_vector_b : 8; - bdrkreg_t sdc_fill : 32; -}; - -#else - -struct md_sdir_coarse_fmt { /* shared (coarse) */ - bdrkreg_t sdc_fill : 32; - bdrkreg_t sdc_vector_b : 8; - bdrkreg_t sdc_reserved : 1; - bdrkreg_t sdc_locprot : 1; - bdrkreg_t sdc_ecc : 6; - bdrkreg_t sdc_vector_a : 8; - bdrkreg_t sdc_reserved_1 : 6; - bdrkreg_t sdc_format : 2; -}; - -#endif - -typedef union md_sdir { - /* The 32 bits of standard directory, in bits 31:0 */ - uint64_t sd_val; - struct md_sdir_pointer_fmt sdp_fmt; - struct md_sdir_fine_fmt sdf_fmt; - struct md_sdir_coarse_fmt sdc_fmt; -} md_sdir_t; - - -/* Premium Directory Entries */ - -#ifdef LITTLE_ENDIAN - -struct md_pdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t pdp_format : 2; - bdrkreg_t pdp_state : 3; - bdrkreg_t pdp_priority : 3; - bdrkreg_t pdp_pointer1_a : 8; - bdrkreg_t pdp_reserved_4 : 6; - bdrkreg_t pdp_pointer1_b : 3; - bdrkreg_t pdp_reserved_3 : 7; - bdrkreg_t pdp_ecc_a : 6; - bdrkreg_t pdp_locprot : 1; - bdrkreg_t pdp_reserved_2 : 1; - bdrkreg_t pdp_crit_word_off : 3; - bdrkreg_t pdp_pointer2_a : 5; - bdrkreg_t pdp_ecc_b : 1; - bdrkreg_t pdp_reserved_1 : 5; - bdrkreg_t pdp_pointer2_b : 3; - bdrkreg_t pdp_reserved : 7; -}; - -#else - -struct md_pdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t pdp_reserved : 7; - bdrkreg_t pdp_pointer2_b : 3; - bdrkreg_t pdp_reserved_1 : 5; - bdrkreg_t pdp_ecc_b : 1; - bdrkreg_t pdp_pointer2_a : 5; - bdrkreg_t pdp_crit_word_off : 3; - bdrkreg_t pdp_reserved_2 : 1; - bdrkreg_t pdp_locprot : 1; - bdrkreg_t pdp_ecc_a : 6; - bdrkreg_t pdp_reserved_3 : 7; - bdrkreg_t pdp_pointer1_b : 3; - bdrkreg_t pdp_reserved_4 : 6; - bdrkreg_t pdp_pointer1_a : 8; - bdrkreg_t pdp_priority : 3; - bdrkreg_t pdp_state : 3; - bdrkreg_t pdp_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_pdir_fine_fmt { /* shared (fine) */ - bdrkreg_t pdf_format : 2; - bdrkreg_t pdf_tag1_a : 3; - bdrkreg_t pdf_tag2_a : 3; - bdrkreg_t pdf_vector1_a : 8; - bdrkreg_t pdf_reserved_1 : 6; - bdrkreg_t pdf_tag1_b : 2; - bdrkreg_t pdf_vector1_b : 8; - bdrkreg_t pdf_ecc_a : 6; - bdrkreg_t pdf_locprot : 1; - bdrkreg_t pdf_tag2valid : 1; - bdrkreg_t pdf_vector2_a : 8; - bdrkreg_t pdf_ecc_b : 1; - bdrkreg_t pdf_reserved : 5; - bdrkreg_t pdf_tag2_b : 2; - bdrkreg_t pdf_vector2_b : 8; -}; - -#else - -struct md_pdir_fine_fmt { /* shared (fine) */ - bdrkreg_t pdf_vector2_b : 8; - bdrkreg_t pdf_tag2_b : 2; - bdrkreg_t pdf_reserved : 5; - bdrkreg_t pdf_ecc_b : 1; - bdrkreg_t pdf_vector2_a : 8; - bdrkreg_t pdf_tag2valid : 1; - bdrkreg_t pdf_locprot : 1; - bdrkreg_t pdf_ecc_a : 6; - bdrkreg_t pdf_vector1_b : 8; - bdrkreg_t pdf_tag1_b : 2; - bdrkreg_t pdf_reserved_1 : 6; - bdrkreg_t pdf_vector1_a : 8; - bdrkreg_t pdf_tag2_a : 3; - bdrkreg_t pdf_tag1_a : 3; - bdrkreg_t pdf_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_pdir_sparse_fmt { /* shared (sparse) */ - bdrkreg_t pds_format : 2; - bdrkreg_t pds_column_a : 6; - bdrkreg_t pds_row_a : 8; - bdrkreg_t pds_column_b : 16; - bdrkreg_t pds_ecc_a : 6; - bdrkreg_t pds_locprot : 1; - bdrkreg_t pds_reserved_1 : 1; - bdrkreg_t pds_row_b : 8; - bdrkreg_t pds_ecc_b : 1; - bdrkreg_t pds_column_c : 10; - bdrkreg_t pds_reserved : 5; -}; - -#else - -struct md_pdir_sparse_fmt { /* shared (sparse) */ - bdrkreg_t pds_reserved : 5; - bdrkreg_t pds_column_c : 10; - bdrkreg_t pds_ecc_b : 1; - bdrkreg_t pds_row_b : 8; - bdrkreg_t pds_reserved_1 : 1; - bdrkreg_t pds_locprot : 1; - bdrkreg_t pds_ecc_a : 6; - bdrkreg_t pds_column_b : 16; - bdrkreg_t pds_row_a : 8; - bdrkreg_t pds_column_a : 6; - bdrkreg_t pds_format : 2; -}; - -#endif - -typedef union md_pdir { - /* The 64 bits of premium directory */ - uint64_t pd_val; - struct md_pdir_pointer_fmt pdp_fmt; - struct md_pdir_fine_fmt pdf_fmt; - struct md_pdir_sparse_fmt pds_fmt; -} md_pdir_t; - -#endif /* __ASSEMBLY__ */ - - -/********************************************************************** - - The defines for backdoor directory and backdoor ECC. - -***********************************************************************/ - -/* Directory formats, for each format's "format" field */ - -#define MD_FORMAT_UNOWNED (UINT64_CAST 0x0) /* 00 */ -#define MD_FORMAT_POINTER (UINT64_CAST 0x1) /* 01 */ -#define MD_FORMAT_SHFINE (UINT64_CAST 0x2) /* 10 */ -#define MD_FORMAT_SHCOARSE (UINT64_CAST 0x3) /* 11 */ - /* Shared coarse (standard) and shared sparse (premium) both use fmt 0x3 */ - - -/* - * Cacheline state values. - * - * These are really *software* notions of the "state" of a cacheline; but the - * actual values have been carefully chosen to align with some hardware values! - * The MD_FMT_ST_TO_STATE macro is used to convert from hardware format/state - * pairs in the directory entried into one of these cacheline state values. - */ - -#define MD_DIR_EXCLUSIVE (UINT64_CAST 0x0) /* ptr format, hw-defined */ -#define MD_DIR_UNOWNED (UINT64_CAST 0x1) /* format=0 */ -#define MD_DIR_SHARED (UINT64_CAST 0x2) /* format=2,3 */ -#define MD_DIR_BUSY_SHARED (UINT64_CAST 0x4) /* ptr format, hw-defined */ -#define MD_DIR_BUSY_EXCL (UINT64_CAST 0x5) /* ptr format, hw-defined */ -#define MD_DIR_WAIT (UINT64_CAST 0x6) /* ptr format, hw-defined */ -#define MD_DIR_POISONED (UINT64_CAST 0x7) /* ptr format, hw-defined */ - -#ifndef __ASSEMBLY__ - -/* Convert format and state fields into a single "cacheline state" value, defined above */ - -#define MD_FMT_ST_TO_STATE(fmt, state) \ - ((fmt) == MD_FORMAT_POINTER ? (state) : \ - (fmt) == MD_FORMAT_UNOWNED ? MD_DIR_UNOWNED : \ - MD_DIR_SHARED) -#define MD_DIR_STATE(x) MD_FMT_ST_TO_STATE(MD_DIR_FORMAT(x), MD_DIR_STVAL(x)) - -#endif /* __ASSEMBLY__ */ - - - -/* Directory field shifts and masks */ - -/* Standard */ - -#define MD_SDIR_FORMAT_SHFT 0 /* All formats */ -#define MD_SDIR_FORMAT_MASK (0x3 << 0) -#define MD_SDIR_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_SDIR_STATE_MASK (0x7 << 2) - -/* Premium */ - -#define MD_PDIR_FORMAT_SHFT 0 /* All formats */ -#define MD_PDIR_FORMAT_MASK (0x3 << 0) -#define MD_PDIR_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_PDIR_STATE_MASK (0x7 << 2) - -/* Generic */ - -#define MD_FORMAT_SHFT 0 /* All formats */ -#define MD_FORMAT_MASK (0x3 << 0) -#define MD_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_STATE_MASK (0x7 << 2) - - -/* Special shifts to reconstruct fields from the _a and _b parts */ - -/* Standard: only shared coarse has split fields */ - -#define MD_SDC_VECTORB_SHFT 8 /* eg: sdc_vector_a is 8 bits */ - -/* Premium: pointer, shared fine, shared sparse */ - -#define MD_PDP_POINTER1A_MASK 0xFF -#define MD_PDP_POINTER1B_SHFT 8 -#define MD_PDP_POINTER2B_SHFT 5 -#define MD_PDP_ECCB_SHFT 6 - -#define MD_PDF_VECTOR1B_SHFT 8 -#define MD_PDF_VECTOR2B_SHFT 8 -#define MD_PDF_TAG1B_SHFT 3 -#define MD_PDF_TAG2B_SHFT 3 -#define MD_PDF_ECC_SHFT 6 - -#define MD_PDS_ROWB_SHFT 8 -#define MD_PDS_COLUMNB_SHFT 6 -#define MD_PDS_COLUMNC_SHFT (MD_PDS_COLUMNB_SHFT + 16) -#define MD_PDS_ECC_SHFT 6 - - - -/* - * Directory/protection/counter initialization values, premium and standard - */ - -#define MD_PDIR_INIT 0 -#define MD_PDIR_INIT_CNT 0 -#define MD_PDIR_INIT_PROT 0 - -#define MD_SDIR_INIT 0 -#define MD_SDIR_INIT_CNT 0 -#define MD_SDIR_INIT_PROT 0 - -#define MD_PDIR_MASK 0xffffffffffffffff -#define MD_SDIR_MASK 0xffffffff - -/* When premium mode is on for probing but standard directory memory - is installed, the valid directory bits depend on the phys. bank */ -#define MD_PDIR_PROBE_MASK(pb) 0xffffffffffffffff -#define MD_SDIR_PROBE_MASK(pb) (0xffff0000ffff << ((pb) ? 16 : 0)) - - -/* - * Misc. field extractions and conversions - */ - -/* Convert an MD pointer (or message source, supplemental fields) */ - -#define MD_PTR_NODE(x) ((x) >> MD_PTR_NODE_SHFT) -#define MD_PTR_DEVICE(x) ((x) & MD_PTR_DEVICE_MASK) -#define MD_PTR_SLICE(x) (((x) & MD_PTR_SUBNODE0_MASK) | \ - ((x) & MD_PTR_SUBNODE1_MASK) >> 1) -#define MD_PTR_OWNER_CPU(x) (! ((x) & 2)) -#define MD_PTR_OWNER_IO(x) ((x) & 2) - -/* Extract format and raw state from a directory entry */ - -#define MD_DIR_FORMAT(x) ((x) >> MD_SDIR_FORMAT_SHFT & \ - MD_SDIR_FORMAT_MASK >> MD_SDIR_FORMAT_SHFT) -#define MD_DIR_STVAL(x) ((x) >> MD_SDIR_STATE_SHFT & \ - MD_SDIR_STATE_MASK >> MD_SDIR_STATE_SHFT) - -/* Mask & Shift to get HSPEC_ADDR from MD DIR_ERROR register */ -#define ERROR_ADDR_SHFT 3 -#define ERROR_HSPEC_SHFT 3 -#define DIR_ERR_HSPEC_MASK 0x1fffffff8 - -/* - * DIR_ERR* and MEM_ERR* defines are used to avoid ugly - * #ifdefs for SN0 and SN1 in memerror.c code. See SN0/hubmd.h - * for corresponding SN0 definitions. - */ -#define md_dir_error_t md_dir_error_u_t -#define md_mem_error_t md_mem_error_u_t -#define derr_reg md_dir_error_regval -#define merr_reg md_mem_error_regval - -#define DIR_ERR_UCE_VALID dir_err.md_dir_error_fld_s.de_uce_valid -#define DIR_ERR_AE_VALID dir_err.md_dir_error_fld_s.de_ae_valid -#define DIR_ERR_BAD_SYN dir_err.md_dir_error_fld_s.de_bad_syn -#define DIR_ERR_CE_OVERRUN dir_err.md_dir_error_fld_s.de_ce_overrun -#define MEM_ERR_ADDRESS mem_err.md_mem_error_fld_s.me_address - /* BRINGUP Can the overrun bit be set without the valid bit? */ -#define MEM_ERR_CE_OVERRUN (mem_err.md_mem_error_fld_s.me_read_ce >> 1) -#define MEM_ERR_BAD_SYN mem_err.md_mem_error_fld_s.me_bad_syn -#define MEM_ERR_UCE_VALID (mem_err.md_mem_error_fld_s.me_read_uce & 1) - - - -/********************************************************************* - - We have the shift and masks of various fields defined below. - - *********************************************************************/ - -/* MD_REFRESH_CONTROL fields */ - -#define MRC_ENABLE_SHFT 63 -#define MRC_ENABLE_MASK (UINT64_CAST 1 << 63) -#define MRC_ENABLE (UINT64_CAST 1 << 63) -#define MRC_COUNTER_SHFT 12 -#define MRC_COUNTER_MASK (UINT64_CAST 0xfff << 12) -#define MRC_CNT_THRESH_MASK 0xfff -#define MRC_RESET_DEFAULTS (UINT64_CAST 0x800) - -/* MD_DIR_CONFIG fields */ - -#define MDC_DIR_PREMIUM (UINT64_CAST 1 << 0) -#define MDC_IGNORE_ECC_SHFT 1 -#define MDC_IGNORE_ECC_MASK (UINT64_CAST 1 << 1) - -/* MD_MEMORY_CONFIG fields */ - -#define MMC_RP_CONFIG_SHFT 61 -#define MMC_RP_CONFIG_MASK (UINT64_CAST 1 << 61) -#define MMC_RCD_CONFIG_SHFT 60 -#define MMC_RCD_CONFIG_MASK (UINT64_CAST 1 << 60) -#define MMC_MB_NEG_EDGE_SHFT 56 -#define MMC_MB_NEG_EDGE_MASK (UINT64_CAST 0x7 << 56) -#define MMC_SAMPLE_TIME_SHFT 52 -#define MMC_SAMPLE_TIME_MASK (UINT64_CAST 0x3 << 52) -#define MMC_DELAY_MUX_SEL_SHFT 50 -#define MMC_DELAY_MUX_SEL_MASK (UINT64_CAST 0x3 << 50) -#define MMC_PHASE_DELAY_SHFT 49 -#define MMC_PHASE_DELAY_MASK (UINT64_CAST 1 << 49) -#define MMC_DB_NEG_EDGE_SHFT 48 -#define MMC_DB_NEG_EDGE_MASK (UINT64_CAST 1 << 48) -#define MMC_CPU_PROT_IGNORE_SHFT 47 -#define MMC_CPU_PROT_IGNORE_MASK (UINT64_CAST 1 << 47) -#define MMC_IO_PROT_IGNORE_SHFT 46 -#define MMC_IO_PROT_IGNORE_MASK (UINT64_CAST 1 << 46) -#define MMC_IO_PROT_EN_SHFT 45 -#define MMC_IO_PROT_EN_MASK (UINT64_CAST 1 << 45) -#define MMC_CC_ENABLE_SHFT 44 -#define MMC_CC_ENABLE_MASK (UINT64_CAST 1 << 44) -#define MMC_DIMM0_SEL_SHFT 32 -#define MMC_DIMM0_SEL_MASK (UINT64_CAST 0x3 << 32) -#define MMC_DIMM_SIZE_SHFT(_dimm) ((_dimm << 3) + 4) -#define MMC_DIMM_SIZE_MASK(_dimm) (UINT64_CAST 0xf << MMC_DIMM_SIZE_SHFT(_dimm)) -#define MMC_DIMM_WIDTH_SHFT(_dimm) ((_dimm << 3) + 3) -#define MMC_DIMM_WIDTH_MASK(_dimm) (UINT64_CAST 0x1 << MMC_DIMM_WIDTH_SHFT(_dimm)) -#define MMC_DIMM_BANKS_SHFT(_dimm) (_dimm << 3) -#define MMC_DIMM_BANKS_MASK(_dimm) (UINT64_CAST 0x3 << MMC_DIMM_BANKS_SHFT(_dimm)) -#define MMC_BANK_ALL_MASK 0xffffffffLL -/* Default values for write-only bits in MD_MEMORY_CONFIG */ -#define MMC_DEFAULT_BITS (UINT64_CAST 0x7 << MMC_MB_NEG_EDGE_SHFT) - -/* MD_MB_ECC_CONFIG fields */ - -#define MEC_IGNORE_ECC (UINT64_CAST 0x1 << 0) - -/* MD_BIST_DATA fields */ - -#define MBD_BIST_WRITE (UINT64_CAST 1 << 7) -#define MBD_BIST_CYCLE (UINT64_CAST 1 << 6) -#define MBD_BIST_BYTE (UINT64_CAST 1 << 5) -#define MBD_BIST_NIBBLE (UINT64_CAST 1 << 4) -#define MBD_BIST_DATA_MASK 0xf - -/* MD_BIST_CTL fields */ - -#define MBC_DIMM_SHFT 5 -#define MBC_DIMM_MASK (UINT64_CAST 0x3 << 5) -#define MBC_BANK_SHFT 4 -#define MBC_BANK_MASK (UINT64_CAST 0x1 << 4) -#define MBC_BIST_RESET (UINT64_CAST 0x1 << 2) -#define MBC_BIST_STOP (UINT64_CAST 0x1 << 1) -#define MBC_BIST_START (UINT64_CAST 0x1 << 0) - -#define MBC_GO(dimm, bank) \ - (((dimm) << MBC_DIMM_SHFT) & MBC_DIMM_MASK | \ - ((bank) << MBC_BANK_SHFT) & MBC_BANK_MASK | \ - MBC_BIST_START) - -/* MD_BIST_STATUS fields */ - -#define MBS_BIST_DONE (UINT64_CAST 0X1 << 1) -#define MBS_BIST_PASSED (UINT64_CAST 0X1 << 0) - -/* MD_JUNK_BUS_TIMING fields */ - -#define MJT_SYNERGY_ENABLE_SHFT 40 -#define MJT_SYNERGY_ENABLE_MASK (UINT64_CAST 0Xff << MJT_SYNERGY_ENABLE_SHFT) -#define MJT_SYNERGY_SETUP_SHFT 32 -#define MJT_SYNERGY_SETUP_MASK (UINT64_CAST 0Xff << MJT_SYNERGY_SETUP_SHFT) -#define MJT_UART_ENABLE_SHFT 24 -#define MJT_UART_ENABLE_MASK (UINT64_CAST 0Xff << MJT_UART_ENABLE_SHFT) -#define MJT_UART_SETUP_SHFT 16 -#define MJT_UART_SETUP_MASK (UINT64_CAST 0Xff << MJT_UART_SETUP_SHFT) -#define MJT_FPROM_ENABLE_SHFT 8 -#define MJT_FPROM_ENABLE_MASK (UINT64_CAST 0Xff << MJT_FPROM_ENABLE_SHFT) -#define MJT_FPROM_SETUP_SHFT 0 -#define MJT_FPROM_SETUP_MASK (UINT64_CAST 0Xff << MJT_FPROM_SETUP_SHFT) - -#define MEM_ERROR_VALID_CE 1 - - -/* MD_FANDOP_CAC_STAT0, MD_FANDOP_CAC_STAT1 addr field shift */ - -#define MFC_ADDR_SHFT 6 - -#endif /* _ASM_IA64_SN_SN1_HUBMD_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hubni.h b/include/asm-ia64/sn/sn1/hubni.h deleted file mode 100644 index 6bfc241fac8..00000000000 --- a/include/asm-ia64/sn/sn1/hubni.h +++ /dev/null @@ -1,1781 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBNI_H -#define _ASM_IA64_SN_SN1_HUBNI_H - - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - -#define NI_PORT_STATUS 0x00680000 /* LLP Status */ - - - -#define NI_PORT_RESET 0x00680008 /* - * Reset the Network - * Interface - */ - - - -#define NI_RESET_ENABLE 0x00680010 /* Warm Reset Enable */ - - - -#define NI_DIAG_PARMS 0x00680018 /* - * Diagnostic - * Parameters - */ - - - -#define NI_CHANNEL_CONTROL 0x00680020 /* - * Virtual channel - * control - */ - - - -#define NI_CHANNEL_TEST 0x00680028 /* LLP Test Control. */ - - - -#define NI_PORT_PARMS 0x00680030 /* LLP Parameters */ - - - -#define NI_CHANNEL_AGE 0x00680038 /* - * Network age - * injection control - */ - - - -#define NI_PORT_ERRORS 0x00680100 /* Errors */ - - - -#define NI_PORT_HEADER_A 0x00680108 /* - * Error Header first - * half - */ - - - -#define NI_PORT_HEADER_B 0x00680110 /* - * Error Header second - * half - */ - - - -#define NI_PORT_SIDEBAND 0x00680118 /* Error Sideband */ - - - -#define NI_PORT_ERROR_CLEAR 0x00680120 /* - * Clear the Error - * bits - */ - - - -#define NI_LOCAL_TABLE_0 0x00681000 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_1 0x00681008 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_2 0x00681010 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_3 0x00681018 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_4 0x00681020 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_5 0x00681028 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_6 0x00681030 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_7 0x00681038 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_8 0x00681040 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_9 0x00681048 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_10 0x00681050 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_11 0x00681058 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_12 0x00681060 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_13 0x00681068 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_14 0x00681070 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_15 0x00681078 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_16 0x00681080 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_17 0x00681088 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_18 0x00681090 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_19 0x00681098 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_20 0x006810A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_21 0x006810A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_22 0x006810B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_23 0x006810B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_24 0x006810C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_25 0x006810C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_26 0x006810D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_27 0x006810D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_28 0x006810E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_29 0x006810E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_30 0x006810F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_31 0x006810F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_32 0x00681100 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_33 0x00681108 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_34 0x00681110 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_35 0x00681118 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_36 0x00681120 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_37 0x00681128 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_38 0x00681130 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_39 0x00681138 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_40 0x00681140 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_41 0x00681148 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_42 0x00681150 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_43 0x00681158 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_44 0x00681160 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_45 0x00681168 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_46 0x00681170 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_47 0x00681178 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_48 0x00681180 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_49 0x00681188 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_50 0x00681190 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_51 0x00681198 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_52 0x006811A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_53 0x006811A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_54 0x006811B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_55 0x006811B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_56 0x006811C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_57 0x006811C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_58 0x006811D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_59 0x006811D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_60 0x006811E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_61 0x006811E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_62 0x006811F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_63 0x006811F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_64 0x00681200 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_65 0x00681208 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_66 0x00681210 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_67 0x00681218 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_68 0x00681220 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_69 0x00681228 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_70 0x00681230 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_71 0x00681238 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_72 0x00681240 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_73 0x00681248 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_74 0x00681250 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_75 0x00681258 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_76 0x00681260 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_77 0x00681268 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_78 0x00681270 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_79 0x00681278 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_80 0x00681280 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_81 0x00681288 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_82 0x00681290 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_83 0x00681298 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_84 0x006812A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_85 0x006812A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_86 0x006812B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_87 0x006812B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_88 0x006812C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_89 0x006812C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_90 0x006812D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_91 0x006812D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_92 0x006812E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_93 0x006812E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_94 0x006812F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_95 0x006812F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_96 0x00681300 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_97 0x00681308 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_98 0x00681310 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_99 0x00681318 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_100 0x00681320 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_101 0x00681328 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_102 0x00681330 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_103 0x00681338 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_104 0x00681340 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_105 0x00681348 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_106 0x00681350 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_107 0x00681358 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_108 0x00681360 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_109 0x00681368 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_110 0x00681370 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_111 0x00681378 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_112 0x00681380 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_113 0x00681388 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_114 0x00681390 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_115 0x00681398 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_116 0x006813A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_117 0x006813A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_118 0x006813B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_119 0x006813B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_120 0x006813C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_121 0x006813C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_122 0x006813D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_123 0x006813D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_124 0x006813E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_125 0x006813E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_126 0x006813F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_127 0x006813F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_GLOBAL_TABLE 0x00682000 /* - * Base of Global - * Mapping Table - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * This register describes the LLP status. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_status_u { - bdrkreg_t ni_port_status_regval; - struct { - bdrkreg_t ps_port_status : 2; - bdrkreg_t ps_remote_power : 1; - bdrkreg_t ps_rsvd : 61; - } ni_port_status_fld_s; -} ni_port_status_u_t; - -#else - -typedef union ni_port_status_u { - bdrkreg_t ni_port_status_regval; - struct { - bdrkreg_t ps_rsvd : 61; - bdrkreg_t ps_remote_power : 1; - bdrkreg_t ps_port_status : 2; - } ni_port_status_fld_s; -} ni_port_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing this register issues a reset to the network interface. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_reset_u { - bdrkreg_t ni_port_reset_regval; - struct { - bdrkreg_t pr_link_reset_out : 1; - bdrkreg_t pr_port_reset : 1; - bdrkreg_t pr_local_reset : 1; - bdrkreg_t pr_rsvd : 61; - } ni_port_reset_fld_s; -} ni_port_reset_u_t; - -#else - -typedef union ni_port_reset_u { - bdrkreg_t ni_port_reset_regval; - struct { - bdrkreg_t pr_rsvd : 61; - bdrkreg_t pr_local_reset : 1; - bdrkreg_t pr_port_reset : 1; - bdrkreg_t pr_link_reset_out : 1; - } ni_port_reset_fld_s; -} ni_port_reset_u_t; - -#endif - - - -/************************************************************************ - * * - * This register contains the warm reset enable bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_reset_enable_u { - bdrkreg_t ni_reset_enable_regval; - struct { - bdrkreg_t re_reset_ok : 1; - bdrkreg_t re_rsvd : 63; - } ni_reset_enable_fld_s; -} ni_reset_enable_u_t; - -#else - -typedef union ni_reset_enable_u { - bdrkreg_t ni_reset_enable_regval; - struct { - bdrkreg_t re_rsvd : 63; - bdrkreg_t re_reset_ok : 1; - } ni_reset_enable_fld_s; -} ni_reset_enable_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains parameters for diagnostics. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_diag_parms_u { - bdrkreg_t ni_diag_parms_regval; - struct { - bdrkreg_t dp_send_data_error : 1; - bdrkreg_t dp_port_disable : 1; - bdrkreg_t dp_send_err_off : 1; - bdrkreg_t dp_rsvd : 61; - } ni_diag_parms_fld_s; -} ni_diag_parms_u_t; - -#else - -typedef union ni_diag_parms_u { - bdrkreg_t ni_diag_parms_regval; - struct { - bdrkreg_t dp_rsvd : 61; - bdrkreg_t dp_send_err_off : 1; - bdrkreg_t dp_port_disable : 1; - bdrkreg_t dp_send_data_error : 1; - } ni_diag_parms_fld_s; -} ni_diag_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the virtual channel selection control for * - * outgoing messages from the Bedrock. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_control_u { - bdrkreg_t ni_channel_control_regval; - struct { - bdrkreg_t cc_vch_one_request : 1; - bdrkreg_t cc_vch_two_request : 1; - bdrkreg_t cc_vch_nine_request : 1; - bdrkreg_t cc_vch_vector_request : 1; - bdrkreg_t cc_vch_one_reply : 1; - bdrkreg_t cc_vch_two_reply : 1; - bdrkreg_t cc_vch_nine_reply : 1; - bdrkreg_t cc_vch_vector_reply : 1; - bdrkreg_t cc_send_vch_sel : 1; - bdrkreg_t cc_rsvd : 55; - } ni_channel_control_fld_s; -} ni_channel_control_u_t; - -#else - -typedef union ni_channel_control_u { - bdrkreg_t ni_channel_control_regval; - struct { - bdrkreg_t cc_rsvd : 55; - bdrkreg_t cc_send_vch_sel : 1; - bdrkreg_t cc_vch_vector_reply : 1; - bdrkreg_t cc_vch_nine_reply : 1; - bdrkreg_t cc_vch_two_reply : 1; - bdrkreg_t cc_vch_one_reply : 1; - bdrkreg_t cc_vch_vector_request : 1; - bdrkreg_t cc_vch_nine_request : 1; - bdrkreg_t cc_vch_two_request : 1; - bdrkreg_t cc_vch_one_request : 1; - } ni_channel_control_fld_s; -} ni_channel_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows access to the LLP test logic. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_test_u { - bdrkreg_t ni_channel_test_regval; - struct { - bdrkreg_t ct_testseed : 20; - bdrkreg_t ct_testmask : 8; - bdrkreg_t ct_testdata : 20; - bdrkreg_t ct_testvalid : 1; - bdrkreg_t ct_testcberr : 1; - bdrkreg_t ct_testflit : 3; - bdrkreg_t ct_testclear : 1; - bdrkreg_t ct_testerrcapture : 1; - bdrkreg_t ct_rsvd : 9; - } ni_channel_test_fld_s; -} ni_channel_test_u_t; - -#else - -typedef union ni_channel_test_u { - bdrkreg_t ni_channel_test_regval; - struct { - bdrkreg_t ct_rsvd : 9; - bdrkreg_t ct_testerrcapture : 1; - bdrkreg_t ct_testclear : 1; - bdrkreg_t ct_testflit : 3; - bdrkreg_t ct_testcberr : 1; - bdrkreg_t ct_testvalid : 1; - bdrkreg_t ct_testdata : 20; - bdrkreg_t ct_testmask : 8; - bdrkreg_t ct_testseed : 20; - } ni_channel_test_fld_s; -} ni_channel_test_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains LLP port parameters and enables for the * - * capture of header data. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_parms_u { - bdrkreg_t ni_port_parms_regval; - struct { - bdrkreg_t pp_max_burst : 10; - bdrkreg_t pp_null_timeout : 6; - bdrkreg_t pp_max_retry : 10; - bdrkreg_t pp_d_avail_sel : 2; - bdrkreg_t pp_rsvd_1 : 1; - bdrkreg_t pp_first_err_enable : 1; - bdrkreg_t pp_squash_err_enable : 1; - bdrkreg_t pp_vch_err_enable : 4; - bdrkreg_t pp_rsvd : 29; - } ni_port_parms_fld_s; -} ni_port_parms_u_t; - -#else - -typedef union ni_port_parms_u { - bdrkreg_t ni_port_parms_regval; - struct { - bdrkreg_t pp_rsvd : 29; - bdrkreg_t pp_vch_err_enable : 4; - bdrkreg_t pp_squash_err_enable : 1; - bdrkreg_t pp_first_err_enable : 1; - bdrkreg_t pp_rsvd_1 : 1; - bdrkreg_t pp_d_avail_sel : 2; - bdrkreg_t pp_max_retry : 10; - bdrkreg_t pp_null_timeout : 6; - bdrkreg_t pp_max_burst : 10; - } ni_port_parms_fld_s; -} ni_port_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the age at which request and reply packets * - * are injected into the network. This feature allows replies to be * - * given a higher fixed priority than requests, which can be * - * important in some network saturation situations. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_age_u { - bdrkreg_t ni_channel_age_regval; - struct { - bdrkreg_t ca_request_inject_age : 8; - bdrkreg_t ca_reply_inject_age : 8; - bdrkreg_t ca_rsvd : 48; - } ni_channel_age_fld_s; -} ni_channel_age_u_t; - -#else - -typedef union ni_channel_age_u { - bdrkreg_t ni_channel_age_regval; - struct { - bdrkreg_t ca_rsvd : 48; - bdrkreg_t ca_reply_inject_age : 8; - bdrkreg_t ca_request_inject_age : 8; - } ni_channel_age_fld_s; -} ni_channel_age_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains latched LLP port and problematic message * - * errors. The contents are the same information as the * - * NI_PORT_ERROR_CLEAR register, but, in this register read accesses * - * are non-destructive. Bits [52:24] assert the NI interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_errors_u { - bdrkreg_t ni_port_errors_regval; - struct { - bdrkreg_t pe_sn_error_count : 8; - bdrkreg_t pe_cb_error_count : 8; - bdrkreg_t pe_retry_count : 8; - bdrkreg_t pe_tail_timeout : 4; - bdrkreg_t pe_fifo_overflow : 4; - bdrkreg_t pe_external_short : 4; - bdrkreg_t pe_external_long : 4; - bdrkreg_t pe_external_bad_header : 4; - bdrkreg_t pe_internal_short : 4; - bdrkreg_t pe_internal_long : 4; - bdrkreg_t pe_link_reset_in : 1; - bdrkreg_t pe_rsvd : 11; - } ni_port_errors_fld_s; -} ni_port_errors_u_t; - -#else - -typedef union ni_port_errors_u { - bdrkreg_t ni_port_errors_regval; - struct { - bdrkreg_t pe_rsvd : 11; - bdrkreg_t pe_link_reset_in : 1; - bdrkreg_t pe_internal_long : 4; - bdrkreg_t pe_internal_short : 4; - bdrkreg_t pe_external_bad_header : 4; - bdrkreg_t pe_external_long : 4; - bdrkreg_t pe_external_short : 4; - bdrkreg_t pe_fifo_overflow : 4; - bdrkreg_t pe_tail_timeout : 4; - bdrkreg_t pe_retry_count : 8; - bdrkreg_t pe_cb_error_count : 8; - bdrkreg_t pe_sn_error_count : 8; - } ni_port_errors_fld_s; -} ni_port_errors_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides the sideband data associated with the * - * NI_PORT_HEADER registers and also additional data for error * - * processing. This register is not cleared on reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_sideband_u { - bdrkreg_t ni_port_sideband_regval; - struct { - bdrkreg_t ps_sideband : 8; - bdrkreg_t ps_bad_dest : 1; - bdrkreg_t ps_bad_prexsel : 1; - bdrkreg_t ps_rcv_error : 1; - bdrkreg_t ps_bad_message : 1; - bdrkreg_t ps_squash : 1; - bdrkreg_t ps_sn_status : 1; - bdrkreg_t ps_cb_status : 1; - bdrkreg_t ps_send_error : 1; - bdrkreg_t ps_vch_active : 4; - bdrkreg_t ps_rsvd : 44; - } ni_port_sideband_fld_s; -} ni_port_sideband_u_t; - -#else - -typedef union ni_port_sideband_u { - bdrkreg_t ni_port_sideband_regval; - struct { - bdrkreg_t ps_rsvd : 44; - bdrkreg_t ps_vch_active : 4; - bdrkreg_t ps_send_error : 1; - bdrkreg_t ps_cb_status : 1; - bdrkreg_t ps_sn_status : 1; - bdrkreg_t ps_squash : 1; - bdrkreg_t ps_bad_message : 1; - bdrkreg_t ps_rcv_error : 1; - bdrkreg_t ps_bad_prexsel : 1; - bdrkreg_t ps_bad_dest : 1; - bdrkreg_t ps_sideband : 8; - } ni_port_sideband_fld_s; -} ni_port_sideband_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains latched LLP port and problematic message * - * errors. The contents are the same information as the * - * NI_PORT_ERROR_CLEAR register, but, in this register read accesses * - * are non-destructive. Bits [52:24] assert the NI interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_error_clear_u { - bdrkreg_t ni_port_error_clear_regval; - struct { - bdrkreg_t pec_sn_error_count : 8; - bdrkreg_t pec_cb_error_count : 8; - bdrkreg_t pec_retry_count : 8; - bdrkreg_t pec_tail_timeout : 4; - bdrkreg_t pec_fifo_overflow : 4; - bdrkreg_t pec_external_short : 4; - bdrkreg_t pec_external_long : 4; - bdrkreg_t pec_external_bad_header : 4; - bdrkreg_t pec_internal_short : 4; - bdrkreg_t pec_internal_long : 4; - bdrkreg_t pec_link_reset_in : 1; - bdrkreg_t pec_rsvd : 11; - } ni_port_error_clear_fld_s; -} ni_port_error_clear_u_t; - -#else - -typedef union ni_port_error_clear_u { - bdrkreg_t ni_port_error_clear_regval; - struct { - bdrkreg_t pec_rsvd : 11; - bdrkreg_t pec_link_reset_in : 1; - bdrkreg_t pec_internal_long : 4; - bdrkreg_t pec_internal_short : 4; - bdrkreg_t pec_external_bad_header : 4; - bdrkreg_t pec_external_long : 4; - bdrkreg_t pec_external_short : 4; - bdrkreg_t pec_fifo_overflow : 4; - bdrkreg_t pec_tail_timeout : 4; - bdrkreg_t pec_retry_count : 8; - bdrkreg_t pec_cb_error_count : 8; - bdrkreg_t pec_sn_error_count : 8; - } ni_port_error_clear_fld_s; -} ni_port_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 7-bit LocalCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_local_table_0_u { - bdrkreg_t ni_local_table_0_regval; - struct { - bdrkreg_t lt0_next_exit_port : 4; - bdrkreg_t lt0_next_vch_lsb : 1; - bdrkreg_t lt0_rsvd : 59; - } ni_local_table_0_fld_s; -} ni_local_table_0_u_t; - -#else - -typedef union ni_local_table_0_u { - bdrkreg_t ni_local_table_0_regval; - struct { - bdrkreg_t lt0_rsvd : 59; - bdrkreg_t lt0_next_vch_lsb : 1; - bdrkreg_t lt0_next_exit_port : 4; - } ni_local_table_0_fld_s; -} ni_local_table_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 7-bit LocalCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_local_table_127_u { - bdrkreg_t ni_local_table_127_regval; - struct { - bdrkreg_t lt1_next_exit_port : 4; - bdrkreg_t lt1_next_vch_lsb : 1; - bdrkreg_t lt1_rsvd : 59; - } ni_local_table_127_fld_s; -} ni_local_table_127_u_t; - -#else - -typedef union ni_local_table_127_u { - bdrkreg_t ni_local_table_127_regval; - struct { - bdrkreg_t lt1_rsvd : 59; - bdrkreg_t lt1_next_vch_lsb : 1; - bdrkreg_t lt1_next_exit_port : 4; - } ni_local_table_127_fld_s; -} ni_local_table_127_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 1-bit MetaCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_global_table_u { - bdrkreg_t ni_global_table_regval; - struct { - bdrkreg_t gt_next_exit_port : 4; - bdrkreg_t gt_next_vch_lsb : 1; - bdrkreg_t gt_rsvd : 59; - } ni_global_table_fld_s; -} ni_global_table_u_t; - -#else - -typedef union ni_global_table_u { - bdrkreg_t ni_global_table_regval; - struct { - bdrkreg_t gt_rsvd : 59; - bdrkreg_t gt_next_vch_lsb : 1; - bdrkreg_t gt_next_exit_port : 4; - } ni_global_table_fld_s; -} ni_global_table_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines which were not formed into structures are * - * probably indentical to another register, and the name of the * - * register is provided against each of these registers. This * - * information needs to be checked carefully * - * * - * NI_LOCAL_TABLE_1 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_2 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_3 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_4 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_5 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_6 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_7 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_8 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_9 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_10 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_11 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_12 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_13 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_14 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_15 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_16 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_17 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_18 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_19 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_20 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_21 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_22 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_23 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_24 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_25 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_26 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_27 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_28 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_29 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_30 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_31 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_32 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_33 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_34 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_35 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_36 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_37 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_38 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_39 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_40 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_41 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_42 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_43 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_44 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_45 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_46 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_47 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_48 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_49 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_50 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_51 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_52 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_53 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_54 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_55 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_56 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_57 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_58 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_59 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_60 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_61 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_62 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_63 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_64 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_65 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_66 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_67 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_68 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_69 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_70 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_71 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_72 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_73 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_74 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_75 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_76 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_77 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_78 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_79 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_80 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_81 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_82 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_83 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_84 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_85 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_86 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_87 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_88 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_89 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_90 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_91 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_92 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_93 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_94 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_95 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_96 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_97 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_98 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_99 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_100 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_101 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_102 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_103 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_104 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_105 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_106 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_107 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_108 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_109 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_110 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_111 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_112 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_113 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_114 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_115 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_116 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_117 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_118 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_119 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_120 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_121 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_122 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_123 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_124 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_125 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_126 NI_LOCAL_TABLE_0 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * The following defines were not formed into structures * - * * - * This could be because the document did not contain details of the * - * register, or because the automated script did not recognize the * - * register details in the documentation. If these register need * - * structure definition, please create them manually * - * * - * NI_PORT_HEADER_A 0x680108 * - * NI_PORT_HEADER_B 0x680110 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBNI_H */ diff --git a/include/asm-ia64/sn/sn1/hubni_next.h b/include/asm-ia64/sn/sn1/hubni_next.h deleted file mode 100644 index ebee5b7ad97..00000000000 --- a/include/asm-ia64/sn/sn1/hubni_next.h +++ /dev/null @@ -1,174 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBNI_NEXT_H -#define _ASM_IA64_SN_SN1_HUBNI_NEXT_H - -#define NI_LOCAL_ENTRIES 128 -#define NI_META_ENTRIES 1 - -#define NI_LOCAL_TABLE(_x) (NI_LOCAL_TABLE_0 + (8 * (_x))) -#define NI_META_TABLE(_x) (NI_GLOBAL_TABLE + (8 * (_x))) - -/************************************************************** - - Masks and shifts for NI registers are defined below. - -**************************************************************/ - -#define NPS_LINKUP_SHFT 1 -#define NPS_LINKUP_MASK (UINT64_CAST 0x1 << 1) - - -#define NPR_LOCALRESET (UINT64_CAST 1 << 2) /* Reset loc. bdrck */ -#define NPR_PORTRESET (UINT64_CAST 1 << 1) /* Send warm reset */ -#define NPR_LINKRESET (UINT64_CAST 1 << 0) /* Send link reset */ - -/* NI_DIAG_PARMS bit definitions */ -#define NDP_SENDERROR (UINT64_CAST 1 << 0) /* Send data error */ -#define NDP_PORTDISABLE (UINT64_CAST 1 << 1) /* Port disable */ -#define NDP_SENDERROFF (UINT64_CAST 1 << 2) /* Disable send error recovery */ - - -/* NI_PORT_ERROR mask and shift definitions (some are not present in SN0) */ - -#define NPE_LINKRESET (UINT64_CAST 1 << 52) -#define NPE_INTLONG_SHFT 48 -#define NPE_INTLONG_MASK (UINT64_CAST 0xf << NPE_INTLONG_SHFT) -#define NPE_INTSHORT_SHFT 44 -#define NPE_INTSHORT_MASK (UINT64_CAST 0xf << NPE_INTSHORT_SHFT) -#define NPE_EXTBADHEADER_SHFT 40 -#define NPE_EXTBADHEADER_MASK (UINT64_CAST 0xf << NPE_EXTBADHEADER_SHFT) -#define NPE_EXTLONG_SHFT 36 -#define NPE_EXTLONG_MASK (UINT64_CAST 0xf << NPE_EXTLONG_SHFT) -#define NPE_EXTSHORT_SHFT 32 -#define NPE_EXTSHORT_MASK (UINT64_CAST 0xf << NPE_EXTSHORT_SHFT) -#define NPE_FIFOOVFLOW_SHFT 28 -#define NPE_FIFOOVFLOW_MASK (UINT64_CAST 0xf << NPE_FIFOOVFLOW_SHFT) -#define NPE_TAILTO_SHFT 24 -#define NPE_TAILTO_MASK (UINT64_CAST 0xf << NPE_TAILTO_SHFT) -#define NPE_RETRYCOUNT_SHFT 16 -#define NPE_RETRYCOUNT_MASK (UINT64_CAST 0xff << NPE_RETRYCOUNT_SHFT) -#define NPE_CBERRCOUNT_SHFT 8 -#define NPE_CBERRCOUNT_MASK (UINT64_CAST 0xff << NPE_CBERRCOUNT_SHFT) -#define NPE_SNERRCOUNT_SHFT 0 -#define NPE_SNERRCOUNT_MASK (UINT64_CAST 0xff << NPE_SNERRCOUNT_SHFT) - -#define NPE_COUNT_MAX 0xff - -#define NPE_FATAL_ERRORS (NPE_LINKRESET | NPE_INTLONG_MASK |\ - NPE_INTSHORT_MASK | NPE_EXTBADHEADER_MASK |\ - NPE_EXTLONG_MASK | NPE_EXTSHORT_MASK |\ - NPE_FIFOOVFLOW_MASK | NPE_TAILTO_MASK) - -#ifndef __ASSEMBLY__ -/* NI_PORT_HEADER[AB] registers (not automatically generated) */ - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_header_a_u { - bdrkreg_t ni_port_header_a_regval; - struct { - bdrkreg_t pha_v : 1; - bdrkreg_t pha_age : 8; - bdrkreg_t pha_direction : 4; - bdrkreg_t pha_destination : 8; - bdrkreg_t pha_reserved_1 : 3; - bdrkreg_t pha_command : 8; - bdrkreg_t pha_prexsel : 3; - bdrkreg_t pha_address_b : 27; - bdrkreg_t pha_reserved : 2; - } ni_port_header_a_fld_s; -} ni_port_header_a_u_t; - -#else - -typedef union ni_port_header_a_u { - bdrkreg_t ni_port_header_a_regval; - struct { - bdrkreg_t pha_reserved : 2; - bdrkreg_t pha_address_b : 27; - bdrkreg_t pha_prexsel : 3; - bdrkreg_t pha_command : 8; - bdrkreg_t pha_reserved_1 : 3; - bdrkreg_t pha_destination : 8; - bdrkreg_t pha_direction : 4; - bdrkreg_t pha_age : 8; - bdrkreg_t pha_v : 1; - } ni_port_header_a_fld_s; -} ni_port_header_a_u_t; - -#endif - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_header_b_u { - bdrkreg_t ni_port_header_b_regval; - struct { - bdrkreg_t phb_supplemental : 11; - bdrkreg_t phb_reserved_2 : 5; - bdrkreg_t phb_source : 11; - bdrkreg_t phb_reserved_1 : 8; - bdrkreg_t phb_address_a : 3; - bdrkreg_t phb_address_c : 8; - bdrkreg_t phb_reserved : 18; - } ni_port_header_b_fld_s; -} ni_port_header_b_u_t; - -#else - -typedef union ni_port_header_b_u { - bdrkreg_t ni_port_header_b_regval; - struct { - bdrkreg_t phb_reserved : 18; - bdrkreg_t phb_address_c : 8; - bdrkreg_t phb_address_a : 3; - bdrkreg_t phb_reserved_1 : 8; - bdrkreg_t phb_source : 11; - bdrkreg_t phb_reserved_2 : 5; - bdrkreg_t phb_supplemental : 11; - } ni_port_header_b_fld_s; -} ni_port_header_b_u_t; - -#endif -#endif - -/* NI_RESET_ENABLE mask definitions */ - -#define NRE_RESETOK (UINT64_CAST 1) /* Let LLP reset bedrock */ - -/* NI PORT_ERRORS, Max number of RETRY_COUNT, Check Bit, and Sequence */ -/* Number errors (8 bit counters that do not wrap). */ -#define NI_LLP_RETRY_MAX 0xff -#define NI_LLP_CB_MAX 0xff -#define NI_LLP_SN_MAX 0xff - -/* NI_PORT_PARMS shift and mask definitions */ - -#define NPP_VCH_ERR_EN_SHFT 31 -#define NPP_VCH_ERR_EN_MASK (0xf << NPP_VCH_ERR_EN_SHFT) -#define NPP_SQUASH_ERR_EN_SHFT 30 -#define NPP_SQUASH_ERR_EN_MASK (0x1 << NPP_SQUASH_ERR_EN_SHFT) -#define NPP_FIRST_ERR_EN_SHFT 29 -#define NPP_FIRST_ERR_EN_MASK (0x1 << NPP_FIRST_ERR_EN_SHFT) -#define NPP_D_AVAIL_SEL_SHFT 26 -#define NPP_D_AVAIL_SEL_MASK (0x3 << NPP_D_AVAIL_SEL_SHFT) -#define NPP_MAX_RETRY_SHFT 16 -#define NPP_MAX_RETRY_MASK (0x3ff << NPP_MAX_RETRY_SHFT) -#define NPP_NULL_TIMEOUT_SHFT 10 -#define NPP_NULL_TIMEOUT_MASK (0x3f << NPP_NULL_TIMEOUT_SHFT) -#define NPP_MAX_BURST_SHFT 0 -#define NPP_MAX_BURST_MASK (0x3ff << NPP_MAX_BURST_SHFT) - -#define NPP_RESET_DEFAULTS (0xf << NPP_VCH_ERR_EN_SHFT | \ - 0x1 << NPP_FIRST_ERR_EN_SHFT | \ - 0x3ff << NPP_MAX_RETRY_SHFT | \ - 0x6 << NPP_NULL_TIMEOUT_SHFT | \ - 0x3f0 << NPP_MAX_BURST_SHFT) - -#endif /* _ASM_IA64_SN_SN1_HUBNI_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hubpi.h b/include/asm-ia64/sn/sn1/hubpi.h deleted file mode 100644 index 7c698412621..00000000000 --- a/include/asm-ia64/sn/sn1/hubpi.h +++ /dev/null @@ -1,4263 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBPI_H -#define _ASM_IA64_SN_SN1_HUBPI_H - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define PI_CPU_PROTECT 0x00000000 /* CPU Protection */ - - - -#define PI_PROT_OVRRD 0x00000008 /* - * Clear CPU - * Protection bit in - * CPU_PROTECT - */ - - - -#define PI_IO_PROTECT 0x00000010 /* - * Interrupt Pending - * Protection for IO - * access - */ - - - -#define PI_REGION_PRESENT 0x00000018 /* Region present */ - - - -#define PI_CPU_NUM 0x00000020 /* CPU Number ID */ - - - -#define PI_CALIAS_SIZE 0x00000028 /* Cached Alias Size */ - - - -#define PI_MAX_CRB_TIMEOUT 0x00000030 /* - * Maximum Timeout for - * CRB - */ - - - -#define PI_CRB_SFACTOR 0x00000038 /* - * Scale Factor for - * CRB Timeout - */ - - - -#define PI_CPU_PRESENT_A 0x00000040 /* - * CPU Present for - * CPU_A - */ - - - -#define PI_CPU_PRESENT_B 0x00000048 /* - * CPU Present for - * CPU_B - */ - - - -#define PI_CPU_ENABLE_A 0x00000050 /* - * CPU Enable for - * CPU_A - */ - - - -#define PI_CPU_ENABLE_B 0x00000058 /* - * CPU Enable for - * CPU_B - */ - - - -#define PI_REPLY_LEVEL 0x00010060 /* - * Reply FIFO Priority - * Control - */ - - - -#define PI_GFX_CREDIT_MODE 0x00020068 /* - * Graphics Credit - * Mode - */ - - - -#define PI_NMI_A 0x00000070 /* - * Non-maskable - * Interrupt to CPU A - */ - - - -#define PI_NMI_B 0x00000078 /* - * Non-maskable - * Interrupt to CPU B - */ - - - -#define PI_INT_PEND_MOD 0x00000090 /* - * Interrupt Pending - * Modify - */ - - - -#define PI_INT_PEND0 0x00000098 /* Interrupt Pending 0 */ - - - -#define PI_INT_PEND1 0x000000A0 /* Interrupt Pending 1 */ - - - -#define PI_INT_MASK0_A 0x000000A8 /* - * Interrupt Mask 0 - * for CPU A - */ - - - -#define PI_INT_MASK1_A 0x000000B0 /* - * Interrupt Mask 1 - * for CPU A - */ - - - -#define PI_INT_MASK0_B 0x000000B8 /* - * Interrupt Mask 0 - * for CPU B - */ - - - -#define PI_INT_MASK1_B 0x000000C0 /* - * Interrupt Mask 1 - * for CPU B - */ - - - -#define PI_CC_PEND_SET_A 0x000000C8 /* - * CC Interrupt - * Pending for CPU A - */ - - - -#define PI_CC_PEND_SET_B 0x000000D0 /* - * CC Interrupt - * Pending for CPU B - */ - - - -#define PI_CC_PEND_CLR_A 0x000000D8 /* - * CPU to CPU - * Interrupt Pending - * Clear for CPU A - */ - - - -#define PI_CC_PEND_CLR_B 0x000000E0 /* - * CPU to CPU - * Interrupt Pending - * Clear for CPU B - */ - - - -#define PI_CC_MASK 0x000000E8 /* - * Mask of both - * CC_PENDs - */ - - - -#define PI_INT_PEND1_REMAP 0x000000F0 /* - * Remap Interrupt - * Pending - */ - - - -#define PI_RT_COUNTER 0x00030100 /* Real Time Counter */ - - - -#define PI_RT_COMPARE_A 0x00000108 /* Real Time Compare A */ - - - -#define PI_RT_COMPARE_B 0x00000110 /* Real Time Compare B */ - - - -#define PI_PROFILE_COMPARE 0x00000118 /* Profiling Compare */ - - - -#define PI_RT_INT_PEND_A 0x00000120 /* - * RT interrupt - * pending - */ - - - -#define PI_RT_INT_PEND_B 0x00000128 /* - * RT interrupt - * pending - */ - - - -#define PI_PROF_INT_PEND_A 0x00000130 /* - * Profiling interrupt - * pending - */ - - - -#define PI_PROF_INT_PEND_B 0x00000138 /* - * Profiling interrupt - * pending - */ - - - -#define PI_RT_INT_EN_A 0x00000140 /* RT Interrupt Enable */ - - - -#define PI_RT_INT_EN_B 0x00000148 /* RT Interrupt Enable */ - - - -#define PI_PROF_INT_EN_A 0x00000150 /* - * Profiling Interrupt - * Enable - */ - - - -#define PI_PROF_INT_EN_B 0x00000158 /* - * Profiling Interrupt - * Enable - */ - - - -#define PI_DEBUG_SEL 0x00000160 /* PI Debug Select */ - - - -#define PI_INT_PEND_MOD_ALIAS 0x00000180 /* - * Interrupt Pending - * Modify - */ - - - -#define PI_PERF_CNTL_A 0x00040200 /* - * Performance Counter - * Control A - */ - - - -#define PI_PERF_CNTR0_A 0x00040208 /* - * Performance Counter - * 0 A - */ - - - -#define PI_PERF_CNTR1_A 0x00040210 /* - * Performance Counter - * 1 A - */ - - - -#define PI_PERF_CNTL_B 0x00050200 /* - * Performance Counter - * Control B - */ - - - -#define PI_PERF_CNTR0_B 0x00050208 /* - * Performance Counter - * 0 B - */ - - - -#define PI_PERF_CNTR1_B 0x00050210 /* - * Performance Counter - * 1 B - */ - - - -#define PI_GFX_PAGE_A 0x00000300 /* Graphics Page */ - - - -#define PI_GFX_CREDIT_CNTR_A 0x00000308 /* - * Graphics Credit - * Counter - */ - - - -#define PI_GFX_BIAS_A 0x00000310 /* TRex+ BIAS */ - - - -#define PI_GFX_INT_CNTR_A 0x00000318 /* - * Graphics Interrupt - * Counter - */ - - - -#define PI_GFX_INT_CMP_A 0x00000320 /* - * Graphics Interrupt - * Compare - */ - - - -#define PI_GFX_PAGE_B 0x00000328 /* Graphics Page */ - - - -#define PI_GFX_CREDIT_CNTR_B 0x00000330 /* - * Graphics Credit - * Counter - */ - - - -#define PI_GFX_BIAS_B 0x00000338 /* TRex+ BIAS */ - - - -#define PI_GFX_INT_CNTR_B 0x00000340 /* - * Graphics Interrupt - * Counter - */ - - - -#define PI_GFX_INT_CMP_B 0x00000348 /* - * Graphics Interrupt - * Compare - */ - - - -#define PI_ERR_INT_PEND_WR 0x000003F8 /* - * Error Interrupt - * Pending (Writable) - */ - - - -#define PI_ERR_INT_PEND 0x00000400 /* - * Error Interrupt - * Pending - */ - - - -#define PI_ERR_INT_MASK_A 0x00000408 /* - * Error Interrupt - * Mask CPU_A - */ - - - -#define PI_ERR_INT_MASK_B 0x00000410 /* - * Error Interrupt - * Mask CPU_B - */ - - - -#define PI_ERR_STACK_ADDR_A 0x00000418 /* - * Error Stack Address - * Pointer - */ - - - -#define PI_ERR_STACK_ADDR_B 0x00000420 /* - * Error Stack Address - * Pointer - */ - - - -#define PI_ERR_STACK_SIZE 0x00000428 /* Error Stack Size */ - - - -#define PI_ERR_STATUS0_A 0x00000430 /* Error Status 0 */ - - - -#define PI_ERR_STATUS0_A_CLR 0x00000438 /* Error Status 0 */ - - - -#define PI_ERR_STATUS1_A 0x00000440 /* Error Status 1 */ - - - -#define PI_ERR_STATUS1_A_CLR 0x00000448 /* Error Status 1 */ - - - -#define PI_ERR_STATUS0_B 0x00000450 /* Error Status 0 */ - - - -#define PI_ERR_STATUS0_B_CLR 0x00000458 /* Error Status 0 */ - - - -#define PI_ERR_STATUS1_B 0x00000460 /* Error Status 1 */ - - - -#define PI_ERR_STATUS1_B_CLR 0x00000468 /* Error Status 1 */ - - - -#define PI_SPOOL_CMP_A 0x00000470 /* Spool Compare */ - - - -#define PI_SPOOL_CMP_B 0x00000478 /* Spool Compare */ - - - -#define PI_CRB_TIMEOUT_A 0x00000480 /* - * CRB entries which - * have timed out but - * are still valid - */ - - - -#define PI_CRB_TIMEOUT_B 0x00000488 /* - * CRB entries which - * have timed out but - * are still valid - */ - - - -#define PI_SYSAD_ERRCHK_EN 0x00000490 /* - * enables - * sysad/cmd/state - * error checking - */ - - - -#define PI_FORCE_BAD_CHECK_BIT_A 0x00000498 /* - * force SysAD Check - * Bit error - */ - - - -#define PI_FORCE_BAD_CHECK_BIT_B 0x000004A0 /* - * force SysAD Check - * Bit error - */ - - - -#define PI_NACK_CNT_A 0x000004A8 /* - * consecutive NACK - * counter - */ - - - -#define PI_NACK_CNT_B 0x000004B0 /* - * consecutive NACK - * counter - */ - - - -#define PI_NACK_CMP 0x000004B8 /* NACK count compare */ - - - -#define PI_SPOOL_MASK 0x000004C0 /* Spool error mask */ - - - -#define PI_SPURIOUS_HDR_0 0x000004C8 /* Spurious Error 0 */ - - - -#define PI_SPURIOUS_HDR_1 0x000004D0 /* Spurious Error 1 */ - - - -#define PI_ERR_INJECT 0x000004D8 /* - * SysAD bus error - * injection - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether incoming CPU-initiated PIO Read and * - * Write to local PI registers are allowed. If access is allowed, the * - * PI's response to a partial read is a PRPLY message, and the * - * response to a partial write is a PACK message. If access is not * - * allowed, the PI's response to a partial read is a PRERR message, * - * and the response to a partial write is a PWERR message. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_cpu_protect_u { - bdrkreg_t pi_cpu_protect_regval; - struct { - bdrkreg_t cp_cpu_protect : 64; - } pi_cpu_protect_fld_s; -} pi_cpu_protect_u_t; - - - - -/************************************************************************ - * * - * A write with a special data pattern allows any CPU to set its * - * region's bit in CPU_PROTECT. This register has data pattern * - * protection. * - * * - ************************************************************************/ - - - - -typedef union pi_prot_ovrrd_u { - bdrkreg_t pi_prot_ovrrd_regval; - struct { - bdrkreg_t po_prot_ovrrd : 64; - } pi_prot_ovrrd_fld_s; -} pi_prot_ovrrd_u_t; - - - - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether incoming IO-initiated interrupts are * - * allowed to set bits in INT_PEND0 and INT_PEND1. If access is * - * allowed, the PI's response to a partial read is a PRPLY message, * - * and the response to a partial write is a PACK message. If access * - * is not allowed, the PI's response to a partial read is a PRERR * - * message, and the response to a partial write is a PWERR message. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_io_protect_u { - bdrkreg_t pi_io_protect_regval; - struct { - bdrkreg_t ip_io_protect : 64; - } pi_io_protect_fld_s; -} pi_io_protect_u_t; - - - - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether read access from a local processor to * - * the region is permissible. For example, setting a bit to 0 * - * prevents speculative reads to that non-existent node. If a read * - * request to a non-present region occurs, an ERR response is issued * - * to the TRex+ (no PI error registers are modified). It is up to * - * software to load this register with the proper contents. * - * Region-present checking is only done for coherent read requests - * - * partial reads/writes will be issued to a non-present region. The * - * setting of these bits does not affect a node's access to its * - * CALIAS space. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_region_present_u { - bdrkreg_t pi_region_present_regval; - struct { - bdrkreg_t rp_region_present : 64; - } pi_region_present_fld_s; -} pi_region_present_u_t; - - - - -/************************************************************************ - * * - * A read to the location will allow a CPU to identify itself as * - * either CPU_A or CPU_B, and will indicate whether the CPU is * - * connected to PI 0 or PI 1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_num_u { - bdrkreg_t pi_cpu_num_regval; - struct { - bdrkreg_t cn_cpu_num : 1; - bdrkreg_t cn_pi_id : 1; - bdrkreg_t cn_rsvd : 62; - } pi_cpu_num_fld_s; -} pi_cpu_num_u_t; - -#else - -typedef union pi_cpu_num_u { - bdrkreg_t pi_cpu_num_regval; - struct { - bdrkreg_t cn_rsvd : 62; - bdrkreg_t cn_pi_id : 1; - bdrkreg_t cn_cpu_num : 1; - } pi_cpu_num_fld_s; -} pi_cpu_num_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This read/write location determines the size of the * - * Calias Space. * - * This register is not reset by a soft reset. * - * NOTE: For predictable behavior, all Calias spaces in a system must * - * be set to the same size. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_calias_size_u { - bdrkreg_t pi_calias_size_regval; - struct { - bdrkreg_t cs_calias_size : 4; - bdrkreg_t cs_rsvd : 60; - } pi_calias_size_fld_s; -} pi_calias_size_u_t; - -#else - -typedef union pi_calias_size_u { - bdrkreg_t pi_calias_size_regval; - struct { - bdrkreg_t cs_rsvd : 60; - bdrkreg_t cs_calias_size : 4; - } pi_calias_size_fld_s; -} pi_calias_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines at which value (increment) * - * the CRB Timeout Counters cause a timeout error to occur. See * - * Section 3.4.2.2, "Time-outs in RRB and WRB" in the * - * Processor Interface chapter, volume 1 of this document for more * - * details. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_max_crb_timeout_u { - bdrkreg_t pi_max_crb_timeout_regval; - struct { - bdrkreg_t mct_max_timeout : 8; - bdrkreg_t mct_rsvd : 56; - } pi_max_crb_timeout_fld_s; -} pi_max_crb_timeout_u_t; - -#else - -typedef union pi_max_crb_timeout_u { - bdrkreg_t pi_max_crb_timeout_regval; - struct { - bdrkreg_t mct_rsvd : 56; - bdrkreg_t mct_max_timeout : 8; - } pi_max_crb_timeout_fld_s; -} pi_max_crb_timeout_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines how often a valid CRB's * - * Timeout Counter is incremented. See Section 3.4.2.2, * - * "Time-outs in RRB and WRB" in the Processor Interface * - * chapter, volume 1 of this document for more details. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_sfactor_u { - bdrkreg_t pi_crb_sfactor_regval; - struct { - bdrkreg_t cs_sfactor : 24; - bdrkreg_t cs_rsvd : 40; - } pi_crb_sfactor_fld_s; -} pi_crb_sfactor_u_t; - -#else - -typedef union pi_crb_sfactor_u { - bdrkreg_t pi_crb_sfactor_regval; - struct { - bdrkreg_t cs_rsvd : 40; - bdrkreg_t cs_sfactor : 24; - } pi_crb_sfactor_fld_s; -} pi_crb_sfactor_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The PI sets this * - * bit when it sees the first transaction initiated by the associated * - * CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_present_a_u { - bdrkreg_t pi_cpu_present_a_regval; - struct { - bdrkreg_t cpa_cpu_present : 1; - bdrkreg_t cpa_rsvd : 63; - } pi_cpu_present_a_fld_s; -} pi_cpu_present_a_u_t; - -#else - -typedef union pi_cpu_present_a_u { - bdrkreg_t pi_cpu_present_a_regval; - struct { - bdrkreg_t cpa_rsvd : 63; - bdrkreg_t cpa_cpu_present : 1; - } pi_cpu_present_a_fld_s; -} pi_cpu_present_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The PI sets this * - * bit when it sees the first transaction initiated by the associated * - * CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_present_b_u { - bdrkreg_t pi_cpu_present_b_regval; - struct { - bdrkreg_t cpb_cpu_present : 1; - bdrkreg_t cpb_rsvd : 63; - } pi_cpu_present_b_fld_s; -} pi_cpu_present_b_u_t; - -#else - -typedef union pi_cpu_present_b_u { - bdrkreg_t pi_cpu_present_b_regval; - struct { - bdrkreg_t cpb_rsvd : 63; - bdrkreg_t cpb_cpu_present : 1; - } pi_cpu_present_b_fld_s; -} pi_cpu_present_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * Read/Write location determines whether the associated CPU is * - * enabled to issue external requests. When this bit is zero for a * - * processor, the PI ignores SysReq_L from that processor, and so * - * never grants it the bus. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_enable_a_u { - bdrkreg_t pi_cpu_enable_a_regval; - struct { - bdrkreg_t cea_cpu_enable : 1; - bdrkreg_t cea_rsvd : 63; - } pi_cpu_enable_a_fld_s; -} pi_cpu_enable_a_u_t; - -#else - -typedef union pi_cpu_enable_a_u { - bdrkreg_t pi_cpu_enable_a_regval; - struct { - bdrkreg_t cea_rsvd : 63; - bdrkreg_t cea_cpu_enable : 1; - } pi_cpu_enable_a_fld_s; -} pi_cpu_enable_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * Read/Write location determines whether the associated CPU is * - * enabled to issue external requests. When this bit is zero for a * - * processor, the PI ignores SysReq_L from that processor, and so * - * never grants it the bus. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_enable_b_u { - bdrkreg_t pi_cpu_enable_b_regval; - struct { - bdrkreg_t ceb_cpu_enable : 1; - bdrkreg_t ceb_rsvd : 63; - } pi_cpu_enable_b_fld_s; -} pi_cpu_enable_b_u_t; - -#else - -typedef union pi_cpu_enable_b_u { - bdrkreg_t pi_cpu_enable_b_regval; - struct { - bdrkreg_t ceb_rsvd : 63; - bdrkreg_t ceb_cpu_enable : 1; - } pi_cpu_enable_b_fld_s; -} pi_cpu_enable_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A write to this * - * location will cause an NMI to be issued to the CPU. * - * * - ************************************************************************/ - - - - -typedef union pi_nmi_a_u { - bdrkreg_t pi_nmi_a_regval; - struct { - bdrkreg_t na_nmi_cpu : 64; - } pi_nmi_a_fld_s; -} pi_nmi_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A write to this * - * location will cause an NMI to be issued to the CPU. * - * * - ************************************************************************/ - - - - -typedef union pi_nmi_b_u { - bdrkreg_t pi_nmi_b_regval; - struct { - bdrkreg_t nb_nmi_cpu : 64; - } pi_nmi_b_fld_s; -} pi_nmi_b_u_t; - - - - -/************************************************************************ - * * - * A write to this register allows a single bit in the INT_PEND0 or * - * INT_PEND1 registers to be set or cleared. If 6 is clear, a bit is * - * modified in INT_PEND0, while if 6 is set, a bit is modified in * - * INT_PEND1. The value in 5:0 (ranging from 63 to 0) will determine * - * which bit in the register is effected. The value of 8 will * - * determine whether the desired bit is set (8=1) or cleared (8=0). * - * This is the only register which is accessible by IO issued PWRI * - * command and is protected through the IO_PROTECT register. If the * - * region bit in the IO_PROTECT is not set then a WERR reply is * - * issued. CPU access is controlled through CPU_PROTECT. The contents * - * of this register are masked with the contents of INT_MASK_A * - * (INT_MASK_B) to determine whether an L2 interrupt is issued to * - * CPU_A (CPU_B). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend_mod_u { - bdrkreg_t pi_int_pend_mod_regval; - struct { - bdrkreg_t ipm_bit_select : 6; - bdrkreg_t ipm_reg_select : 1; - bdrkreg_t ipm_rsvd_1 : 1; - bdrkreg_t ipm_value : 1; - bdrkreg_t ipm_rsvd : 55; - } pi_int_pend_mod_fld_s; -} pi_int_pend_mod_u_t; - -#else - -typedef union pi_int_pend_mod_u { - bdrkreg_t pi_int_pend_mod_regval; - struct { - bdrkreg_t ipm_rsvd : 55; - bdrkreg_t ipm_value : 1; - bdrkreg_t ipm_rsvd_1 : 1; - bdrkreg_t ipm_reg_select : 1; - bdrkreg_t ipm_bit_select : 6; - } pi_int_pend_mod_fld_s; -} pi_int_pend_mod_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read-only register provides information about interrupts * - * that are currently pending. The interrupts in this register map to * - * interrupt level 2 (L2). The GFX_INT_A/B bits are set by hardware * - * but must be cleared by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend0_u { - bdrkreg_t pi_int_pend0_regval; - struct { - bdrkreg_t ip_int_pend0_lo : 1; - bdrkreg_t ip_gfx_int_a : 1; - bdrkreg_t ip_gfx_int_b : 1; - bdrkreg_t ip_page_migration : 1; - bdrkreg_t ip_uart_ucntrl : 1; - bdrkreg_t ip_or_cc_pend_a : 1; - bdrkreg_t ip_or_cc_pend_b : 1; - bdrkreg_t ip_int_pend0_hi : 57; - } pi_int_pend0_fld_s; -} pi_int_pend0_u_t; - -#else - -typedef union pi_int_pend0_u { - bdrkreg_t pi_int_pend0_regval; - struct { - bdrkreg_t ip_int_pend0_hi : 57; - bdrkreg_t ip_or_cc_pend_b : 1; - bdrkreg_t ip_or_cc_pend_a : 1; - bdrkreg_t ip_uart_ucntrl : 1; - bdrkreg_t ip_page_migration : 1; - bdrkreg_t ip_gfx_int_b : 1; - bdrkreg_t ip_gfx_int_a : 1; - bdrkreg_t ip_int_pend0_lo : 1; - } pi_int_pend0_fld_s; -} pi_int_pend0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read-only register provides information about interrupts * - * that are currently pending. The interrupts in this register map to * - * interrupt level 3 (L3), unless remapped by the INT_PEND1_REMAP * - * register. The SYS_COR_ERR_A/B, RTC_DROP_OUT, and NACK_INT_A/B bits * - * are set by hardware but must be cleared by software. The * - * SYSTEM_SHUTDOWN, NI_ERROR, LB_ERROR and XB_ERROR bits just reflect * - * the value of other logic, and cannot be changed by PI register * - * writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend1_u { - bdrkreg_t pi_int_pend1_regval; - struct { - bdrkreg_t ip_int_pend1 : 54; - bdrkreg_t ip_xb_error : 1; - bdrkreg_t ip_lb_error : 1; - bdrkreg_t ip_nack_int_a : 1; - bdrkreg_t ip_nack_int_b : 1; - bdrkreg_t ip_perf_cntr_oflow : 1; - bdrkreg_t ip_sys_cor_err_b : 1; - bdrkreg_t ip_sys_cor_err_a : 1; - bdrkreg_t ip_md_corr_error : 1; - bdrkreg_t ip_ni_error : 1; - bdrkreg_t ip_system_shutdown : 1; - } pi_int_pend1_fld_s; -} pi_int_pend1_u_t; - -#else - -typedef union pi_int_pend1_u { - bdrkreg_t pi_int_pend1_regval; - struct { - bdrkreg_t ip_system_shutdown : 1; - bdrkreg_t ip_ni_error : 1; - bdrkreg_t ip_md_corr_error : 1; - bdrkreg_t ip_sys_cor_err_a : 1; - bdrkreg_t ip_sys_cor_err_b : 1; - bdrkreg_t ip_perf_cntr_oflow : 1; - bdrkreg_t ip_nack_int_b : 1; - bdrkreg_t ip_nack_int_a : 1; - bdrkreg_t ip_lb_error : 1; - bdrkreg_t ip_xb_error : 1; - bdrkreg_t ip_int_pend1 : 54; - } pi_int_pend1_fld_s; -} pi_int_pend1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND0 to * - * determine whether an L2 interrupt (bit 10 of the processor's Cause * - * register) is sent to CPU_A if the same bit in the INT_PEND0 * - * register is also set. Only one processor in a Bedrock should * - * enable the PAGE_MIGRATION bit/interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_mask0_a_u { - bdrkreg_t pi_int_mask0_a_regval; - struct { - bdrkreg_t ima_int_mask0_lo : 1; - bdrkreg_t ima_gfx_int_a : 1; - bdrkreg_t ima_gfx_int_b : 1; - bdrkreg_t ima_page_migration : 1; - bdrkreg_t ima_uart_ucntrl : 1; - bdrkreg_t ima_or_ccp_mask_a : 1; - bdrkreg_t ima_or_ccp_mask_b : 1; - bdrkreg_t ima_int_mask0_hi : 57; - } pi_int_mask0_a_fld_s; -} pi_int_mask0_a_u_t; - -#else - -typedef union pi_int_mask0_a_u { - bdrkreg_t pi_int_mask0_a_regval; - struct { - bdrkreg_t ima_int_mask0_hi : 57; - bdrkreg_t ima_or_ccp_mask_b : 1; - bdrkreg_t ima_or_ccp_mask_a : 1; - bdrkreg_t ima_uart_ucntrl : 1; - bdrkreg_t ima_page_migration : 1; - bdrkreg_t ima_gfx_int_b : 1; - bdrkreg_t ima_gfx_int_a : 1; - bdrkreg_t ima_int_mask0_lo : 1; - } pi_int_mask0_a_fld_s; -} pi_int_mask0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND1 to * - * determine whether an interrupt should be sent. Bits 63:32 always * - * generate an L3 interrupt (bit 11 of the processor's Cause * - * register) is sent to CPU_A if the same bit in the INT_PEND1 * - * register is set. Bits 31:0 can generate either an L3 or L2 * - * interrupt, depending on the value of INT_PEND1_REMAP[3:0]. Only * - * one processor in a Bedrock should enable the NI_ERROR, LB_ERROR, * - * XB_ERROR and MD_CORR_ERROR bits. * - * * - ************************************************************************/ - - - - -typedef union pi_int_mask1_a_u { - bdrkreg_t pi_int_mask1_a_regval; - struct { - bdrkreg_t ima_int_mask1 : 64; - } pi_int_mask1_a_fld_s; -} pi_int_mask1_a_u_t; - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND0 to * - * determine whether an L2 interrupt (bit 10 of the processor's Cause * - * register) is sent to CPU_B if the same bit in the INT_PEND0 * - * register is also set. Only one processor in a Bedrock should * - * enable the PAGE_MIGRATION bit/interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_mask0_b_u { - bdrkreg_t pi_int_mask0_b_regval; - struct { - bdrkreg_t imb_int_mask0_lo : 1; - bdrkreg_t imb_gfx_int_a : 1; - bdrkreg_t imb_gfx_int_b : 1; - bdrkreg_t imb_page_migration : 1; - bdrkreg_t imb_uart_ucntrl : 1; - bdrkreg_t imb_or_ccp_mask_a : 1; - bdrkreg_t imb_or_ccp_mask_b : 1; - bdrkreg_t imb_int_mask0_hi : 57; - } pi_int_mask0_b_fld_s; -} pi_int_mask0_b_u_t; - -#else - -typedef union pi_int_mask0_b_u { - bdrkreg_t pi_int_mask0_b_regval; - struct { - bdrkreg_t imb_int_mask0_hi : 57; - bdrkreg_t imb_or_ccp_mask_b : 1; - bdrkreg_t imb_or_ccp_mask_a : 1; - bdrkreg_t imb_uart_ucntrl : 1; - bdrkreg_t imb_page_migration : 1; - bdrkreg_t imb_gfx_int_b : 1; - bdrkreg_t imb_gfx_int_a : 1; - bdrkreg_t imb_int_mask0_lo : 1; - } pi_int_mask0_b_fld_s; -} pi_int_mask0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND1 to * - * determine whether an interrupt should be sent. Bits 63:32 always * - * generate an L3 interrupt (bit 11 of the processor's Cause * - * register) is sent to CPU_B if the same bit in the INT_PEND1 * - * register is set. Bits 31:0 can generate either an L3 or L2 * - * interrupt, depending on the value of INT_PEND1_REMAP[3:0]. Only * - * one processor in a Bedrock should enable the NI_ERROR, LB_ERROR, * - * XB_ERROR and MD_CORR_ERROR bits. * - * * - ************************************************************************/ - - - - -typedef union pi_int_mask1_b_u { - bdrkreg_t pi_int_mask1_b_regval; - struct { - bdrkreg_t imb_int_mask1 : 64; - } pi_int_mask1_b_fld_s; -} pi_int_mask1_b_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. These registers do * - * not have access protection. A store to this location by a CPU will * - * cause the bit corresponding to the source's region to be set in * - * CC_PEND_A (or CC_PEND_B). The contents of CC_PEND_A (or CC_PEND_B) * - * determines on a bit-per-region basis whether a CPU-to-CPU * - * interrupt is pending CPU_A (or CPU_B). * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_set_a_u { - bdrkreg_t pi_cc_pend_set_a_regval; - struct { - bdrkreg_t cpsa_cc_pend : 64; - } pi_cc_pend_set_a_fld_s; -} pi_cc_pend_set_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. These registers do * - * not have access protection. A store to this location by a CPU will * - * cause the bit corresponding to the source's region to be set in * - * CC_PEND_A (or CC_PEND_B). The contents of CC_PEND_A (or CC_PEND_B) * - * determines on a bit-per-region basis whether a CPU-to-CPU * - * interrupt is pending CPU_A (or CPU_B). * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_set_b_u { - bdrkreg_t pi_cc_pend_set_b_regval; - struct { - bdrkreg_t cpsb_cc_pend : 64; - } pi_cc_pend_set_b_fld_s; -} pi_cc_pend_set_b_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Reading this * - * location will return the contents of CC_PEND_A (or CC_PEND_B). * - * Writing this location will clear the bits corresponding to which * - * data bits are driven high during the store; therefore, storing all * - * ones would clear all bits. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_clr_a_u { - bdrkreg_t pi_cc_pend_clr_a_regval; - struct { - bdrkreg_t cpca_cc_pend : 64; - } pi_cc_pend_clr_a_fld_s; -} pi_cc_pend_clr_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Reading this * - * location will return the contents of CC_PEND_A (or CC_PEND_B). * - * Writing this location will clear the bits corresponding to which * - * data bits are driven high during the store; therefore, storing all * - * ones would clear all bits. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_clr_b_u { - bdrkreg_t pi_cc_pend_clr_b_regval; - struct { - bdrkreg_t cpcb_cc_pend : 64; - } pi_cc_pend_clr_b_fld_s; -} pi_cc_pend_clr_b_u_t; - - - - -/************************************************************************ - * * - * This read/write register masks the contents of both CC_PEND_A and * - * CC_PEND_B. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_mask_u { - bdrkreg_t pi_cc_mask_regval; - struct { - bdrkreg_t cm_cc_mask : 64; - } pi_cc_mask_fld_s; -} pi_cc_mask_u_t; - - - - -/************************************************************************ - * * - * This read/write register redirects INT_PEND1[31:0] from L3 to L2 * - * interrupt level.Bit 4 in this register is used to enable error * - * interrupt forwarding to the II. When this bit is set, if any of * - * the three memory interrupts (correctable error, uncorrectable * - * error, or page migration), or the NI, LB or XB error interrupts * - * are set, the PI_II_ERROR_INT wire will be asserted. When this wire * - * is asserted, the II will send an interrupt to the node specified * - * in its IIDSR (Interrupt Destination Register). This allows these * - * interrupts to be forwarded to another node. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend1_remap_u { - bdrkreg_t pi_int_pend1_remap_regval; - struct { - bdrkreg_t ipr_remap_0 : 1; - bdrkreg_t ipr_remap_1 : 1; - bdrkreg_t ipr_remap_2 : 1; - bdrkreg_t ipr_remap_3 : 1; - bdrkreg_t ipr_error_forward : 1; - bdrkreg_t ipr_reserved : 59; - } pi_int_pend1_remap_fld_s; -} pi_int_pend1_remap_u_t; - -#else - -typedef union pi_int_pend1_remap_u { - bdrkreg_t pi_int_pend1_remap_regval; - struct { - bdrkreg_t ipr_reserved : 59; - bdrkreg_t ipr_error_forward : 1; - bdrkreg_t ipr_remap_3 : 1; - bdrkreg_t ipr_remap_2 : 1; - bdrkreg_t ipr_remap_1 : 1; - bdrkreg_t ipr_remap_0 : 1; - } pi_int_pend1_remap_fld_s; -} pi_int_pend1_remap_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the real time * - * counter (RT_Counter) is equal to the value in this register, the * - * RT_INT_PEND register is set, which causes a Level-4 interrupt to * - * be sent to the processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_compare_a_u { - bdrkreg_t pi_rt_compare_a_regval; - struct { - bdrkreg_t rca_rt_compare : 55; - bdrkreg_t rca_rsvd : 9; - } pi_rt_compare_a_fld_s; -} pi_rt_compare_a_u_t; - -#else - -typedef union pi_rt_compare_a_u { - bdrkreg_t pi_rt_compare_a_regval; - struct { - bdrkreg_t rca_rsvd : 9; - bdrkreg_t rca_rt_compare : 55; - } pi_rt_compare_a_fld_s; -} pi_rt_compare_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the real time * - * counter (RT_Counter) is equal to the value in this register, the * - * RT_INT_PEND register is set, which causes a Level-4 interrupt to * - * be sent to the processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_compare_b_u { - bdrkreg_t pi_rt_compare_b_regval; - struct { - bdrkreg_t rcb_rt_compare : 55; - bdrkreg_t rcb_rsvd : 9; - } pi_rt_compare_b_fld_s; -} pi_rt_compare_b_u_t; - -#else - -typedef union pi_rt_compare_b_u { - bdrkreg_t pi_rt_compare_b_regval; - struct { - bdrkreg_t rcb_rsvd : 9; - bdrkreg_t rcb_rt_compare : 55; - } pi_rt_compare_b_fld_s; -} pi_rt_compare_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * When the least significant 32 bits of the real time counter * - * (RT_Counter) are equal to the value in this register, the * - * PROF_INT_PEND_A and PROF_INT_PEND_B registers are set to 0x1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_profile_compare_u { - bdrkreg_t pi_profile_compare_regval; - struct { - bdrkreg_t pc_profile_compare : 32; - bdrkreg_t pc_rsvd : 32; - } pi_profile_compare_fld_s; -} pi_profile_compare_u_t; - -#else - -typedef union pi_profile_compare_u { - bdrkreg_t pi_profile_compare_regval; - struct { - bdrkreg_t pc_rsvd : 32; - bdrkreg_t pc_profile_compare : 32; - } pi_profile_compare_fld_s; -} pi_profile_compare_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If the bit in the * - * corresponding RT_INT_EN_A/B register is set, the processor's level * - * 5 interrupt is set to the value of the RTC_INT_PEND bit in this * - * register. Storing any value to this location will clear the * - * RTC_INT_PEND bit in the register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_pend_a_u { - bdrkreg_t pi_rt_int_pend_a_regval; - struct { - bdrkreg_t ripa_rtc_int_pend : 1; - bdrkreg_t ripa_rsvd : 63; - } pi_rt_int_pend_a_fld_s; -} pi_rt_int_pend_a_u_t; - -#else - -typedef union pi_rt_int_pend_a_u { - bdrkreg_t pi_rt_int_pend_a_regval; - struct { - bdrkreg_t ripa_rsvd : 63; - bdrkreg_t ripa_rtc_int_pend : 1; - } pi_rt_int_pend_a_fld_s; -} pi_rt_int_pend_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If the bit in the * - * corresponding RT_INT_EN_A/B register is set, the processor's level * - * 5 interrupt is set to the value of the RTC_INT_PEND bit in this * - * register. Storing any value to this location will clear the * - * RTC_INT_PEND bit in the register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_pend_b_u { - bdrkreg_t pi_rt_int_pend_b_regval; - struct { - bdrkreg_t ripb_rtc_int_pend : 1; - bdrkreg_t ripb_rsvd : 63; - } pi_rt_int_pend_b_fld_s; -} pi_rt_int_pend_b_u_t; - -#else - -typedef union pi_rt_int_pend_b_u { - bdrkreg_t pi_rt_int_pend_b_regval; - struct { - bdrkreg_t ripb_rsvd : 63; - bdrkreg_t ripb_rtc_int_pend : 1; - } pi_rt_int_pend_b_fld_s; -} pi_rt_int_pend_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Both registers are * - * set when the PROFILE_COMPARE register is equal to bits [31:0] of * - * the RT_Counter. If the bit in the corresponding PROF_INT_EN_A/B * - * register is set, the processor's level 5 interrupt is set to the * - * value of the PROF_INT_PEND bit in this register. Storing any value * - * to this location will clear the PROF_INT_PEND bit in the register. * - * The reason for having A and B versions of this register is that * - * they need to be cleared independently. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_pend_a_u { - bdrkreg_t pi_prof_int_pend_a_regval; - struct { - bdrkreg_t pipa_prof_int_pend : 1; - bdrkreg_t pipa_rsvd : 63; - } pi_prof_int_pend_a_fld_s; -} pi_prof_int_pend_a_u_t; - -#else - -typedef union pi_prof_int_pend_a_u { - bdrkreg_t pi_prof_int_pend_a_regval; - struct { - bdrkreg_t pipa_rsvd : 63; - bdrkreg_t pipa_prof_int_pend : 1; - } pi_prof_int_pend_a_fld_s; -} pi_prof_int_pend_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Both registers are * - * set when the PROFILE_COMPARE register is equal to bits [31:0] of * - * the RT_Counter. If the bit in the corresponding PROF_INT_EN_A/B * - * register is set, the processor's level 5 interrupt is set to the * - * value of the PROF_INT_PEND bit in this register. Storing any value * - * to this location will clear the PROF_INT_PEND bit in the register. * - * The reason for having A and B versions of this register is that * - * they need to be cleared independently. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_pend_b_u { - bdrkreg_t pi_prof_int_pend_b_regval; - struct { - bdrkreg_t pipb_prof_int_pend : 1; - bdrkreg_t pipb_rsvd : 63; - } pi_prof_int_pend_b_fld_s; -} pi_prof_int_pend_b_u_t; - -#else - -typedef union pi_prof_int_pend_b_u { - bdrkreg_t pi_prof_int_pend_b_regval; - struct { - bdrkreg_t pipb_rsvd : 63; - bdrkreg_t pipb_prof_int_pend : 1; - } pi_prof_int_pend_b_fld_s; -} pi_prof_int_pend_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables RTC * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_en_a_u { - bdrkreg_t pi_rt_int_en_a_regval; - struct { - bdrkreg_t riea_rtc_int_en : 1; - bdrkreg_t riea_rsvd : 63; - } pi_rt_int_en_a_fld_s; -} pi_rt_int_en_a_u_t; - -#else - -typedef union pi_rt_int_en_a_u { - bdrkreg_t pi_rt_int_en_a_regval; - struct { - bdrkreg_t riea_rsvd : 63; - bdrkreg_t riea_rtc_int_en : 1; - } pi_rt_int_en_a_fld_s; -} pi_rt_int_en_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables RTC * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_en_b_u { - bdrkreg_t pi_rt_int_en_b_regval; - struct { - bdrkreg_t rieb_rtc_int_en : 1; - bdrkreg_t rieb_rsvd : 63; - } pi_rt_int_en_b_fld_s; -} pi_rt_int_en_b_u_t; - -#else - -typedef union pi_rt_int_en_b_u { - bdrkreg_t pi_rt_int_en_b_regval; - struct { - bdrkreg_t rieb_rsvd : 63; - bdrkreg_t rieb_rtc_int_en : 1; - } pi_rt_int_en_b_fld_s; -} pi_rt_int_en_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables profiling * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_en_a_u { - bdrkreg_t pi_prof_int_en_a_regval; - struct { - bdrkreg_t piea_prof_int_en : 1; - bdrkreg_t piea_rsvd : 63; - } pi_prof_int_en_a_fld_s; -} pi_prof_int_en_a_u_t; - -#else - -typedef union pi_prof_int_en_a_u { - bdrkreg_t pi_prof_int_en_a_regval; - struct { - bdrkreg_t piea_rsvd : 63; - bdrkreg_t piea_prof_int_en : 1; - } pi_prof_int_en_a_fld_s; -} pi_prof_int_en_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables profiling * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_en_b_u { - bdrkreg_t pi_prof_int_en_b_regval; - struct { - bdrkreg_t pieb_prof_int_en : 1; - bdrkreg_t pieb_rsvd : 63; - } pi_prof_int_en_b_fld_s; -} pi_prof_int_en_b_u_t; - -#else - -typedef union pi_prof_int_en_b_u { - bdrkreg_t pi_prof_int_en_b_regval; - struct { - bdrkreg_t pieb_rsvd : 63; - bdrkreg_t pieb_prof_int_en : 1; - } pi_prof_int_en_b_fld_s; -} pi_prof_int_en_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls operation of the debug data from the PI, * - * along with Debug_Sel[2:0] from the Debug module. For some values * - * of Debug_Sel[2:0], the B_SEL bit selects whether the debug bits * - * are looking at the processor A or processor B logic. The remaining * - * bits select which signal(s) are ORed to create DebugData bits 31 * - * and 30 for all of the PI debug selections. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_debug_sel_u { - bdrkreg_t pi_debug_sel_regval; - struct { - bdrkreg_t ds_low_t5cc_a : 1; - bdrkreg_t ds_low_t5cc_b : 1; - bdrkreg_t ds_low_totcc_a : 1; - bdrkreg_t ds_low_totcc_b : 1; - bdrkreg_t ds_low_reqcc_a : 1; - bdrkreg_t ds_low_reqcc_b : 1; - bdrkreg_t ds_low_rplcc_a : 1; - bdrkreg_t ds_low_rplcc_b : 1; - bdrkreg_t ds_low_intcc : 1; - bdrkreg_t ds_low_perf_inc_a_0 : 1; - bdrkreg_t ds_low_perf_inc_a_1 : 1; - bdrkreg_t ds_low_perf_inc_b_0 : 1; - bdrkreg_t ds_low_perf_inc_b_1 : 1; - bdrkreg_t ds_high_t5cc_a : 1; - bdrkreg_t ds_high_t5cc_b : 1; - bdrkreg_t ds_high_totcc_a : 1; - bdrkreg_t ds_high_totcc_b : 1; - bdrkreg_t ds_high_reqcc_a : 1; - bdrkreg_t ds_high_reqcc_b : 1; - bdrkreg_t ds_high_rplcc_a : 1; - bdrkreg_t ds_high_rplcc_b : 1; - bdrkreg_t ds_high_intcc : 1; - bdrkreg_t ds_high_perf_inc_a_0 : 1; - bdrkreg_t ds_high_perf_inc_a_1 : 1; - bdrkreg_t ds_high_perf_inc_b_0 : 1; - bdrkreg_t ds_high_perf_inc_b_1 : 1; - bdrkreg_t ds_b_sel : 1; - bdrkreg_t ds_rsvd : 37; - } pi_debug_sel_fld_s; -} pi_debug_sel_u_t; - -#else - -typedef union pi_debug_sel_u { - bdrkreg_t pi_debug_sel_regval; - struct { - bdrkreg_t ds_rsvd : 37; - bdrkreg_t ds_b_sel : 1; - bdrkreg_t ds_high_perf_inc_b_1 : 1; - bdrkreg_t ds_high_perf_inc_b_0 : 1; - bdrkreg_t ds_high_perf_inc_a_1 : 1; - bdrkreg_t ds_high_perf_inc_a_0 : 1; - bdrkreg_t ds_high_intcc : 1; - bdrkreg_t ds_high_rplcc_b : 1; - bdrkreg_t ds_high_rplcc_a : 1; - bdrkreg_t ds_high_reqcc_b : 1; - bdrkreg_t ds_high_reqcc_a : 1; - bdrkreg_t ds_high_totcc_b : 1; - bdrkreg_t ds_high_totcc_a : 1; - bdrkreg_t ds_high_t5cc_b : 1; - bdrkreg_t ds_high_t5cc_a : 1; - bdrkreg_t ds_low_perf_inc_b_1 : 1; - bdrkreg_t ds_low_perf_inc_b_0 : 1; - bdrkreg_t ds_low_perf_inc_a_1 : 1; - bdrkreg_t ds_low_perf_inc_a_0 : 1; - bdrkreg_t ds_low_intcc : 1; - bdrkreg_t ds_low_rplcc_b : 1; - bdrkreg_t ds_low_rplcc_a : 1; - bdrkreg_t ds_low_reqcc_b : 1; - bdrkreg_t ds_low_reqcc_a : 1; - bdrkreg_t ds_low_totcc_b : 1; - bdrkreg_t ds_low_totcc_a : 1; - bdrkreg_t ds_low_t5cc_b : 1; - bdrkreg_t ds_low_t5cc_a : 1; - } pi_debug_sel_fld_s; -} pi_debug_sel_u_t; - -#endif - - -/************************************************************************ - * * - * A write to this register allows a single bit in the INT_PEND0 or * - * INT_PEND1 registers to be set or cleared. If 6 is clear, a bit is * - * modified in INT_PEND0, while if 6 is set, a bit is modified in * - * INT_PEND1. The value in 5:0 (ranging from 63 to 0) will determine * - * which bit in the register is effected. The value of 8 will * - * determine whether the desired bit is set (8=1) or cleared (8=0). * - * This is the only register which is accessible by IO issued PWRI * - * command and is protected through the IO_PROTECT register. If the * - * region bit in the IO_PROTECT is not set then a WERR reply is * - * issued. CPU access is controlled through CPU_PROTECT. The contents * - * of this register are masked with the contents of INT_MASK_A * - * (INT_MASK_B) to determine whether an L2 interrupt is issued to * - * CPU_A (CPU_B). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend_mod_alias_u { - bdrkreg_t pi_int_pend_mod_alias_regval; - struct { - bdrkreg_t ipma_bit_select : 6; - bdrkreg_t ipma_reg_select : 1; - bdrkreg_t ipma_rsvd_1 : 1; - bdrkreg_t ipma_value : 1; - bdrkreg_t ipma_rsvd : 55; - } pi_int_pend_mod_alias_fld_s; -} pi_int_pend_mod_alias_u_t; - -#else - -typedef union pi_int_pend_mod_alias_u { - bdrkreg_t pi_int_pend_mod_alias_regval; - struct { - bdrkreg_t ipma_rsvd : 55; - bdrkreg_t ipma_value : 1; - bdrkreg_t ipma_rsvd_1 : 1; - bdrkreg_t ipma_reg_select : 1; - bdrkreg_t ipma_bit_select : 6; - } pi_int_pend_mod_alias_fld_s; -} pi_int_pend_mod_alias_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * specifies the value of the Graphics Page. Uncached writes into the * - * Graphics Page (with uncached attribute of IO) are done with GFXWS * - * commands rather than the normal PWRI commands. GFXWS commands are * - * tracked with the graphics credit counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_page_a_u { - bdrkreg_t pi_gfx_page_a_regval; - struct { - bdrkreg_t gpa_rsvd_1 : 17; - bdrkreg_t gpa_gfx_page_addr : 23; - bdrkreg_t gpa_en_gfx_page : 1; - bdrkreg_t gpa_rsvd : 23; - } pi_gfx_page_a_fld_s; -} pi_gfx_page_a_u_t; - -#else - -typedef union pi_gfx_page_a_u { - bdrkreg_t pi_gfx_page_a_regval; - struct { - bdrkreg_t gpa_rsvd : 23; - bdrkreg_t gpa_en_gfx_page : 1; - bdrkreg_t gpa_gfx_page_addr : 23; - bdrkreg_t gpa_rsvd_1 : 17; - } pi_gfx_page_a_fld_s; -} pi_gfx_page_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * counts graphics credits. This counter is decremented for each * - * doubleword sent to graphics with GFXWS or GFXWL commands. It is * - * incremented for each doubleword acknowledge from graphics. When * - * this counter has a smaller value than the GFX_BIAS register, * - * SysWrRdy_L is deasserted, an interrupt is sent to the processor, * - * and SysWrRdy_L is allowed to be asserted again. This is the basic * - * mechanism for flow-controlling graphics writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_cntr_a_u { - bdrkreg_t pi_gfx_credit_cntr_a_regval; - struct { - bdrkreg_t gcca_gfx_credit_cntr : 12; - bdrkreg_t gcca_rsvd : 52; - } pi_gfx_credit_cntr_a_fld_s; -} pi_gfx_credit_cntr_a_u_t; - -#else - -typedef union pi_gfx_credit_cntr_a_u { - bdrkreg_t pi_gfx_credit_cntr_a_regval; - struct { - bdrkreg_t gcca_rsvd : 52; - bdrkreg_t gcca_gfx_credit_cntr : 12; - } pi_gfx_credit_cntr_a_fld_s; -} pi_gfx_credit_cntr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the graphics * - * credit counter is less than or equal to this value, a flow control * - * interrupt is sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_bias_a_u { - bdrkreg_t pi_gfx_bias_a_regval; - struct { - bdrkreg_t gba_gfx_bias : 12; - bdrkreg_t gba_rsvd : 52; - } pi_gfx_bias_a_fld_s; -} pi_gfx_bias_a_u_t; - -#else - -typedef union pi_gfx_bias_a_u { - bdrkreg_t pi_gfx_bias_a_regval; - struct { - bdrkreg_t gba_rsvd : 52; - bdrkreg_t gba_gfx_bias : 12; - } pi_gfx_bias_a_fld_s; -} pi_gfx_bias_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. When * - * this counter reaches the value of the GFX_INT_CMP register, an * - * interrupt is sent to the associated processor. At each clock * - * cycle, the value in this register can be changed by any one of the * - * following actions: * - * - Written by software. * - * - Loaded with the value of GFX_INT_CMP, when an interrupt, NMI, or * - * soft reset occurs, thus preventing an additional interrupt. * - * - Zeroed, when the GFX_CREDIT_CNTR rises above the bias value. * - * - Incremented (by one at each clock) for each clock that the * - * GFX_CREDIT_CNTR is less than or equal to zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cntr_a_u { - bdrkreg_t pi_gfx_int_cntr_a_regval; - struct { - bdrkreg_t gica_gfx_int_cntr : 26; - bdrkreg_t gica_rsvd : 38; - } pi_gfx_int_cntr_a_fld_s; -} pi_gfx_int_cntr_a_u_t; - -#else - -typedef union pi_gfx_int_cntr_a_u { - bdrkreg_t pi_gfx_int_cntr_a_regval; - struct { - bdrkreg_t gica_rsvd : 38; - bdrkreg_t gica_gfx_int_cntr : 26; - } pi_gfx_int_cntr_a_fld_s; -} pi_gfx_int_cntr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The value in this * - * register is loaded into the GFX_INT_CNTR register when an * - * interrupt, NMI, or soft reset is sent to the processor. The value * - * in this register is compared to the value of GFX_INT_CNTR and an * - * interrupt is sent when they become equal. * - * * - ************************************************************************/ - - - - -#ifdef LINUX - -typedef union pi_gfx_int_cmp_a_u { - bdrkreg_t pi_gfx_int_cmp_a_regval; - struct { - bdrkreg_t gica_gfx_int_cmp : 26; - bdrkreg_t gica_rsvd : 38; - } pi_gfx_int_cmp_a_fld_s; -} pi_gfx_int_cmp_a_u_t; - -#else - -typedef union pi_gfx_int_cmp_a_u { - bdrkreg_t pi_gfx_int_cmp_a_regval; - struct { - bdrkreg_t gica_rsvd : 38; - bdrkreg_t gica_gfx_int_cmp : 26; - } pi_gfx_int_cmp_a_fld_s; -} pi_gfx_int_cmp_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * specifies the value of the Graphics Page. Uncached writes into the * - * Graphics Page (with uncached attribute of IO) are done with GFXWS * - * commands rather than the normal PWRI commands. GFXWS commands are * - * tracked with the graphics credit counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_page_b_u { - bdrkreg_t pi_gfx_page_b_regval; - struct { - bdrkreg_t gpb_rsvd_1 : 17; - bdrkreg_t gpb_gfx_page_addr : 23; - bdrkreg_t gpb_en_gfx_page : 1; - bdrkreg_t gpb_rsvd : 23; - } pi_gfx_page_b_fld_s; -} pi_gfx_page_b_u_t; - -#else - -typedef union pi_gfx_page_b_u { - bdrkreg_t pi_gfx_page_b_regval; - struct { - bdrkreg_t gpb_rsvd : 23; - bdrkreg_t gpb_en_gfx_page : 1; - bdrkreg_t gpb_gfx_page_addr : 23; - bdrkreg_t gpb_rsvd_1 : 17; - } pi_gfx_page_b_fld_s; -} pi_gfx_page_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * counts graphics credits. This counter is decremented for each * - * doubleword sent to graphics with GFXWS or GFXWL commands. It is * - * incremented for each doubleword acknowledge from graphics. When * - * this counter has a smaller value than the GFX_BIAS register, * - * SysWrRdy_L is deasserted, an interrupt is sent to the processor, * - * and SysWrRdy_L is allowed to be asserted again. This is the basic * - * mechanism for flow-controlling graphics writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_cntr_b_u { - bdrkreg_t pi_gfx_credit_cntr_b_regval; - struct { - bdrkreg_t gccb_gfx_credit_cntr : 12; - bdrkreg_t gccb_rsvd : 52; - } pi_gfx_credit_cntr_b_fld_s; -} pi_gfx_credit_cntr_b_u_t; - -#else - -typedef union pi_gfx_credit_cntr_b_u { - bdrkreg_t pi_gfx_credit_cntr_b_regval; - struct { - bdrkreg_t gccb_rsvd : 52; - bdrkreg_t gccb_gfx_credit_cntr : 12; - } pi_gfx_credit_cntr_b_fld_s; -} pi_gfx_credit_cntr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the graphics * - * credit counter is less than or equal to this value, a flow control * - * interrupt is sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_bias_b_u { - bdrkreg_t pi_gfx_bias_b_regval; - struct { - bdrkreg_t gbb_gfx_bias : 12; - bdrkreg_t gbb_rsvd : 52; - } pi_gfx_bias_b_fld_s; -} pi_gfx_bias_b_u_t; - -#else - -typedef union pi_gfx_bias_b_u { - bdrkreg_t pi_gfx_bias_b_regval; - struct { - bdrkreg_t gbb_rsvd : 52; - bdrkreg_t gbb_gfx_bias : 12; - } pi_gfx_bias_b_fld_s; -} pi_gfx_bias_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. When * - * this counter reaches the value of the GFX_INT_CMP register, an * - * interrupt is sent to the associated processor. At each clock * - * cycle, the value in this register can be changed by any one of the * - * following actions: * - * - Written by software. * - * - Loaded with the value of GFX_INT_CMP, when an interrupt, NMI, or * - * soft reset occurs, thus preventing an additional interrupt. * - * - Zeroed, when the GFX_CREDIT_CNTR rises above the bias value. * - * - Incremented (by one at each clock) for each clock that the * - * GFX_CREDIT_CNTR is less than or equal to zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cntr_b_u { - bdrkreg_t pi_gfx_int_cntr_b_regval; - struct { - bdrkreg_t gicb_gfx_int_cntr : 26; - bdrkreg_t gicb_rsvd : 38; - } pi_gfx_int_cntr_b_fld_s; -} pi_gfx_int_cntr_b_u_t; - -#else - -typedef union pi_gfx_int_cntr_b_u { - bdrkreg_t pi_gfx_int_cntr_b_regval; - struct { - bdrkreg_t gicb_rsvd : 38; - bdrkreg_t gicb_gfx_int_cntr : 26; - } pi_gfx_int_cntr_b_fld_s; -} pi_gfx_int_cntr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The value in this * - * register is loaded into the GFX_INT_CNTR register when an * - * interrupt, NMI, or soft reset is sent to the processor. The value * - * in this register is compared to the value of GFX_INT_CNTR and an * - * interrupt is sent when they become equal. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cmp_b_u { - bdrkreg_t pi_gfx_int_cmp_b_regval; - struct { - bdrkreg_t gicb_gfx_int_cmp : 26; - bdrkreg_t gicb_rsvd : 38; - } pi_gfx_int_cmp_b_fld_s; -} pi_gfx_int_cmp_b_u_t; - -#else - -typedef union pi_gfx_int_cmp_b_u { - bdrkreg_t pi_gfx_int_cmp_b_regval; - struct { - bdrkreg_t gicb_rsvd : 38; - bdrkreg_t gicb_gfx_int_cmp : 26; - } pi_gfx_int_cmp_b_fld_s; -} pi_gfx_int_cmp_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: A read of this register returns all sources of * - * Bedrock Error Interrupts. Storing to the write-with-clear location * - * clears any bit for which a one appears on the data bus. Storing to * - * the writable location does a direct write to all unreserved bits * - * (except for MEM_UNC). * - * In Synergy mode, the processor that is the source of the command * - * that got an error is independent of the A or B SysAD bus. So in * - * Synergy mode, Synergy provides the source processor number in bit * - * 52 of the SysAD bus in all commands. The PI saves this in the RRB * - * or WRB entry, and uses that value to determine which error bit (A * - * or B) to set, as well as which ERR_STATUS and spool registers to * - * use, for all error types in this register that are specified as an * - * error to CPU_A or CPU_B. * - * This register is not cleared at reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_pend_wr_u { - bdrkreg_t pi_err_int_pend_wr_regval; - struct { - bdrkreg_t eipw_spool_comp_b : 1; - bdrkreg_t eipw_spool_comp_a : 1; - bdrkreg_t eipw_spurious_b : 1; - bdrkreg_t eipw_spurious_a : 1; - bdrkreg_t eipw_wrb_terr_b : 1; - bdrkreg_t eipw_wrb_terr_a : 1; - bdrkreg_t eipw_wrb_werr_b : 1; - bdrkreg_t eipw_wrb_werr_a : 1; - bdrkreg_t eipw_sysstate_par_b : 1; - bdrkreg_t eipw_sysstate_par_a : 1; - bdrkreg_t eipw_sysad_data_ecc_b : 1; - bdrkreg_t eipw_sysad_data_ecc_a : 1; - bdrkreg_t eipw_sysad_addr_ecc_b : 1; - bdrkreg_t eipw_sysad_addr_ecc_a : 1; - bdrkreg_t eipw_syscmd_data_par_b : 1; - bdrkreg_t eipw_syscmd_data_par_a : 1; - bdrkreg_t eipw_syscmd_addr_par_b : 1; - bdrkreg_t eipw_syscmd_addr_par_a : 1; - bdrkreg_t eipw_spool_err_b : 1; - bdrkreg_t eipw_spool_err_a : 1; - bdrkreg_t eipw_ue_uncached_b : 1; - bdrkreg_t eipw_ue_uncached_a : 1; - bdrkreg_t eipw_sysstate_tag_b : 1; - bdrkreg_t eipw_sysstate_tag_a : 1; - bdrkreg_t eipw_mem_unc : 1; - bdrkreg_t eipw_sysad_bad_data_b : 1; - bdrkreg_t eipw_sysad_bad_data_a : 1; - bdrkreg_t eipw_ue_cached_b : 1; - bdrkreg_t eipw_ue_cached_a : 1; - bdrkreg_t eipw_pkt_len_err_b : 1; - bdrkreg_t eipw_pkt_len_err_a : 1; - bdrkreg_t eipw_irb_err_b : 1; - bdrkreg_t eipw_irb_err_a : 1; - bdrkreg_t eipw_irb_timeout_b : 1; - bdrkreg_t eipw_irb_timeout_a : 1; - bdrkreg_t eipw_rsvd : 29; - } pi_err_int_pend_wr_fld_s; -} pi_err_int_pend_wr_u_t; - -#else - -typedef union pi_err_int_pend_wr_u { - bdrkreg_t pi_err_int_pend_wr_regval; - struct { - bdrkreg_t eipw_rsvd : 29; - bdrkreg_t eipw_irb_timeout_a : 1; - bdrkreg_t eipw_irb_timeout_b : 1; - bdrkreg_t eipw_irb_err_a : 1; - bdrkreg_t eipw_irb_err_b : 1; - bdrkreg_t eipw_pkt_len_err_a : 1; - bdrkreg_t eipw_pkt_len_err_b : 1; - bdrkreg_t eipw_ue_cached_a : 1; - bdrkreg_t eipw_ue_cached_b : 1; - bdrkreg_t eipw_sysad_bad_data_a : 1; - bdrkreg_t eipw_sysad_bad_data_b : 1; - bdrkreg_t eipw_mem_unc : 1; - bdrkreg_t eipw_sysstate_tag_a : 1; - bdrkreg_t eipw_sysstate_tag_b : 1; - bdrkreg_t eipw_ue_uncached_a : 1; - bdrkreg_t eipw_ue_uncached_b : 1; - bdrkreg_t eipw_spool_err_a : 1; - bdrkreg_t eipw_spool_err_b : 1; - bdrkreg_t eipw_syscmd_addr_par_a : 1; - bdrkreg_t eipw_syscmd_addr_par_b : 1; - bdrkreg_t eipw_syscmd_data_par_a : 1; - bdrkreg_t eipw_syscmd_data_par_b : 1; - bdrkreg_t eipw_sysad_addr_ecc_a : 1; - bdrkreg_t eipw_sysad_addr_ecc_b : 1; - bdrkreg_t eipw_sysad_data_ecc_a : 1; - bdrkreg_t eipw_sysad_data_ecc_b : 1; - bdrkreg_t eipw_sysstate_par_a : 1; - bdrkreg_t eipw_sysstate_par_b : 1; - bdrkreg_t eipw_wrb_werr_a : 1; - bdrkreg_t eipw_wrb_werr_b : 1; - bdrkreg_t eipw_wrb_terr_a : 1; - bdrkreg_t eipw_wrb_terr_b : 1; - bdrkreg_t eipw_spurious_a : 1; - bdrkreg_t eipw_spurious_b : 1; - bdrkreg_t eipw_spool_comp_a : 1; - bdrkreg_t eipw_spool_comp_b : 1; - } pi_err_int_pend_wr_fld_s; -} pi_err_int_pend_wr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: A read of this register returns all sources of * - * Bedrock Error Interrupts. Storing to the write-with-clear location * - * clears any bit for which a one appears on the data bus. Storing to * - * the writable location does a direct write to all unreserved bits * - * (except for MEM_UNC). * - * In Synergy mode, the processor that is the source of the command * - * that got an error is independent of the A or B SysAD bus. So in * - * Synergy mode, Synergy provides the source processor number in bit * - * 52 of the SysAD bus in all commands. The PI saves this in the RRB * - * or WRB entry, and uses that value to determine which error bit (A * - * or B) to set, as well as which ERR_STATUS and spool registers to * - * use, for all error types in this register that are specified as an * - * error to CPU_A or CPU_B. * - * This register is not cleared at reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_pend_u { - bdrkreg_t pi_err_int_pend_regval; - struct { - bdrkreg_t eip_spool_comp_b : 1; - bdrkreg_t eip_spool_comp_a : 1; - bdrkreg_t eip_spurious_b : 1; - bdrkreg_t eip_spurious_a : 1; - bdrkreg_t eip_wrb_terr_b : 1; - bdrkreg_t eip_wrb_terr_a : 1; - bdrkreg_t eip_wrb_werr_b : 1; - bdrkreg_t eip_wrb_werr_a : 1; - bdrkreg_t eip_sysstate_par_b : 1; - bdrkreg_t eip_sysstate_par_a : 1; - bdrkreg_t eip_sysad_data_ecc_b : 1; - bdrkreg_t eip_sysad_data_ecc_a : 1; - bdrkreg_t eip_sysad_addr_ecc_b : 1; - bdrkreg_t eip_sysad_addr_ecc_a : 1; - bdrkreg_t eip_syscmd_data_par_b : 1; - bdrkreg_t eip_syscmd_data_par_a : 1; - bdrkreg_t eip_syscmd_addr_par_b : 1; - bdrkreg_t eip_syscmd_addr_par_a : 1; - bdrkreg_t eip_spool_err_b : 1; - bdrkreg_t eip_spool_err_a : 1; - bdrkreg_t eip_ue_uncached_b : 1; - bdrkreg_t eip_ue_uncached_a : 1; - bdrkreg_t eip_sysstate_tag_b : 1; - bdrkreg_t eip_sysstate_tag_a : 1; - bdrkreg_t eip_mem_unc : 1; - bdrkreg_t eip_sysad_bad_data_b : 1; - bdrkreg_t eip_sysad_bad_data_a : 1; - bdrkreg_t eip_ue_cached_b : 1; - bdrkreg_t eip_ue_cached_a : 1; - bdrkreg_t eip_pkt_len_err_b : 1; - bdrkreg_t eip_pkt_len_err_a : 1; - bdrkreg_t eip_irb_err_b : 1; - bdrkreg_t eip_irb_err_a : 1; - bdrkreg_t eip_irb_timeout_b : 1; - bdrkreg_t eip_irb_timeout_a : 1; - bdrkreg_t eip_rsvd : 29; - } pi_err_int_pend_fld_s; -} pi_err_int_pend_u_t; - -#else - -typedef union pi_err_int_pend_u { - bdrkreg_t pi_err_int_pend_regval; - struct { - bdrkreg_t eip_rsvd : 29; - bdrkreg_t eip_irb_timeout_a : 1; - bdrkreg_t eip_irb_timeout_b : 1; - bdrkreg_t eip_irb_err_a : 1; - bdrkreg_t eip_irb_err_b : 1; - bdrkreg_t eip_pkt_len_err_a : 1; - bdrkreg_t eip_pkt_len_err_b : 1; - bdrkreg_t eip_ue_cached_a : 1; - bdrkreg_t eip_ue_cached_b : 1; - bdrkreg_t eip_sysad_bad_data_a : 1; - bdrkreg_t eip_sysad_bad_data_b : 1; - bdrkreg_t eip_mem_unc : 1; - bdrkreg_t eip_sysstate_tag_a : 1; - bdrkreg_t eip_sysstate_tag_b : 1; - bdrkreg_t eip_ue_uncached_a : 1; - bdrkreg_t eip_ue_uncached_b : 1; - bdrkreg_t eip_spool_err_a : 1; - bdrkreg_t eip_spool_err_b : 1; - bdrkreg_t eip_syscmd_addr_par_a : 1; - bdrkreg_t eip_syscmd_addr_par_b : 1; - bdrkreg_t eip_syscmd_data_par_a : 1; - bdrkreg_t eip_syscmd_data_par_b : 1; - bdrkreg_t eip_sysad_addr_ecc_a : 1; - bdrkreg_t eip_sysad_addr_ecc_b : 1; - bdrkreg_t eip_sysad_data_ecc_a : 1; - bdrkreg_t eip_sysad_data_ecc_b : 1; - bdrkreg_t eip_sysstate_par_a : 1; - bdrkreg_t eip_sysstate_par_b : 1; - bdrkreg_t eip_wrb_werr_a : 1; - bdrkreg_t eip_wrb_werr_b : 1; - bdrkreg_t eip_wrb_terr_a : 1; - bdrkreg_t eip_wrb_terr_b : 1; - bdrkreg_t eip_spurious_a : 1; - bdrkreg_t eip_spurious_b : 1; - bdrkreg_t eip_spool_comp_a : 1; - bdrkreg_t eip_spool_comp_b : 1; - } pi_err_int_pend_fld_s; -} pi_err_int_pend_u_t; - -#endif - - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This read/write * - * register masks the contents of ERR_INT_PEND to determine which * - * conditions cause a Level-6 interrupt to CPU_A or CPU_B. A bit set * - * allows the interrupt. Only one processor in a Bedrock should * - * enable the Memory/Directory Uncorrectable Error bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_mask_a_u { - bdrkreg_t pi_err_int_mask_a_regval; - struct { - bdrkreg_t eima_mask : 35; - bdrkreg_t eima_rsvd : 29; - } pi_err_int_mask_a_fld_s; -} pi_err_int_mask_a_u_t; - -#else - -typedef union pi_err_int_mask_a_u { - bdrkreg_t pi_err_int_mask_a_regval; - struct { - bdrkreg_t eima_rsvd : 29; - bdrkreg_t eima_mask : 35; - } pi_err_int_mask_a_fld_s; -} pi_err_int_mask_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This read/write * - * register masks the contents of ERR_INT_PEND to determine which * - * conditions cause a Level-6 interrupt to CPU_A or CPU_B. A bit set * - * allows the interrupt. Only one processor in a Bedrock should * - * enable the Memory/Directory Uncorrectable Error bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_mask_b_u { - bdrkreg_t pi_err_int_mask_b_regval; - struct { - bdrkreg_t eimb_mask : 35; - bdrkreg_t eimb_rsvd : 29; - } pi_err_int_mask_b_fld_s; -} pi_err_int_mask_b_u_t; - -#else - -typedef union pi_err_int_mask_b_u { - bdrkreg_t pi_err_int_mask_b_regval; - struct { - bdrkreg_t eimb_rsvd : 29; - bdrkreg_t eimb_mask : 35; - } pi_err_int_mask_b_fld_s; -} pi_err_int_mask_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * register is the address of the next write to the error stack. This * - * register is incremented after each such write. Only the low N bits * - * are incremented, where N is defined by the size of the error stack * - * specified in the ERR_STACK_SIZE register. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_addr_a_u { - bdrkreg_t pi_err_stack_addr_a_regval; - struct { - bdrkreg_t esaa_rsvd_1 : 3; - bdrkreg_t esaa_addr : 30; - bdrkreg_t esaa_rsvd : 31; - } pi_err_stack_addr_a_fld_s; -} pi_err_stack_addr_a_u_t; - -#else - -typedef union pi_err_stack_addr_a_u { - bdrkreg_t pi_err_stack_addr_a_regval; - struct { - bdrkreg_t esaa_rsvd : 31; - bdrkreg_t esaa_addr : 30; - bdrkreg_t esaa_rsvd_1 : 3; - } pi_err_stack_addr_a_fld_s; -} pi_err_stack_addr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * register is the address of the next write to the error stack. This * - * register is incremented after each such write. Only the low N bits * - * are incremented, where N is defined by the size of the error stack * - * specified in the ERR_STACK_SIZE register. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_addr_b_u { - bdrkreg_t pi_err_stack_addr_b_regval; - struct { - bdrkreg_t esab_rsvd_1 : 3; - bdrkreg_t esab_addr : 30; - bdrkreg_t esab_rsvd : 31; - } pi_err_stack_addr_b_fld_s; -} pi_err_stack_addr_b_u_t; - -#else - -typedef union pi_err_stack_addr_b_u { - bdrkreg_t pi_err_stack_addr_b_regval; - struct { - bdrkreg_t esab_rsvd : 31; - bdrkreg_t esab_addr : 30; - bdrkreg_t esab_rsvd_1 : 3; - } pi_err_stack_addr_b_fld_s; -} pi_err_stack_addr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Sets the size (number of 64-bit entries) in the * - * error stack that is spooled to local memory when an error occurs. * - * Table16 defines the format of each entry in the spooled error * - * stack. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_size_u { - bdrkreg_t pi_err_stack_size_regval; - struct { - bdrkreg_t ess_size : 4; - bdrkreg_t ess_rsvd : 60; - } pi_err_stack_size_fld_s; -} pi_err_stack_size_u_t; - -#else - -typedef union pi_err_stack_size_u { - bdrkreg_t pi_err_stack_size_regval; - struct { - bdrkreg_t ess_rsvd : 60; - bdrkreg_t ess_size : 4; - } pi_err_stack_size_fld_s; -} pi_err_stack_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_a_u { - bdrkreg_t pi_err_status0_a_regval; - struct { - bdrkreg_t esa_error_type : 3; - bdrkreg_t esa_proc_req_num : 3; - bdrkreg_t esa_supplemental : 11; - bdrkreg_t esa_cmd : 8; - bdrkreg_t esa_addr : 37; - bdrkreg_t esa_over_run : 1; - bdrkreg_t esa_valid : 1; - } pi_err_status0_a_fld_s; -} pi_err_status0_a_u_t; - -#else - -typedef union pi_err_status0_a_u { - bdrkreg_t pi_err_status0_a_regval; - struct { - bdrkreg_t esa_valid : 1; - bdrkreg_t esa_over_run : 1; - bdrkreg_t esa_addr : 37; - bdrkreg_t esa_cmd : 8; - bdrkreg_t esa_supplemental : 11; - bdrkreg_t esa_proc_req_num : 3; - bdrkreg_t esa_error_type : 3; - } pi_err_status0_a_fld_s; -} pi_err_status0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_a_clr_u { - bdrkreg_t pi_err_status0_a_clr_regval; - struct { - bdrkreg_t esac_error_type : 3; - bdrkreg_t esac_proc_req_num : 3; - bdrkreg_t esac_supplemental : 11; - bdrkreg_t esac_cmd : 8; - bdrkreg_t esac_addr : 37; - bdrkreg_t esac_over_run : 1; - bdrkreg_t esac_valid : 1; - } pi_err_status0_a_clr_fld_s; -} pi_err_status0_a_clr_u_t; - -#else - -typedef union pi_err_status0_a_clr_u { - bdrkreg_t pi_err_status0_a_clr_regval; - struct { - bdrkreg_t esac_valid : 1; - bdrkreg_t esac_over_run : 1; - bdrkreg_t esac_addr : 37; - bdrkreg_t esac_cmd : 8; - bdrkreg_t esac_supplemental : 11; - bdrkreg_t esac_proc_req_num : 3; - bdrkreg_t esac_error_type : 3; - } pi_err_status0_a_clr_fld_s; -} pi_err_status0_a_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_a_u { - bdrkreg_t pi_err_status1_a_regval; - struct { - bdrkreg_t esa_spool_count : 21; - bdrkreg_t esa_time_out_count : 8; - bdrkreg_t esa_inval_count : 10; - bdrkreg_t esa_crb_num : 3; - bdrkreg_t esa_wrb : 1; - bdrkreg_t esa_e_bits : 2; - bdrkreg_t esa_t_bit : 1; - bdrkreg_t esa_i_bit : 1; - bdrkreg_t esa_h_bit : 1; - bdrkreg_t esa_w_bit : 1; - bdrkreg_t esa_a_bit : 1; - bdrkreg_t esa_r_bit : 1; - bdrkreg_t esa_v_bit : 1; - bdrkreg_t esa_p_bit : 1; - bdrkreg_t esa_source : 11; - } pi_err_status1_a_fld_s; -} pi_err_status1_a_u_t; - -#else - -typedef union pi_err_status1_a_u { - bdrkreg_t pi_err_status1_a_regval; - struct { - bdrkreg_t esa_source : 11; - bdrkreg_t esa_p_bit : 1; - bdrkreg_t esa_v_bit : 1; - bdrkreg_t esa_r_bit : 1; - bdrkreg_t esa_a_bit : 1; - bdrkreg_t esa_w_bit : 1; - bdrkreg_t esa_h_bit : 1; - bdrkreg_t esa_i_bit : 1; - bdrkreg_t esa_t_bit : 1; - bdrkreg_t esa_e_bits : 2; - bdrkreg_t esa_wrb : 1; - bdrkreg_t esa_crb_num : 3; - bdrkreg_t esa_inval_count : 10; - bdrkreg_t esa_time_out_count : 8; - bdrkreg_t esa_spool_count : 21; - } pi_err_status1_a_fld_s; -} pi_err_status1_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_a_clr_u { - bdrkreg_t pi_err_status1_a_clr_regval; - struct { - bdrkreg_t esac_spool_count : 21; - bdrkreg_t esac_time_out_count : 8; - bdrkreg_t esac_inval_count : 10; - bdrkreg_t esac_crb_num : 3; - bdrkreg_t esac_wrb : 1; - bdrkreg_t esac_e_bits : 2; - bdrkreg_t esac_t_bit : 1; - bdrkreg_t esac_i_bit : 1; - bdrkreg_t esac_h_bit : 1; - bdrkreg_t esac_w_bit : 1; - bdrkreg_t esac_a_bit : 1; - bdrkreg_t esac_r_bit : 1; - bdrkreg_t esac_v_bit : 1; - bdrkreg_t esac_p_bit : 1; - bdrkreg_t esac_source : 11; - } pi_err_status1_a_clr_fld_s; -} pi_err_status1_a_clr_u_t; - -#else - -typedef union pi_err_status1_a_clr_u { - bdrkreg_t pi_err_status1_a_clr_regval; - struct { - bdrkreg_t esac_source : 11; - bdrkreg_t esac_p_bit : 1; - bdrkreg_t esac_v_bit : 1; - bdrkreg_t esac_r_bit : 1; - bdrkreg_t esac_a_bit : 1; - bdrkreg_t esac_w_bit : 1; - bdrkreg_t esac_h_bit : 1; - bdrkreg_t esac_i_bit : 1; - bdrkreg_t esac_t_bit : 1; - bdrkreg_t esac_e_bits : 2; - bdrkreg_t esac_wrb : 1; - bdrkreg_t esac_crb_num : 3; - bdrkreg_t esac_inval_count : 10; - bdrkreg_t esac_time_out_count : 8; - bdrkreg_t esac_spool_count : 21; - } pi_err_status1_a_clr_fld_s; -} pi_err_status1_a_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_b_u { - bdrkreg_t pi_err_status0_b_regval; - struct { - bdrkreg_t esb_error_type : 3; - bdrkreg_t esb_proc_request_number : 3; - bdrkreg_t esb_supplemental : 11; - bdrkreg_t esb_cmd : 8; - bdrkreg_t esb_addr : 37; - bdrkreg_t esb_over_run : 1; - bdrkreg_t esb_valid : 1; - } pi_err_status0_b_fld_s; -} pi_err_status0_b_u_t; - -#else - -typedef union pi_err_status0_b_u { - bdrkreg_t pi_err_status0_b_regval; - struct { - bdrkreg_t esb_valid : 1; - bdrkreg_t esb_over_run : 1; - bdrkreg_t esb_addr : 37; - bdrkreg_t esb_cmd : 8; - bdrkreg_t esb_supplemental : 11; - bdrkreg_t esb_proc_request_number : 3; - bdrkreg_t esb_error_type : 3; - } pi_err_status0_b_fld_s; -} pi_err_status0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_b_clr_u { - bdrkreg_t pi_err_status0_b_clr_regval; - struct { - bdrkreg_t esbc_error_type : 3; - bdrkreg_t esbc_proc_request_number : 3; - bdrkreg_t esbc_supplemental : 11; - bdrkreg_t esbc_cmd : 8; - bdrkreg_t esbc_addr : 37; - bdrkreg_t esbc_over_run : 1; - bdrkreg_t esbc_valid : 1; - } pi_err_status0_b_clr_fld_s; -} pi_err_status0_b_clr_u_t; - -#else - -typedef union pi_err_status0_b_clr_u { - bdrkreg_t pi_err_status0_b_clr_regval; - struct { - bdrkreg_t esbc_valid : 1; - bdrkreg_t esbc_over_run : 1; - bdrkreg_t esbc_addr : 37; - bdrkreg_t esbc_cmd : 8; - bdrkreg_t esbc_supplemental : 11; - bdrkreg_t esbc_proc_request_number : 3; - bdrkreg_t esbc_error_type : 3; - } pi_err_status0_b_clr_fld_s; -} pi_err_status0_b_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_b_u { - bdrkreg_t pi_err_status1_b_regval; - struct { - bdrkreg_t esb_spool_count : 21; - bdrkreg_t esb_time_out_count : 8; - bdrkreg_t esb_inval_count : 10; - bdrkreg_t esb_crb_num : 3; - bdrkreg_t esb_wrb : 1; - bdrkreg_t esb_e_bits : 2; - bdrkreg_t esb_t_bit : 1; - bdrkreg_t esb_i_bit : 1; - bdrkreg_t esb_h_bit : 1; - bdrkreg_t esb_w_bit : 1; - bdrkreg_t esb_a_bit : 1; - bdrkreg_t esb_r_bit : 1; - bdrkreg_t esb_v_bit : 1; - bdrkreg_t esb_p_bit : 1; - bdrkreg_t esb_source : 11; - } pi_err_status1_b_fld_s; -} pi_err_status1_b_u_t; - -#else - -typedef union pi_err_status1_b_u { - bdrkreg_t pi_err_status1_b_regval; - struct { - bdrkreg_t esb_source : 11; - bdrkreg_t esb_p_bit : 1; - bdrkreg_t esb_v_bit : 1; - bdrkreg_t esb_r_bit : 1; - bdrkreg_t esb_a_bit : 1; - bdrkreg_t esb_w_bit : 1; - bdrkreg_t esb_h_bit : 1; - bdrkreg_t esb_i_bit : 1; - bdrkreg_t esb_t_bit : 1; - bdrkreg_t esb_e_bits : 2; - bdrkreg_t esb_wrb : 1; - bdrkreg_t esb_crb_num : 3; - bdrkreg_t esb_inval_count : 10; - bdrkreg_t esb_time_out_count : 8; - bdrkreg_t esb_spool_count : 21; - } pi_err_status1_b_fld_s; -} pi_err_status1_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_b_clr_u { - bdrkreg_t pi_err_status1_b_clr_regval; - struct { - bdrkreg_t esbc_spool_count : 21; - bdrkreg_t esbc_time_out_count : 8; - bdrkreg_t esbc_inval_count : 10; - bdrkreg_t esbc_crb_num : 3; - bdrkreg_t esbc_wrb : 1; - bdrkreg_t esbc_e_bits : 2; - bdrkreg_t esbc_t_bit : 1; - bdrkreg_t esbc_i_bit : 1; - bdrkreg_t esbc_h_bit : 1; - bdrkreg_t esbc_w_bit : 1; - bdrkreg_t esbc_a_bit : 1; - bdrkreg_t esbc_r_bit : 1; - bdrkreg_t esbc_v_bit : 1; - bdrkreg_t esbc_p_bit : 1; - bdrkreg_t esbc_source : 11; - } pi_err_status1_b_clr_fld_s; -} pi_err_status1_b_clr_u_t; - -#else - -typedef union pi_err_status1_b_clr_u { - bdrkreg_t pi_err_status1_b_clr_regval; - struct { - bdrkreg_t esbc_source : 11; - bdrkreg_t esbc_p_bit : 1; - bdrkreg_t esbc_v_bit : 1; - bdrkreg_t esbc_r_bit : 1; - bdrkreg_t esbc_a_bit : 1; - bdrkreg_t esbc_w_bit : 1; - bdrkreg_t esbc_h_bit : 1; - bdrkreg_t esbc_i_bit : 1; - bdrkreg_t esbc_t_bit : 1; - bdrkreg_t esbc_e_bits : 2; - bdrkreg_t esbc_wrb : 1; - bdrkreg_t esbc_crb_num : 3; - bdrkreg_t esbc_inval_count : 10; - bdrkreg_t esbc_time_out_count : 8; - bdrkreg_t esbc_spool_count : 21; - } pi_err_status1_b_clr_fld_s; -} pi_err_status1_b_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_cmp_a_u { - bdrkreg_t pi_spool_cmp_a_regval; - struct { - bdrkreg_t sca_compare : 20; - bdrkreg_t sca_rsvd : 44; - } pi_spool_cmp_a_fld_s; -} pi_spool_cmp_a_u_t; - -#else - -typedef union pi_spool_cmp_a_u { - bdrkreg_t pi_spool_cmp_a_regval; - struct { - bdrkreg_t sca_rsvd : 44; - bdrkreg_t sca_compare : 20; - } pi_spool_cmp_a_fld_s; -} pi_spool_cmp_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_cmp_b_u { - bdrkreg_t pi_spool_cmp_b_regval; - struct { - bdrkreg_t scb_compare : 20; - bdrkreg_t scb_rsvd : 44; - } pi_spool_cmp_b_fld_s; -} pi_spool_cmp_b_u_t; - -#else - -typedef union pi_spool_cmp_b_u { - bdrkreg_t pi_spool_cmp_b_regval; - struct { - bdrkreg_t scb_rsvd : 44; - bdrkreg_t scb_compare : 20; - } pi_spool_cmp_b_fld_s; -} pi_spool_cmp_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A timeout can be * - * forced by writing one(s). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_timeout_a_u { - bdrkreg_t pi_crb_timeout_a_regval; - struct { - bdrkreg_t cta_rrb : 4; - bdrkreg_t cta_wrb : 8; - bdrkreg_t cta_rsvd : 52; - } pi_crb_timeout_a_fld_s; -} pi_crb_timeout_a_u_t; - -#else - -typedef union pi_crb_timeout_a_u { - bdrkreg_t pi_crb_timeout_a_regval; - struct { - bdrkreg_t cta_rsvd : 52; - bdrkreg_t cta_wrb : 8; - bdrkreg_t cta_rrb : 4; - } pi_crb_timeout_a_fld_s; -} pi_crb_timeout_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A timeout can be * - * forced by writing one(s). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_timeout_b_u { - bdrkreg_t pi_crb_timeout_b_regval; - struct { - bdrkreg_t ctb_rrb : 4; - bdrkreg_t ctb_wrb : 8; - bdrkreg_t ctb_rsvd : 52; - } pi_crb_timeout_b_fld_s; -} pi_crb_timeout_b_u_t; - -#else - -typedef union pi_crb_timeout_b_u { - bdrkreg_t pi_crb_timeout_b_regval; - struct { - bdrkreg_t ctb_rsvd : 52; - bdrkreg_t ctb_wrb : 8; - bdrkreg_t ctb_rrb : 4; - } pi_crb_timeout_b_fld_s; -} pi_crb_timeout_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls error checking and forwarding of SysAD * - * errors. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_sysad_errchk_en_u { - bdrkreg_t pi_sysad_errchk_en_regval; - struct { - bdrkreg_t see_ecc_gen_en : 1; - bdrkreg_t see_qual_gen_en : 1; - bdrkreg_t see_sadp_chk_en : 1; - bdrkreg_t see_cmdp_chk_en : 1; - bdrkreg_t see_state_chk_en : 1; - bdrkreg_t see_qual_chk_en : 1; - bdrkreg_t see_rsvd : 58; - } pi_sysad_errchk_en_fld_s; -} pi_sysad_errchk_en_u_t; - -#else - -typedef union pi_sysad_errchk_en_u { - bdrkreg_t pi_sysad_errchk_en_regval; - struct { - bdrkreg_t see_rsvd : 58; - bdrkreg_t see_qual_chk_en : 1; - bdrkreg_t see_state_chk_en : 1; - bdrkreg_t see_cmdp_chk_en : 1; - bdrkreg_t see_sadp_chk_en : 1; - bdrkreg_t see_qual_gen_en : 1; - bdrkreg_t see_ecc_gen_en : 1; - } pi_sysad_errchk_en_fld_s; -} pi_sysad_errchk_en_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If any bit in this * - * register is set, then whenever reply data arrives with the UE * - * (uncorrectable error) indication set, the check-bits that are * - * generated and sent to the SysAD will be inverted corresponding to * - * the bits set in the register. This will also prevent the assertion * - * of the data quality indicator. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_force_bad_check_bit_a_u { - bdrkreg_t pi_force_bad_check_bit_a_regval; - struct { - bdrkreg_t fbcba_bad_check_bit : 8; - bdrkreg_t fbcba_rsvd : 56; - } pi_force_bad_check_bit_a_fld_s; -} pi_force_bad_check_bit_a_u_t; - -#else - -typedef union pi_force_bad_check_bit_a_u { - bdrkreg_t pi_force_bad_check_bit_a_regval; - struct { - bdrkreg_t fbcba_rsvd : 56; - bdrkreg_t fbcba_bad_check_bit : 8; - } pi_force_bad_check_bit_a_fld_s; -} pi_force_bad_check_bit_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If any bit in this * - * register is set, then whenever reply data arrives with the UE * - * (uncorrectable error) indication set, the check-bits that are * - * generated and sent to the SysAD will be inverted corresponding to * - * the bits set in the register. This will also prevent the assertion * - * of the data quality indicator. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_force_bad_check_bit_b_u { - bdrkreg_t pi_force_bad_check_bit_b_regval; - struct { - bdrkreg_t fbcbb_bad_check_bit : 8; - bdrkreg_t fbcbb_rsvd : 56; - } pi_force_bad_check_bit_b_fld_s; -} pi_force_bad_check_bit_b_u_t; - -#else - -typedef union pi_force_bad_check_bit_b_u { - bdrkreg_t pi_force_bad_check_bit_b_regval; - struct { - bdrkreg_t fbcbb_rsvd : 56; - bdrkreg_t fbcbb_bad_check_bit : 8; - } pi_force_bad_check_bit_b_fld_s; -} pi_force_bad_check_bit_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When a counter is * - * enabled, it increments each time a DNACK reply is received. The * - * counter is cleared when any other reply is received. The register * - * is cleared when the CNT_EN bit is zero. If a DNACK reply is * - * received when the counter equals the value in the NACK_CMP * - * register, the counter is cleared, an error response is sent to the * - * CPU instead of a nack response, and the NACK_INT_A/B bit is set in * - * INT_PEND1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cnt_a_u { - bdrkreg_t pi_nack_cnt_a_regval; - struct { - bdrkreg_t nca_nack_cnt : 20; - bdrkreg_t nca_cnt_en : 1; - bdrkreg_t nca_rsvd : 43; - } pi_nack_cnt_a_fld_s; -} pi_nack_cnt_a_u_t; - -#else - -typedef union pi_nack_cnt_a_u { - bdrkreg_t pi_nack_cnt_a_regval; - struct { - bdrkreg_t nca_rsvd : 43; - bdrkreg_t nca_cnt_en : 1; - bdrkreg_t nca_nack_cnt : 20; - } pi_nack_cnt_a_fld_s; -} pi_nack_cnt_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When a counter is * - * enabled, it increments each time a DNACK reply is received. The * - * counter is cleared when any other reply is received. The register * - * is cleared when the CNT_EN bit is zero. If a DNACK reply is * - * received when the counter equals the value in the NACK_CMP * - * register, the counter is cleared, an error response is sent to the * - * CPU instead of a nack response, and the NACK_INT_A/B bit is set in * - * INT_PEND1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cnt_b_u { - bdrkreg_t pi_nack_cnt_b_regval; - struct { - bdrkreg_t ncb_nack_cnt : 20; - bdrkreg_t ncb_cnt_en : 1; - bdrkreg_t ncb_rsvd : 43; - } pi_nack_cnt_b_fld_s; -} pi_nack_cnt_b_u_t; - -#else - -typedef union pi_nack_cnt_b_u { - bdrkreg_t pi_nack_cnt_b_regval; - struct { - bdrkreg_t ncb_rsvd : 43; - bdrkreg_t ncb_cnt_en : 1; - bdrkreg_t ncb_nack_cnt : 20; - } pi_nack_cnt_b_fld_s; -} pi_nack_cnt_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * The setting of this register affects both CPUs on this PI. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cmp_u { - bdrkreg_t pi_nack_cmp_regval; - struct { - bdrkreg_t nc_nack_cmp : 20; - bdrkreg_t nc_rsvd : 44; - } pi_nack_cmp_fld_s; -} pi_nack_cmp_u_t; - -#else - -typedef union pi_nack_cmp_u { - bdrkreg_t pi_nack_cmp_regval; - struct { - bdrkreg_t nc_rsvd : 44; - bdrkreg_t nc_nack_cmp : 20; - } pi_nack_cmp_fld_s; -} pi_nack_cmp_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls which errors are spooled. When a bit in * - * this register is set, the corresponding error is spooled. The * - * setting of this register affects both CPUs on this PI. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_mask_u { - bdrkreg_t pi_spool_mask_regval; - struct { - bdrkreg_t sm_access_err : 1; - bdrkreg_t sm_uncached_err : 1; - bdrkreg_t sm_dir_err : 1; - bdrkreg_t sm_timeout_err : 1; - bdrkreg_t sm_poison_err : 1; - bdrkreg_t sm_nack_oflow_err : 1; - bdrkreg_t sm_rsvd : 58; - } pi_spool_mask_fld_s; -} pi_spool_mask_u_t; - -#else - -typedef union pi_spool_mask_u { - bdrkreg_t pi_spool_mask_regval; - struct { - bdrkreg_t sm_rsvd : 58; - bdrkreg_t sm_nack_oflow_err : 1; - bdrkreg_t sm_poison_err : 1; - bdrkreg_t sm_timeout_err : 1; - bdrkreg_t sm_dir_err : 1; - bdrkreg_t sm_uncached_err : 1; - bdrkreg_t sm_access_err : 1; - } pi_spool_mask_fld_s; -} pi_spool_mask_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. When the VALID bit is * - * zero, this register (along with SPURIOUS_HDR_1) will capture the * - * header of an incoming spurious message received from the XBar. A * - * spurious message is a message that does not match up with any of * - * the CRB entries. This is a read/write register, so it is cleared * - * by writing of all zeros. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spurious_hdr_0_u { - bdrkreg_t pi_spurious_hdr_0_regval; - struct { - bdrkreg_t sh0_prev_valid_b : 1; - bdrkreg_t sh0_prev_valid_a : 1; - bdrkreg_t sh0_rsvd : 4; - bdrkreg_t sh0_supplemental : 11; - bdrkreg_t sh0_cmd : 8; - bdrkreg_t sh0_addr : 37; - bdrkreg_t sh0_tail : 1; - bdrkreg_t sh0_valid : 1; - } pi_spurious_hdr_0_fld_s; -} pi_spurious_hdr_0_u_t; - -#else - -typedef union pi_spurious_hdr_0_u { - bdrkreg_t pi_spurious_hdr_0_regval; - struct { - bdrkreg_t sh0_valid : 1; - bdrkreg_t sh0_tail : 1; - bdrkreg_t sh0_addr : 37; - bdrkreg_t sh0_cmd : 8; - bdrkreg_t sh0_supplemental : 11; - bdrkreg_t sh0_rsvd : 4; - bdrkreg_t sh0_prev_valid_a : 1; - bdrkreg_t sh0_prev_valid_b : 1; - } pi_spurious_hdr_0_fld_s; -} pi_spurious_hdr_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. When the VALID bit in * - * SPURIOUS_HDR_0 is zero, this register (along with SPURIOUS_HDR_0) * - * will capture the header of an incoming spurious message received * - * from the XBar. A spurious message is a message that does not match * - * up with any of the CRB entries. This is a read/write register, so * - * it is cleared by writing of all zeros. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spurious_hdr_1_u { - bdrkreg_t pi_spurious_hdr_1_regval; - struct { - bdrkreg_t sh1_rsvd : 53; - bdrkreg_t sh1_source : 11; - } pi_spurious_hdr_1_fld_s; -} pi_spurious_hdr_1_u_t; - -#else - -typedef union pi_spurious_hdr_1_u { - bdrkreg_t pi_spurious_hdr_1_regval; - struct { - bdrkreg_t sh1_source : 11; - bdrkreg_t sh1_rsvd : 53; - } pi_spurious_hdr_1_fld_s; -} pi_spurious_hdr_1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register controls the injection of errors in * - * outbound SysAD transfers. When a write sets a bit in this * - * register, the PI logic is "armed" to inject that error. At the * - * first transfer of the specified type, the error is injected and * - * the bit in this register is cleared. Writing to this register does * - * not cause a transaction to occur. A bit in this register will * - * remain set until a transaction of the specified type occurs as a * - * result of normal system activity. This register can be polled to * - * determine if an error has been injected or is still "armed". * - * This register does not control injection of data quality bad * - * indicator on a data cycle. This type of error can be created by * - * reading from a memory location that has an uncorrectable ECC * - * error. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_inject_u { - bdrkreg_t pi_err_inject_regval; - struct { - bdrkreg_t ei_cmd_syscmd_par_a : 1; - bdrkreg_t ei_data_syscmd_par_a : 1; - bdrkreg_t ei_cmd_sysad_corecc_a : 1; - bdrkreg_t ei_data_sysad_corecc_a : 1; - bdrkreg_t ei_cmd_sysad_uncecc_a : 1; - bdrkreg_t ei_data_sysad_uncecc_a : 1; - bdrkreg_t ei_sysresp_par_a : 1; - bdrkreg_t ei_reserved_1 : 25; - bdrkreg_t ei_cmd_syscmd_par_b : 1; - bdrkreg_t ei_data_syscmd_par_b : 1; - bdrkreg_t ei_cmd_sysad_corecc_b : 1; - bdrkreg_t ei_data_sysad_corecc_b : 1; - bdrkreg_t ei_cmd_sysad_uncecc_b : 1; - bdrkreg_t ei_data_sysad_uncecc_b : 1; - bdrkreg_t ei_sysresp_par_b : 1; - bdrkreg_t ei_reserved : 25; - } pi_err_inject_fld_s; -} pi_err_inject_u_t; - -#else - -typedef union pi_err_inject_u { - bdrkreg_t pi_err_inject_regval; - struct { - bdrkreg_t ei_reserved : 25; - bdrkreg_t ei_sysresp_par_b : 1; - bdrkreg_t ei_data_sysad_uncecc_b : 1; - bdrkreg_t ei_cmd_sysad_uncecc_b : 1; - bdrkreg_t ei_data_sysad_corecc_b : 1; - bdrkreg_t ei_cmd_sysad_corecc_b : 1; - bdrkreg_t ei_data_syscmd_par_b : 1; - bdrkreg_t ei_cmd_syscmd_par_b : 1; - bdrkreg_t ei_reserved_1 : 25; - bdrkreg_t ei_sysresp_par_a : 1; - bdrkreg_t ei_data_sysad_uncecc_a : 1; - bdrkreg_t ei_cmd_sysad_uncecc_a : 1; - bdrkreg_t ei_data_sysad_corecc_a : 1; - bdrkreg_t ei_cmd_sysad_corecc_a : 1; - bdrkreg_t ei_data_syscmd_par_a : 1; - bdrkreg_t ei_cmd_syscmd_par_a : 1; - } pi_err_inject_fld_s; -} pi_err_inject_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines at what point the TRex+ is * - * stopped from issuing requests, based on the number of entries in * - * the incoming reply FIFO. When the number of entries in the Reply * - * FIFO is greater than the value of this register, the PI will * - * deassert both SysWrRdy and SysRdRdy to both processors. The Reply * - * FIFO has a depth of 0x3F entries, so setting this register to 0x3F * - * effectively disables this feature, allowing requests to be issued * - * always. Setting this register to 0x00 effectively lowers the * - * TRex+'s priority below the reply FIFO, disabling TRex+ requests * - * any time there is an entry waiting in the incoming FIFO.This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_reply_level_u { - bdrkreg_t pi_reply_level_regval; - struct { - bdrkreg_t rl_reply_level : 6; - bdrkreg_t rl_rsvd : 58; - } pi_reply_level_fld_s; -} pi_reply_level_u_t; - -#else - -typedef union pi_reply_level_u { - bdrkreg_t pi_reply_level_regval; - struct { - bdrkreg_t rl_rsvd : 58; - bdrkreg_t rl_reply_level : 6; - } pi_reply_level_fld_s; -} pi_reply_level_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is used to change the graphics credit counter * - * operation from "Doubleword" mode to "Transaction" mode. This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_mode_u { - bdrkreg_t pi_gfx_credit_mode_regval; - struct { - bdrkreg_t gcm_trans_mode : 1; - bdrkreg_t gcm_rsvd : 63; - } pi_gfx_credit_mode_fld_s; -} pi_gfx_credit_mode_u_t; - -#else - -typedef union pi_gfx_credit_mode_u { - bdrkreg_t pi_gfx_credit_mode_regval; - struct { - bdrkreg_t gcm_rsvd : 63; - bdrkreg_t gcm_trans_mode : 1; - } pi_gfx_credit_mode_fld_s; -} pi_gfx_credit_mode_u_t; - -#endif - - - -/************************************************************************ - * * - * This location contains a 55-bit read/write counter that wraps to * - * zero when the maximum value is reached. This counter is * - * incremented at each rising edge of the global clock (GCLK). This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_counter_u { - bdrkreg_t pi_rt_counter_regval; - struct { - bdrkreg_t rc_count : 55; - bdrkreg_t rc_rsvd : 9; - } pi_rt_counter_fld_s; -} pi_rt_counter_u_t; - -#else - -typedef union pi_rt_counter_u { - bdrkreg_t pi_rt_counter_regval; - struct { - bdrkreg_t rc_rsvd : 9; - bdrkreg_t rc_count : 55; - } pi_rt_counter_fld_s; -} pi_rt_counter_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls the performance counters for one CPU. * - * There are two counters for each CPU. Each counter can be * - * configured to count a variety of events. The performance counter * - * registers for each processor are in their own 64KB page so that * - * they can be mapped to user space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntl_a_u { - bdrkreg_t pi_perf_cntl_a_regval; - struct { - bdrkreg_t pca_cntr_0_select : 28; - bdrkreg_t pca_cntr_0_mode : 3; - bdrkreg_t pca_cntr_0_enable : 1; - bdrkreg_t pca_cntr_1_select : 28; - bdrkreg_t pca_cntr_1_mode : 3; - bdrkreg_t pca_cntr_1_enable : 1; - } pi_perf_cntl_a_fld_s; -} pi_perf_cntl_a_u_t; - -#else - -typedef union pi_perf_cntl_a_u { - bdrkreg_t pi_perf_cntl_a_regval; - struct { - bdrkreg_t pca_cntr_1_enable : 1; - bdrkreg_t pca_cntr_1_mode : 3; - bdrkreg_t pca_cntr_1_select : 28; - bdrkreg_t pca_cntr_0_enable : 1; - bdrkreg_t pca_cntr_0_mode : 3; - bdrkreg_t pca_cntr_0_select : 28; - } pi_perf_cntl_a_fld_s; -} pi_perf_cntl_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 0 for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr0_a_u { - bdrkreg_t pi_perf_cntr0_a_regval; - struct { - bdrkreg_t pca_count_value : 40; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_rsvd : 23; - } pi_perf_cntr0_a_fld_s; -} pi_perf_cntr0_a_u_t; - -#else - -typedef union pi_perf_cntr0_a_u { - bdrkreg_t pi_perf_cntr0_a_regval; - struct { - bdrkreg_t pca_rsvd : 23; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_count_value : 40; - } pi_perf_cntr0_a_fld_s; -} pi_perf_cntr0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 1for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr1_a_u { - bdrkreg_t pi_perf_cntr1_a_regval; - struct { - bdrkreg_t pca_count_value : 40; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_rsvd : 23; - } pi_perf_cntr1_a_fld_s; -} pi_perf_cntr1_a_u_t; - -#else - -typedef union pi_perf_cntr1_a_u { - bdrkreg_t pi_perf_cntr1_a_regval; - struct { - bdrkreg_t pca_rsvd : 23; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_count_value : 40; - } pi_perf_cntr1_a_fld_s; -} pi_perf_cntr1_a_u_t; - -#endif - - - - - -/************************************************************************ - * * - * This register controls the performance counters for one CPU. * - * There are two counters for each CPU. Each counter can be * - * configured to count a variety of events. The performance counter * - * registers for each processor are in their own 64KB page so that * - * they can be mapped to user space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntl_b_u { - bdrkreg_t pi_perf_cntl_b_regval; - struct { - bdrkreg_t pcb_cntr_0_select : 28; - bdrkreg_t pcb_cntr_0_mode : 3; - bdrkreg_t pcb_cntr_0_enable : 1; - bdrkreg_t pcb_cntr_1_select : 28; - bdrkreg_t pcb_cntr_1_mode : 3; - bdrkreg_t pcb_cntr_1_enable : 1; - } pi_perf_cntl_b_fld_s; -} pi_perf_cntl_b_u_t; - -#else - -typedef union pi_perf_cntl_b_u { - bdrkreg_t pi_perf_cntl_b_regval; - struct { - bdrkreg_t pcb_cntr_1_enable : 1; - bdrkreg_t pcb_cntr_1_mode : 3; - bdrkreg_t pcb_cntr_1_select : 28; - bdrkreg_t pcb_cntr_0_enable : 1; - bdrkreg_t pcb_cntr_0_mode : 3; - bdrkreg_t pcb_cntr_0_select : 28; - } pi_perf_cntl_b_fld_s; -} pi_perf_cntl_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 0 for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr0_b_u { - bdrkreg_t pi_perf_cntr0_b_regval; - struct { - bdrkreg_t pcb_count_value : 40; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_rsvd : 23; - } pi_perf_cntr0_b_fld_s; -} pi_perf_cntr0_b_u_t; - -#else - -typedef union pi_perf_cntr0_b_u { - bdrkreg_t pi_perf_cntr0_b_regval; - struct { - bdrkreg_t pcb_rsvd : 23; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_count_value : 40; - } pi_perf_cntr0_b_fld_s; -} pi_perf_cntr0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 1for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr1_b_u { - bdrkreg_t pi_perf_cntr1_b_regval; - struct { - bdrkreg_t pcb_count_value : 40; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_rsvd : 23; - } pi_perf_cntr1_b_fld_s; -} pi_perf_cntr1_b_u_t; - -#else - -typedef union pi_perf_cntr1_b_u { - bdrkreg_t pi_perf_cntr1_b_regval; - struct { - bdrkreg_t pcb_rsvd : 23; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_count_value : 40; - } pi_perf_cntr1_b_fld_s; -} pi_perf_cntr1_b_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - -#define PI_GFX_OFFSET (PI_GFX_PAGE_B - PI_GFX_PAGE_A) -#define PI_GFX_PAGE_ENABLE 0x0000010000000000LL - - -#endif /* _ASM_IA64_SN_SN1_HUBPI_H */ diff --git a/include/asm-ia64/sn/sn1/hubpi_next.h b/include/asm-ia64/sn/sn1/hubpi_next.h deleted file mode 100644 index a4ea9f3277b..00000000000 --- a/include/asm-ia64/sn/sn1/hubpi_next.h +++ /dev/null @@ -1,331 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBPI_NEXT_H -#define _ASM_IA64_SN_SN1_HUBPI_NEXT_H - - -/* define for remote PI_1 space. It is always half of a node_addressspace - * from PI_0. The normal REMOTE_HUB space for PI registers access - * the PI_0 space, unless they are qualified by PI_1. - */ -#define PI_0(x) (x) -#define PI_1(x) ((x) + 0x200000) -#define PIREG(x,sn) ((sn) ? PI_1(x) : PI_0(x)) - -#define PI_MIN_STACK_SIZE 4096 /* For figuring out the size to set */ -#define PI_STACK_SIZE_SHFT 12 /* 4k */ - -#define PI_STACKADDR_OFFSET (PI_ERR_STACK_ADDR_B - PI_ERR_STACK_ADDR_A) -#define PI_ERRSTAT_OFFSET (PI_ERR_STATUS0_B - PI_ERR_STATUS0_A) -#define PI_RDCLR_OFFSET (PI_ERR_STATUS0_A_RCLR - PI_ERR_STATUS0_A) -/* these macros are correct, but fix their users to understand two PIs - and 4 CPUs (slices) per bedrock */ -#define PI_INT_MASK_OFFSET (PI_INT_MASK0_B - PI_INT_MASK0_A) -#define PI_INT_SET_OFFSET (PI_CC_PEND_CLR_B - PI_CC_PEND_CLR_A) -#define PI_NMI_OFFSET (PI_NMI_B - PI_NMI_A) - -#define ERR_STACK_SIZE_BYTES(_sz) \ - ((_sz) ? (PI_MIN_STACK_SIZE << ((_sz) - 1)) : 0) - -#define PI_CRB_STS_P (1 << 9) /* "P" (partial word read/write) bit */ -#define PI_CRB_STS_V (1 << 8) /* "V" (valid) bit */ -#define PI_CRB_STS_R (1 << 7) /* "R" (response data sent to CPU) */ -#define PI_CRB_STS_A (1 << 6) /* "A" (data ack. received) bit */ -#define PI_CRB_STS_W (1 << 5) /* "W" (waiting for write compl.) */ -#define PI_CRB_STS_H (1 << 4) /* "H" (gathering invalidates) bit */ -#define PI_CRB_STS_I (1 << 3) /* "I" (targ. inbound invalidate) */ -#define PI_CRB_STS_T (1 << 2) /* "T" (targ. inbound intervention) */ -#define PI_CRB_STS_E (0x3) /* "E" (coherent read type) */ - -/* When the "P" bit is set in the sk_crb_sts field of an error stack - * entry, the "R," "A," "H," and "I" bits are actually bits 6..3 of - * the address. This macro extracts those address bits and shifts - * them to their proper positions, ready to be ORed in to the rest of - * the address (which is calculated as sk_addr << 7). - */ -#define PI_CRB_STS_ADDR_BITS(sts) \ - ((sts) & (PI_CRB_STS_I | PI_CRB_STS_H) | \ - ((sts) & (PI_CRB_STS_A | PI_CRB_STS_R)) >> 1) - -#ifndef __ASSEMBLY__ -/* - * format of error stack and error status registers. - */ - -#ifdef LITTLE_ENDIAN - -struct err_stack_format { - uint64_t sk_err_type: 3, /* error type */ - sk_suppl : 3, /* lowest 3 bit of supplemental */ - sk_t5_req : 3, /* RRB T5 request number */ - sk_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - sk_rw_rb : 1, /* RRB == 0, WRB == 1 */ - sk_crb_sts : 10, /* status from RRB or WRB */ - sk_cmd : 8, /* message command */ - sk_addr : 33; /* address */ -}; - -#else - -struct err_stack_format { - uint64_t sk_addr : 33, /* address */ - sk_cmd : 8, /* message command */ - sk_crb_sts : 10, /* status from RRB or WRB */ - sk_rw_rb : 1, /* RRB == 0, WRB == 1 */ - sk_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - sk_t5_req : 3, /* RRB T5 request number */ - sk_suppl : 3, /* lowest 3 bit of supplemental */ - sk_err_type: 3; /* error type */ -}; - -#endif - -typedef union pi_err_stack { - uint64_t pi_stk_word; - struct err_stack_format pi_stk_fmt; -} pi_err_stack_t; - -/* Simplified version of pi_err_status0_a_u_t (PI_ERR_STATUS0_A) */ -#ifdef LITTLE_ENDIAN - -struct err_status0_format { - uint64_t s0_err_type : 3, /* Encoded error cause */ - s0_proc_req_num : 3, /* Request number for RRB only */ - s0_supplemental : 11, /* ncoming message sup field */ - s0_cmd : 8, /* Incoming message command */ - s0_addr : 37, /* Address */ - s0_over_run : 1, /* Subsequent errors spooled */ - s0_valid : 1; /* error is valid */ -}; - -#else - -struct err_status0_format { - uint64_t s0_valid : 1, /* error is valid */ - s0_over_run : 1, /* Subsequent errors spooled */ - s0_addr : 37, /* Address */ - s0_cmd : 8, /* Incoming message command */ - s0_supplemental : 11, /* ncoming message sup field */ - s0_proc_req_num : 3, /* Request number for RRB only */ - s0_err_type : 3; /* Encoded error cause */ -}; - -#endif - - -typedef union pi_err_stat0 { - uint64_t pi_stat0_word; - struct err_status0_format pi_stat0_fmt; -} pi_err_stat0_t; - -/* Simplified version of pi_err_status1_a_u_t (PI_ERR_STATUS1_A) */ - -#ifdef LITTLE_ENDIAN - -struct err_status1_format { - uint64_t s1_spl_cnt : 21, /* number spooled to memory */ - s1_to_cnt : 8, /* crb timeout counter */ - s1_inval_cnt:10, /* signed invalidate counter RRB */ - s1_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - s1_rw_rb : 1, /* RRB == 0, WRB == 1 */ - s1_crb_sts : 10, /* status from RRB or WRB */ - s1_src : 11; /* message source */ -}; - -#else - -struct err_status1_format { - uint64_t s1_src : 11, /* message source */ - s1_crb_sts : 10, /* status from RRB or WRB */ - s1_rw_rb : 1, /* RRB == 0, WRB == 1 */ - s1_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - s1_inval_cnt:10, /* signed invalidate counter RRB */ - s1_to_cnt : 8, /* crb timeout counter */ - s1_spl_cnt : 21; /* number spooled to memory */ -}; - -#endif - -typedef union pi_err_stat1 { - uint64_t pi_stat1_word; - struct err_status1_format pi_stat1_fmt; -} pi_err_stat1_t; -#endif - -/* Error stack types (sk_err_type) for reads: */ -#define PI_ERR_RD_AERR 0 /* Read Access Error */ -#define PI_ERR_RD_PRERR 1 /* Uncached Partitial Read */ -#define PI_ERR_RD_DERR 2 /* Directory Error */ -#define PI_ERR_RD_TERR 3 /* read timeout */ -#define PI_ERR_RD_PERR 4 /* Poison Access Violation */ -#define PI_ERR_RD_NACK 5 /* Excessive NACKs */ -#define PI_ERR_RD_RDE 6 /* Response Data Error */ -#define PI_ERR_RD_PLERR 7 /* Packet Length Error */ -/* Error stack types (sk_err_type) for writes: */ -#define PI_ERR_WR_WERR 0 /* Write Access Error */ -#define PI_ERR_WR_PWERR 1 /* Uncached Write Error */ -#define PI_ERR_WR_TERR 3 /* write timeout */ -#define PI_ERR_WR_RDE 6 /* Response Data Error */ -#define PI_ERR_WR_PLERR 7 /* Packet Length Error */ - - -/* For backwards compatibility */ -#define PI_RT_COUNT PI_RT_COUNTER /* Real Time Counter */ -#define PI_RT_EN_A PI_RT_INT_EN_A /* RT int for CPU A enable */ -#define PI_RT_EN_B PI_RT_INT_EN_B /* RT int for CPU B enable */ -#define PI_PROF_EN_A PI_PROF_INT_EN_A /* PROF int for CPU A enable */ -#define PI_PROF_EN_B PI_PROF_INT_EN_B /* PROF int for CPU B enable */ -#define PI_RT_PEND_A PI_RT_INT_PEND_A /* RT interrupt pending */ -#define PI_RT_PEND_B PI_RT_INT_PEND_B /* RT interrupt pending */ -#define PI_PROF_PEND_A PI_PROF_INT_PEND_A /* Profiling interrupt pending */ -#define PI_PROF_PEND_B PI_PROF_INT_PEND_B /* Profiling interrupt pending */ - - -/* Bits in PI_SYSAD_ERRCHK_EN */ -#define PI_SYSAD_ERRCHK_ECCGEN 0x01 /* Enable ECC generation */ -#define PI_SYSAD_ERRCHK_QUALGEN 0x02 /* Enable data quality signal gen. */ -#define PI_SYSAD_ERRCHK_SADP 0x04 /* Enable SysAD parity checking */ -#define PI_SYSAD_ERRCHK_CMDP 0x08 /* Enable SysCmd parity checking */ -#define PI_SYSAD_ERRCHK_STATE 0x10 /* Enable SysState parity checking */ -#define PI_SYSAD_ERRCHK_QUAL 0x20 /* Enable data quality checking */ -#define PI_SYSAD_CHECK_ALL 0x3f /* Generate and check all signals. */ - -/* CALIAS values */ -#define PI_CALIAS_SIZE_0 0 -#define PI_CALIAS_SIZE_4K 1 -#define PI_CALIAS_SIZE_8K 2 -#define PI_CALIAS_SIZE_16K 3 -#define PI_CALIAS_SIZE_32K 4 -#define PI_CALIAS_SIZE_64K 5 -#define PI_CALIAS_SIZE_128K 6 -#define PI_CALIAS_SIZE_256K 7 -#define PI_CALIAS_SIZE_512K 8 -#define PI_CALIAS_SIZE_1M 9 -#define PI_CALIAS_SIZE_2M 10 -#define PI_CALIAS_SIZE_4M 11 -#define PI_CALIAS_SIZE_8M 12 -#define PI_CALIAS_SIZE_16M 13 -#define PI_CALIAS_SIZE_32M 14 -#define PI_CALIAS_SIZE_64M 15 - -/* Fields in PI_ERR_STATUS0_[AB] */ -#define PI_ERR_ST0_VALID_MASK 0x8000000000000000 -#define PI_ERR_ST0_VALID_SHFT 63 - -/* Fields in PI_SPURIOUS_HDR_0 */ -#define PI_SPURIOUS_HDR_VALID_MASK 0x8000000000000000 -#define PI_SPURIOUS_HDR_VALID_SHFT 63 - -/* Fields in PI_NACK_CNT_A/B */ -#define PI_NACK_CNT_EN_SHFT 20 -#define PI_NACK_CNT_EN_MASK 0x100000 -#define PI_NACK_CNT_MASK 0x0fffff -#define PI_NACK_CNT_MAX 0x0fffff - -/* Bits in PI_ERR_INT_PEND */ -#define PI_ERR_SPOOL_CMP_B 0x000000001 /* Spool end hit high water */ -#define PI_ERR_SPOOL_CMP_A 0x000000002 -#define PI_ERR_SPUR_MSG_B 0x000000004 /* Spurious message intr. */ -#define PI_ERR_SPUR_MSG_A 0x000000008 -#define PI_ERR_WRB_TERR_B 0x000000010 /* WRB TERR */ -#define PI_ERR_WRB_TERR_A 0x000000020 -#define PI_ERR_WRB_WERR_B 0x000000040 /* WRB WERR */ -#define PI_ERR_WRB_WERR_A 0x000000080 -#define PI_ERR_SYSSTATE_B 0x000000100 /* SysState parity error */ -#define PI_ERR_SYSSTATE_A 0x000000200 -#define PI_ERR_SYSAD_DATA_B 0x000000400 /* SysAD data parity error */ -#define PI_ERR_SYSAD_DATA_A 0x000000800 -#define PI_ERR_SYSAD_ADDR_B 0x000001000 /* SysAD addr parity error */ -#define PI_ERR_SYSAD_ADDR_A 0x000002000 -#define PI_ERR_SYSCMD_DATA_B 0x000004000 /* SysCmd data parity error */ -#define PI_ERR_SYSCMD_DATA_A 0x000008000 -#define PI_ERR_SYSCMD_ADDR_B 0x000010000 /* SysCmd addr parity error */ -#define PI_ERR_SYSCMD_ADDR_A 0x000020000 -#define PI_ERR_BAD_SPOOL_B 0x000040000 /* Error spooling to memory */ -#define PI_ERR_BAD_SPOOL_A 0x000080000 -#define PI_ERR_UNCAC_UNCORR_B 0x000100000 /* Uncached uncorrectable */ -#define PI_ERR_UNCAC_UNCORR_A 0x000200000 -#define PI_ERR_SYSSTATE_TAG_B 0x000400000 /* SysState tag parity error */ -#define PI_ERR_SYSSTATE_TAG_A 0x000800000 -#define PI_ERR_MD_UNCORR 0x001000000 /* Must be cleared in MD */ -#define PI_ERR_SYSAD_BAD_DATA_B 0x002000000 /* SysAD Data quality bad */ -#define PI_ERR_SYSAD_BAD_DATA_A 0x004000000 -#define PI_ERR_UE_CACHED_B 0x008000000 /* UE during cached load */ -#define PI_ERR_UE_CACHED_A 0x010000000 -#define PI_ERR_PKT_LEN_ERR_B 0x020000000 /* Xbar data too long/short */ -#define PI_ERR_PKT_LEN_ERR_A 0x040000000 -#define PI_ERR_IRB_ERR_B 0x080000000 /* Protocol error */ -#define PI_ERR_IRB_ERR_A 0x100000000 -#define PI_ERR_IRB_TIMEOUT_B 0x200000000 /* IRB_B got a timeout */ -#define PI_ERR_IRB_TIMEOUT_A 0x400000000 - -#define PI_ERR_CLEAR_ALL_A 0x554aaaaaa -#define PI_ERR_CLEAR_ALL_B 0x2aa555555 - - -/* - * The following three macros define all possible error int pends. - */ - -#define PI_FATAL_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ - PI_ERR_IRB_ERR_A | \ - PI_ERR_PKT_LEN_ERR_A | \ - PI_ERR_SYSSTATE_TAG_A | \ - PI_ERR_BAD_SPOOL_A | \ - PI_ERR_SYSCMD_ADDR_A | \ - PI_ERR_SYSCMD_DATA_A | \ - PI_ERR_SYSAD_ADDR_A | \ - PI_ERR_SYSAD_DATA_A | \ - PI_ERR_SYSSTATE_A) - -#define PI_MISC_ERR_CPU_A (PI_ERR_UE_CACHED_A | \ - PI_ERR_SYSAD_BAD_DATA_A| \ - PI_ERR_UNCAC_UNCORR_A | \ - PI_ERR_WRB_WERR_A | \ - PI_ERR_WRB_TERR_A | \ - PI_ERR_SPUR_MSG_A | \ - PI_ERR_SPOOL_CMP_A) - -#define PI_FATAL_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ - PI_ERR_IRB_ERR_B | \ - PI_ERR_PKT_LEN_ERR_B | \ - PI_ERR_SYSSTATE_TAG_B | \ - PI_ERR_BAD_SPOOL_B | \ - PI_ERR_SYSCMD_ADDR_B | \ - PI_ERR_SYSCMD_DATA_B | \ - PI_ERR_SYSAD_ADDR_B | \ - PI_ERR_SYSAD_DATA_B | \ - PI_ERR_SYSSTATE_B) - -#define PI_MISC_ERR_CPU_B (PI_ERR_UE_CACHED_B | \ - PI_ERR_SYSAD_BAD_DATA_B| \ - PI_ERR_UNCAC_UNCORR_B | \ - PI_ERR_WRB_WERR_B | \ - PI_ERR_WRB_TERR_B | \ - PI_ERR_SPUR_MSG_B | \ - PI_ERR_SPOOL_CMP_B) - -#define PI_ERR_GENERIC (PI_ERR_MD_UNCORR) - -/* Values for PI_MAX_CRB_TIMEOUT and PI_CRB_SFACTOR */ -#define PMCT_MAX 0xff -#define PCS_MAX 0xffffff - -/* pi_err_status0_a_u_t address shift */ -#define ERR_STAT0_ADDR_SHFT 3 - -/* PI error read/write bit (RRB == 0, WRB == 1) */ -/* pi_err_status1_a_u_t.pi_err_status1_a_fld_s.esa_wrb */ -#define PI_ERR_RRB 0 -#define PI_ERR_WRB 1 - -/* Error stack address shift, for use with pi_stk_fmt.sk_addr */ -#define ERR_STK_ADDR_SHFT 3 - -#endif /* _ASM_IA64_SN_SN1_HUBPI_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hubspc.h b/include/asm-ia64/sn/sn1/hubspc.h deleted file mode 100644 index c0af0b6de55..00000000000 --- a/include/asm-ia64/sn/sn1/hubspc.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBSPC_H -#define _ASM_IA64_SN_SN1_HUBSPC_H - -typedef enum { - HUBSPC_REFCOUNTERS, - HUBSPC_PROM -} hubspc_subdevice_t; - - -/* - * Reference Counters - */ - -extern int refcounters_attach(devfs_handle_t hub); - -#endif /* _ASM_IA64_SN_SN1_HUBSPC_H */ diff --git a/include/asm-ia64/sn/sn1/hubstat.h b/include/asm-ia64/sn/sn1/hubstat.h deleted file mode 100644 index ddf3626243d..00000000000 --- a/include/asm-ia64/sn/sn1/hubstat.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 - 2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_HUBSTAT_H -#define _ASM_IA64_SN_SN1_HUBSTAT_H - -typedef int64_t hub_count_t; - -#define HUBSTAT_VERSION 1 - -typedef struct hubstat_s { - char hs_version; /* structure version */ - cnodeid_t hs_cnode; /* cnode of this hub */ - nasid_t hs_nasid; /* Nasid of same */ - int64_t hs_timebase; /* Time of first sample */ - int64_t hs_timestamp; /* Time of last sample */ - int64_t hs_per_minute; /* Ticks per minute */ - - union { - hubreg_t hs_niu_stat_rev_id; /* SN0: Status rev ID */ - hubreg_t hs_niu_port_status; /* SN1: Port status */ - } hs_niu; - - hub_count_t hs_ni_retry_errors; /* Total retry errors */ - hub_count_t hs_ni_sn_errors; /* Total sn errors */ - hub_count_t hs_ni_cb_errors; /* Total cb errors */ - int hs_ni_overflows; /* NI count overflows */ - hub_count_t hs_ii_sn_errors; /* Total sn errors */ - hub_count_t hs_ii_cb_errors; /* Total cb errors */ - int hs_ii_overflows; /* II count overflows */ - - /* - * Anything below this comment is intended for kernel internal-use - * only and may be changed at any time. - * - * Any members that contain pointers or are conditionally compiled - * need to be below here also. - */ - int64_t hs_last_print; /* When we last printed */ - char hs_print; /* Should we print */ - - char *hs_name; /* This hub's name */ - unsigned char hs_maint; /* Should we print to availmon */ -} hubstat_t; - -#define hs_ni_stat_rev_id hs_niu.hs_niu_stat_rev_id -#define hs_ni_port_status hs_niu.hs_niu_port_status - -extern struct file_operations hub_mon_fops; - -#endif /* _ASM_IA64_SN_SN1_HUBSTAT_H */ diff --git a/include/asm-ia64/sn/sn1/hubxb.h b/include/asm-ia64/sn/sn1/hubxb.h deleted file mode 100644 index 8a9ee36ae31..00000000000 --- a/include/asm-ia64/sn/sn1/hubxb.h +++ /dev/null @@ -1,1288 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBXB_H -#define _ASM_IA64_SN_SN1_HUBXB_H - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define XB_PARMS 0x00700000 /* - * Controls - * crossbar-wide - * parameters. - */ - - - -#define XB_SLOW_GNT 0x00700008 /* - * Controls wavefront - * arbiter grant - * frequency, used to - * slow XB grants - */ - - - -#define XB_SPEW_CONTROL 0x00700010 /* - * Controls spew - * settings (debug - * only). - */ - - - -#define XB_IOQ_ARB_TRIGGER 0x00700018 /* - * Controls IOQ - * trigger level - */ - - - -#define XB_FIRST_ERROR 0x00700090 /* - * Records the first - * crossbar error - * seen. - */ - - - -#define XB_POQ0_ERROR 0x00700020 /* - * POQ0 error - * register. - */ - - - -#define XB_PIQ0_ERROR 0x00700028 /* - * PIQ0 error - * register. - */ - - - -#define XB_POQ1_ERROR 0x00700030 /* - * POQ1 error - * register. - */ - - - -#define XB_PIQ1_ERROR 0x00700038 /* - * PIQ1 error - * register. - */ - - - -#define XB_MP0_ERROR 0x00700040 /* - * MOQ for PI0 error - * register. - */ - - - -#define XB_MP1_ERROR 0x00700048 /* - * MOQ for PI1 error - * register. - */ - - - -#define XB_MMQ_ERROR 0x00700050 /* - * MOQ for misc. (LB, - * NI, II) error - * register. - */ - - - -#define XB_MIQ_ERROR 0x00700058 /* - * MIQ error register, - * addtional MIQ - * errors are logged - * in MD "Input - * Error - * Registers". - */ - - - -#define XB_NOQ_ERROR 0x00700060 /* NOQ error register. */ - - - -#define XB_NIQ_ERROR 0x00700068 /* NIQ error register. */ - - - -#define XB_IOQ_ERROR 0x00700070 /* IOQ error register. */ - - - -#define XB_IIQ_ERROR 0x00700078 /* IIQ error register. */ - - - -#define XB_LOQ_ERROR 0x00700080 /* LOQ error register. */ - - - -#define XB_LIQ_ERROR 0x00700088 /* LIQ error register. */ - - - -#define XB_DEBUG_DATA_CTL 0x00700098 /* - * Debug Datapath - * Select - */ - - - -#define XB_DEBUG_ARB_CTL 0x007000A0 /* - * XB master debug - * control - */ - - - -#define XB_POQ0_ERROR_CLEAR 0x00700120 /* - * Clears - * XB_POQ0_ERROR - * register. - */ - - - -#define XB_PIQ0_ERROR_CLEAR 0x00700128 /* - * Clears - * XB_PIQ0_ERROR - * register. - */ - - - -#define XB_POQ1_ERROR_CLEAR 0x00700130 /* - * Clears - * XB_POQ1_ERROR - * register. - */ - - - -#define XB_PIQ1_ERROR_CLEAR 0x00700138 /* - * Clears - * XB_PIQ1_ERROR - * register. - */ - - - -#define XB_MP0_ERROR_CLEAR 0x00700140 /* - * Clears XB_MP0_ERROR - * register. - */ - - - -#define XB_MP1_ERROR_CLEAR 0x00700148 /* - * Clears XB_MP1_ERROR - * register. - */ - - - -#define XB_MMQ_ERROR_CLEAR 0x00700150 /* - * Clears XB_MMQ_ERROR - * register. - */ - - - -#define XB_XM_MIQ_ERROR_CLEAR 0x00700158 /* - * Clears XB_MIQ_ERROR - * register - */ - - - -#define XB_NOQ_ERROR_CLEAR 0x00700160 /* - * Clears XB_NOQ_ERROR - * register. - */ - - - -#define XB_NIQ_ERROR_CLEAR 0x00700168 /* - * Clears XB_NIQ_ERROR - * register. - */ - - - -#define XB_IOQ_ERROR_CLEAR 0x00700170 /* - * Clears XB_IOQ - * _ERROR register. - */ - - - -#define XB_IIQ_ERROR_CLEAR 0x00700178 /* - * Clears XB_IIQ - * _ERROR register. - */ - - - -#define XB_LOQ_ERROR_CLEAR 0x00700180 /* - * Clears XB_LOQ_ERROR - * register. - */ - - - -#define XB_LIQ_ERROR_CLEAR 0x00700188 /* - * Clears XB_LIQ_ERROR - * register. - */ - - - -#define XB_FIRST_ERROR_CLEAR 0x00700190 /* - * Clears - * XB_FIRST_ERROR - * register - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Access to parameters which control various aspects of the * - * crossbar's operation. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_parms_u { - bdrkreg_t xb_parms_regval; - struct { - bdrkreg_t p_byp_en : 1; - bdrkreg_t p_rsrvd_1 : 3; - bdrkreg_t p_age_wrap : 8; - bdrkreg_t p_deadlock_to_wrap : 20; - bdrkreg_t p_tail_to_wrap : 20; - bdrkreg_t p_rsrvd : 12; - } xb_parms_fld_s; -} xb_parms_u_t; - -#else - -typedef union xb_parms_u { - bdrkreg_t xb_parms_regval; - struct { - bdrkreg_t p_rsrvd : 12; - bdrkreg_t p_tail_to_wrap : 20; - bdrkreg_t p_deadlock_to_wrap : 20; - bdrkreg_t p_age_wrap : 8; - bdrkreg_t p_rsrvd_1 : 3; - bdrkreg_t p_byp_en : 1; - } xb_parms_fld_s; -} xb_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * Sets the period of wavefront grants given to each unit. The * - * register's value corresponds to the number of cycles between each * - * wavefront grant opportunity given to the requesting unit. If set * - * to 0xF, no grants are given to this unit. If set to 0xE, the unit * - * is granted at the slowest rate (sometimes called "molasses mode"). * - * This feature can be used to apply backpressure to a unit's output * - * queue(s). The setting does not affect bypass grants. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_slow_gnt_u { - bdrkreg_t xb_slow_gnt_regval; - struct { - bdrkreg_t sg_lb_slow_gnt : 4; - bdrkreg_t sg_ii_slow_gnt : 4; - bdrkreg_t sg_ni_slow_gnt : 4; - bdrkreg_t sg_mmq_slow_gnt : 4; - bdrkreg_t sg_mp1_slow_gnt : 4; - bdrkreg_t sg_mp0_slow_gnt : 4; - bdrkreg_t sg_pi1_slow_gnt : 4; - bdrkreg_t sg_pi0_slow_gnt : 4; - bdrkreg_t sg_rsrvd : 32; - } xb_slow_gnt_fld_s; -} xb_slow_gnt_u_t; - -#else - -typedef union xb_slow_gnt_u { - bdrkreg_t xb_slow_gnt_regval; - struct { - bdrkreg_t sg_rsrvd : 32; - bdrkreg_t sg_pi0_slow_gnt : 4; - bdrkreg_t sg_pi1_slow_gnt : 4; - bdrkreg_t sg_mp0_slow_gnt : 4; - bdrkreg_t sg_mp1_slow_gnt : 4; - bdrkreg_t sg_mmq_slow_gnt : 4; - bdrkreg_t sg_ni_slow_gnt : 4; - bdrkreg_t sg_ii_slow_gnt : 4; - bdrkreg_t sg_lb_slow_gnt : 4; - } xb_slow_gnt_fld_s; -} xb_slow_gnt_u_t; - -#endif - - - - -/************************************************************************ - * * - * Enables snooping of internal crossbar traffic by spewing all * - * traffic across a selected crossbar point to the PI1 port. Only one * - * bit should be set at any one time, and any bit set will preclude * - * using the P1 for anything but a debug connection. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_spew_control_u { - bdrkreg_t xb_spew_control_regval; - struct { - bdrkreg_t sc_snoop_liq : 1; - bdrkreg_t sc_snoop_iiq : 1; - bdrkreg_t sc_snoop_niq : 1; - bdrkreg_t sc_snoop_miq : 1; - bdrkreg_t sc_snoop_piq0 : 1; - bdrkreg_t sc_snoop_loq : 1; - bdrkreg_t sc_snoop_ioq : 1; - bdrkreg_t sc_snoop_noq : 1; - bdrkreg_t sc_snoop_mmq : 1; - bdrkreg_t sc_snoop_mp0 : 1; - bdrkreg_t sc_snoop_poq0 : 1; - bdrkreg_t sc_rsrvd : 53; - } xb_spew_control_fld_s; -} xb_spew_control_u_t; - -#else - -typedef union xb_spew_control_u { - bdrkreg_t xb_spew_control_regval; - struct { - bdrkreg_t sc_rsrvd : 53; - bdrkreg_t sc_snoop_poq0 : 1; - bdrkreg_t sc_snoop_mp0 : 1; - bdrkreg_t sc_snoop_mmq : 1; - bdrkreg_t sc_snoop_noq : 1; - bdrkreg_t sc_snoop_ioq : 1; - bdrkreg_t sc_snoop_loq : 1; - bdrkreg_t sc_snoop_piq0 : 1; - bdrkreg_t sc_snoop_miq : 1; - bdrkreg_t sc_snoop_niq : 1; - bdrkreg_t sc_snoop_iiq : 1; - bdrkreg_t sc_snoop_liq : 1; - } xb_spew_control_fld_s; -} xb_spew_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * Number of clocks the IOQ will wait before beginning XB * - * arbitration. This is set so that the slower IOQ data rate can * - * catch up up with the XB data rate in the IOQ buffer. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_ioq_arb_trigger_u { - bdrkreg_t xb_ioq_arb_trigger_regval; - struct { - bdrkreg_t iat_ioq_arb_trigger : 4; - bdrkreg_t iat_rsrvd : 60; - } xb_ioq_arb_trigger_fld_s; -} xb_ioq_arb_trigger_u_t; - -#else - -typedef union xb_ioq_arb_trigger_u { - bdrkreg_t xb_ioq_arb_trigger_regval; - struct { - bdrkreg_t iat_rsrvd : 60; - bdrkreg_t iat_ioq_arb_trigger : 4; - } xb_ioq_arb_trigger_fld_s; -} xb_ioq_arb_trigger_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by POQ0.Can be written to test software, will * - * cause an interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_poq0_error_u { - bdrkreg_t xb_poq0_error_regval; - struct { - bdrkreg_t pe_invalid_xsel : 2; - bdrkreg_t pe_rsrvd_3 : 2; - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_2 : 2; - bdrkreg_t pe_underflow : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_tail_timeout : 2; - bdrkreg_t pe_unused : 6; - bdrkreg_t pe_rsrvd : 44; - } xb_poq0_error_fld_s; -} xb_poq0_error_u_t; - -#else - -typedef union xb_poq0_error_u { - bdrkreg_t xb_poq0_error_regval; - struct { - bdrkreg_t pe_rsrvd : 44; - bdrkreg_t pe_unused : 6; - bdrkreg_t pe_tail_timeout : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_underflow : 2; - bdrkreg_t pe_rsrvd_2 : 2; - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_3 : 2; - bdrkreg_t pe_invalid_xsel : 2; - } xb_poq0_error_fld_s; -} xb_poq0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by PIQ0. Note that the PIQ/PI interface * - * precludes PIQ underflow. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_piq0_error_u { - bdrkreg_t xb_piq0_error_regval; - struct { - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_deadlock_timeout : 2; - bdrkreg_t pe_rsrvd : 58; - } xb_piq0_error_fld_s; -} xb_piq0_error_u_t; - -#else - -typedef union xb_piq0_error_u { - bdrkreg_t xb_piq0_error_regval; - struct { - bdrkreg_t pe_rsrvd : 58; - bdrkreg_t pe_deadlock_timeout : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_overflow : 2; - } xb_piq0_error_fld_s; -} xb_piq0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MP0 queue (the MOQ for processor 0). Since * - * the xselect is decoded on the MD/MOQ interface, no invalid xselect * - * errors are possible. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_mp0_error_u { - bdrkreg_t xb_mp0_error_regval; - struct { - bdrkreg_t me_rsrvd_3 : 4; - bdrkreg_t me_overflow : 2; - bdrkreg_t me_rsrvd_2 : 2; - bdrkreg_t me_underflow : 2; - bdrkreg_t me_rsrvd_1 : 2; - bdrkreg_t me_tail_timeout : 2; - bdrkreg_t me_rsrvd : 50; - } xb_mp0_error_fld_s; -} xb_mp0_error_u_t; - -#else - -typedef union xb_mp0_error_u { - bdrkreg_t xb_mp0_error_regval; - struct { - bdrkreg_t me_rsrvd : 50; - bdrkreg_t me_tail_timeout : 2; - bdrkreg_t me_rsrvd_1 : 2; - bdrkreg_t me_underflow : 2; - bdrkreg_t me_rsrvd_2 : 2; - bdrkreg_t me_overflow : 2; - bdrkreg_t me_rsrvd_3 : 4; - } xb_mp0_error_fld_s; -} xb_mp0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MIQ. * - * * - ************************************************************************/ - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_miq_error_u { - bdrkreg_t xb_miq_error_regval; - struct { - bdrkreg_t me_rsrvd_1 : 4; - bdrkreg_t me_deadlock_timeout : 4; - bdrkreg_t me_rsrvd : 56; - } xb_miq_error_fld_s; -} xb_miq_error_u_t; - -#else - -typedef union xb_miq_error_u { - bdrkreg_t xb_miq_error_regval; - struct { - bdrkreg_t me_rsrvd : 56; - bdrkreg_t me_deadlock_timeout : 4; - bdrkreg_t me_rsrvd_1 : 4; - } xb_miq_error_fld_s; -} xb_miq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by NOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_noq_error_u { - bdrkreg_t xb_noq_error_regval; - struct { - bdrkreg_t ne_rsvd : 4; - bdrkreg_t ne_overflow : 4; - bdrkreg_t ne_underflow : 4; - bdrkreg_t ne_tail_timeout : 4; - bdrkreg_t ne_rsrvd : 48; - } xb_noq_error_fld_s; -} xb_noq_error_u_t; - -#else - -typedef union xb_noq_error_u { - bdrkreg_t xb_noq_error_regval; - struct { - bdrkreg_t ne_rsrvd : 48; - bdrkreg_t ne_tail_timeout : 4; - bdrkreg_t ne_underflow : 4; - bdrkreg_t ne_overflow : 4; - bdrkreg_t ne_rsvd : 4; - } xb_noq_error_fld_s; -} xb_noq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_loq_error_u { - bdrkreg_t xb_loq_error_regval; - struct { - bdrkreg_t le_invalid_xsel : 2; - bdrkreg_t le_rsrvd_1 : 6; - bdrkreg_t le_underflow : 2; - bdrkreg_t le_rsvd : 2; - bdrkreg_t le_tail_timeout : 2; - bdrkreg_t le_rsrvd : 50; - } xb_loq_error_fld_s; -} xb_loq_error_u_t; - -#else - -typedef union xb_loq_error_u { - bdrkreg_t xb_loq_error_regval; - struct { - bdrkreg_t le_rsrvd : 50; - bdrkreg_t le_tail_timeout : 2; - bdrkreg_t le_rsvd : 2; - bdrkreg_t le_underflow : 2; - bdrkreg_t le_rsrvd_1 : 6; - bdrkreg_t le_invalid_xsel : 2; - } xb_loq_error_fld_s; -} xb_loq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LIQ. Note that the LIQ only records errors * - * for the request channel. The reply channel can never deadlock or * - * overflow because it does not have hardware flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_liq_error_u { - bdrkreg_t xb_liq_error_regval; - struct { - bdrkreg_t le_overflow : 1; - bdrkreg_t le_rsrvd_1 : 3; - bdrkreg_t le_deadlock_timeout : 1; - bdrkreg_t le_rsrvd : 59; - } xb_liq_error_fld_s; -} xb_liq_error_u_t; - -#else - -typedef union xb_liq_error_u { - bdrkreg_t xb_liq_error_regval; - struct { - bdrkreg_t le_rsrvd : 59; - bdrkreg_t le_deadlock_timeout : 1; - bdrkreg_t le_rsrvd_1 : 3; - bdrkreg_t le_overflow : 1; - } xb_liq_error_fld_s; -} xb_liq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * First error is latched whenever the Valid bit is clear and an * - * error occurs. Any valid bit on in this register causes an * - * interrupt to PI0 and PI1. This interrupt bit will persist until * - * the specific error register to capture the error is cleared, then * - * the FIRST_ERROR register is cleared (in that oder.) The * - * FIRST_ERROR register is not writable, but will be set when any of * - * the corresponding error registers are written by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_first_error_u { - bdrkreg_t xb_first_error_regval; - struct { - bdrkreg_t fe_type : 4; - bdrkreg_t fe_channel : 4; - bdrkreg_t fe_source : 4; - bdrkreg_t fe_valid : 1; - bdrkreg_t fe_rsrvd : 51; - } xb_first_error_fld_s; -} xb_first_error_u_t; - -#else - -typedef union xb_first_error_u { - bdrkreg_t xb_first_error_regval; - struct { - bdrkreg_t fe_rsrvd : 51; - bdrkreg_t fe_valid : 1; - bdrkreg_t fe_source : 4; - bdrkreg_t fe_channel : 4; - bdrkreg_t fe_type : 4; - } xb_first_error_fld_s; -} xb_first_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls DEBUG_DATA mux setting. Allows user to watch the output * - * of any OQ or input of any IQ on the DEBUG port. Note that bits * - * 13:0 are one-hot. If more than one bit is set in [13:0], the debug * - * output is undefined. Details on the debug output lines can be * - * found in the XB chapter of the Bedrock Interface Specification. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_debug_data_ctl_u { - bdrkreg_t xb_debug_data_ctl_regval; - struct { - bdrkreg_t ddc_observe_liq_traffic : 1; - bdrkreg_t ddc_observe_iiq_traffic : 1; - bdrkreg_t ddc_observe_niq_traffic : 1; - bdrkreg_t ddc_observe_miq_traffic : 1; - bdrkreg_t ddc_observe_piq1_traffic : 1; - bdrkreg_t ddc_observe_piq0_traffic : 1; - bdrkreg_t ddc_observe_loq_traffic : 1; - bdrkreg_t ddc_observe_ioq_traffic : 1; - bdrkreg_t ddc_observe_noq_traffic : 1; - bdrkreg_t ddc_observe_mp1_traffic : 1; - bdrkreg_t ddc_observe_mp0_traffic : 1; - bdrkreg_t ddc_observe_mmq_traffic : 1; - bdrkreg_t ddc_observe_poq1_traffic : 1; - bdrkreg_t ddc_observe_poq0_traffic : 1; - bdrkreg_t ddc_observe_source_field : 1; - bdrkreg_t ddc_observe_lodata : 1; - bdrkreg_t ddc_rsrvd : 48; - } xb_debug_data_ctl_fld_s; -} xb_debug_data_ctl_u_t; - -#else - -typedef union xb_debug_data_ctl_u { - bdrkreg_t xb_debug_data_ctl_regval; - struct { - bdrkreg_t ddc_rsrvd : 48; - bdrkreg_t ddc_observe_lodata : 1; - bdrkreg_t ddc_observe_source_field : 1; - bdrkreg_t ddc_observe_poq0_traffic : 1; - bdrkreg_t ddc_observe_poq1_traffic : 1; - bdrkreg_t ddc_observe_mmq_traffic : 1; - bdrkreg_t ddc_observe_mp0_traffic : 1; - bdrkreg_t ddc_observe_mp1_traffic : 1; - bdrkreg_t ddc_observe_noq_traffic : 1; - bdrkreg_t ddc_observe_ioq_traffic : 1; - bdrkreg_t ddc_observe_loq_traffic : 1; - bdrkreg_t ddc_observe_piq0_traffic : 1; - bdrkreg_t ddc_observe_piq1_traffic : 1; - bdrkreg_t ddc_observe_miq_traffic : 1; - bdrkreg_t ddc_observe_niq_traffic : 1; - bdrkreg_t ddc_observe_iiq_traffic : 1; - bdrkreg_t ddc_observe_liq_traffic : 1; - } xb_debug_data_ctl_fld_s; -} xb_debug_data_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls debug mux setting for XB Input/Output Queues and * - * Arbiter. Can select one of the following values. Details on the * - * debug output lines can be found in the XB chapter of the Bedrock * - * Interface Specification. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_debug_arb_ctl_u { - bdrkreg_t xb_debug_arb_ctl_regval; - struct { - bdrkreg_t dac_xb_debug_select : 3; - bdrkreg_t dac_rsrvd : 61; - } xb_debug_arb_ctl_fld_s; -} xb_debug_arb_ctl_u_t; - -#else - -typedef union xb_debug_arb_ctl_u { - bdrkreg_t xb_debug_arb_ctl_regval; - struct { - bdrkreg_t dac_rsrvd : 61; - bdrkreg_t dac_xb_debug_select : 3; - } xb_debug_arb_ctl_fld_s; -} xb_debug_arb_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by POQ0.Can be written to test software, will * - * cause an interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_poq0_error_clear_u { - bdrkreg_t xb_poq0_error_clear_regval; - struct { - bdrkreg_t pec_invalid_xsel : 2; - bdrkreg_t pec_rsrvd_3 : 2; - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_2 : 2; - bdrkreg_t pec_underflow : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_tail_timeout : 2; - bdrkreg_t pec_unused : 6; - bdrkreg_t pec_rsrvd : 44; - } xb_poq0_error_clear_fld_s; -} xb_poq0_error_clear_u_t; - -#else - -typedef union xb_poq0_error_clear_u { - bdrkreg_t xb_poq0_error_clear_regval; - struct { - bdrkreg_t pec_rsrvd : 44; - bdrkreg_t pec_unused : 6; - bdrkreg_t pec_tail_timeout : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_underflow : 2; - bdrkreg_t pec_rsrvd_2 : 2; - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_3 : 2; - bdrkreg_t pec_invalid_xsel : 2; - } xb_poq0_error_clear_fld_s; -} xb_poq0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by PIQ0. Note that the PIQ/PI interface * - * precludes PIQ underflow. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_piq0_error_clear_u { - bdrkreg_t xb_piq0_error_clear_regval; - struct { - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_deadlock_timeout : 2; - bdrkreg_t pec_rsrvd : 58; - } xb_piq0_error_clear_fld_s; -} xb_piq0_error_clear_u_t; - -#else - -typedef union xb_piq0_error_clear_u { - bdrkreg_t xb_piq0_error_clear_regval; - struct { - bdrkreg_t pec_rsrvd : 58; - bdrkreg_t pec_deadlock_timeout : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_overflow : 2; - } xb_piq0_error_clear_fld_s; -} xb_piq0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MP0 queue (the MOQ for processor 0). Since * - * the xselect is decoded on the MD/MOQ interface, no invalid xselect * - * errors are possible. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_mp0_error_clear_u { - bdrkreg_t xb_mp0_error_clear_regval; - struct { - bdrkreg_t mec_rsrvd_3 : 4; - bdrkreg_t mec_overflow : 2; - bdrkreg_t mec_rsrvd_2 : 2; - bdrkreg_t mec_underflow : 2; - bdrkreg_t mec_rsrvd_1 : 2; - bdrkreg_t mec_tail_timeout : 2; - bdrkreg_t mec_rsrvd : 50; - } xb_mp0_error_clear_fld_s; -} xb_mp0_error_clear_u_t; - -#else - -typedef union xb_mp0_error_clear_u { - bdrkreg_t xb_mp0_error_clear_regval; - struct { - bdrkreg_t mec_rsrvd : 50; - bdrkreg_t mec_tail_timeout : 2; - bdrkreg_t mec_rsrvd_1 : 2; - bdrkreg_t mec_underflow : 2; - bdrkreg_t mec_rsrvd_2 : 2; - bdrkreg_t mec_overflow : 2; - bdrkreg_t mec_rsrvd_3 : 4; - } xb_mp0_error_clear_fld_s; -} xb_mp0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MIQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_xm_miq_error_clear_u { - bdrkreg_t xb_xm_miq_error_clear_regval; - struct { - bdrkreg_t xmec_rsrvd_1 : 4; - bdrkreg_t xmec_deadlock_timeout : 4; - bdrkreg_t xmec_rsrvd : 56; - } xb_xm_miq_error_clear_fld_s; -} xb_xm_miq_error_clear_u_t; - -#else - -typedef union xb_xm_miq_error_clear_u { - bdrkreg_t xb_xm_miq_error_clear_regval; - struct { - bdrkreg_t xmec_rsrvd : 56; - bdrkreg_t xmec_deadlock_timeout : 4; - bdrkreg_t xmec_rsrvd_1 : 4; - } xb_xm_miq_error_clear_fld_s; -} xb_xm_miq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by NOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_noq_error_clear_u { - bdrkreg_t xb_noq_error_clear_regval; - struct { - bdrkreg_t nec_rsvd : 4; - bdrkreg_t nec_overflow : 4; - bdrkreg_t nec_underflow : 4; - bdrkreg_t nec_tail_timeout : 4; - bdrkreg_t nec_rsrvd : 48; - } xb_noq_error_clear_fld_s; -} xb_noq_error_clear_u_t; - -#else - -typedef union xb_noq_error_clear_u { - bdrkreg_t xb_noq_error_clear_regval; - struct { - bdrkreg_t nec_rsrvd : 48; - bdrkreg_t nec_tail_timeout : 4; - bdrkreg_t nec_underflow : 4; - bdrkreg_t nec_overflow : 4; - bdrkreg_t nec_rsvd : 4; - } xb_noq_error_clear_fld_s; -} xb_noq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_loq_error_clear_u { - bdrkreg_t xb_loq_error_clear_regval; - struct { - bdrkreg_t lec_invalid_xsel : 2; - bdrkreg_t lec_rsrvd_1 : 6; - bdrkreg_t lec_underflow : 2; - bdrkreg_t lec_rsvd : 2; - bdrkreg_t lec_tail_timeout : 2; - bdrkreg_t lec_rsrvd : 50; - } xb_loq_error_clear_fld_s; -} xb_loq_error_clear_u_t; - -#else - -typedef union xb_loq_error_clear_u { - bdrkreg_t xb_loq_error_clear_regval; - struct { - bdrkreg_t lec_rsrvd : 50; - bdrkreg_t lec_tail_timeout : 2; - bdrkreg_t lec_rsvd : 2; - bdrkreg_t lec_underflow : 2; - bdrkreg_t lec_rsrvd_1 : 6; - bdrkreg_t lec_invalid_xsel : 2; - } xb_loq_error_clear_fld_s; -} xb_loq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LIQ. Note that the LIQ only records errors * - * for the request channel. The reply channel can never deadlock or * - * overflow because it does not have hardware flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_liq_error_clear_u { - bdrkreg_t xb_liq_error_clear_regval; - struct { - bdrkreg_t lec_overflow : 1; - bdrkreg_t lec_rsrvd_1 : 3; - bdrkreg_t lec_deadlock_timeout : 1; - bdrkreg_t lec_rsrvd : 59; - } xb_liq_error_clear_fld_s; -} xb_liq_error_clear_u_t; - -#else - -typedef union xb_liq_error_clear_u { - bdrkreg_t xb_liq_error_clear_regval; - struct { - bdrkreg_t lec_rsrvd : 59; - bdrkreg_t lec_deadlock_timeout : 1; - bdrkreg_t lec_rsrvd_1 : 3; - bdrkreg_t lec_overflow : 1; - } xb_liq_error_clear_fld_s; -} xb_liq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * First error is latched whenever the Valid bit is clear and an * - * error occurs. Any valid bit on in this register causes an * - * interrupt to PI0 and PI1. This interrupt bit will persist until * - * the specific error register to capture the error is cleared, then * - * the FIRST_ERROR register is cleared (in that oder.) The * - * FIRST_ERROR register is not writable, but will be set when any of * - * the corresponding error registers are written by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_first_error_clear_u { - bdrkreg_t xb_first_error_clear_regval; - struct { - bdrkreg_t fec_type : 4; - bdrkreg_t fec_channel : 4; - bdrkreg_t fec_source : 4; - bdrkreg_t fec_valid : 1; - bdrkreg_t fec_rsrvd : 51; - } xb_first_error_clear_fld_s; -} xb_first_error_clear_u_t; - -#else - -typedef union xb_first_error_clear_u { - bdrkreg_t xb_first_error_clear_regval; - struct { - bdrkreg_t fec_rsrvd : 51; - bdrkreg_t fec_valid : 1; - bdrkreg_t fec_source : 4; - bdrkreg_t fec_channel : 4; - bdrkreg_t fec_type : 4; - } xb_first_error_clear_fld_s; -} xb_first_error_clear_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines were not formed into structures * - * * - * This could be because the document did not contain details of the * - * register, or because the automated script did not recognize the * - * register details in the documentation. If these register need * - * structure definition, please create them manually * - * * - * XB_POQ1_ERROR 0x700030 * - * XB_PIQ1_ERROR 0x700038 * - * XB_MP1_ERROR 0x700048 * - * XB_MMQ_ERROR 0x700050 * - * XB_NIQ_ERROR 0x700068 * - * XB_IOQ_ERROR 0x700070 * - * XB_IIQ_ERROR 0x700078 * - * XB_POQ1_ERROR_CLEAR 0x700130 * - * XB_PIQ1_ERROR_CLEAR 0x700138 * - * XB_MP1_ERROR_CLEAR 0x700148 * - * XB_MMQ_ERROR_CLEAR 0x700150 * - * XB_NIQ_ERROR_CLEAR 0x700168 * - * XB_IOQ_ERROR_CLEAR 0x700170 * - * XB_IIQ_ERROR_CLEAR 0x700178 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBXB_H */ diff --git a/include/asm-ia64/sn/sn1/hubxb_next.h b/include/asm-ia64/sn/sn1/hubxb_next.h deleted file mode 100644 index b9df887b937..00000000000 --- a/include/asm-ia64/sn/sn1/hubxb_next.h +++ /dev/null @@ -1,32 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBXB_NEXT_H -#define _ASM_IA64_SN_SN1_HUBXB_NEXT_H - -/* XB_FIRST_ERROR fe_source field encoding */ -#define XVE_SOURCE_POQ0 0xf /* 1111 */ -#define XVE_SOURCE_PIQ0 0xe /* 1110 */ -#define XVE_SOURCE_POQ1 0xd /* 1101 */ -#define XVE_SOURCE_PIQ1 0xc /* 1100 */ -#define XVE_SOURCE_MP0 0xb /* 1011 */ -#define XVE_SOURCE_MP1 0xa /* 1010 */ -#define XVE_SOURCE_MMQ 0x9 /* 1001 */ -#define XVE_SOURCE_MIQ 0x8 /* 1000 */ -#define XVE_SOURCE_NOQ 0x7 /* 0111 */ -#define XVE_SOURCE_NIQ 0x6 /* 0110 */ -#define XVE_SOURCE_IOQ 0x5 /* 0101 */ -#define XVE_SOURCE_IIQ 0x4 /* 0100 */ -#define XVE_SOURCE_LOQ 0x3 /* 0011 */ -#define XVE_SOURCE_LIQ 0x2 /* 0010 */ - -/* XB_PARMS fields */ -#define XBP_RESET_DEFAULTS 0x0008000080000021LL -#define XBP_ACTIVE_DEFAULTS 0x00080000fffff021LL - -#endif /* _ASM_IA64_SN_SN1_HUBXB_NEXT_H */ diff --git a/include/asm-ia64/sn/sn1/hwcntrs.h b/include/asm-ia64/sn/sn1/hwcntrs.h deleted file mode 100644 index 0ec78e887ab..00000000000 --- a/include/asm-ia64/sn/sn1/hwcntrs.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HWCNTRS_H -#define _ASM_IA64_SN_SN1_HWCNTRS_H - - -typedef uint64_t refcnt_t; - -#define SN0_REFCNT_MAX_COUNTERS 64 - -typedef struct sn0_refcnt_set { - refcnt_t refcnt[SN0_REFCNT_MAX_COUNTERS]; - uint64_t flags; - uint64_t reserved[4]; -} sn0_refcnt_set_t; - -typedef struct sn0_refcnt_buf { - sn0_refcnt_set_t refcnt_set; - uint64_t paddr; - uint64_t page_size; - cnodeid_t cnodeid; /* cnodeid + pad[3] use 64 bits */ - uint16_t pad[3]; - uint64_t reserved[4]; -} sn0_refcnt_buf_t; - -typedef struct sn0_refcnt_args { - uint64_t vaddr; - uint64_t len; - sn0_refcnt_buf_t* buf; - uint64_t reserved[4]; -} sn0_refcnt_args_t; - -/* - * Info needed by the user level program - * to mmap the refcnt buffer - */ - -#define RCB_INFO_GET 1 -#define RCB_SLOT_GET 2 - -typedef struct rcb_info { - uint64_t rcb_len; /* total refcnt buffer len in bytes */ - - int rcb_sw_sets; /* number of sw counter sets in buffer */ - int rcb_sw_counters_per_set; /* sw counters per set -- num_compact_nodes */ - int rcb_sw_counter_size; /* sizeof(refcnt_t) -- size of sw cntr */ - - int rcb_base_pages; /* number of base pages in node */ - int rcb_base_page_size; /* sw base page size */ - uint64_t rcb_base_paddr; /* base physical address for this node */ - - int rcb_cnodeid; /* cnodeid for this node */ - int rcb_granularity; /* hw page size used for counter sets */ - uint rcb_hw_counter_max; /* max hwcounter count (width mask) */ - int rcb_diff_threshold; /* current node differential threshold */ - int rcb_abs_threshold; /* current node absolute threshold */ - int rcb_num_slots; /* physmem slots */ - - int rcb_reserved[512]; - -} rcb_info_t; - -typedef struct rcb_slot { - uint64_t base; - uint64_t size; -} rcb_slot_t; - -#if defined(__KERNEL__) -typedef struct sn0_refcnt_args_32 { - uint64_t vaddr; - uint64_t len; - app32_ptr_t buf; - uint64_t reserved[4]; -} sn0_refcnt_args_32_t; - -/* Defines and Macros */ -/* A set of reference counts are for 4k bytes of physical memory */ -#define NBPREFCNTP 0x1000 -#define BPREFCNTPSHIFT 12 -#define bytes_to_refcntpages(x) (((__psunsigned_t)(x)+(NBPREFCNTP-1))>>BPREFCNTPSHIFT) -#define refcntpage_offset(x) ((__psunsigned_t)(x)&((NBPP-1)&~(NBPREFCNTP-1))) -#define align_to_refcntpage(x) ((__psunsigned_t)(x)&(~(NBPREFCNTP-1))) - -extern void migr_refcnt_read(sn0_refcnt_buf_t*); -extern void migr_refcnt_read_extended(sn0_refcnt_buf_t*); -extern int migr_refcnt_enabled(void); - -#endif /* __KERNEL__ */ - -#endif /* _ASM_IA64_SN_SN1_HWCNTRS_H */ diff --git a/include/asm-ia64/sn/sn1/intr.h b/include/asm-ia64/sn/sn1/intr.h deleted file mode 100644 index a05b7898c0a..00000000000 --- a/include/asm-ia64/sn/sn1/intr.h +++ /dev/null @@ -1,237 +0,0 @@ -/* $Id: intr.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_INTR_H -#define _ASM_IA64_SN_SN1_INTR_H - -/* Subnode wildcard */ -#define SUBNODE_ANY (-1) - -/* Number of interrupt levels associated with each interrupt register. */ -#define N_INTPEND_BITS 64 - -#define INT_PEND0_BASELVL 0 -#define INT_PEND1_BASELVL 64 - -#define N_INTPENDJUNK_BITS 8 -#define INTPENDJUNK_CLRBIT 0x80 - -#include -#include -#include -#include - -#ifndef __ASSEMBLY__ -#define II_NAMELEN 24 - -/* - * Dispatch table entry - contains information needed to call an interrupt - * routine. - */ -typedef struct intr_vector_s { - intr_func_t iv_func; /* Interrupt handler function */ - intr_func_t iv_prefunc; /* Interrupt handler prologue func */ - void *iv_arg; /* Argument to pass to handler */ - cpuid_t iv_mustruncpu; /* Where we must run. */ -} intr_vector_t; - -/* Interrupt information table. */ -typedef struct intr_info_s { - xtalk_intr_setfunc_t ii_setfunc; /* Function to set the interrupt - * destination and level register. - * It returns 0 (success) or an - * error code. - */ - void *ii_cookie; /* arg passed to setfunc */ - devfs_handle_t ii_owner_dev; /* device that owns this intr */ - char ii_name[II_NAMELEN]; /* Name of this intr. */ - int ii_flags; /* informational flags */ -} intr_info_t; - - -#define THD_CREATED 0x00000001 /* - * We've created a thread for this - * interrupt. - */ - -/* - * Bits for ii_flags: - */ -#define II_UNRESERVE 0 -#define II_RESERVE 1 /* Interrupt reserved. */ -#define II_INUSE 2 /* Interrupt connected */ -#define II_ERRORINT 4 /* INterrupt is an error condition */ -#define II_THREADED 8 /* Interrupt handler is threaded. */ - -/* - * Interrupt level wildcard - */ -#define INTRCONNECT_ANYBIT (-1) - -/* - * This structure holds information needed both to call and to maintain - * interrupts. The two are in separate arrays for the locality benefits. - * Since there's only one set of vectors per hub chip (but more than one - * CPU, the lock to change the vector tables must be here rather than in - * the PDA. - */ - -typedef struct intr_vecblk_s { - intr_vector_t vectors[N_INTPEND_BITS]; /* information needed to - call an intr routine. */ - intr_info_t info[N_INTPEND_BITS]; /* information needed only - to maintain interrupts. */ - spinlock_t vector_lock; /* Lock for this and the - masks in the PDA. */ - splfunc_t vector_spl; /* vector_lock req'd spl */ - int vector_state; /* Initialized to zero. - Set to INTR_INITED - by hubintr_init. - */ - int vector_count; /* Number of vectors - * reserved. - */ - int cpu_count[CPUS_PER_SUBNODE]; /* How many interrupts are - * connected to each CPU - */ - int ithreads_enabled; /* Are interrupt threads - * initialized on this node. - * and block? - */ -} intr_vecblk_t; - -/* Possible values for vector_state: */ -#define VECTOR_UNINITED 0 -#define VECTOR_INITED 1 -#define VECTOR_SET 2 - -#define hub_intrvect0 private.p_intmasks.dispatch0->vectors -#define hub_intrvect1 private.p_intmasks.dispatch1->vectors -#define hub_intrinfo0 private.p_intmasks.dispatch0->info -#define hub_intrinfo1 private.p_intmasks.dispatch1->info - -/* - * Macros to manipulate the interrupt register on the calling hub chip. - */ - -#define LOCAL_HUB_SEND_INTR(_level) LOCAL_HUB_S(PI_INT_PEND_MOD, \ - (0x100|(_level))) -#define REMOTE_HUB_PI_SEND_INTR(_hub, _sn, _level) \ - REMOTE_HUB_PI_S((_hub), _sn, PI_INT_PEND_MOD, (0x100|(_level))) - -#define REMOTE_CPU_SEND_INTR(_cpuid, _level) \ - REMOTE_HUB_PI_S(cpuid_to_nasid(_cpuid), \ - SUBNODE(cpuid_to_slice(_cpuid)), \ - PI_INT_PEND_MOD, (0x100|(_level))) - -/* - * When clearing the interrupt, make sure this clear does make it - * to the hub. Otherwise we could end up losing interrupts. - * We do an uncached load of the int_pend0 register to ensure this. - */ - -#define LOCAL_HUB_CLR_INTR(_level) \ - LOCAL_HUB_S(PI_INT_PEND_MOD, (_level)), \ - LOCAL_HUB_L(PI_INT_PEND0) -#define REMOTE_HUB_PI_CLR_INTR(_hub, _sn, _level) \ - REMOTE_HUB_PI_S((_hub), (_sn), PI_INT_PEND_MOD, (_level)), \ - REMOTE_HUB_PI_L((_hub), (_sn), PI_INT_PEND0) - -/* Special support for use by gfx driver only. Supports special gfx hub interrupt. */ -extern void install_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg); - -void setrtvector(intr_func_t func); - -/* - * Interrupt blocking - */ -extern void intr_block_bit(cpuid_t cpu, int bit); -extern void intr_unblock_bit(cpuid_t cpu, int bit); - -#endif /* __ASSEMBLY__ */ - -/* - * Hard-coded interrupt levels: - */ - -/* - * L0 = SW1 - * L1 = SW2 - * L2 = INT_PEND0 - * L3 = INT_PEND1 - * L4 = RTC - * L5 = Profiling Timer - * L6 = Hub Errors - * L7 = Count/Compare (T5 counters) - */ - - -/* INT_PEND0 hard-coded bits. */ -#ifdef DEBUG_INTR_TSTAMP -/* hard coded interrupt level for interrupt latency test interrupt */ -#define CPU_INTRLAT_B 62 -#define CPU_INTRLAT_A 61 -#endif - -/* Hardcoded bits required by software. */ -#define MSC_MESG_INTR 9 -#define CPU_ACTION_B 8 -#define CPU_ACTION_A 7 - -/* These are determined by hardware: */ -#define CC_PEND_B 6 -#define CC_PEND_A 5 -#define UART_INTR 4 -#define PG_MIG_INTR 3 -#define GFX_INTR_B 2 -#define GFX_INTR_A 1 -#define RESERVED_INTR 0 - -/* INT_PEND1 hard-coded bits: */ -#define MSC_PANIC_INTR 63 -#define NI_ERROR_INTR 62 -#define MD_COR_ERR_INTR 61 -#define COR_ERR_INTR_B 60 -#define COR_ERR_INTR_A 59 -#define CLK_ERR_INTR 58 - -# define NACK_INT_B 57 -# define NACK_INT_A 56 -# define LB_ERROR 55 -# define XB_ERROR 54 - -#define BRIDGE_ERROR_INTR 53 /* Setup by PROM to catch Bridge Errors */ - -#define IP27_INTR_0 52 /* Reserved for PROM use */ -#define IP27_INTR_1 51 /* (do not use in Kernel) */ -#define IP27_INTR_2 50 -#define IP27_INTR_3 49 -#define IP27_INTR_4 48 -#define IP27_INTR_5 47 -#define IP27_INTR_6 46 -#define IP27_INTR_7 45 - -#define TLB_INTR_B 44 /* used for tlb flush random */ -#define TLB_INTR_A 43 - -#define LLP_PFAIL_INTR_B 42 /* see ml/SN/SN0/sysctlr.c */ -#define LLP_PFAIL_INTR_A 41 - -#define NI_BRDCAST_ERR_B 40 -#define NI_BRDCAST_ERR_A 39 - -# define IO_ERROR_INTR 38 /* set up by prom */ -# define DEBUG_INTR_B 37 /* used by symmon to stop all cpus */ -# define DEBUG_INTR_A 36 - -// These aren't strictly accurate or complete. See the -// Synergy Spec. for details. -#define SGI_UART_IRQ (65) -#define SGI_HUB_ERROR_IRQ (182) - -#endif /* _ASM_IA64_SN_SN1_INTR_H */ diff --git a/include/asm-ia64/sn/sn1/intr_public.h b/include/asm-ia64/sn/sn1/intr_public.h deleted file mode 100644 index 3d2d1e2d9d4..00000000000 --- a/include/asm-ia64/sn/sn1/intr_public.h +++ /dev/null @@ -1,53 +0,0 @@ -/* $Id: intr_public.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_INTR_PUBLIC_H -#define _ASM_IA64_SN_SN1_INTR_PUBLIC_H - -/* REMEMBER: If you change these, the whole world needs to be recompiled. - * It would also require changing the hubspl.s code and SN0/intr.c - * Currently, the spl code has no support for multiple INTPEND1 masks. - */ - -#define N_INTPEND0_MASKS 1 -#define N_INTPEND1_MASKS 1 - -#define INTPEND0_MAXMASK (N_INTPEND0_MASKS - 1) -#define INTPEND1_MAXMASK (N_INTPEND1_MASKS - 1) - -#ifndef __ASSEMBLY__ -#include - -struct intr_vecblk_s; /* defined in asm/sn/intr.h */ - -/* - * The following are necessary to create the illusion of a CEL - * on the IP27 hub. We'll add more priority levels soon, but for - * now, any interrupt in a particular band effectively does an spl. - * These must be in the PDA since they're different for each processor. - * Users of this structure must hold the vector_lock in the appropriate vector - * block before modifying the mask arrays. There's only one vector block - * for each Hub so a lock in the PDA wouldn't be adequate. - */ -typedef struct hub_intmasks_s { - /* - * The masks are stored with the lowest-priority (most inclusive) - * in the lowest-numbered masks (i.e., 0, 1, 2...). - */ - /* INT_PEND0: */ - hubreg_t intpend0_masks[N_INTPEND0_MASKS]; - /* INT_PEND1: */ - hubreg_t intpend1_masks[N_INTPEND1_MASKS]; - /* INT_PEND0: */ - struct intr_vecblk_s *dispatch0; - /* INT_PEND1: */ - struct intr_vecblk_s *dispatch1; -} hub_intmasks_t; - -#endif /* __ASSEMBLY__ */ -#endif /* _ASM_IA64_SN_SN1_INTR_PUBLIC_H */ diff --git a/include/asm-ia64/sn/sn1/ip27config.h b/include/asm-ia64/sn/sn1/ip27config.h deleted file mode 100644 index 71b92c46697..00000000000 --- a/include/asm-ia64/sn/sn1/ip27config.h +++ /dev/null @@ -1,657 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_IP27CONFIG_H -#define _ASM_IA64_SN_SN1_IP27CONFIG_H - - -/* - * Structure: ip27config_s - * Typedef: ip27config_t - * Purpose: Maps out the region of the boot prom used to define - * configuration information. - * Notes: Corresponds to ip27config structure found in start.s. - * Fields are ulong where possible to facilitate IP27 PROM fetches. - */ - -#define CONFIG_INFO_OFFSET 0x60 - -#define IP27CONFIG_ADDR (LBOOT_BASE + \ - CONFIG_INFO_OFFSET) -#define IP27CONFIG_ADDR_NODE(n) (NODE_RBOOT_BASE(n) + \ - CONFIG_INFO_OFFSET) - -/* Offset to the config_type field within local ip27config structure */ -#define CONFIG_FLAGS_ADDR (IP27CONFIG_ADDR + 72) -/* Offset to the config_type field in the ip27config structure on - * node with nasid n - */ -#define CONFIG_FLAGS_ADDR_NODE(n) (IP27CONFIG_ADDR_NODE(n) + 72) - -/* Meaning of each valid bit in the config flags - * None are currently defined - */ - -/* Meaning of each mach_type value - */ -#define SN1_MACH_TYPE 0 - -/* - * Since 800 ns works well with various HUB frequencies, (such as 360, - * 380, 390, and 400 MHZ), we now use 800ns rtc cycle time instead of - * 1 microsec. - */ -#define IP27_RTC_FREQ 1250 /* 800ns cycle time */ - -#ifndef __ASSEMBLY__ - -typedef struct ip27config_s { /* KEEP IN SYNC w/ start.s & below */ - uint time_const; /* Time constant */ - uint r10k_mode; /* R10k boot mode bits */ - - uint64_t magic; /* CONFIG_MAGIC */ - - uint64_t freq_cpu; /* Hz */ - uint64_t freq_hub; /* Hz */ - uint64_t freq_rtc; /* Hz */ - - uint ecc_enable; /* ECC enable flag */ - uint fprom_cyc; /* FPROM_CYC speed control */ - - uint mach_type; /* Inidicate IP27 (0) or Sn00 (1) */ - - uint check_sum_adj; /* Used after config hdr overlay */ - /* to make the checksum 0 again */ - uint flash_count; /* Value incr'd on each PROM flash */ - uint fprom_wr; /* FPROM_WR speed control */ - - uint pvers_vers; /* Prom version number */ - uint pvers_rev; /* Prom revision number */ - uint config_type; /* To support special configurations - * (none currently defined) - */ -} ip27config_t; - -typedef struct { - uint r10k_mode; /* R10k boot mode bits */ - uint freq_cpu; /* Hz */ - uint freq_hub; /* Hz */ - char fprom_cyc; /* FPROM_CYC speed control */ - char mach_type; /* IP35(0) is only type defined */ - char fprom_wr; /* FPROM_WR speed control */ -} config_modifiable_t; - -#define IP27CONFIG (*(ip27config_t *) IP27CONFIG_ADDR) -#define IP27CONFIG_NODE(n) (*(ip27config_t *) IP27CONFIG_ADDR_NODE(n)) -#define SN00 0 /* IP35 has no Speedo equivalent */ - -/* Get the config flags from local ip27config */ -#define CONFIG_FLAGS (*(uint *) (CONFIG_FLAGS_ADDR)) - -/* Get the config flags from ip27config on the node - * with nasid n - */ -#define CONFIG_FLAGS_NODE(n) (*(uint *) (CONFIG_FLAGS_ADDR_NODE(n))) - -/* Macro to check if the local ip27config indicates a config - * of 12 p 4io - */ -#define CONFIG_12P4I (0) /* IP35 has no 12p4i equivalent */ - -/* Macro to check if the ip27config on node with nasid n - * indicates a config of 12 p 4io - */ -#define CONFIG_12P4I_NODE(n) (0) - -#endif /* __ASSEMBLY__ */ - -#if __ASSEMBLY__ - .struct 0 /* KEEP IN SYNC WITH C structure */ - -ip27c_time_const: .word 0 -ip27c_r10k_mode: .word 0 - -ip27c_magic: .dword 0 - -ip27c_freq_cpu: .dword 0 -ip27c_freq_hub: .dword 0 -ip27c_freq_rtc: .dword 0 - -ip27c_ecc_enable: .word 1 -ip27c_fprom_cyc: .word 0 - -ip27c_mach_type: .word 0 -ip27c_check_sum_adj: .word 0 - -ip27c_flash_count: .word 0 -ip27c_fprom_wr: .word 0 - -ip27c_pvers_vers: .word 0 -ip27c_pvers_rev: .word 0 - -ip27c_config_type: .word 0 /* To recognize special configs */ -#endif /* __ASSEMBLY__ */ - -/* - * R10000 Configuration Cycle - These define the SYSAD values used - * during the reset cycle. - */ - -#define IP27C_R10000_KSEG0CA_SHFT 0 -#define IP27C_R10000_KSEG0CA_MASK (7 << IP27C_R10000_KSEG0CA_SHFT) -#define IP27C_R10000_KSEG0CA(_B) ((_B) << IP27C_R10000_KSEG0CA_SHFT) - -#define IP27C_R10000_DEVNUM_SHFT 3 -#define IP27C_R10000_DEVNUM_MASK (3 << IP27C_R10000_DEVNUM_SHFT) -#define IP27C_R10000_DEVNUM(_B) ((_B) << IP27C_R10000_DEVNUM_SHFT) - -#define IP27C_R10000_CRPT_SHFT 5 -#define IP27C_R10000_CRPT_MASK (1 << IP27C_R10000_CRPT_SHFT) -#define IP27C_R10000_CPRT(_B) ((_B)< - - -/* - * SGI SN1 Arch defined values - * - * An SN1 physical address is broken down as follows: - * - * +-----------------------------------------+ - * | | | | node offset | - * | unused | AS | node |-------------------| - * | | | | cn | clump offset | - * +-----------------------------------------+ - * 6 4 4 4 3 3 3 3 2 0 - * 3 4 3 0 9 3 2 0 9 0 - * - * bits 63-44 Unused - must be zero - * bits 43-40 Address space ID. Cached memory has a value of 0. - * Chipset & IO addresses have non-zero values. - * bits 39-33 Node number. Note that some configurations do NOT - * have a node zero. - * bits 32-0 Node offset. - * - * The node offset can be further broken down as: - * bits 32-30 Clump (bank) number. - * bits 29-0 Clump (bank) offset. - * - * A node consists of up to 8 clumps (banks) of memory. A clump may be empty, or may be - * populated with a single contiguous block of memory starting at clump - * offset 0. The size of the block is (2**n) * 64MB, where 0> SN1_NODE_SHIFT) & SN1_NODE_MASK) -#define SN1_NODE_CLUMP_NUMBER(addr) (((unsigned long)(addr) >>30) & 7) -#define SN1_NODE_OFFSET(addr) (((unsigned long)(addr)) & SN1_NODE_OFFSET_MASK) -#define SN1_KADDR(nasid, offset) (((unsigned long)(nasid)<> SN1_CHUNKSHIFT) - - -/* - * Given a kaddr, find the nid (compact nodeid) - */ -#ifdef CONFIG_IA64_SGI_SN_DEBUG -#define DISCONBUG(kaddr) panic("DISCONTIG BUG: line %d, %s. kaddr 0x%lx", \ - __LINE__, __FILE__, (long)(kaddr)) - -#define KVADDR_TO_NID(kaddr) ({long _ktn=(long)(kaddr); \ - kern_addr_valid(_ktn) ? \ - local_node_data->physical_node_map[SN1_NODE_NUMBER(_ktn)] :\ - (DISCONBUG(_ktn), 0UL);}) -#else -#define KVADDR_TO_NID(kaddr) (local_node_data->physical_node_map[SN1_NODE_NUMBER(kaddr)]) -#endif - - - -/* - * Given a kaddr, find the index into the clump_mem_map_base array of the page struct entry - * for the first page of the clump. - */ -#define PLAT_CLUMP_MEM_MAP_INDEX(kaddr) ({long _kmmi=(long)(kaddr); \ - KVADDR_TO_NID(_kmmi) * PLAT_CLUMPS_PER_NODE + \ - SN1_NODE_CLUMP_NUMBER(_kmmi);}) - - -/* - * Calculate a "goal" value to be passed to __alloc_bootmem_node for allocating structures on - * nodes so that they don't alias to the same line in the cache as the previous allocated structure. - * This macro takes an address of the end of previous allocation, rounds it to a page boundary & - * changes the node number. - */ -#define PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) __pa(SN1_KADDR(PLAT_PXM_TO_PHYS_NODE_NUMBER(nid_to_pxm_map[cnode]), \ - (SN1_NODE_OFFSET(kaddr) + PAGE_SIZE - 1) >> PAGE_SHIFT << PAGE_SHIFT)) - - - - -/* - * Convert a proximity domain number (from the ACPI tables) into a physical node number. - */ - -#define PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) (pxm) - -#endif /* _ASM_IA64_SN_MMZONE_SN1_H */ diff --git a/include/asm-ia64/sn/sn1/slotnum.h b/include/asm-ia64/sn/sn1/slotnum.h deleted file mode 100644 index 1d5f05a70e5..00000000000 --- a/include/asm-ia64/sn/sn1/slotnum.h +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_SLOTNUM_H -#define _ASM_IA64_SN_SN1_SLOTNUM_H - -#define SLOTNUM_MAXLENGTH 16 - -/* - * This file attempts to define a slot number space across all slots. - * - * Node slots - * Router slots - * Crosstalk slots - * - * Other slots are children of their parent crosstalk slot: - * PCI slots - * VME slots - * - * The PCI class has been added since the XBridge ASIC on SN-MIPS - * has built-in PCI bridges (2). On IBricks, widget E & F serve - * PCI busses, and on PBricks all widgets serve as PCI busses - * with the use of the super-bridge mode of the XBridge ASIC. - */ - -#define SLOTNUM_NODE_CLASS 0x00 /* Node */ -#define SLOTNUM_ROUTER_CLASS 0x10 /* Router */ -#define SLOTNUM_XTALK_CLASS 0x20 /* Xtalk */ -#define SLOTNUM_MIDPLANE_CLASS 0x30 /* Midplane */ -#define SLOTNUM_XBOW_CLASS 0x40 /* Xbow */ -#define SLOTNUM_KNODE_CLASS 0x50 /* Kego node */ -#define SLOTNUM_PCI_CLASS 0x60 /* PCI widgets on XBridge */ -#define SLOTNUM_INVALID_CLASS 0xf0 /* Invalid */ - -#define SLOTNUM_CLASS_MASK 0xf0 -#define SLOTNUM_SLOT_MASK 0x0f - -#define SLOTNUM_GETCLASS(_sn) ((_sn) & SLOTNUM_CLASS_MASK) -#define SLOTNUM_GETSLOT(_sn) ((_sn) & SLOTNUM_SLOT_MASK) - -/* This determines module to pnode mapping. */ -/* NODESLOTS_PER_MODULE has changed from 4 to 6 - * to support the 12P 4IO configuration. This change - * helps in minimum number of changes to code which - * depend on the number of node boards within a module. - */ -#define NODESLOTS_PER_MODULE 6 -#define NODESLOTS_PER_MODULE_SHFT 2 - -#define HIGHEST_I2C_VISIBLE_NODESLOT 4 -#define RTRSLOTS_PER_MODULE 2 - -#if __KERNEL__ -#include - -extern slotid_t xbwidget_to_xtslot(int crossbow, int widget); -extern slotid_t hub_slotbits_to_slot(slotid_t slotbits); -extern slotid_t hub_slot_to_crossbow(slotid_t hub_slot); -extern slotid_t router_slotbits_to_slot(slotid_t slotbits); -extern slotid_t get_node_slotid(nasid_t nasid); -extern slotid_t get_my_slotid(void); -extern slotid_t get_node_crossbow(nasid_t); -extern xwidgetnum_t hub_slot_to_widget(slotid_t); -extern void get_slotname(slotid_t, char *); -extern void get_my_slotname(char *); -extern slotid_t get_widget_slotnum(int xbow, int widget); -extern void get_widget_slotname(int, int, char *); -extern void router_slotbits_to_slotname(int, char *); -extern slotid_t meta_router_slotbits_to_slot(slotid_t) ; -extern slotid_t hub_slot_get(void); - -extern int node_can_talk_to_elsc(void); - -extern int slot_to_widget(int) ; -#define MAX_IO_SLOT_NUM 12 -#define MAX_NODE_SLOT_NUM 4 -#define MAX_ROUTER_SLOTNUM 2 - -#endif /* __KERNEL__ */ - -#endif /* _ASM_IA64_SN_SN1_SLOTNUM_H */ diff --git a/include/asm-ia64/sn/sn1/sn_private.h b/include/asm-ia64/sn/sn1/sn_private.h deleted file mode 100644 index 27ebfe4c815..00000000000 --- a/include/asm-ia64/sn/sn1/sn_private.h +++ /dev/null @@ -1,292 +0,0 @@ -/* $Id: sn_private.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_SN_PRIVATE_H -#define _ASM_IA64_SN_SN1_SN_PRIVATE_H - -#include -#include -#include - -extern nasid_t master_nasid; - -/* promif.c */ -#ifdef LATER -extern cpuid_t cpu_node_probe(cpumask_t *cpumask, int *numnodes); -#endif -extern void he_arcs_set_vectors(void); -extern void mem_init(void); -#ifdef LATER -extern int cpu_enabled(cpuid_t); -#endif -extern void cpu_unenable(cpuid_t); -extern nasid_t get_lowest_nasid(void); -extern __psunsigned_t get_master_bridge_base(void); -extern void set_master_bridge_base(void); -extern int check_nasid_equiv(nasid_t, nasid_t); -extern nasid_t get_console_nasid(void); -extern char get_console_pcislot(void); -#ifdef LATER -extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); -#endif - -extern int is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid); - -/* memsupport.c */ -extern void poison_state_alter_range(__psunsigned_t start, int len, int poison); -extern int memory_present(paddr_t); -extern int memory_read_accessible(paddr_t); -extern int memory_write_accessible(paddr_t); -extern void memory_set_access(paddr_t, int, int); -extern void show_dir_state(paddr_t, void (*)(char *, ...)); -extern void check_dir_state(nasid_t, int, void (*)(char *, ...)); -extern void set_dir_owner(paddr_t, int); -extern void set_dir_state(paddr_t, int); -extern void set_dir_state_POISONED(paddr_t); -extern void set_dir_state_UNOWNED(paddr_t); -extern int is_POISONED_dir_state(paddr_t); -extern int is_UNOWNED_dir_state(paddr_t); -extern void get_dir_ent(paddr_t paddr, int *state, - uint64_t *vec_ptr, hubreg_t *elo); - -/* intr.c */ -extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name); -extern void intr_unreserve_level(cpuid_t cpu, int level); -extern int intr_connect_level(cpuid_t cpu, int bit, ilvl_t mask_no, - intr_func_t intr_prefunc); -extern int intr_disconnect_level(cpuid_t cpu, int bit); -extern cpuid_t intr_heuristic(devfs_handle_t dev, device_desc_t dev_desc, - int req_bit,int intr_resflags,devfs_handle_t owner_dev, - char *intr_name,int *resp_bit); -extern void intr_block_bit(cpuid_t cpu, int bit); -extern void intr_unblock_bit(cpuid_t cpu, int bit); -extern void setrtvector(intr_func_t); -extern void install_cpuintr(cpuid_t cpu); -extern void install_dbgintr(cpuid_t cpu); -extern void install_tlbintr(cpuid_t cpu); -extern void hub_migrintr_init(cnodeid_t /*cnode*/); -extern int cause_intr_connect(int level, intr_func_t handler, uint intr_spl_mask); -extern int cause_intr_disconnect(int level); -extern void intr_reserve_hardwired(cnodeid_t); -extern void intr_clear_all(nasid_t); -extern void intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)); - -/* error_dump.c */ -extern char *hub_rrb_err_type[]; -extern char *hub_wrb_err_type[]; - -void nmi_dump(void); -void install_cpu_nmi_handler(int slice); - -/* klclock.c */ -extern void hub_rtc_init(cnodeid_t); - -/* bte.c */ -void bte_lateinit(void); -void bte_wait_for_xfer_completion(void *); - -/* klgraph.c */ -void klhwg_add_all_nodes(devfs_handle_t); -void klhwg_add_all_modules(devfs_handle_t); - -/* klidbg.c */ -void install_klidbg_functions(void); - -/* klnuma.c */ -extern void replicate_kernel_text(int numnodes); -extern __psunsigned_t get_freemem_start(cnodeid_t cnode); -extern void setup_replication_mask(int maxnodes); - -/* init.c */ -extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ -extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); -extern void init_platform_pda(cpuid_t cpu); -extern void per_cpu_init(void); -#ifdef LATER -extern cpumask_t boot_cpumask; -#endif -extern int is_fine_dirmode(void); -extern void update_node_information(cnodeid_t); - -#ifdef LATER -/* clksupport.c */ -extern void early_counter_intr(eframe_t *); -#endif - -/* hubio.c */ -extern void hubio_init(void); -extern void hub_merge_clean(nasid_t nasid); -extern void hub_set_piomode(nasid_t nasid, int conveyor); - -/* huberror.c */ -extern void hub_error_init(cnodeid_t); -extern void dump_error_spool(cpuid_t cpu, void (*pf)(char *, ...)); -extern void hubni_error_handler(char *, int); -extern int check_ni_errors(void); - -/* Used for debugger to signal upper software a breakpoint has taken place */ - -extern void *debugger_update; -extern __psunsigned_t debugger_stopped; - -/* - * IP27 piomap, created by hub_pio_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_piomap_s by generic xtalk routines. - */ -struct hub_piomap_s { - struct xtalk_piomap_s hpio_xtalk_info;/* standard crosstalk pio info */ - devfs_handle_t hpio_hub; /* which hub's mapping registers are set up */ - short hpio_holdcnt; /* count of current users of bigwin mapping */ - char hpio_bigwin_num;/* if big window map, which one */ - int hpio_flags; /* defined below */ -}; -/* hub_piomap flags */ -#define HUB_PIOMAP_IS_VALID 0x1 -#define HUB_PIOMAP_IS_BIGWINDOW 0x2 -#define HUB_PIOMAP_IS_FIXED 0x4 - -#define hub_piomap_xt_piomap(hp) (&hp->hpio_xtalk_info) -#define hub_piomap_hub_v(hp) (hp->hpio_hub) -#define hub_piomap_winnum(hp) (hp->hpio_bigwin_num) - -#if TBD - /* Ensure that hpio_xtalk_info is first */ - #assert (&(((struct hub_piomap_s *)0)->hpio_xtalk_info) == 0) -#endif - - -/* - * IP27 dmamap, created by hub_pio_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_dmamap_s by generic xtalk routines. - */ -struct hub_dmamap_s { - struct xtalk_dmamap_s hdma_xtalk_info;/* standard crosstalk dma info */ - devfs_handle_t hdma_hub; /* which hub we go through */ - int hdma_flags; /* defined below */ -}; -/* hub_dmamap flags */ -#define HUB_DMAMAP_IS_VALID 0x1 -#define HUB_DMAMAP_USED 0x2 -#define HUB_DMAMAP_IS_FIXED 0x4 - -#if TBD - /* Ensure that hdma_xtalk_info is first */ - #assert (&(((struct hub_dmamap_s *)0)->hdma_xtalk_info) == 0) -#endif - -/* - * IP27 interrupt handle, created by hub_intr_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_intr_s by generic xtalk routines. - */ -struct hub_intr_s { - struct xtalk_intr_s i_xtalk_info; /* standard crosstalk intr info */ - ilvl_t i_swlevel; /* software level for blocking intr */ - cpuid_t i_cpuid; /* which cpu */ - int i_bit; /* which bit */ - int i_flags; -}; -/* flag values */ -#define HUB_INTR_IS_ALLOCED 0x1 /* for debug: allocated */ -#define HUB_INTR_IS_CONNECTED 0x4 /* for debug: connected to a software driver */ - -#if TBD - /* Ensure that i_xtalk_info is first */ - #assert (&(((struct hub_intr_s *)0)->i_xtalk_info) == 0) -#endif - - -/* IP27 hub-specific information stored under INFO_LBL_HUB_INFO */ -/* TBD: IP27-dependent stuff currently in nodepda.h should be here */ -typedef struct hubinfo_s { - nodepda_t *h_nodepda; /* pointer to node's private data area */ - cnodeid_t h_cnodeid; /* compact nodeid */ - nasid_t h_nasid; /* nasid */ - - /* structures for PIO management */ - xwidgetnum_t h_widgetid; /* my widget # (as viewed from xbow) */ - struct hub_piomap_s h_small_window_piomap[HUB_WIDGET_ID_MAX+1]; - sv_t h_bwwait; /* wait for big window to free */ - spinlock_t h_bwlock; /* guard big window piomap's */ - spinlock_t h_crblock; /* gaurd CRB error handling */ - int h_num_big_window_fixed; /* count number of FIXED maps */ - struct hub_piomap_s h_big_window_piomap[HUB_NUM_BIG_WINDOW]; - hub_intr_t hub_ii_errintr; -} *hubinfo_t; - -#define hubinfo_get(vhdl, infoptr) ((void)hwgraph_info_get_LBL \ - (vhdl, INFO_LBL_NODE_INFO, (arbitrary_info_t *)infoptr)) - -#define hubinfo_set(vhdl, infoptr) (void)hwgraph_info_add_LBL \ - (vhdl, INFO_LBL_NODE_INFO, (arbitrary_info_t)infoptr) - -#define hubinfo_to_hubv(hinfo, hub_v) (hinfo->h_nodepda->node_vertex) - -/* - * Hub info PIO map access functions. - */ -#define hubinfo_bwin_piomap_get(hinfo, win) \ - (&hinfo->h_big_window_piomap[win]) -#define hubinfo_swin_piomap_get(hinfo, win) \ - (&hinfo->h_small_window_piomap[win]) - -/* IP27 cpu-specific information stored under INFO_LBL_CPU_INFO */ -/* TBD: IP27-dependent stuff currently in pda.h should be here */ -typedef struct cpuinfo_s { -#ifdef LATER - pda_t *ci_cpupda; /* pointer to CPU's private data area */ -#endif - cpuid_t ci_cpuid; /* CPU ID */ -} *cpuinfo_t; - -#define cpuinfo_get(vhdl, infoptr) ((void)hwgraph_info_get_LBL \ - (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t *)infoptr)) - -#define cpuinfo_set(vhdl, infoptr) (void)hwgraph_info_add_LBL \ - (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t)infoptr) - -/* Special initialization function for xswitch vertices created during startup. */ -extern void xswitch_vertex_init(devfs_handle_t xswitch); - -extern xtalk_provider_t hub_provider; - -/* du.c */ -int ducons_write(char *buf, int len); - -/* memerror.c */ - -extern void install_eccintr(cpuid_t cpu); -extern void memerror_get_stats(cnodeid_t cnode, - int *bank_stats, int *bank_stats_max); -extern void probe_md_errors(nasid_t); -/* sysctlr.c */ -extern void sysctlr_init(void); -extern void sysctlr_power_off(int sdonly); -extern void sysctlr_keepalive(void); - -#define valid_cpuid(_x) (((_x) >= 0) && ((_x) < maxcpus)) - -/* Useful definitions to get the memory dimm given a physical - * address. - */ -#define paddr_dimm(_pa) ((_pa & MD_BANK_MASK) >> MD_BANK_SHFT) -#define paddr_cnode(_pa) (NASID_TO_COMPACT_NODEID(NASID_GET(_pa))) -extern void membank_pathname_get(paddr_t,char *); - -/* To redirect the output into the error buffer */ -#define errbuf_print(_s) printf("#%s",_s) - -extern void crbx(nasid_t nasid, void (*pf)(char *, ...)); -void bootstrap(void); - -/* sndrv.c */ -extern int sndrv_attach(devfs_handle_t vertex); - -#endif /* _ASM_IA64_SN_SN1_SN_PRIVATE_H */ diff --git a/include/asm-ia64/sn/sn1/synergy.h b/include/asm-ia64/sn/sn1/synergy.h deleted file mode 100644 index f99dee05192..00000000000 --- a/include/asm-ia64/sn/sn1/synergy.h +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef _ASM_IA64_SN_SN1_SYNERGY_H -#define _ASM_IA64_SN_SN1_SYNERGY_H - -#include -#include -#include -#include - - -/* - * Definitions for the synergy asic driver - * - * These are for SGI platforms only. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#define SYNERGY_L4_BYTES (64UL*1024*1024) -#define SYNERGY_L4_WAYS 8 -#define SYNERGY_L4_BYTES_PER_WAY (SYNERGY_L4_BYTES/SYNERGY_L4_WAYS) -#define SYNERGY_BLOCK_SIZE 512UL - - -#define SSPEC_BASE (0xe0000000000UL) -#define LB_REG_BASE (SSPEC_BASE + 0x0) - -#define VEC_MASK3A_ADDR (0x2a0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK3B_ADDR (0x2a8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK3A (0x2a0) -#define VEC_MASK3B (0x2a8) - -#define VEC_MASK2A_ADDR (0x2b0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK2B_ADDR (0x2b8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK2A (0x2b0) -#define VEC_MASK2B (0x2b8) - -#define VEC_MASK1A_ADDR (0x2c0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK1B_ADDR (0x2c8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK1A (0x2c0) -#define VEC_MASK1B (0x2c8) - -#define VEC_MASK0A_ADDR (0x2d0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK0B_ADDR (0x2d8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK0A (0x2d0) -#define VEC_MASK0B (0x2d8) - -#define GBL_PERF_A_ADDR (0x330 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define GBL_PERF_B_ADDR (0x338 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) - -#define WRITE_LOCAL_SYNERGY_REG(addr, value) __synergy_out(addr, value) - -#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ -#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ -#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) -#define REMOTE_HSPEC(_n, _x) (HUBREG_CAST (RREG_BASE(_n) + (_x))) - -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) -#ifndef HSPEC_BASE -#define HSPEC_BASE (SYN_UNCACHED_SPACE | HSPEC_BASE_SYN) -#endif -#define SYN_UNCACHED_SPACE 0xc000000000000000 -#define HSPEC_BASE_SYN 0x00000b0000000000 -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#define NODE_SIZE_BITS 33 - -#define SYN_TAG_DISABLE_WAY (SSPEC_BASE+0xae0) - - -#define RSYN_REG_OFFSET(fsb, reg) (((fsb) ? HSPEC_SYNERGY1_0 : HSPEC_SYNERGY0_0) | (reg)) - -#define REMOTE_SYNERGY_LOAD(nasid, fsb, reg) __remote_synergy_in(nasid, fsb, reg) -#define REMOTE_SYNERGY_STORE(nasid, fsb, reg, val) __remote_synergy_out(nasid, fsb, reg, val) - -static inline uint64_t -__remote_synergy_in(int nasid, int fsb, uint64_t reg) { - volatile uint64_t *addr; - - addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, reg)); - return (*addr); -} - -static inline void -__remote_synergy_out(int nasid, int fsb, uint64_t reg, uint64_t value) { - volatile uint64_t *addr; - - addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, (reg<<2))); - *(addr+0) = value >> 48; - *(addr+1) = value >> 32; - *(addr+2) = value >> 16; - *(addr+3) = value; - __ia64_mf_a(); -} - -/* XX this doesn't make a lot of sense. Which fsb? */ -static inline void -__synergy_out(unsigned long addr, unsigned long value) -{ - volatile unsigned long *adr = (unsigned long *) - (addr | __IA64_UNCACHED_OFFSET); - - *adr = value; - __ia64_mf_a(); -} - -#define READ_LOCAL_SYNERGY_REG(addr) __synergy_in(addr) - -/* XX this doesn't make a lot of sense. Which fsb? */ -static inline unsigned long -__synergy_in(unsigned long addr) -{ - unsigned long ret, *adr = (unsigned long *) - (addr | __IA64_UNCACHED_OFFSET); - - ret = *adr; - __ia64_mf_a(); - return ret; -} - -struct sn1_intr_action { - void (*handler)(int, void *, struct pt_regs *); - void *intr_arg; - unsigned long flags; - struct sn1_intr_action * next; -}; - -typedef struct synergy_da_s { - hub_intmasks_t s_intmasks; -}synergy_da_t; - -struct sn1_cnode_action_list { - spinlock_t action_list_lock; - struct sn1_intr_action *action_list; -}; - -/* - * ioctl cmds for node/hub/synergy/[01]/mon for synergy - * perf monitoring are defined in sndrv.h - */ - -/* multiplex the counters every 10 timer interrupts */ -#define SYNERGY_PERF_FREQ_DEFAULT 10 - -/* macros for synergy "mon" device ioctl handler */ -#define SYNERGY_PERF_INFO(_s, _f) (arbitrary_info_t)(((_s) << 16)|(_f)) -#define SYNERGY_PERF_INFO_CNODE(_x) (cnodeid_t)(((uint64_t)_x) >> 16) -#define SYNERGY_PERF_INFO_FSB(_x) (((uint64_t)_x) & 1) - -/* synergy perf control registers */ -#define PERF_CNTL0_A 0xab0UL /* control A on FSB0 */ -#define PERF_CNTL0_B 0xab8UL /* control B on FSB0 */ -#define PERF_CNTL1_A 0xac0UL /* control A on FSB1 */ -#define PERF_CNTL1_B 0xac8UL /* control B on FSB1 */ - -/* synergy perf counters */ -#define PERF_CNTR0_A 0xad0UL /* counter A on FSB0 */ -#define PERF_CNTR0_B 0xad8UL /* counter B on FSB0 */ -#define PERF_CNTR1_A 0xaf0UL /* counter A on FSB1 */ -#define PERF_CNTR1_B 0xaf8UL /* counter B on FSB1 */ - -/* Synergy perf data. Each nodepda keeps a list of these */ -struct synergy_perf_s { - uint64_t intervals; /* count of active intervals for this event */ - uint64_t total_intervals;/* snapshot of total intervals */ - uint64_t modesel; /* mode and sel bits, both A and B registers */ - struct synergy_perf_s *next; /* next in circular linked list */ - uint64_t counts[2]; /* [0] is synergy-A counter, [1] synergy-B counter */ -}; - -typedef struct synergy_perf_s synergy_perf_t; - -typedef struct synergy_info_s synergy_info_t; - -extern void synergy_perf_init(void); -extern void synergy_perf_update(int); -extern struct file_operations synergy_mon_fops; - -#endif /* _ASM_IA64_SN_SN1_SYNERGY_H */ diff --git a/include/asm-ia64/sn/sn2/addrs.h b/include/asm-ia64/sn/sn2/addrs.h index ba12fbd2eed..c415366196b 100644 --- a/include/asm-ia64/sn/sn2/addrs.h +++ b/include/asm-ia64/sn/sn2/addrs.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ADDRS_H @@ -57,7 +57,7 @@ typedef union ia64_sn2_pa { #define LOCAL_MEM_SPACE 0xc000010000000000 /* Local Memory space */ #define GLOBAL_MMR_SPACE 0xc000000800000000 /* Global MMR space */ #define GLOBAL_PHYS_MMR_SPACE 0x0000000800000000 /* Global Physical MMR space */ -#define GET_SPACE 0xc000001000000000 /* GET space */ +#define GET_SPACE 0xe000001000000000 /* GET space */ #define AMO_SPACE 0xc000002000000000 /* AMO space */ #define CACHEABLE_MEM_SPACE 0xe000003000000000 /* Cacheable memory space */ #define UNCACHED 0xc000000000000000 /* UnCacheable memory space */ diff --git a/include/asm-ia64/sn/sn2/arch.h b/include/asm-ia64/sn/sn2/arch.h index d630ed226f1..f31578259dd 100644 --- a/include/asm-ia64/sn/sn2/arch.h +++ b/include/asm-ia64/sn/sn2/arch.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ARCH_H #define _ASM_IA64_SN_SN2_ARCH_H @@ -46,6 +46,7 @@ #define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) +#define CNASID_MASK_BYTES (NASID_MASK_BYTES / 2) /* diff --git a/include/asm-ia64/sn/sn2/intr.h b/include/asm-ia64/sn/sn2/intr.h index 09cb8319474..d021292d9bf 100644 --- a/include/asm-ia64/sn/sn2/intr.h +++ b/include/asm-ia64/sn/sn2/intr.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_INTR_H #define _ASM_IA64_SN_SN2_INTR_H @@ -14,13 +14,17 @@ // These two IRQ's are used by partitioning. #define SGI_XPC_ACTIVATE (0x30) +#define SGI_II_ERROR (0x31) +#define SGI_XBOW_ERROR (0x32) +#define SGI_PCIBR_ERROR (0x33) #define SGI_XPC_NOTIFY (0xe7) -#define IA64_SN2_FIRST_DEVICE_VECTOR (0x31) +#define IA64_SN2_FIRST_DEVICE_VECTOR (0x34) #define IA64_SN2_LAST_DEVICE_VECTOR (0xe6) #define SN2_IRQ_RESERVED (0x1) #define SN2_IRQ_CONNECTED (0x2) +#define SN2_IRQ_SHARED (0x4) #define SN2_IRQ_PER_HUB (2048) diff --git a/include/asm-ia64/sn/sn2/io.h b/include/asm-ia64/sn/sn2/io.h index b0c928f0191..eff4f8641b1 100644 --- a/include/asm-ia64/sn/sn2/io.h +++ b/include/asm-ia64/sn/sn2/io.h @@ -32,8 +32,8 @@ __sn_inb (unsigned long port) unsigned char ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -44,8 +44,8 @@ __sn_inw (unsigned long port) unsigned short ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -56,8 +56,8 @@ __sn_inl (unsigned long port) unsigned int ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -103,6 +103,7 @@ __sn_readb (void *addr) unsigned char val; val = *(volatile unsigned char *)addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -113,6 +114,7 @@ __sn_readw (void *addr) unsigned short val; val = *(volatile unsigned short *)addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -123,6 +125,7 @@ __sn_readl (void *addr) unsigned int val; val = *(volatile unsigned int *) addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -133,6 +136,7 @@ __sn_readq (void *addr) unsigned long val; val = *(volatile unsigned long *) addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } diff --git a/include/asm-ia64/sn/sn2/mmzone_sn2.h b/include/asm-ia64/sn/sn2/mmzone_sn2.h deleted file mode 100644 index e495529d787..00000000000 --- a/include/asm-ia64/sn/sn2/mmzone_sn2.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _ASM_IA64_SN_MMZONE_SN2_H -#define _ASM_IA64_SN_MMZONE_SN2_H - -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include - - -/* - * SGI SN2 Arch defined values - * - * An SN2 physical address is broken down as follows: - * - * +-----------------------------------------+ - * | | | | node offset | - * | unused | node | AS |-------------------| - * | | | | cn | clump offset | - * +-----------------------------------------+ - * 6 4 4 3 3 3 3 3 3 0 - * 3 9 8 8 7 6 5 4 3 0 - * - * bits 63-49 Unused - must be zero - * bits 48-38 Node number. Note that some configurations do NOT - * have a node zero. - * bits 37-36 Address space ID. Cached memory has a value of 3 (!!!). - * Chipset & IO addresses have other values. - * (Yikes!! The hardware folks hate us...) - * bits 35-0 Node offset. - * - * The node offset can be further broken down as: - * bits 35-34 Clump (bank) number. - * bits 33-0 Clump (bank) offset. - * - * A node consists of up to 4 clumps (banks) of memory. A clump may be empty, or may be - * populated with a single contiguous block of memory starting at clump - * offset 0. The size of the block is (2**n) * 64MB, where 0> SN2_NODE_SHIFT) & SN2_NODE_MASK) -#define SN2_NODE_CLUMP_NUMBER(kaddr) (((unsigned long)(kaddr) >>34) & 3) -#define SN2_NODE_OFFSET(addr) (((unsigned long)(addr)) & SN2_NODE_OFFSET_MASK) -#define SN2_KADDR(nasid, offset) (((unsigned long)(nasid)<>2) | \ - (_p&SN2_NODE_OFFSET_MASK)) >>SN2_CHUNKSHIFT;}) - -/* - * Given a kaddr, find the nid (compact nodeid) - */ -#ifdef CONFIG_IA64_SGI_SN_DEBUG -#define DISCONBUG(kaddr) panic("DISCONTIG BUG: line %d, %s. kaddr 0x%lx", \ - __LINE__, __FILE__, (long)(kaddr)) - -#define KVADDR_TO_NID(kaddr) ({long _ktn=(long)(kaddr); \ - kern_addr_valid(_ktn) ? \ - local_node_data->physical_node_map[SN2_NODE_NUMBER(_ktn)] : \ - (DISCONBUG(_ktn), 0UL);}) -#else -#define KVADDR_TO_NID(kaddr) (local_node_data->physical_node_map[SN2_NODE_NUMBER(kaddr)]) -#endif - - - -/* - * Given a kaddr, find the index into the clump_mem_map_base array of the page struct entry - * for the first page of the clump. - */ -#define PLAT_CLUMP_MEM_MAP_INDEX(kaddr) ({long _kmmi=(long)(kaddr); \ - KVADDR_TO_NID(_kmmi) * PLAT_CLUMPS_PER_NODE + \ - SN2_NODE_CLUMP_NUMBER(_kmmi);}) - - - -/* - * Calculate a "goal" value to be passed to __alloc_bootmem_node for allocating structures on - * nodes so that they don't alias to the same line in the cache as the previous allocated structure. - * This macro takes an address of the end of previous allocation, rounds it to a page boundary & - * changes the node number. - */ -#define PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) __pa(SN2_KADDR(PLAT_PXM_TO_PHYS_NODE_NUMBER(nid_to_pxm_map[cnode]), \ - (SN2_NODE_OFFSET(kaddr) + PAGE_SIZE - 1) >> PAGE_SHIFT << PAGE_SHIFT)) - - - - -/* - * Convert a proximity domain number (from the ACPI tables) into a physical node number. - * Note: on SN2, the promity domain number is the same as bits [8:1] of the NASID. The following - * algorithm relies on: - * - bit 0 of the NASID for cpu nodes is always 0 - * - bits [10:9] of all NASIDs in a partition are always the same - * - hard_smp_processor_id return the SAPIC of the current cpu & - * bits 0..11 contain the NASID. - * - * All of this complexity is because MS architectually limited proximity domain numbers to - * 8 bits. - */ - -#define PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) (((pxm)<<1) | (hard_smp_processor_id() & 0x300)) - -#endif /* _ASM_IA64_SN_MMZONE_SN2_H */ diff --git a/include/asm-ia64/sn/sn2/shub.h b/include/asm-ia64/sn/sn2/shub.h index 2c6719107c8..4547ff44055 100644 --- a/include/asm-ia64/sn/sn2/shub.h +++ b/include/asm-ia64/sn/sn2/shub.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff --git a/include/asm-ia64/sn/sn2/shub_md.h b/include/asm-ia64/sn/sn2/shub_md.h index 874b1c30a96..2c4a7dc3b4f 100644 --- a/include/asm-ia64/sn/sn2/shub_md.h +++ b/include/asm-ia64/sn/sn2/shub_md.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001, 2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001, 2002-2003 Silicon Graphics, Inc. All rights reserved. */ diff --git a/include/asm-ia64/sn/sn2/shub_mmr.h b/include/asm-ia64/sn/sn2/shub_mmr.h index 61aa480414d..05ea7efaf45 100644 --- a/include/asm-ia64/sn/sn2/shub_mmr.h +++ b/include/asm-ia64/sn/sn2/shub_mmr.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -25746,14 +25746,14 @@ /* Real-time Clock */ /* ==================================================================== */ -#define SH_RTC 0x00000001101c0000 -#define SH_RTC_MASK 0x007fffffffffffff +#define SH_RTC 0x00000001101c0000UL +#define SH_RTC_MASK 0x007fffffffffffffUL #define SH_RTC_INIT 0x0000000000000000 /* SH_RTC_REAL_TIME_CLOCK */ /* Description: Real-time Clock */ #define SH_RTC_REAL_TIME_CLOCK_SHFT 0 -#define SH_RTC_REAL_TIME_CLOCK_MASK 0x007fffffffffffff +#define SH_RTC_REAL_TIME_CLOCK_MASK 0x007fffffffffffffUL /* ==================================================================== */ /* Register "SH_SCRATCH0" */ diff --git a/include/asm-ia64/sn/sn2/shub_mmr_t.h b/include/asm-ia64/sn/sn2/shub_mmr_t.h index d2cef5e24a8..f0397c40075 100644 --- a/include/asm-ia64/sn/sn2/shub_mmr_t.h +++ b/include/asm-ia64/sn/sn2/shub_mmr_t.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff --git a/include/asm-ia64/sn/sn2/shubio.h b/include/asm-ia64/sn/sn2/shubio.h index 51c33b67c9c..1e6780c26a8 100644 --- a/include/asm-ia64/sn/sn2/shubio.h +++ b/include/asm-ia64/sn/sn2/shubio.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SHUBIO_H @@ -3035,31 +3035,31 @@ typedef union ii_ippr_u { /* Scratch registers (all bits available) */ #define IIO_SCRATCH_REG0 IIO_ISCR0 #define IIO_SCRATCH_REG1 IIO_ISCR1 -#define IIO_SCRATCH_MASK 0xffffffffffffffff - -#define IIO_SCRATCH_BIT0_0 0x0000000000000001 -#define IIO_SCRATCH_BIT0_1 0x0000000000000002 -#define IIO_SCRATCH_BIT0_2 0x0000000000000004 -#define IIO_SCRATCH_BIT0_3 0x0000000000000008 -#define IIO_SCRATCH_BIT0_4 0x0000000000000010 -#define IIO_SCRATCH_BIT0_5 0x0000000000000020 -#define IIO_SCRATCH_BIT0_6 0x0000000000000040 -#define IIO_SCRATCH_BIT0_7 0x0000000000000080 -#define IIO_SCRATCH_BIT0_8 0x0000000000000100 -#define IIO_SCRATCH_BIT0_9 0x0000000000000200 -#define IIO_SCRATCH_BIT0_A 0x0000000000000400 - -#define IIO_SCRATCH_BIT1_0 0x0000000000000001 -#define IIO_SCRATCH_BIT1_1 0x0000000000000002 +#define IIO_SCRATCH_MASK 0xffffffffffffffffUL + +#define IIO_SCRATCH_BIT0_0 0x0000000000000001UL +#define IIO_SCRATCH_BIT0_1 0x0000000000000002UL +#define IIO_SCRATCH_BIT0_2 0x0000000000000004UL +#define IIO_SCRATCH_BIT0_3 0x0000000000000008UL +#define IIO_SCRATCH_BIT0_4 0x0000000000000010UL +#define IIO_SCRATCH_BIT0_5 0x0000000000000020UL +#define IIO_SCRATCH_BIT0_6 0x0000000000000040UL +#define IIO_SCRATCH_BIT0_7 0x0000000000000080UL +#define IIO_SCRATCH_BIT0_8 0x0000000000000100UL +#define IIO_SCRATCH_BIT0_9 0x0000000000000200UL +#define IIO_SCRATCH_BIT0_A 0x0000000000000400UL + +#define IIO_SCRATCH_BIT1_0 0x0000000000000001UL +#define IIO_SCRATCH_BIT1_1 0x0000000000000002UL /* IO Translation Table Entries */ #define IIO_NUM_ITTES 7 /* ITTEs numbered 0..6 */ /* Hw manuals number them 1..7! */ /* * IIO_IMEM Register fields. */ -#define IIO_IMEM_W0ESD 0x1 /* Widget 0 shut down due to error */ -#define IIO_IMEM_B0ESD (1 << 4) /* BTE 0 shut down due to error */ -#define IIO_IMEM_B1ESD (1 << 8) /* BTE 1 Shut down due to error */ +#define IIO_IMEM_W0ESD 0x1UL /* Widget 0 shut down due to error */ +#define IIO_IMEM_B0ESD (1UL << 4) /* BTE 0 shut down due to error */ +#define IIO_IMEM_B1ESD (1UL << 8) /* BTE 1 Shut down due to error */ /* * As a permanent workaround for a bug in the PI side of the shub, we've @@ -3191,23 +3191,23 @@ typedef union ii_ippr_u { /* * IO BTE Length/Status (IIO_IBLS) register bit field definitions */ -#define IBLS_BUSY (0x1 << 20) +#define IBLS_BUSY (0x1UL << 20) #define IBLS_ERROR_SHFT 16 -#define IBLS_ERROR (0x1 << IBLS_ERROR_SHFT) +#define IBLS_ERROR (0x1UL << IBLS_ERROR_SHFT) #define IBLS_LENGTH_MASK 0xffff /* * IO BTE Control/Terminate register (IBCT) register bit field definitions */ -#define IBCT_POISON (0x1 << 8) -#define IBCT_NOTIFY (0x1 << 4) -#define IBCT_ZFIL_MODE (0x1 << 0) +#define IBCT_POISON (0x1UL << 8) +#define IBCT_NOTIFY (0x1UL << 4) +#define IBCT_ZFIL_MODE (0x1UL << 0) /* * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2) */ -#define IIEPH1_VALID (1 << 44) -#define IIEPH1_OVERRUN (1 << 40) +#define IIEPH1_VALID (1UL << 44) +#define IIEPH1_OVERRUN (1UL << 40) #define IIEPH1_ERR_TYPE_SHFT 32 #define IIEPH1_ERR_TYPE_MASK 0xf #define IIEPH1_SOURCE_SHFT 20 @@ -3217,7 +3217,7 @@ typedef union ii_ippr_u { #define IIEPH1_CMD_SHFT 0 #define IIEPH1_CMD_MASK 7 -#define IIEPH2_TAIL (1 << 40) +#define IIEPH2_TAIL (1UL << 40) #define IIEPH2_ADDRESS_SHFT 0 #define IIEPH2_ADDRESS_MASK 38 @@ -3229,21 +3229,21 @@ typedef union ii_ippr_u { /* * IO Error Clear register bit field definitions */ -#define IECLR_PI1_FWD_INT (1 << 31) /* clear PI1_FORWARD_INT in iidsr */ -#define IECLR_PI0_FWD_INT (1 << 30) /* clear PI0_FORWARD_INT in iidsr */ -#define IECLR_SPUR_RD_HDR (1 << 29) /* clear valid bit in ixss reg */ -#define IECLR_BTE1 (1 << 18) /* clear bte error 1 */ -#define IECLR_BTE0 (1 << 17) /* clear bte error 0 */ -#define IECLR_CRAZY (1 << 16) /* clear crazy bit in wstat reg */ -#define IECLR_PRB_F (1 << 15) /* clear err bit in PRB_F reg */ -#define IECLR_PRB_E (1 << 14) /* clear err bit in PRB_E reg */ -#define IECLR_PRB_D (1 << 13) /* clear err bit in PRB_D reg */ -#define IECLR_PRB_C (1 << 12) /* clear err bit in PRB_C reg */ -#define IECLR_PRB_B (1 << 11) /* clear err bit in PRB_B reg */ -#define IECLR_PRB_A (1 << 10) /* clear err bit in PRB_A reg */ -#define IECLR_PRB_9 (1 << 9) /* clear err bit in PRB_9 reg */ -#define IECLR_PRB_8 (1 << 8) /* clear err bit in PRB_8 reg */ -#define IECLR_PRB_0 (1 << 0) /* clear err bit in PRB_0 reg */ +#define IECLR_PI1_FWD_INT (1UL << 31) /* clear PI1_FORWARD_INT in iidsr */ +#define IECLR_PI0_FWD_INT (1UL << 30) /* clear PI0_FORWARD_INT in iidsr */ +#define IECLR_SPUR_RD_HDR (1UL << 29) /* clear valid bit in ixss reg */ +#define IECLR_BTE1 (1UL << 18) /* clear bte error 1 */ +#define IECLR_BTE0 (1UL << 17) /* clear bte error 0 */ +#define IECLR_CRAZY (1UL << 16) /* clear crazy bit in wstat reg */ +#define IECLR_PRB_F (1UL << 15) /* clear err bit in PRB_F reg */ +#define IECLR_PRB_E (1UL << 14) /* clear err bit in PRB_E reg */ +#define IECLR_PRB_D (1UL << 13) /* clear err bit in PRB_D reg */ +#define IECLR_PRB_C (1UL << 12) /* clear err bit in PRB_C reg */ +#define IECLR_PRB_B (1UL << 11) /* clear err bit in PRB_B reg */ +#define IECLR_PRB_A (1UL << 10) /* clear err bit in PRB_A reg */ +#define IECLR_PRB_9 (1UL << 9) /* clear err bit in PRB_9 reg */ +#define IECLR_PRB_8 (1UL << 8) /* clear err bit in PRB_8 reg */ +#define IECLR_PRB_0 (1UL << 0) /* clear err bit in PRB_0 reg */ /* * IIO CRB control register Fields: IIO_ICCR @@ -3495,7 +3495,7 @@ typedef union iprte_a { typedef struct hub_piomap_s *hub_piomap_t; extern hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +hub_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -3513,7 +3513,7 @@ extern void hub_piomap_done(hub_piomap_t hub_piomap); extern caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ +hub_piotrans_addr( vertex_hdl_t dev, /* translate to this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -3523,7 +3523,7 @@ hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ typedef struct hub_dmamap_s *hub_dmamap_t; extern hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for dev */ +hub_dmamap_alloc( vertex_hdl_t dev, /* set up mappings for dev */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -3545,14 +3545,14 @@ extern void hub_dmamap_done( hub_dmamap_t dmamap); /* done w/ mapping resources */ extern iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_addr( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); /* defined in dma.h */ extern alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_list( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system addr/length list */ unsigned flags); /* defined in dma.h */ @@ -3561,12 +3561,12 @@ extern void hub_dmamap_drain( hub_dmamap_t map); extern void -hub_dmaaddr_drain( devfs_handle_t vhdl, +hub_dmaaddr_drain( vertex_hdl_t vhdl, paddr_t addr, size_t bytes); extern void -hub_dmalist_drain( devfs_handle_t vhdl, +hub_dmalist_drain( vertex_hdl_t vhdl, alenlist_t list); @@ -3574,14 +3574,14 @@ hub_dmalist_drain( devfs_handle_t vhdl, typedef struct hub_intr_s *hub_intr_t; extern hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which device */ +hub_intr_alloc( vertex_hdl_t dev, /* which device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ + vertex_hdl_t owner_dev); /* owner of this interrupt */ extern hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ +hub_intr_alloc_nothd(vertex_hdl_t dev, /* which device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ + vertex_hdl_t owner_dev); /* owner of this interrupt */ extern void hub_intr_free(hub_intr_t intr_hdl); @@ -3596,16 +3596,14 @@ hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource hndl */ extern void hub_intr_disconnect(hub_intr_t intr_hdl); -extern devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl); /* CONFIGURATION MANAGEMENT */ extern void -hub_provider_startup(devfs_handle_t hub); +hub_provider_startup(vertex_hdl_t hub); extern void -hub_provider_shutdown(devfs_handle_t hub); +hub_provider_shutdown(vertex_hdl_t hub); #define HUB_PIO_CONVEYOR 0x1 /* PIO in conveyor belt mode */ #define HUB_PIO_FIRE_N_FORGET 0x2 /* PIO in fire-and-forget mode */ @@ -3619,38 +3617,17 @@ hub_provider_shutdown(devfs_handle_t hub); typedef int hub_widget_flags_t; -/* Set the PIO mode for a widget. These two functions perform the - * same operation, but hub_device_flags_set() takes a hardware graph - * vertex while hub_widget_flags_set() takes a nasid and widget - * number. In most cases, hub_device_flags_set() should be used. - */ +/* Set the PIO mode for a widget. */ extern int hub_widget_flags_set(nasid_t nasid, xwidgetnum_t widget_num, hub_widget_flags_t flags); -/* Depending on the flags set take the appropriate actions */ -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); - - /* Error Handling. */ -extern int hub_ioerror_handler(devfs_handle_t, int, int, struct io_error_s *); +extern int hub_ioerror_handler(vertex_hdl_t, int, int, struct io_error_s *); extern int kl_ioerror_handler(cnodeid_t, cnodeid_t, cpuid_t, int, paddr_t, caddr_t, ioerror_mode_t); -extern void hub_widget_reset(devfs_handle_t, xwidgetnum_t); -extern int hub_error_devenable(devfs_handle_t, int, int); -extern void hub_widgetdev_enable(devfs_handle_t, int); -extern void hub_widgetdev_shutdown(devfs_handle_t, int); -extern int hub_dma_enabled(devfs_handle_t); - -/* hubdev */ -extern void hubdev_init(void); -extern void hubdev_register(int (*attach_method)(devfs_handle_t)); -extern int hubdev_unregister(int (*attach_method)(devfs_handle_t)); -extern int hubdev_docallouts(devfs_handle_t hub); - -extern caddr_t hubdev_prombase_get(devfs_handle_t hub); -extern cnodeid_t hubdev_cnodeid_get(devfs_handle_t hub); +extern int hub_error_devenable(vertex_hdl_t, int, int); +extern int hub_dma_enabled(vertex_hdl_t); #endif /* __ASSEMBLY__ */ #endif /* _KERNEL */ diff --git a/include/asm-ia64/sn/sn2/slotnum.h b/include/asm-ia64/sn/sn2/slotnum.h index 3ebb4ba93a4..03146d5e6cb 100644 --- a/include/asm-ia64/sn/sn2/slotnum.h +++ b/include/asm-ia64/sn/sn2/slotnum.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992 - 1997,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SLOTNUM_H diff --git a/include/asm-ia64/sn/sn2/sn_private.h b/include/asm-ia64/sn/sn2/sn_private.h index 51baf4015dc..5b553d81c79 100644 --- a/include/asm-ia64/sn/sn2/sn_private.h +++ b/include/asm-ia64/sn/sn2/sn_private.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SN_PRIVATE_H #define _ASM_IA64_SN_SN2_SN_PRIVATE_H @@ -49,13 +49,13 @@ extern void get_dir_ent(paddr_t paddr, int *state, #endif /* intr.c */ -extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name); +extern int intr_reserve_level(cpuid_t cpu, int level, int err, vertex_hdl_t owner_dev, char *name); extern void intr_unreserve_level(cpuid_t cpu, int level); extern int intr_connect_level(cpuid_t cpu, int bit, ilvl_t mask_no, intr_func_t intr_prefunc); extern int intr_disconnect_level(cpuid_t cpu, int bit); -extern cpuid_t intr_heuristic(devfs_handle_t dev, device_desc_t dev_desc, - int req_bit,int intr_resflags,devfs_handle_t owner_dev, +extern cpuid_t intr_heuristic(vertex_hdl_t dev, device_desc_t dev_desc, + int req_bit,int intr_resflags,vertex_hdl_t owner_dev, char *intr_name,int *resp_bit); extern void intr_block_bit(cpuid_t cpu, int bit); extern void intr_unblock_bit(cpuid_t cpu, int bit); @@ -83,8 +83,8 @@ void bte_lateinit(void); void bte_wait_for_xfer_completion(void *); /* klgraph.c */ -void klhwg_add_all_nodes(devfs_handle_t); -void klhwg_add_all_modules(devfs_handle_t); +void klhwg_add_all_nodes(vertex_hdl_t); +void klhwg_add_all_modules(vertex_hdl_t); /* klidbg.c */ void install_klidbg_functions(void); @@ -97,7 +97,6 @@ extern void setup_replication_mask(int maxnodes); /* init.c */ extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); -extern void init_platform_pda(cpuid_t cpu); extern void per_cpu_init(void); extern int is_fine_dirmode(void); extern void update_node_information(cnodeid_t); @@ -125,7 +124,7 @@ extern __psunsigned_t debugger_stopped; */ struct hub_piomap_s { struct xtalk_piomap_s hpio_xtalk_info;/* standard crosstalk pio info */ - devfs_handle_t hpio_hub; /* which shub's mapping registers are set up */ + vertex_hdl_t hpio_hub; /* which shub's mapping registers are set up */ short hpio_holdcnt; /* count of current users of bigwin mapping */ char hpio_bigwin_num;/* if big window map, which one */ int hpio_flags; /* defined below */ @@ -146,7 +145,7 @@ struct hub_piomap_s { */ struct hub_dmamap_s { struct xtalk_dmamap_s hdma_xtalk_info;/* standard crosstalk dma info */ - devfs_handle_t hdma_hub; /* which shub we go through */ + vertex_hdl_t hdma_hub; /* which shub we go through */ int hdma_flags; /* defined below */ }; /* shub_dmamap flags */ @@ -214,7 +213,7 @@ typedef struct cpuinfo_s { (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t)infoptr) /* Special initialization function for xswitch vertices created during startup. */ -extern void xswitch_vertex_init(devfs_handle_t xswitch); +extern void xswitch_vertex_init(vertex_hdl_t xswitch); extern xtalk_provider_t hub_provider; @@ -248,6 +247,6 @@ extern void crbx(nasid_t nasid, void (*pf)(char *, ...)); void bootstrap(void); /* sndrv.c */ -extern int sndrv_attach(devfs_handle_t vertex); +extern int sndrv_attach(vertex_hdl_t vertex); #endif /* _ASM_IA64_SN_SN2_SN_PRIVATE_H */ diff --git a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h index 3a56e4aeff3..74dd5a6d246 100644 --- a/include/asm-ia64/sn/sn_cpuid.h +++ b/include/asm-ia64/sn/sn_cpuid.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -18,6 +18,7 @@ #include #include #include +#include /* @@ -51,11 +52,6 @@ * * LID - processor defined register (see PRM V2). * - * On SN1 - * 31:24 - id Contains the NASID - * 23:16 - eid Contains 0-3 to identify the cpu on the node - * bit 17 - synergy number - * bit 16 - FSB slot number * On SN2 * 31:28 - id Contains 0-3 to identify the cpu on the node * 27:16 - eid Contains the NASID @@ -64,34 +60,30 @@ * * The following assumes the following mappings for LID register values: * - * The macros convert between cpu physical ids & slice/fsb/synergy/nasid/cnodeid. + * The macros convert between cpu physical ids & slice/nasid/cnodeid. * These terms are described below: * * + * Brick * ----- ----- ----- ----- CPU - * | 0 | | 1 | | 2 | | 3 | SLICE + * | 0 | | 1 | | 0 | | 1 | SLICE * ----- ----- ----- ----- * | | | | * | | | | - * 0 | | 1 0 | | 1 FSB SLOT + * 0 | | 2 0 | | 2 FSB SLOT * ------- ------- * | | * | | - * ------- ------- - * | | | | - * | 0 | | 1 | SYNERGY (SN1 only) - * | | | | - * ------- ------- * | | - * | | - * ------------------------------- - * | | - * | BEDROCK / SHUB | NASID (0..MAX_NASIDS) - * | | CNODEID (0..num_compact_nodes-1) - * | | - * | | - * ------------------------------- - * | + * ------------ ------------- + * | | | | + * | SHUB | | SHUB | NASID (0..MAX_NASIDS) + * | |----- | | CNODEID (0..num_compact_nodes-1) + * | | | | + * | | | | + * ------------ ------------- + * | | + * * */ @@ -100,25 +92,15 @@ #define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) #endif -#ifdef CONFIG_IA64_SGI_SN1 /* * macros for some of these exist in sn/addrs.h & sn/arch.h, etc. However, * trying #include these files here causes circular dependencies. */ -#define cpu_physical_id_to_nasid(cpi) ((cpi) >> 8) -#define cpu_physical_id_to_synergy(cpi) (((cpi) >> 1) & 1) -#define cpu_physical_id_to_fsb_slot(cpi) ((cpi) & 1) -#define cpu_physical_id_to_slice(cpi) ((cpi) & 3) -#define get_nasid() ((ia64_get_lid() >> 24)) -#define get_slice() ((ia64_get_lid() >> 16) & 3) -#define get_node_number(addr) (((unsigned long)(addr)>>33) & 0x7f) -#else #define cpu_physical_id_to_nasid(cpi) ((cpi) &0xfff) #define cpu_physical_id_to_slice(cpi) ((cpi>>12) & 3) #define get_nasid() ((ia64_get_lid() >> 16) & 0xfff) #define get_slice() ((ia64_get_lid() >> 28) & 0xf) #define get_node_number(addr) (((unsigned long)(addr)>>38) & 0x7ff) -#endif /* * NOTE: id & eid refer to Intel's definitions of the LID register @@ -129,11 +111,7 @@ #define nasid_slice_to_cpuid(nasid,slice) (cpu_logical_id(nasid_slice_to_cpu_physical_id((nasid),(slice)))) -#ifdef CONFIG_IA64_SGI_SN1 -#define nasid_slice_to_cpu_physical_id(nasid, slice) (((nasid)<<8) | (slice)) -#else #define nasid_slice_to_cpu_physical_id(nasid, slice) (((slice)<<12) | (nasid)) -#endif /* * The following table/struct is used for managing PTC coherency domains. @@ -145,26 +123,9 @@ typedef struct { } sn_sapicid_info_t; extern sn_sapicid_info_t sn_sapicid_info[]; /* indexed by cpuid */ +extern short physical_node_map[]; /* indexed by nasid to get cnode */ - -#ifdef CONFIG_IA64_SGI_SN1 -/* - * cpuid_to_fsb_slot - convert a cpuid to the fsb slot number that it is in. - * (there are 2 cpus per FSB. This function returns 0 or 1) - */ -#define cpuid_to_fsb_slot(cpuid) (cpu_physical_id_to_fsb_slot(cpu_physical_id(cpuid))) - - -/* - * cpuid_to_synergy - convert a cpuid to the synergy that it resides on - * (there are 2 synergies per node. Function returns 0 or 1 to - * specify which synergy the cpu is on) - */ -#define cpuid_to_synergy(cpuid) (cpu_physical_id_to_synergy(cpu_physical_id(cpuid))) - -#endif - /* * cpuid_to_slice - convert a cpuid to the slice that it resides on * There are 4 cpus per node. This function returns 0 .. 3) @@ -181,7 +142,7 @@ extern sn_sapicid_info_t sn_sapicid_info[]; /* indexed by cpuid */ /* * cpuid_to_cnodeid - convert a cpuid to the cnode that it resides on */ -#define cpuid_to_cnodeid(cpuid) (local_node_data->physical_node_map[cpuid_to_nasid(cpuid)]) +#define cpuid_to_cnodeid(cpuid) (physical_node_map[cpuid_to_nasid(cpuid)]) /* @@ -190,13 +151,13 @@ extern sn_sapicid_info_t sn_sapicid_info[]; /* indexed by cpuid */ * Just extract the NASID from the pointer. * */ -#define cnodeid_to_nasid(cnodeid) (get_node_number(local_node_data->pg_data_ptrs[cnodeid])) +#define cnodeid_to_nasid(cnodeid) pda->cnodeid_to_nasid_table[cnodeid] /* * nasid_to_cnodeid - convert a NASID to a cnodeid */ -#define nasid_to_cnodeid(nasid) (nasid) /* (local_node_data->physical_node_map[nasid]) */ +#define nasid_to_cnodeid(nasid) (physical_node_map[nasid]) /* @@ -214,23 +175,8 @@ extern sn_sapicid_info_t sn_sapicid_info[]; /* indexed by cpuid */ #define cpuid_to_subnode(cpuid) ((cpuid_to_slice(cpuid)<2) ? 0 : 1) -/* - * cpuid_to_localslice - convert a cpuid to a local slice - * slice 0 & 2 are local slice 0 - * slice 1 & 3 are local slice 1 - */ -#define cpuid_to_localslice(cpuid) (cpuid_to_slice(cpuid) & 1) - - #define smp_physical_node_id() (cpuid_to_nasid(smp_processor_id())) -/* - * cnodeid_to_cpuid - convert a cnode to a cpuid of a cpu on the node. - * returns -1 if no cpus exist on the node - */ -extern int cnodeid_to_cpuid(int cnode); - - #endif /* _ASM_IA64_SN_SN_CPUID_H */ diff --git a/include/asm-ia64/sn/sn_fru.h b/include/asm-ia64/sn/sn_fru.h index f2800c17805..c70bb7ea1fc 100644 --- a/include/asm-ia64/sn/sn_fru.h +++ b/include/asm-ia64/sn/sn_fru.h @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 1999-2001 Silicon Graphics, Inc. - * All rights reserved. + * Copyright (C) 1992-1997,1999-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_FRU_H #define _ASM_IA64_SN_SN_FRU_H diff --git a/include/asm-ia64/sn/sn_pio_sync.h b/include/asm-ia64/sn/sn_pio_sync.h deleted file mode 100644 index 1fc590447ee..00000000000 --- a/include/asm-ia64/sn/sn_pio_sync.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H -#define _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H - -#include -#ifdef CONFIG_IA64_SGI_SN2 -#include -#include -#include -#include - -/* - * This macro flushes all outstanding PIOs performed by this cpu to the - * intended destination SHUB. This in essence ensures that all PIO's - * issues by this cpu has landed at it's destination. - * - * This macro expects the caller: - * 1. The thread is locked. - * 2. All prior PIO operations has been fenced with __ia64_mf_a(). - * - * The expectation is that get_slice() will return either 0 or 2. - * When we have multi-core cpu's, the expectation is get_slice() will - * return either 0,1 or 2,3. - */ - -#define SN_PIO_WRITE_SYNC \ - { \ - volatile unsigned long sn_pio_writes_done; \ - do { \ - sn_pio_writes_done = (volatile unsigned long) (SH_PIO_WRITE_STATUS_0_WRITES_OK_MASK & HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(get_nasid(), (get_slice() < 2) ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ))); \ - } while (!sn_pio_writes_done); \ - __ia64_mf_a(); \ - } -#else - -/* - * For all ARCHITECTURE type, this is a NOOP. - */ - -#define SN_PIO_WRITE_SYNC - -#endif - -#endif /* _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H */ diff --git a/include/asm-ia64/sn/sn_private.h b/include/asm-ia64/sn/sn_private.h index e382cb5d80e..4fd2074bd54 100644 --- a/include/asm-ia64/sn/sn_private.h +++ b/include/asm-ia64/sn/sn_private.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_PRIVATE_H #define _ASM_IA64_SN_SN_PRIVATE_H @@ -14,10 +14,6 @@ #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif #endif /* _ASM_IA64_SN_SN_PRIVATE_H */ diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index e1f1b3e4d0a..66fd8ef46c7 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -8,7 +8,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -36,6 +36,8 @@ #define SN_SAL_CONSOLE_POLL 0x02000026 #define SN_SAL_CONSOLE_INTR 0x02000027 #define SN_SAL_CONSOLE_PUTB 0x02000028 +#define SN_SAL_CONSOLE_XMIT_CHARS 0x0200002a +#define SN_SAL_CONSOLE_READC 0x0200002b #define SN_SAL_SYSCTL_MODID_GET 0x02000031 #define SN_SAL_SYSCTL_GET 0x02000032 #define SN_SAL_SYSCTL_IOBRICK_MODULE_GET 0x02000033 @@ -47,17 +49,22 @@ #define SN_SAL_SYSCTL_PARTITION_GET 0x0200003a #define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b #define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c +#define SN_SAL_COHERENCE 0x0200003d +#define SN_SAL_SYSCTL_FRU_CAPTURE 0x0200003f /* * Service-specific constants */ -#define SAL_CONSOLE_INTR_IN 0 /* manipulate input interrupts */ -#define SAL_CONSOLE_INTR_OUT 1 /* manipulate output low-water - * interrupts - */ + +/* Console interrupt manipulation */ + /* action codes */ #define SAL_CONSOLE_INTR_OFF 0 /* turn the interrupt off */ #define SAL_CONSOLE_INTR_ON 1 /* turn the interrupt on */ +#define SAL_CONSOLE_INTR_STATUS 2 /* retrieve the interrupt status */ + /* interrupt specification & status return codes */ +#define SAL_CONSOLE_INTR_XMIT 1 /* output interrupt */ +#define SAL_CONSOLE_INTR_RECV 2 /* input interrupt */ /* @@ -103,15 +110,8 @@ sn_sal_rev_minor(void) * Specify the minimum PROM revsion required for this kernel. * Note that they're stored in hex format... */ -#ifdef CONFIG_IA64_SGI_SN1 -#define SN_SAL_MIN_MAJOR 0x0 -#define SN_SAL_MIN_MINOR 0x03 /* SN1 PROMs are stuck at rev 0.03 */ -#elif defined(CONFIG_IA64_SGI_SN2) -#define SN_SAL_MIN_MAJOR 0x0 -#define SN_SAL_MIN_MINOR 0x11 -#else -#error "must specify which PROM revisions this kernel needs" -#endif /* CONFIG_IA64_SGI_SN1 */ +#define SN_SAL_MIN_MAJOR 0x1 /* SN2 kernels need at least PROM 1.0 */ +#define SN_SAL_MIN_MINOR 0x0 u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr); @@ -124,10 +124,10 @@ ia64_sn_get_console_nasid(void) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0); if (ret_stuff.status < 0) @@ -146,10 +146,10 @@ ia64_sn_get_master_baseio_nasid(void) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0); if (ret_stuff.status < 0) @@ -166,12 +166,12 @@ ia64_sn_get_klconfig_addr(nasid_t nasid) extern u64 klgraph_addr[]; int cnodeid; - cnodeid = 0 /* nasid_to_cnodeid(nasid) */; + cnodeid = nasid_to_cnodeid(nasid); if (klgraph_addr[cnodeid] == 0) { - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, (u64)nasid, 0, 0, 0, 0, 0, 0); /* @@ -195,11 +195,11 @@ ia64_sn_console_getc(int *ch) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); /* character is in 'v0' */ *ch = (int)ret_stuff.v0; @@ -208,6 +208,26 @@ ia64_sn_console_getc(int *ch) } /* + * Read a character from the SAL console device, after a previous interrupt + * or poll operation has given us to know that a character is available + * to be read. + */ +static inline u64 +ia64_sn_console_readc(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_READC, 0, 0, 0, 0, 0, 0, 0); + + /* character is in 'v0' */ + return ret_stuff.v0; +} + +/* * Sends the given character to the console. */ static inline u64 @@ -215,11 +235,11 @@ ia64_sn_console_putc(char ch) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -228,17 +248,20 @@ ia64_sn_console_putc(char ch) * Sends the given buffer to the console. */ static inline u64 -ia64_sn_console_putb(char *buf, int len) +ia64_sn_console_putb(const char *buf, int len) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0); - return ret_stuff.status; + if ( ret_stuff.status == 0 ) { + return ret_stuff.v0; + } + return (u64)0; } /* @@ -249,11 +272,11 @@ ia64_sn_plat_specific_err_print(int (*hook)(const char*, ...), char *rec) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -266,11 +289,11 @@ ia64_sn_plat_cpei_handler(void) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -283,11 +306,11 @@ ia64_sn_console_check(int *result) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); /* result is in 'v0' */ *result = (int)ret_stuff.v0; @@ -296,6 +319,86 @@ ia64_sn_console_check(int *result) } /* + * Checks console interrupt status + */ +static inline u64 +ia64_sn_console_intr_status(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + 0, SAL_CONSOLE_INTR_STATUS, + 0, 0, 0, 0, 0); + + if (ret_stuff.status == 0) { + return ret_stuff.v0; + } + + return 0; +} + +/* + * Enable an interrupt on the SAL console device. + */ +static inline void +ia64_sn_console_intr_enable(uint64_t intr) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + intr, SAL_CONSOLE_INTR_ON, + 0, 0, 0, 0, 0); +} + +/* + * Disable an interrupt on the SAL console device. + */ +static inline void +ia64_sn_console_intr_disable(uint64_t intr) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + intr, SAL_CONSOLE_INTR_OFF, + 0, 0, 0, 0, 0); +} + +/* + * Sends a character buffer to the console asynchronously. + */ +static inline u64 +ia64_sn_console_xmit_chars(char *buf, int len) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_XMIT_CHARS, + (uint64_t)buf, (uint64_t)len, + 0, 0, 0, 0, 0); + + if (ret_stuff.status == 0) { + return ret_stuff.v0; + } + + return 0; +} + +/* * Returns the iobrick module Id */ static inline u64 @@ -303,11 +406,11 @@ ia64_sn_sysctl_iobrick_module_get(nasid_t nasid, int *result) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); /* result is in 'v0' */ *result = (int)ret_stuff.v0; @@ -339,7 +442,7 @@ static inline u64 ia64_sn_sys_serial_get(char *buf) { struct ia64_sal_retval ret_stuff; - SAL_CALL(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -395,7 +498,6 @@ ia64_sn_sysctl_partition_get(nasid_t nasid) return ((partid_t)ret_stuff.v0); } -#ifdef CONFIG_IA64_SGI_SN2 /* * Returns the partition id of the current processor. */ @@ -411,7 +513,25 @@ sn_local_partid(void) { } } -#endif /* CONFIG_IA64_SGI_SN2 */ +/* + * Change or query the coherence domain for this partition. Each cpu-based + * nasid is represented by a bit in an array of 64-bit words: + * 0 = not in this partition's coherency domain + * 1 = in this partition's coherency domain + * It is not possible for the local system's nasids to be removed from + * the coherency domain. + * + * new_domain = set the coherence domain to the given nasids + * old_domain = return the current coherence domain + */ +static inline int +sn_change_coherence(u64 *new_domain, u64 *old_domain) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_COHERENCE, new_domain, old_domain, 0, 0, + 0, 0, 0); + return ret_stuff.status; +} /* * Turns off system power. @@ -425,5 +545,20 @@ ia64_sn_power_down(void) /* never returns */ } +/** + * ia64_sn_fru_capture - tell the system controller to capture hw state + * + * This routine will call the SAL which will tell the system controller(s) + * to capture hw mmr information from each SHub in the system. + */ +static inline u64 +ia64_sn_fru_capture(void) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SN_SAL_SYSCTL_FRU_CAPTURE, 0, 0, 0, 0, 0, 0, 0); + if (isrv.status) + return 0; + return isrv.v0; +} #endif /* _ASM_IA64_SN_SN_SAL_H */ diff --git a/include/asm-ia64/sn/snconfig.h b/include/asm-ia64/sn/snconfig.h deleted file mode 100644 index 0ea7f49d1cc..00000000000 --- a/include/asm-ia64/sn/snconfig.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. - */ -#ifndef _ASM_IA64_SN_SNCONFIG_H -#define _ASM_IA64_SN_SNCONFIG_H - -#include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) -#endif - -#endif /* _ASM_IA64_SN_SNCONFIG_H */ diff --git a/arch/ia64/sn/kernel/probe.c b/include/asm-ia64/sn/sndrv.h similarity index 50% copy from arch/ia64/sn/kernel/probe.c copy to include/asm-ia64/sn/sndrv.h index 4b2cf42c284..b657c16c869 100644 --- a/arch/ia64/sn/kernel/probe.c +++ b/include/asm-ia64/sn/sndrv.h @@ -1,7 +1,5 @@ /* - * Platform dependent support for IO probing. - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -32,50 +30,49 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include +#ifndef _ASM_IA64_SN_SNDRV_H +#define _ASM_IA64_SN_SNDRV_H -/** - * ia64_sn_probe_io_slot - test a memory location for readability - * @paddr: physical address to probe - * @size: number bytes to read (1,2,4,8) - * @data_ptr: address to store value read by probe (-1 returned if probe fails) - * - * This function will probe a physical address to determine if - * the address can be read. If reading the address causes a BUS - * error, an error is returned. If the probe succeeds, the contents - * of the memory location is returned. - * - * Return values: - * 0 - probe successful - * 1 - probe failed (generated MCA) - * 2 - Bad arg - * <0 - PAL error - */ -u64 -ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr) -{ - struct ia64_sal_retval isrv; +/* ioctl commands */ +#define SNDRV_GET_ROUTERINFO 1 +#define SNDRV_GET_INFOSIZE 2 +#define SNDRV_GET_HUBINFO 3 +#define SNDRV_GET_FLASHLOGSIZE 4 +#define SNDRV_SET_FLASHSYNC 5 +#define SNDRV_GET_FLASHLOGDATA 6 +#define SNDRV_GET_FLASHLOGALL 7 + +#define SNDRV_SET_HISTOGRAM_TYPE 14 + +#define SNDRV_ELSC_COMMAND 19 +#define SNDRV_CLEAR_LOG 20 +#define SNDRV_INIT_LOG 21 +#define SNDRV_GET_PIMM_PSC 22 +#define SNDRV_SET_PARTITION 23 +#define SNDRV_GET_PARTITION 24 + +/* see synergy_perf_ioctl() */ +#define SNDRV_GET_SYNERGY_VERSION 30 +#define SNDRV_GET_SYNERGY_STATUS 31 +#define SNDRV_GET_SYNERGYINFO 32 +#define SNDRV_SYNERGY_APPEND 33 +#define SNDRV_SYNERGY_ENABLE 34 +#define SNDRV_SYNERGY_FREQ 35 - SAL_CALL(isrv, SN_SAL_PROBE, paddr, size, 0, 0, 0, 0, 0); +/* see shubstats_ioctl() */ +#define SNDRV_SHUB_INFOSIZE 40 +#define SNDRV_SHUB_CONFIGURE 41 +#define SNDRV_SHUB_RESETSTATS 42 +#define SNDRV_SHUB_GETSTATS 43 +#define SNDRV_SHUB_GETNASID 44 - if (data_ptr) { - switch (size) { - case 1: - *((u8*)data_ptr) = (u8)isrv.v0; - break; - case 2: - *((u16*)data_ptr) = (u16)isrv.v0; - break; - case 4: - *((u32*)data_ptr) = (u32)isrv.v0; - break; - case 8: - *((u64*)data_ptr) = (u64)isrv.v0; - break; - default: - isrv.status = 2; - } - } +/* Devices */ +#define SNDRV_UKNOWN_DEVICE -1 +#define SNDRV_ROUTER_DEVICE 1 +#define SNDRV_HUB_DEVICE 2 +#define SNDRV_ELSC_NVRAM_DEVICE 3 +#define SNDRV_ELSC_CONTROLLER_DEVICE 4 +#define SNDRV_SYSCTL_SUBCH 5 +#define SNDRV_SYNERGY_DEVICE 6 - return isrv.status; -} +#endif /* _ASM_IA64_SN_SNDRV_H */ diff --git a/include/asm-ia64/sn/sv.h b/include/asm-ia64/sn/sv.h index 8e93fb91e0e..69ae9762f20 100644 --- a/include/asm-ia64/sn/sv.h +++ b/include/asm-ia64/sn/sv.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff --git a/include/asm-ia64/sn/systeminfo.h b/include/asm-ia64/sn/systeminfo.h index 819e2a043f3..b8d85db1c54 100644 --- a/include/asm-ia64/sn/systeminfo.h +++ b/include/asm-ia64/sn/systeminfo.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SYSTEMINFO_H #define _ASM_IA64_SN_SYSTEMINFO_H diff --git a/include/asm-ia64/sn/types.h b/include/asm-ia64/sn/types.h index acc56951766..0275ce759ab 100644 --- a/include/asm-ia64/sn/types.h +++ b/include/asm-ia64/sn/types.h @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_TYPES_H @@ -13,16 +13,10 @@ #include typedef unsigned long cpuid_t; -typedef unsigned long cpumask_t; typedef signed short nasid_t; /* node id in numa-as-id space */ typedef signed char partid_t; /* partition ID type */ -#ifdef CONFIG_IA64_SGI_SN2 typedef unsigned int moduleid_t; /* user-visible module number type */ typedef unsigned int cmoduleid_t; /* kernel compact module id type */ -#else -typedef signed short moduleid_t; /* user-visible module number type */ -typedef signed short cmoduleid_t; /* kernel compact module id type */ -#endif typedef signed char slabid_t; typedef unsigned char clusterid_t; /* Clusterid of the cell */ @@ -32,5 +26,6 @@ typedef unsigned long iopaddr_t; typedef unsigned char uchar_t; typedef unsigned long paddr_t; typedef unsigned long pfn_t; +typedef short cnodeid_t; #endif /* _ASM_IA64_SN_TYPES_H */ diff --git a/include/asm-ia64/sn/uart16550.h b/include/asm-ia64/sn/uart16550.h index e7f9251a5ce..96f39fd43d4 100644 --- a/include/asm-ia64/sn/uart16550.h +++ b/include/asm-ia64/sn/uart16550.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_UART16550_H diff --git a/include/asm-ia64/sn/vector.h b/include/asm-ia64/sn/vector.h index f6db63e3dad..a01d7b9aea6 100644 --- a/include/asm-ia64/sn/vector.h +++ b/include/asm-ia64/sn/vector.h @@ -4,29 +4,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_VECTOR_H #define _ASM_IA64_SN_VECTOR_H #include -#include #define NET_VEC_NULL ((net_vec_t) 0) #define NET_VEC_BAD ((net_vec_t) -1) -#ifdef RTL - -#define VEC_POLLS_W 16 /* Polls before write times out */ -#define VEC_POLLS_R 16 /* Polls before read times out */ -#define VEC_POLLS_X 16 /* Polls before exch times out */ - -#define VEC_RETRIES_W 1 /* Retries before write fails */ -#define VEC_RETRIES_R 1 /* Retries before read fails */ -#define VEC_RETRIES_X 1 /* Retries before exch fails */ - -#else /* RTL */ - #define VEC_POLLS_W 128 /* Polls before write times out */ #define VEC_POLLS_R 128 /* Polls before read times out */ #define VEC_POLLS_X 128 /* Polls before exch times out */ @@ -35,37 +22,6 @@ #define VEC_RETRIES_R 8 /* Retries before read fails */ #define VEC_RETRIES_X 4 /* Retries before exch fails */ -#endif /* RTL */ - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#define VECTOR_PARMS LB_VECTOR_PARMS -#define VECTOR_ROUTE LB_VECTOR_ROUTE -#define VECTOR_DATA LB_VECTOR_DATA -#define VECTOR_STATUS LB_VECTOR_STATUS -#define VECTOR_RETURN LB_VECTOR_RETURN -#define VECTOR_READ_DATA LB_VECTOR_READ_DATA -#define VECTOR_STATUS_CLEAR LB_VECTOR_STATUS_CLEAR -#define VP_PIOID_SHFT LVP_PIOID_SHFT -#define VP_PIOID_MASK LVP_PIOID_MASK -#define VP_WRITEID_SHFT LVP_WRITEID_SHFT -#define VP_WRITEID_MASK LVP_WRITEID_MASK -#define VP_ADDRESS_MASK LVP_ADDRESS_MASK -#define VP_TYPE_SHFT LVP_TYPE_SHFT -#define VP_TYPE_MASK LVP_TYPE_MASK -#define VS_VALID LVS_VALID -#define VS_OVERRUN LVS_OVERRUN -#define VS_TARGET_SHFT LVS_TARGET_SHFT -#define VS_TARGET_MASK LVS_TARGET_MASK -#define VS_PIOID_SHFT LVS_PIOID_SHFT -#define VS_PIOID_MASK LVS_PIOID_MASK -#define VS_WRITEID_SHFT LVS_WRITEID_SHFT -#define VS_WRITEID_MASK LVS_WRITEID_MASK -#define VS_ADDRESS_MASK LVS_ADDRESS_MASK -#define VS_TYPE_SHFT LVS_TYPE_SHFT -#define VS_TYPE_MASK LVS_TYPE_MASK -#define VS_ERROR_MASK LVS_ERROR_MASK -#endif - #define NET_ERROR_NONE 0 /* No error */ #define NET_ERROR_HARDWARE (-1) /* Hardware error */ #define NET_ERROR_OVERRUN (-2) /* Extra response(s) */ diff --git a/include/asm-ia64/sn/xtalk/xbow.h b/include/asm-ia64/sn/xtalk/xbow.h index a23ba30c2ca..702d10be57f 100644 --- a/include/asm-ia64/sn/xtalk/xbow.h +++ b/include/asm-ia64/sn/xtalk/xbow.h @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_SN_XTALK_XBOW_H #define _ASM_SN_SN_XTALK_XBOW_H @@ -406,12 +405,6 @@ typedef struct xbow_cfg_s { /* XBOW_WID_ARB_RELOAD */ #define XBOW_WID_ARB_RELOAD_INT 0x3f /* GBR reload interval */ - -#ifdef CONFIG_IA64_SGI_SN1 -#define nasid_has_xbridge(nasid) \ - (XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM) -#endif - #define IS_XBRIDGE_XBOW(wid) \ (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \ XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM) diff --git a/include/asm-ia64/sn/xtalk/xbow_info.h b/include/asm-ia64/sn/xtalk/xbow_info.h index c4b32bb98a2..ccfc3348652 100644 --- a/include/asm-ia64/sn/xtalk/xbow_info.h +++ b/include/asm-ia64/sn/xtalk/xbow_info.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XBOW_INFO_H #define _ASM_SN_XTALK_XBOW_INFO_H @@ -48,9 +48,9 @@ typedef struct xbow_perf { volatile uint32_t *xp_perf_reg; } xbow_perf_t; -extern void xbow_update_perf_counters(devfs_handle_t); -extern xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -extern int xbow_enable_perf_counter(devfs_handle_t, int, int, int); +extern void xbow_update_perf_counters(vertex_hdl_t); +extern xbow_perf_link_t *xbow_get_perf_counters(vertex_hdl_t); +extern int xbow_enable_perf_counter(vertex_hdl_t, int, int, int); #define XBOWIOC_PERF_ENABLE 1 #define XBOWIOC_PERF_DISABLE 2 diff --git a/include/asm-ia64/sn/xtalk/xswitch.h b/include/asm-ia64/sn/xtalk/xswitch.h index beb44a0271e..a406bea97d5 100644 --- a/include/asm-ia64/sn/xtalk/xswitch.h +++ b/include/asm-ia64/sn/xtalk/xswitch.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XSWITCH_H #define _ASM_SN_XTALK_XSWITCH_H @@ -23,39 +23,36 @@ typedef struct xswitch_info_s *xswitch_info_t; typedef int - xswitch_reset_link_f(devfs_handle_t xconn); + xswitch_reset_link_f(vertex_hdl_t xconn); typedef struct xswitch_provider_s { xswitch_reset_link_f *reset_link; } xswitch_provider_t; -extern void xswitch_provider_register(devfs_handle_t sw_vhdl, xswitch_provider_t * xsw_fns); +extern void xswitch_provider_register(vertex_hdl_t sw_vhdl, xswitch_provider_t * xsw_fns); xswitch_reset_link_f xswitch_reset_link; -extern xswitch_info_t xswitch_info_new(devfs_handle_t vhdl); +extern xswitch_info_t xswitch_info_new(vertex_hdl_t vhdl); extern void xswitch_info_link_is_ok(xswitch_info_t xswitch_info, xwidgetnum_t port); extern void xswitch_info_vhdl_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t xwidget); + vertex_hdl_t xwidget); extern void xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t master_vhdl); + vertex_hdl_t master_vhdl); -extern xswitch_info_t xswitch_info_get(devfs_handle_t vhdl); +extern xswitch_info_t xswitch_info_get(vertex_hdl_t vhdl); extern int xswitch_info_link_ok(xswitch_info_t xswitch_info, xwidgetnum_t port); -extern devfs_handle_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, +extern vertex_hdl_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port); -extern devfs_handle_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, +extern vertex_hdl_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, xwidgetnum_t port); -extern int xswitch_id_get(devfs_handle_t vhdl); -extern void xswitch_id_set(devfs_handle_t vhdl,int xbow_num); - #endif /* __ASSEMBLY__ */ #endif /* _ASM_SN_XTALK_XSWITCH_H */ diff --git a/include/asm-ia64/sn/xtalk/xtalk.h b/include/asm-ia64/sn/xtalk/xtalk.h index 14b1680f13d..0a55893fb95 100644 --- a/include/asm-ia64/sn/xtalk/xtalk.h +++ b/include/asm-ia64/sn/xtalk/xtalk.h @@ -4,12 +4,15 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_H #define _ASM_SN_XTALK_XTALK_H #include +#include "asm/sn/sgi.h" + + /* * xtalk.h -- platform-independent crosstalk interface */ @@ -85,7 +88,7 @@ struct xwidget_hwid_s; /* PIO MANAGEMENT */ typedef xtalk_piomap_t -xtalk_piomap_alloc_f (devfs_handle_t dev, /* set up mapping for this device */ +xtalk_piomap_alloc_f (vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -103,14 +106,14 @@ typedef void xtalk_piomap_done_f (xtalk_piomap_t xtalk_piomap); typedef caddr_t -xtalk_piotrans_addr_f (devfs_handle_t dev, /* translate for this device */ +xtalk_piotrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ unsigned flags); /* (currently unused) */ extern caddr_t -xtalk_pio_addr (devfs_handle_t dev, /* translate for this device */ +xtalk_pio_addr (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -122,7 +125,7 @@ xtalk_pio_addr (devfs_handle_t dev, /* translate for this device */ typedef struct xtalk_dmamap_s *xtalk_dmamap_t; typedef xtalk_dmamap_t -xtalk_dmamap_alloc_f (devfs_handle_t dev, /* set up mappings for this device */ +xtalk_dmamap_alloc_f (vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -144,14 +147,14 @@ typedef void xtalk_dmamap_done_f (xtalk_dmamap_t dmamap); typedef iopaddr_t -xtalk_dmatrans_addr_f (devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); typedef alenlist_t -xtalk_dmatrans_list_f (devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_list_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags); @@ -160,12 +163,12 @@ typedef void xtalk_dmamap_drain_f (xtalk_dmamap_t map); /* drain this map's channel */ typedef void -xtalk_dmaaddr_drain_f (devfs_handle_t vhdl, /* drain channel from this device */ +xtalk_dmaaddr_drain_f (vertex_hdl_t vhdl, /* drain channel from this device */ paddr_t addr, /* to this physical address */ size_t bytes); /* for this many bytes */ typedef void -xtalk_dmalist_drain_f (devfs_handle_t vhdl, /* drain channel from this device */ +xtalk_dmalist_drain_f (vertex_hdl_t vhdl, /* drain channel from this device */ alenlist_t list); /* for this set of physical blocks */ @@ -196,54 +199,47 @@ typedef int xtalk_intr_setfunc_f (xtalk_intr_t intr_hdl); /* interrupt handle */ typedef xtalk_intr_t -xtalk_intr_alloc_f (devfs_handle_t dev, /* which crosstalk device */ +xtalk_intr_alloc_f (vertex_hdl_t dev, /* which crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this intr */ + vertex_hdl_t owner_dev); /* owner of this intr */ typedef void xtalk_intr_free_f (xtalk_intr_t intr_hdl); -#ifdef CONFIG_IA64_SGI_SN1 -typedef int -xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ - void *setfunc_arg); /* arg to setfunc */ -#else typedef int xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ intr_func_t intr_func, /* xtalk intr handler */ void *intr_arg, /* arg to intr handler */ xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ void *setfunc_arg); /* arg to setfunc */ -#endif typedef void xtalk_intr_disconnect_f (xtalk_intr_t intr_hdl); -typedef devfs_handle_t +typedef vertex_hdl_t xtalk_intr_cpu_get_f (xtalk_intr_t intr_hdl); /* xtalk intr resource handle */ /* CONFIGURATION MANAGEMENT */ typedef void -xtalk_provider_startup_f (devfs_handle_t xtalk_provider); +xtalk_provider_startup_f (vertex_hdl_t xtalk_provider); typedef void -xtalk_provider_shutdown_f (devfs_handle_t xtalk_provider); +xtalk_provider_shutdown_f (vertex_hdl_t xtalk_provider); typedef void -xtalk_widgetdev_enable_f (devfs_handle_t, int); +xtalk_widgetdev_enable_f (vertex_hdl_t, int); typedef void -xtalk_widgetdev_shutdown_f (devfs_handle_t, int); +xtalk_widgetdev_shutdown_f (vertex_hdl_t, int); typedef int -xtalk_dma_enabled_f (devfs_handle_t); +xtalk_dma_enabled_f (vertex_hdl_t); /* Error Management */ typedef int -xtalk_error_devenable_f (devfs_handle_t xconn_vhdl, +xtalk_error_devenable_f (vertex_hdl_t xconn_vhdl, int devnum, int error_code); @@ -285,7 +281,6 @@ typedef struct xtalk_provider_s { xtalk_intr_free_f *intr_free; xtalk_intr_connect_f *intr_connect; xtalk_intr_disconnect_f *intr_disconnect; - xtalk_intr_cpu_get_f *intr_cpu_get; /* CONFIGURATION MANAGEMENT */ xtalk_provider_startup_f *provider_startup; @@ -327,7 +322,7 @@ extern xtalk_early_piotrans_addr_f xtalk_early_piotrans_addr; /* error management */ -extern int xtalk_error_handler(devfs_handle_t, +extern int xtalk_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); @@ -341,33 +336,33 @@ typedef unchar xtalk_intr_vector_t; /* crosstalk interrupt vector (0..255) */ #define XTALK_INTR_VECTOR_NONE (xtalk_intr_vector_t)0 /* Generic crosstalk interrupt interfaces */ -extern devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr); +extern vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr); extern xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t xtalk_intr); extern xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t xtalk_intr); extern iopaddr_t xtalk_intr_addr_get(xtalk_intr_t xtalk_intr); -extern devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); +extern vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); extern void *xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr); /* Generic crosstalk pio interfaces */ -extern devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); +extern vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); extern xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap); extern iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap); extern size_t xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap); extern caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap); /* Generic crosstalk dma interfaces */ -extern devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap); +extern vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap); extern xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap); /* Register/unregister Crosstalk providers and get implementation handle */ extern void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -extern void xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns); -extern void xtalk_provider_unregister(devfs_handle_t provider); -extern xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t provider); +extern void xtalk_provider_register(vertex_hdl_t provider, xtalk_provider_t *xtalk_fns); +extern void xtalk_provider_unregister(vertex_hdl_t provider); +extern xtalk_provider_t *xtalk_provider_fns_get(vertex_hdl_t provider); /* Crosstalk Switch generic layer, for use by initialization code */ -extern void xswitch_census(devfs_handle_t xswitchv); -extern void xswitch_init_widgets(devfs_handle_t xswitchv); +extern void xswitch_census(vertex_hdl_t xswitchv); +extern void xswitch_init_widgets(vertex_hdl_t xswitchv); /* early init interrupt management */ @@ -397,7 +392,7 @@ xtalk_intr_preconn_f (void *which_xtalk, typedef xtalk_intr_setfunc_f *xtalk_intr_setfunc_t; -typedef void xtalk_iter_f(devfs_handle_t vhdl); +typedef void xtalk_iter_f(vertex_hdl_t vhdl); extern void xtalk_iterate(char *prefix, xtalk_iter_f *func); diff --git a/include/asm-ia64/sn/xtalk/xtalk_private.h b/include/asm-ia64/sn/xtalk/xtalk_private.h index 4f5fcd43011..cfa029d0fe4 100644 --- a/include/asm-ia64/sn/xtalk/xtalk_private.h +++ b/include/asm-ia64/sn/xtalk/xtalk_private.h @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H #define _ASM_SN_XTALK_XTALK_PRIVATE_H @@ -23,7 +23,7 @@ * All Crosstalk providers set up PIO using this information. */ struct xtalk_piomap_s { - devfs_handle_t xp_dev; /* a requestor of this mapping */ + vertex_hdl_t xp_dev; /* a requestor of this mapping */ xwidgetnum_t xp_target; /* target (node's widget number) */ iopaddr_t xp_xtalk_addr; /* which crosstalk addr is mapped */ size_t xp_mapsz; /* size of this mapping */ @@ -34,7 +34,7 @@ struct xtalk_piomap_s { * All Crosstalk providers set up DMA using this information. */ struct xtalk_dmamap_s { - devfs_handle_t xd_dev; /* a requestor of this mapping */ + vertex_hdl_t xd_dev; /* a requestor of this mapping */ xwidgetnum_t xd_target; /* target (node's widget number) */ }; @@ -42,7 +42,7 @@ struct xtalk_dmamap_s { * All Crosstalk providers set up interrupts using this information. */ struct xtalk_intr_s { - devfs_handle_t xi_dev; /* requestor of this intr */ + vertex_hdl_t xi_dev; /* requestor of this intr */ xwidgetnum_t xi_target; /* master's widget number */ xtalk_intr_vector_t xi_vector; /* 8-bit interrupt vector */ iopaddr_t xi_addr; /* xtalk address to generate intr */ @@ -72,10 +72,10 @@ struct xtalk_intr_s { */ struct xwidget_info_s { char *w_fingerprint; - devfs_handle_t w_vertex; /* back pointer to vertex */ + vertex_hdl_t w_vertex; /* back pointer to vertex */ xwidgetnum_t w_id; /* widget id */ struct xwidget_hwid_s w_hwid; /* hardware identification (part/rev/mfg) */ - devfs_handle_t w_master; /* CACHED widget's master */ + vertex_hdl_t w_master; /* CACHED widget's master */ xwidgetnum_t w_masterid; /* CACHED widget's master's widgetnum */ error_handler_f *w_efunc; /* error handling function */ error_handler_arg_t w_einfo; /* first parameter for efunc */ diff --git a/include/asm-ia64/sn/xtalk/xtalkaddrs.h b/include/asm-ia64/sn/xtalk/xtalkaddrs.h index 0f2069c9000..2528b00a4ea 100644 --- a/include/asm-ia64/sn/xtalk/xtalkaddrs.h +++ b/include/asm-ia64/sn/xtalk/xtalkaddrs.h @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALKADDRS_H #define _ASM_SN_XTALK_XTALKADDRS_H diff --git a/include/asm-ia64/sn/xtalk/xwidget.h b/include/asm-ia64/sn/xtalk/xwidget.h index bea83bb83ba..a49b9425a3d 100644 --- a/include/asm-ia64/sn/xtalk/xwidget.h +++ b/include/asm-ia64/sn/xtalk/xwidget.h @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __ASM_SN_XTALK_XWIDGET_H__ #define __ASM_SN_XTALK_XWIDGET_H__ @@ -261,27 +260,26 @@ extern int xwidget_driver_register(xwidget_part_num_t part_num, extern void xwidget_driver_unregister(char *driver_prefix); extern int xwidget_register(struct xwidget_hwid_s *hwid, - devfs_handle_t dev, + vertex_hdl_t dev, xwidgetnum_t id, - devfs_handle_t master, - xwidgetnum_t targetid, - async_attach_t aa); + vertex_hdl_t master, + xwidgetnum_t targetid); -extern int xwidget_unregister(devfs_handle_t); +extern int xwidget_unregister(vertex_hdl_t); -extern void xwidget_reset(devfs_handle_t xwidget); -extern void xwidget_gfx_reset(devfs_handle_t xwidget); -extern char *xwidget_name_get(devfs_handle_t xwidget); +extern void xwidget_reset(vertex_hdl_t xwidget); +extern void xwidget_gfx_reset(vertex_hdl_t xwidget); +extern char *xwidget_name_get(vertex_hdl_t xwidget); /* Generic crosstalk widget information access interface */ -extern xwidget_info_t xwidget_info_chk(devfs_handle_t widget); -extern xwidget_info_t xwidget_info_get(devfs_handle_t widget); -extern void xwidget_info_set(devfs_handle_t widget, xwidget_info_t widget_info); -extern devfs_handle_t xwidget_info_dev_get(xwidget_info_t xwidget_info); +extern xwidget_info_t xwidget_info_chk(vertex_hdl_t widget); +extern xwidget_info_t xwidget_info_get(vertex_hdl_t widget); +extern void xwidget_info_set(vertex_hdl_t widget, xwidget_info_t widget_info); +extern vertex_hdl_t xwidget_info_dev_get(xwidget_info_t xwidget_info); extern xwidgetnum_t xwidget_info_id_get(xwidget_info_t xwidget_info); extern int xwidget_info_type_get(xwidget_info_t xwidget_info); extern int xwidget_info_state_get(xwidget_info_t xwidget_info); -extern devfs_handle_t xwidget_info_master_get(xwidget_info_t xwidget_info); +extern vertex_hdl_t xwidget_info_master_get(xwidget_info_t xwidget_info); extern xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t xwidget_info); extern xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t xwidget_info); extern xwidget_rev_num_t xwidget_info_rev_num_get(xwidget_info_t xwidget_info); diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h index 96e298c6fc4..82873bc8c68 100644 --- a/include/asm-ia64/spinlock.h +++ b/include/asm-ia64/spinlock.h @@ -32,7 +32,7 @@ typedef struct { * carefully coded to touch only those registers that spin_lock() marks "clobbered". */ -#define IA64_SPINLOCK_CLOBBERS "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory" +#define IA64_SPINLOCK_CLOBBERS "ar.ccv", "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory" static inline void _raw_spin_lock (spinlock_t *lock) @@ -133,8 +133,7 @@ do { \ while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, "acq") < 0)) { \ ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel"); \ while (*(volatile int *)__read_lock_ptr < 0) \ - barrier(); \ - \ + cpu_relax(); \ } \ } while (0) diff --git a/include/asm-ia64/statfs.h b/include/asm-ia64/statfs.h index 4e684d5c8e1..56f545513f9 100644 --- a/include/asm-ia64/statfs.h +++ b/include/asm-ia64/statfs.h @@ -6,11 +6,9 @@ * Copyright (C) 1998, 1999 David Mosberger-Tang */ -# ifndef __KERNEL_STRICT_NAMES -# include - typedef __kernel_fsid_t fsid_t; -# endif - +/* + * This is ugly --- we're already 64-bit, so just duplicate the definitions + */ struct statfs { long f_type; long f_bsize; @@ -21,7 +19,24 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; + #endif /* _ASM_IA64_STATFS_H */ diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index 250c0fa35ab..2d7f0b28d8b 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -19,11 +19,10 @@ #include #include -#define KERNEL_START (PAGE_OFFSET + 68*1024*1024) - -/* 0xa000000000000000 - 0xa000000000000000+PERCPU_MAX_SIZE remain unmapped */ +/* 0xa000000000000000 - 0xa000000000000000+PERCPU_PAGE_SIZE remain unmapped */ #define PERCPU_ADDR (0xa000000000000000 + PERCPU_PAGE_SIZE) #define GATE_ADDR (0xa000000000000000 + 2*PERCPU_PAGE_SIZE) +#define KERNEL_START 0xa000000100000000 #ifndef __ASSEMBLY__ @@ -217,13 +216,11 @@ extern void ia64_load_extra (struct task_struct *task); || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE()) #define __switch_to(prev,next,last) do { \ - struct task_struct *__fpu_owner = ia64_get_fpu_owner(); \ if (IA64_HAS_EXTRA_STATE(prev)) \ ia64_save_extra(prev); \ if (IA64_HAS_EXTRA_STATE(next)) \ ia64_load_extra(next); \ - ia64_psr(ia64_task_regs(next))->dfh = \ - !(__fpu_owner == (next) && ((next)->thread.last_fph_cpu == smp_processor_id())); \ + ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \ (last) = ia64_switch_to((next)); \ } while (0) @@ -239,7 +236,6 @@ extern void ia64_load_extra (struct task_struct *task); ia64_psr(ia64_task_regs(prev))->mfh = 0; \ (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ __ia64_save_fpu((prev)->thread.fph); \ - (prev)->thread.last_fph_cpu = smp_processor_id(); \ } \ __switch_to(prev, next, last); \ } while (0) @@ -279,6 +275,8 @@ do { \ #define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock) #define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) +#define ia64_platform_is(x) (strcmp(x, platform_name) == 0) + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h index a505da92575..bfe7aba7d51 100644 --- a/include/asm-ia64/thread_info.h +++ b/include/asm-ia64/thread_info.h @@ -9,11 +9,13 @@ #include #include -#define TI_EXEC_DOMAIN 0x00 -#define TI_FLAGS 0x08 -#define TI_CPU 0x0c -#define TI_ADDR_LIMIT 0x10 -#define TI_PRE_COUNT 0x18 +#define TI_TASK 0x00 +#define TI_EXEC_DOMAIN 0x08 +#define TI_FLAGS 0x10 +#define TI_CPU 0x14 +#define TI_ADDR_LIMIT 0x18 +#define TI_PRE_COUNT 0x20 +#define TI_RESTART_BLOCK 0x28 #define PREEMPT_ACTIVE_BIT 30 #define PREEMPT_ACTIVE (1 << PREEMPT_ACTIVE_BIT) @@ -26,6 +28,7 @@ * without having to do pointer masking. */ struct thread_info { + struct task_struct *task; /* XXX not really needed, except for dup_task_struct() */ struct exec_domain *exec_domain;/* execution domain */ __u32 flags; /* thread_info flags (see TIF_*) */ __u32 cpu; /* current CPU */ @@ -37,8 +40,9 @@ struct thread_info { #define INIT_THREAD_SIZE /* tell sched.h not to declare the thread_union */ #define THREAD_SIZE KERNEL_STACK_SIZE -#define INIT_THREAD_INFO(ti) \ +#define INIT_THREAD_INFO(tsk) \ { \ + .task = &tsk, \ .exec_domain = &default_exec_domain, \ .flags = 0, \ .cpu = 0, \ @@ -50,9 +54,14 @@ struct thread_info { } /* how to get the thread information struct from C */ -#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) +#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) +#define alloc_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE)) #define free_thread_info(ti) /* nothing */ +#define __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +#define alloc_task_struct() ((task_t *)__get_free_pages(GFP_KERNEL, KERNEL_STACK_SIZE_ORDER)) +#define free_task_struct(tsk) free_pages((unsigned long) (tsk), KERNEL_STACK_SIZE_ORDER) + #endif /* !__ASSEMBLY */ /* diff --git a/include/asm-ia64/timex.h b/include/asm-ia64/timex.h index c0145c25971..255107c680a 100644 --- a/include/asm-ia64/timex.h +++ b/include/asm-ia64/timex.h @@ -2,7 +2,7 @@ #define _ASM_IA64_TIMEX_H /* - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * David Mosberger-Tang */ /* diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h index 2edbcee407e..cfd093b5835 100644 --- a/include/asm-ia64/tlb.h +++ b/include/asm-ia64/tlb.h @@ -63,7 +63,7 @@ struct mmu_gather { }; /* Users of the generic TLB shootdown code must declare this storage space. */ -extern struct mmu_gather mmu_gathers[NR_CPUS]; +DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); /* * Flush the TLB for address range START to END and, if not in fast mode, release the @@ -125,7 +125,7 @@ ia64_tlb_flush_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long e static inline struct mmu_gather * tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush) { - struct mmu_gather *tlb = &mmu_gathers[smp_processor_id()]; + struct mmu_gather *tlb = &per_cpu(mmu_gathers, smp_processor_id()); tlb->mm = mm; /* diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h index bedeca6077e..0adc40cb7e5 100644 --- a/include/asm-ia64/topology.h +++ b/include/asm-ia64/topology.h @@ -63,4 +63,6 @@ /* Cross-node load balancing interval. */ #define NODE_BALANCE_RATE 10 +void build_cpu_to_node_map(void); + #endif /* _ASM_IA64_TOPOLOGY_H */ diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 01aebf7f38d..8a254dbd5e1 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -246,6 +246,12 @@ #define __NR_sys_clock_gettime 1254 #define __NR_sys_clock_getres 1255 #define __NR_sys_clock_nanosleep 1256 +#define __NR_sys_fstatfs64 1257 +#define __NR_sys_statfs64 1258 + +#ifdef __KERNEL__ + +#define NR_syscalls 256 /* length of syscall table */ #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) @@ -348,10 +354,12 @@ waitpid (int pid, int *wait_stat, int flags) /* * "Conditional" syscalls * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), but it doesn't work on + * all toolchains, so we just do it by hand. Note, this macro can only be used in the + * file which defines sys_ni_syscall, i.e., in kernel/sys.c. */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); #endif /* !__ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_IA64_UNISTD_H */ diff --git a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h index 153f06c1b12..3f7624a10e9 100644 --- a/include/asm-ia64/unwind.h +++ b/include/asm-ia64/unwind.h @@ -26,7 +26,9 @@ enum unw_application_register { UNW_AR_EC, UNW_AR_FPSR, UNW_AR_RSC, - UNW_AR_CCV + UNW_AR_CCV, + UNW_AR_CSD, + UNW_AR_SSD }; /* @@ -95,7 +97,6 @@ struct unw_frame_info { * Initialize unwind support. */ extern void unw_init (void); -extern void unw_create_gate_table (void); extern void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp, const void *table_start, const void *table_end); diff --git a/include/asm-ia64/ustack.h b/include/asm-ia64/ustack.h new file mode 100644 index 00000000000..da55c91246e --- /dev/null +++ b/include/asm-ia64/ustack.h @@ -0,0 +1,16 @@ +#ifndef _ASM_IA64_USTACK_H +#define _ASM_IA64_USTACK_H + +/* + * Constants for the user stack size + */ + +#include + +/* The absolute hard limit for stack size is 1/2 of the mappable space in the region */ +#define MAX_USER_STACK_SIZE (RGN_MAP_LIMIT/2) +/* Make a default stack size of 2GB */ +#define DEFAULT_USER_STACK_SIZE (1UL << 31) +#define STACK_TOP (0x6000000000000000UL + RGN_MAP_LIMIT) + +#endif /* _ASM_IA64_USTACK_H */ diff --git a/include/asm-ia64/xor.h b/include/asm-ia64/xor.h dissimilarity index 77% index 28aca667c4a..41fb8744d17 100644 --- a/include/asm-ia64/xor.h +++ b/include/asm-ia64/xor.h @@ -1,283 +1,33 @@ -/* - * include/asm-ia64/xor.h - * - * Optimized RAID-5 checksumming functions for IA-64. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -extern void xor_ia64_2(unsigned long, unsigned long *, unsigned long *); -extern void xor_ia64_3(unsigned long, unsigned long *, unsigned long *, - unsigned long *); -extern void xor_ia64_4(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void xor_ia64_5(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); - -asm (" - .text - - // Assume L2 memory latency of 6 cycles. - - .proc xor_ia64_2 -xor_ia64_2: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 3, 0, 13, 16 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov ar.lc = in0 - mov pr.rot = 1 << 16 - ;; - } - .rotr s1[6+1], s2[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mfb -(p[6+1]) st8.nta [r8] = d[1], 8 - nop.f 0 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_2 - - .proc xor_ia64_3 -xor_ia64_3: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 4, 0, 20, 24 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - ;; - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], s3[6] - } - { .bbb - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_3 - - .proc xor_ia64_4 -xor_ia64_4: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 5, 0, 27, 32 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - } - { .mfb - mov r19 = in4 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[0]) ld8.nta s4[0] = [r19], 8 -(p[6]) xor r20 = s3[6], s4[6] - ;; - } - { .mib -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], r20 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_4 - - .proc xor_ia64_5 -xor_ia64_5: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 6, 0, 34, 40 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - } - { .mib - mov r19 = in4 - mov r20 = in5 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], s5[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[0]) ld8.nta s4[0] = [r19], 8 -(p[6]) xor r21 = s3[6], s4[6] - ;; - } - { .mmi -(p[0]) ld8.nta s5[0] = [r20], 8 -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], r21 - ;; - } - { .mfb -(p[6]) xor d[0] = d[0], s5[6] - nop.f 0 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_5 -"); - -static struct xor_block_template xor_block_ia64 = { - name: "ia64", - do_2: xor_ia64_2, - do_3: xor_ia64_3, - do_4: xor_ia64_4, - do_5: xor_ia64_5, -}; - -#define XOR_TRY_TEMPLATES xor_speed(&xor_block_ia64) +/* + * include/asm-ia64/xor.h + * + * Optimized RAID-5 checksumming functions for IA-64. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +extern void xor_ia64_2(unsigned long, unsigned long *, unsigned long *); +extern void xor_ia64_3(unsigned long, unsigned long *, unsigned long *, + unsigned long *); +extern void xor_ia64_4(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *); +extern void xor_ia64_5(unsigned long, unsigned long *, unsigned long *, + unsigned long *, unsigned long *, unsigned long *); + +static struct xor_block_template xor_block_ia64 = { + .name = "ia64", + .do_2 = xor_ia64_2, + .do_3 = xor_ia64_3, + .do_4 = xor_ia64_4, + .do_5 = xor_ia64_5, +}; + +#define XOR_TRY_TEMPLATES xor_speed(&xor_block_ia64) diff --git a/include/asm-m68k/statfs.h b/include/asm-m68k/statfs.h index 1ee08965d53..08d93f14e06 100644 --- a/include/asm-m68k/statfs.h +++ b/include/asm-m68k/statfs.h @@ -1,25 +1,6 @@ #ifndef _M68K_STATFS_H #define _M68K_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; +#include #endif /* _M68K_STATFS_H */ diff --git a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h index 48a4d74bc22..6ff1747b02e 100644 --- a/include/asm-m68knommu/uaccess.h +++ b/include/asm-m68knommu/uaccess.h @@ -6,6 +6,8 @@ */ #include #include +#include + #include #define VERIFY_READ 0 @@ -178,7 +180,7 @@ static inline unsigned long clear_user(void *to, unsigned long n) { memset(to, 0, n); - return(0); + return 0; } #endif /* _M68KNOMMU_UACCESS_H */ diff --git a/include/asm-mips/statfs.h b/include/asm-mips/statfs.h index 9b6b36be4f0..fb56e50c2cf 100644 --- a/include/asm-mips/statfs.h +++ b/include/asm-mips/statfs.h @@ -35,4 +35,21 @@ struct statfs { long f_spare[6]; }; +/* + * Unlike the 32-bit version the 64-bit version has none of the ABI baggage. + */ +struct statfs64 { + __u32 f_type; + __u32 f_bsize; + __u64 f_blocks; + __u64 f_bfree; + __u64 f_bavail; + __u64 f_files; + __u64 f_ffree; + __kernel_fsid_t f_fsid; + __u32 f_namelen; + __u32 f_frsize; + __u32 f_spare[5]; +}; + #endif /* _ASM_STATFS_H */ diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index 0b1e5ae8e1c..cf324a06eaf 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h @@ -264,11 +264,13 @@ #define __NR_set_tid_address (__NR_Linux + 252) #define __NR_restart_syscall (__NR_Linux + 253) #define __NR_fadvise64 (__NR_Linux + 254) +#define __NR_statfs64 (__NR_Linux + 255) +#define __NR_fstatfs64 (__NR_Linux + 256) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 254 +#define __NR_Linux_syscalls 256 #ifndef __ASSEMBLY__ diff --git a/include/asm-mips64/statfs.h b/include/asm-mips64/statfs.h index 9b6b36be4f0..ae1d46966d2 100644 --- a/include/asm-mips64/statfs.h +++ b/include/asm-mips64/statfs.h @@ -35,4 +35,20 @@ struct statfs { long f_spare[6]; }; +struct statfs64 { /* Same as struct statfs */ + long f_type; + long f_bsize; + long f_frsize; /* Fragment size - unsupported */ + long f_blocks; + long f_bfree; + long f_files; + long f_ffree; + + /* Linux specials */ + long f_bavail; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_spare[6]; +}; + #endif /* _ASM_STATFS_H */ diff --git a/include/asm-mips64/unistd.h b/include/asm-mips64/unistd.h index a88d38e98ad..01a0f8656af 100644 --- a/include/asm-mips64/unistd.h +++ b/include/asm-mips64/unistd.h @@ -271,11 +271,13 @@ #define __NR_O32_set_tid_address (__NR_O32_Linux + 252) #define __NR_O32_restart_syscall (__NR_O32_Linux + 253) #define __NR_O32_fadvise64 (__NR_O32_Linux + 254) +#define __NR_O32_statfs64 (__NR_O32_Linux + 255) +#define __NR_O32_fstatfs64 (__NR_O32_Linux + 256) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_O32_Linux_syscalls 254 +#define __NR_O32_Linux_syscalls 256 /* @@ -724,12 +726,14 @@ #define __NR_N32_set_tid_address (__NR_N32_Linux + 213) #define __NR_N32_restart_syscall (__NR_N32_Linux + 214) #define __NR_N32_semtimedop (__NR_N32_Linux + 215) -#define __NR_N32_sys_fadvise64 (__NR_N32_Linux + 216) +#define __NR_N32_fadvise64 (__NR_N32_Linux + 216) +#define __NR_N32_statfs64 (__NR_N32_Linux + 217) +#define __NR_N32_fstatfs64 (__NR_N32_Linux + 218) /* * Offset of the last N32 flavoured syscall */ -#define __NR_N32_Linux_syscalls 216 +#define __NR_N32_Linux_syscalls 218 #ifndef __ASSEMBLY__ diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index f888716df94..cbb69630731 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h @@ -97,7 +97,8 @@ struct compat_statfs { s32 f_ffree; __kernel_fsid_t f_fsid; s32 f_namelen; - s32 f_spare[6]; + s32 f_frsize; + s32 f_spare[5]; }; #define COMPAT_RLIM_INFINITY 0xffffffff diff --git a/include/asm-parisc/smp.h b/include/asm-parisc/smp.h index cda89e45e05..e03ccc7732c 100644 --- a/include/asm-parisc/smp.h +++ b/include/asm-parisc/smp.h @@ -60,12 +60,12 @@ extern inline unsigned int num_online_cpus(void) return hweight32(cpu_online_map); } -extern inline int any_online_cpu(unsigned int mask) +extern inline unsigned int any_online_cpu(unsigned int mask) { if (mask & cpu_online_map) return __ffs(mask & cpu_online_map); - return -1; + return NR_CPUS; } #endif /* CONFIG_SMP */ diff --git a/include/asm-parisc/statfs.h b/include/asm-parisc/statfs.h index db72e852efd..e8c8169d5d7 100644 --- a/include/asm-parisc/statfs.h +++ b/include/asm-parisc/statfs.h @@ -9,6 +9,10 @@ typedef __kernel_fsid_t fsid_t; #endif +/* + * It appears that PARISC could be 64 _or_ 32 bit. + * 64-bit fields must be explicitly 64-bit in statfs64. + */ struct statfs { long f_type; long f_bsize; @@ -19,7 +23,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_files; + u64 f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index ae9f2d0d8a4..0f535e374c9 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -269,6 +269,13 @@ pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, /* Return the index of the PCI controller for device PDEV. */ #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + /* Map a range of PCI memory or I/O space for a device into user space */ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h index e8c8a89342d..0f458a0f115 100644 --- a/include/asm-ppc/smp.h +++ b/include/asm-ppc/smp.h @@ -53,12 +53,12 @@ extern inline unsigned int num_online_cpus(void) return hweight32(cpu_online_map); } -extern inline int any_online_cpu(unsigned int mask) +extern inline unsigned int any_online_cpu(unsigned int mask) { if (mask & cpu_online_map) return __ffs(mask & cpu_online_map); - return -1; + return NR_CPUS; } extern int __cpu_up(unsigned int cpu); diff --git a/include/asm-ppc/statfs.h b/include/asm-ppc/statfs.h index b2fd7356431..807c69954a1 100644 --- a/include/asm-ppc/statfs.h +++ b/include/asm-ppc/statfs.h @@ -1,27 +1,7 @@ #ifndef _PPC_STATFS_H #define _PPC_STATFS_H -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_spare[6]; -}; - +#include #endif diff --git a/include/asm-ppc64/compat.h b/include/asm-ppc64/compat.h index 31e9ce21090..e4bacd3278a 100644 --- a/include/asm-ppc64/compat.h +++ b/include/asm-ppc64/compat.h @@ -91,7 +91,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 12c74914bc5..28968302803 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -88,6 +88,13 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) extern int pci_domain_nr(struct pci_bus *bus); +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + struct vm_area_struct; /* Map a range of PCI memory or I/O space for a device into user space */ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, diff --git a/include/asm-ppc64/statfs.h b/include/asm-ppc64/statfs.h index dc3830d054c..7cce64bf7ee 100644 --- a/include/asm-ppc64/statfs.h +++ b/include/asm-ppc64/statfs.h @@ -13,6 +13,9 @@ typedef __kernel_fsid_t fsid_t; #endif +/* + * We're already 64-bit, so duplicate the definition + */ struct statfs { long f_type; long f_bsize; @@ -23,7 +26,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif /* _PPC64_STATFS_H */ diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index 532ad996326..5a5ca3f07e5 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -59,12 +59,12 @@ extern inline unsigned int num_online_cpus(void) #endif /* __s390x__ */ } -extern inline int any_online_cpu(unsigned int mask) +extern inline unsigned int any_online_cpu(unsigned int mask) { if (mask & cpu_online_map) return __ffs(mask & cpu_online_map); - return -1; + return NR_CPUS; } extern __inline__ __u16 hard_smp_processor_id(void) diff --git a/include/asm-sparc/statfs.h b/include/asm-sparc/statfs.h dissimilarity index 73% index 91a19b92aa2..d623f144247 100644 --- a/include/asm-sparc/statfs.h +++ b/include/asm-sparc/statfs.h @@ -1,26 +1,7 @@ -/* $Id: statfs.h,v 1.4 1996/06/07 00:41:05 ecd Exp $ */ -#ifndef _SPARC_STATFS_H -#define _SPARC_STATFS_H - -#ifndef __KERNEL_STRICT_NAMES - -#include - -typedef __kernel_fsid_t fsid_t; - -#endif - -struct statfs { - long f_type; - long f_bsize; - long f_blocks; - long f_bfree; - long f_bavail; - long f_files; - long f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; /* SunOS ignores this field. */ - long f_spare[6]; -}; - -#endif +/* $Id: statfs.h,v 1.4 1996/06/07 00:41:05 ecd Exp $ */ +#ifndef _SPARC_STATFS_H +#define _SPARC_STATFS_H + +#include + +#endif diff --git a/include/asm-sparc/xor.h b/include/asm-sparc/xor.h index 1c57036e451..f34b2cfa820 100644 --- a/include/asm-sparc/xor.h +++ b/include/asm-sparc/xor.h @@ -250,11 +250,11 @@ sparc_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, } static struct xor_block_template xor_block_SPARC = { - name: "SPARC", - do_2: sparc_2, - do_3: sparc_3, - do_4: sparc_4, - do_5: sparc_5, + .name = "SPARC", + .do_2 = sparc_2, + .do_3 = sparc_3, + .do_4 = sparc_4, + .do_5 = sparc_5, }; /* For grins, also test the generic routines. */ diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 440e7ac0c93..c276200453a 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -191,6 +191,13 @@ pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, extern int pci_domain_nr(struct pci_bus *bus); +/* Set the name of the bus as it appears in /proc/bus/pci */ +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} + /* Platform support for /proc/bus/pci/X/Y mmap()s. */ #define HAVE_PCI_MMAP diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index b57fd36a119..fab5999a9a7 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -80,11 +80,11 @@ extern atomic_t sparc64_num_cpus_online; extern atomic_t sparc64_num_cpus_possible; #define num_possible_cpus() (atomic_read(&sparc64_num_cpus_possible)) -static inline int any_online_cpu(unsigned long mask) +static inline unsigned int any_online_cpu(unsigned long mask) { if ((mask &= cpu_online_map) != 0UL) return __ffs(mask); - return -1; + return NR_CPUS; } /* diff --git a/include/asm-sparc64/statfs.h b/include/asm-sparc64/statfs.h index 3866255b84d..5985f1901cf 100644 --- a/include/asm-sparc64/statfs.h +++ b/include/asm-sparc64/statfs.h @@ -20,7 +20,22 @@ struct statfs { long f_ffree; __kernel_fsid_t f_fsid; long f_namelen; - long f_spare[6]; + long f_frsize; + long f_spare[5]; +}; + +struct statfs64 { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; }; #endif diff --git a/include/asm-sparc64/xor.h b/include/asm-sparc64/xor.h index 97acf538539..9ecc98f667d 100644 --- a/include/asm-sparc64/xor.h +++ b/include/asm-sparc64/xor.h @@ -388,11 +388,11 @@ xor_vis_5: "); static struct xor_block_template xor_block_VIS = { - name: "VIS", - do_2: xor_vis_2, - do_3: xor_vis_3, - do_4: xor_vis_4, - do_5: xor_vis_5, + .name = "VIS", + .do_2 = xor_vis_2, + .do_3 = xor_vis_3, + .do_4 = xor_vis_4, + .do_5 = xor_vis_5, }; #define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) diff --git a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h index 7bb8bf4f1fd..a997f9f8fdd 100644 --- a/include/asm-v850/hardirq.h +++ b/include/asm-v850/hardirq.h @@ -80,12 +80,12 @@ typedef struct { # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif -#define irq_exit() \ -do { \ - preempt_count() -= IRQ_EXIT_OFFSET; \ - if (!in_interrupt() && softirq_pending(smp_processor_id())) \ - do_softirq(); \ - preempt_enable_no_resched(); \ +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ } while (0) #ifndef CONFIG_SMP diff --git a/include/asm-v850/io.h b/include/asm-v850/io.h index fb37d2fb69d..ed796a1d4e2 100644 --- a/include/asm-v850/io.h +++ b/include/asm-v850/io.h @@ -1,8 +1,8 @@ /* * include/asm-v850/io.h -- Misc I/O operations * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -30,6 +30,13 @@ #define writel(b, addr) \ (void)((*(volatile unsigned int *) (addr)) = (b)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + #define inb(addr) readb (addr) #define inw(addr) readw (addr) #define inl(addr) readl (addr) diff --git a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h index 63064e77936..60eb12d5cc0 100644 --- a/include/asm-x86_64/compat.h +++ b/include/asm-x86_64/compat.h @@ -101,7 +101,8 @@ struct compat_statfs { int f_ffree; compat_fsid_t f_fsid; int f_namelen; /* SunOS ignores this field. */ - int f_spare[6]; + int f_frsize; + int f_spare[5]; }; #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h index 281063a933f..820ed467a36 100644 --- a/include/asm-x86_64/smp.h +++ b/include/asm-x86_64/smp.h @@ -66,12 +66,12 @@ extern volatile unsigned long cpu_callout_map; cpu = __ffs(mask), mask != 0; \ mask &= ~(1UL<> 4) & 0x0F); } -static inline unsigned long generic_hweight64(u64 w) +static inline unsigned long generic_hweight64(__u64 w) { #if BITS_PER_LONG < 64 return generic_hweight32((unsigned int)(w >> 32)) + diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h index 5c3fefddd4f..e355bcacac1 100644 --- a/include/linux/coda_psdev.h +++ b/include/linux/coda_psdev.h @@ -73,7 +73,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, unsigned int cmd, struct PioctlData *data); int coda_downcall(int opcode, union outputArgs *out, struct super_block *sb); int venus_fsync(struct super_block *sb, struct ViceFid *fid); -int venus_statfs(struct super_block *sb, struct statfs *sfs); +int venus_statfs(struct super_block *sb, struct kstatfs *sfs); /* messages between coda filesystem in kernel and Venus */ diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h index 808df872789..c78e9c2a7b3 100644 --- a/include/linux/efs_fs.h +++ b/include/linux/efs_fs.h @@ -41,7 +41,7 @@ extern struct file_operations efs_dir_operations; extern struct address_space_operations efs_symlink_aops; extern int efs_fill_super(struct super_block *, void *, int); -extern int efs_statfs(struct super_block *, struct statfs *); +extern int efs_statfs(struct super_block *, struct kstatfs *); extern void efs_read_inode(struct inode *); extern efs_block_t efs_map_block(struct inode *, efs_block_t); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index c2f36c9d802..62f37c1a17b 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -344,7 +344,9 @@ struct ext3_inode { #endif #define ext3_set_bit ext2_set_bit +#define ext3_set_bit_atomic ext2_set_bit_atomic #define ext3_clear_bit ext2_clear_bit +#define ext3_clear_bit_atomic ext2_clear_bit_atomic #define ext3_test_bit ext2_test_bit #define ext3_find_first_zero_bit ext2_find_first_zero_bit #define ext3_find_next_zero_bit ext2_find_next_zero_bit @@ -733,6 +735,7 @@ extern void ext3_dirty_inode(struct inode *); extern int ext3_change_inode_journal_flag(struct inode *, int); extern void ext3_truncate (struct inode *); extern void ext3_set_inode_flags(struct inode *); +extern void ext3_set_aops(struct inode *inode); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, @@ -761,7 +764,7 @@ extern void ext3_write_super (struct super_block *); extern void ext3_write_super_lockfs (struct super_block *); extern void ext3_unlockfs (struct super_block *); extern int ext3_remount (struct super_block *, int *, char *); -extern int ext3_statfs (struct super_block *, struct statfs *); +extern int ext3_statfs (struct super_block *, struct kstatfs *); #define ext3_std_error(sb, errno) \ do { \ @@ -781,10 +784,6 @@ extern struct file_operations ext3_dir_operations; extern struct inode_operations ext3_file_inode_operations; extern struct file_operations ext3_file_operations; -/* inode.c */ -extern struct address_space_operations ext3_aops; -extern struct address_space_operations ext3_writeback_aops; - /* namei.c */ extern struct inode_operations ext3_dir_inode_operations; extern struct inode_operations ext3_special_inode_operations; diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 02021676dd7..1a6a6c5922f 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -66,7 +66,7 @@ struct ext3_inode_info { struct posix_acl *i_acl; struct posix_acl *i_default_acl; #endif - + struct list_head i_orphan; /* unlinked but open inodes */ /* diff --git a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h index 19bf2e13234..e9b4012cc77 100644 --- a/include/linux/ext3_fs_sb.h +++ b/include/linux/ext3_fs_sb.h @@ -19,6 +19,8 @@ #ifdef __KERNEL__ #include #include +#include +#include #endif /* @@ -50,8 +52,11 @@ struct ext3_sb_info { u32 s_next_generation; u32 s_hash_seed[4]; int s_def_hash_version; - unsigned long s_dir_count; - u8 *s_debts; + u8 *s_debts; + struct percpu_counter s_freeblocks_counter; + struct percpu_counter s_freeinodes_counter; + struct percpu_counter s_dirs_counter; + struct blockgroup_lock s_blockgroup_lock; /* Journaling */ struct inode * s_journal_inode; diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h index cb54b435a9d..27b21821ce7 100644 --- a/include/linux/ext3_jbd.h +++ b/include/linux/ext3_jbd.h @@ -97,26 +97,33 @@ void ext3_journal_abort_handle(const char *caller, const char *err_fn, struct buffer_head *bh, handle_t *handle, int err); static inline int -__ext3_journal_get_undo_access(const char *where, - handle_t *handle, struct buffer_head *bh) +__ext3_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh, int *credits) { - int err = journal_get_undo_access(handle, bh); + int err = journal_get_undo_access(handle, bh, credits); if (err) ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_get_write_access(const char *where, - handle_t *handle, struct buffer_head *bh) +__ext3_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh, int *credits) { - int err = journal_get_write_access(handle, bh); + int err = journal_get_write_access(handle, bh, credits); if (err) ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline void +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh, + int credits) +{ + journal_release_buffer(handle, bh, credits); +} + +static inline void ext3_journal_forget(handle_t *handle, struct buffer_head *bh) { journal_forget(handle, bh); @@ -153,10 +160,12 @@ __ext3_journal_dirty_metadata(const char *where, } -#define ext3_journal_get_undo_access(handle, bh) \ - __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_get_undo_access(handle, bh, credits) \ + __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits)) #define ext3_journal_get_write_access(handle, bh) \ - __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL) +#define ext3_journal_get_write_access_credits(handle, bh, credits) \ + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits)) #define ext3_journal_revoke(handle, blocknr, bh) \ __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) #define ext3_journal_get_create_access(handle, bh) \ @@ -175,17 +184,6 @@ static inline handle_t *ext3_journal_current_handle(void) return journal_current_handle(); } -static inline void -ext3_log_start_commit(journal_t *journal, transaction_t *transaction) -{ - log_start_commit(journal, transaction); -} - -static inline void ext3_log_wait_commit(journal_t *journal, tid_t tid) -{ - log_wait_commit(journal, tid); -} - static inline int ext3_journal_extend(handle_t *handle, int nblocks) { return journal_extend(handle, nblocks); diff --git a/include/linux/firmware.h b/include/linux/firmware.h new file mode 100644 index 00000000000..93dd77eb786 --- /dev/null +++ b/include/linux/firmware.h @@ -0,0 +1,19 @@ +#ifndef _LINUX_FIRMWARE_H +#define _LINUX_FIRMWARE_H +#include +#include +#define FIRMWARE_NAME_MAX 30 +struct firmware { + size_t size; + u8 *data; +}; +int request_firmware(const struct firmware **fw, const char *name, + struct device *device); +int request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)); + +void release_firmware(const struct firmware *fw); +void register_firmware(const char *name, const u8 *data, size_t size); +#endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 0f79ec6c694..c3bda88631b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -25,7 +25,7 @@ struct iovec; struct nameidata; struct pipe_inode_info; struct poll_table_struct; -struct statfs; +struct kstatfs; struct vm_area_struct; struct vfsmount; @@ -781,7 +781,7 @@ struct super_operations { int (*sync_fs)(struct super_block *sb, int wait); void (*write_super_lockfs) (struct super_block *); void (*unlockfs) (struct super_block *); - int (*statfs) (struct super_block *, struct statfs *); + int (*statfs) (struct super_block *, struct kstatfs *); int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); @@ -960,7 +960,7 @@ extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); extern long do_mount(char *, char *, char *, unsigned long, void *); -extern int vfs_statfs(struct super_block *, struct statfs *); +extern int vfs_statfs(struct super_block *, struct kstatfs *); /* Return value for VFS lock functions - tells locks.c to lock conventionally * REALLY kosha for root NFS and nfs_lock @@ -1278,7 +1278,7 @@ extern int dcache_dir_close(struct inode *, struct file *); extern loff_t dcache_dir_lseek(struct file *, loff_t, int); extern int dcache_readdir(struct file *, void *, filldir_t); extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int simple_statfs(struct super_block *, struct statfs *); +extern int simple_statfs(struct super_block *, struct kstatfs *); extern int simple_link(struct dentry *, struct inode *, struct dentry *); extern int simple_unlink(struct inode *, struct dentry *); extern int simple_rmdir(struct inode *, struct dentry *); diff --git a/include/linux/gfp.h b/include/linux/gfp.h index be82baa340f..aa3705a9a21 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -7,7 +7,7 @@ /* * GFP bitmasks.. */ -/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */ +/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */ #define __GFP_DMA 0x01 #define __GFP_HIGHMEM 0x02 diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 4cd2f596e70..2c9139a94f8 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -3,6 +3,8 @@ #include #include +#include + #include #ifdef CONFIG_HIGHMEM diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 266762203a7..edc512ee628 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -73,11 +73,28 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) #ifdef CONFIG_HUGETLBFS struct hugetlbfs_config { - uid_t uid; - gid_t gid; - umode_t mode; + uid_t uid; + gid_t gid; + umode_t mode; + long nr_blocks; + long nr_inodes; }; +struct hugetlbfs_sb_info { + long max_blocks; /* blocks allowed */ + long free_blocks; /* blocks free */ + long max_inodes; /* inodes allowed */ + long free_inodes; /* inodes free */ + spinlock_t stat_lock; +}; + +static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) +{ + return sb->s_fs_info; +} + +#define PSEUDO_DIRENT_SIZE 20 + extern struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); diff --git a/include/linux/input.h b/include/linux/input.h index 20dfaad9fe4..da49f7ee0f1 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -358,6 +358,7 @@ struct input_absinfo { #define BTN_EXTRA 0x114 #define BTN_FORWARD 0x115 #define BTN_BACK 0x116 +#define BTN_TASK 0x117 #define BTN_JOYSTICK 0x120 #define BTN_TRIGGER 0x120 diff --git a/include/linux/isdn.h b/include/linux/isdn.h index fe4e4f154b1..ecd0f5394e9 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -283,7 +283,7 @@ typedef struct atemu { #endif int mdmcmdl; /* Length of Modem-Commandbuffer */ int pluscount; /* Counter for +++ sequence */ - int lastplus; /* Timestamp of last + */ + unsigned long lastplus; /* Timestamp of last + */ char mdmcmd[255]; /* Modem-Commandbuffer */ unsigned int charge; /* Charge units of current connection */ } atemu; diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 669822e2868..c32f338a5a2 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -95,7 +95,8 @@ struct isdn_ppp_resetparams { * check the original include for more information */ struct isdn_ppp_compressor { - struct isdn_ppp_compressor *next, *prev; + struct module *owner; + struct list_head list; int num; /* CCP compression protocol number */ void *(*alloc) (struct isdn_ppp_comp_data *); diff --git a/include/linux/jbd.h b/include/linux/jbd.h index e00aec05a9b..42d0caccf7e 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -178,7 +178,7 @@ typedef struct journal_superblock_s __u32 s_blocksize; /* journal device blocksize */ __u32 s_maxlen; /* total blocks in journal file */ __u32 s_first; /* first block of log information */ - + /* 0x0018 */ /* Dynamic information describing the current state of the log */ __u32 s_sequence; /* first commit ID expected in log */ @@ -198,9 +198,9 @@ typedef struct journal_superblock_s /* 0x0040 */ __u32 s_nr_users; /* Nr of filesystems sharing log */ - + __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ - + /* 0x0048 */ __u32 s_max_transaction; /* Limit of journal blocks per trans.*/ __u32 s_max_trans_data; /* Limit of data blocks per trans. */ @@ -286,15 +286,18 @@ void buffer_assertion_failure(struct buffer_head *bh); enum jbd_state_bits { BH_JBD /* Has an attached ext3 journal_head */ - = BH_PrivateStart, + = BH_PrivateStart, BH_JWrite, /* Being written to log (@@@ DEBUGGING) */ BH_Freed, /* Has been freed (truncated) */ BH_Revoked, /* Has been revoked from the log */ BH_RevokeValid, /* Revoked flag is valid */ BH_JBDDirty, /* Is dirty but journaled */ + BH_State, /* Pins most journal_head state */ + BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ }; BUFFER_FNS(JBD, jbd) +BUFFER_FNS(JWrite, jwrite) BUFFER_FNS(JBDDirty, jbddirty) TAS_BUFFER_FNS(JBDDirty, jbddirty) BUFFER_FNS(Freed, freed) @@ -309,6 +312,36 @@ static inline struct journal_head *bh2jh(struct buffer_head *bh) return bh->b_private; } +static inline void jbd_lock_bh_state(struct buffer_head *bh) +{ + bit_spin_lock(BH_State, &bh->b_state); +} + +static inline int jbd_trylock_bh_state(struct buffer_head *bh) +{ + return bit_spin_trylock(BH_State, &bh->b_state); +} + +static inline int jbd_is_locked_bh_state(struct buffer_head *bh) +{ + return bit_spin_is_locked(BH_State, &bh->b_state); +} + +static inline void jbd_unlock_bh_state(struct buffer_head *bh) +{ + bit_spin_unlock(BH_State, &bh->b_state); +} + +static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_lock(BH_JournalHead, &bh->b_state); +} + +static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_unlock(BH_JournalHead, &bh->b_state); +} + #define HAVE_JOURNAL_CALLBACK_STATUS /** * struct journal_callback - Base structure for callback information. @@ -325,7 +358,7 @@ static inline struct journal_head *bh2jh(struct buffer_head *bh) * See journal_callback_set for more information. **/ struct journal_callback { - struct list_head jcb_list; + struct list_head jcb_list; /* t_jcb_lock */ void (*jcb_func)(struct journal_callback *jcb, int error); /* user data goes here */ }; @@ -333,7 +366,8 @@ struct journal_callback { struct jbd_revoke_table_s; /** - * struct handle_s - The handle_s type is the concrete type associated with handle_t. + * struct handle_s - The handle_s type is the concrete type associated with + * handle_t. * @h_transaction: Which compound transaction is this update a part of? * @h_buffer_credits: Number of remaining buffers we are allowed to dirty. * @h_ref: Reference count on this handle @@ -351,7 +385,7 @@ struct jbd_revoke_table_s; struct handle_s { /* Which compound transaction is this update a part of? */ - transaction_t * h_transaction; + transaction_t *h_transaction; /* Number of remaining buffers we are allowed to dirty: */ int h_buffer_credits; @@ -363,13 +397,14 @@ struct handle_s /* operations */ int h_err; - /* List of application registered callbacks for this handle. - * The function(s) will be called after the transaction that - * this handle is part of has been committed to disk. + /* + * List of application registered callbacks for this handle. The + * function(s) will be called after the transaction that this handle is + * part of has been committed to disk. [t_jcb_lock] */ struct list_head h_jcb; - /* Flags */ + /* Flags [no locking] */ unsigned int h_sync: 1; /* sync-on-close */ unsigned int h_jdata: 1; /* force data journaling */ unsigned int h_aborted: 1; /* fatal error on handle */ @@ -392,15 +427,42 @@ struct handle_s * flushed to home for finished transactions. */ +/* + * Lock ranking: + * + * j_list_lock + * ->jbd_lock_bh_journal_head() (This is "innermost") + * + * j_state_lock + * ->jbd_lock_bh_state() + * + * jbd_lock_bh_state() + * ->j_list_lock + * + * j_state_lock + * ->t_handle_lock + * + * j_state_lock + * ->j_list_lock (journal_unmap_buffer) + * + * t_handle_lock + * ->t_jcb_lock + */ + struct transaction_s { - /* Pointer to the journal for this transaction. */ - journal_t * t_journal; - - /* Sequence number for this transaction */ + /* Pointer to the journal for this transaction. [no locking] */ + journal_t *t_journal; + + /* Sequence number for this transaction [no locking] */ tid_t t_tid; - - /* Transaction's current state */ + + /* + * Transaction's current state + * [no locking - only kjournald alters this] + * FIXME: needs barriers + * KLUDGE: [use j_state_lock] + */ enum { T_RUNNING, T_LOCKED, @@ -410,87 +472,115 @@ struct transaction_s T_FINISHED } t_state; - /* Where in the log does this transaction's commit start? */ + /* + * Where in the log does this transaction's commit start? [no locking] + */ unsigned long t_log_start; - - /* Doubly-linked circular list of all inodes owned by this - transaction */ /* AKPM: unused */ - struct inode * t_ilist; - - /* Number of buffers on the t_buffers list */ + + /* Number of buffers on the t_buffers list [j_list_lock] */ int t_nr_buffers; - - /* Doubly-linked circular list of all buffers reserved but not - yet modified by this transaction */ - struct journal_head * t_reserved_list; - - /* Doubly-linked circular list of all metadata buffers owned by this - transaction */ - struct journal_head * t_buffers; - + + /* + * Doubly-linked circular list of all buffers reserved but not yet + * modified by this transaction [j_list_lock] + */ + struct journal_head *t_reserved_list; + + /* + * Doubly-linked circular list of all metadata buffers owned by this + * transaction [j_list_lock] + */ + struct journal_head *t_buffers; + /* * Doubly-linked circular list of all data buffers still to be - * flushed before this transaction can be committed. - * Protected by journal_datalist_lock. - */ - struct journal_head * t_sync_datalist; - - /* Doubly-linked circular list of all forget buffers (superseded - buffers which we can un-checkpoint once this transaction - commits) */ - struct journal_head * t_forget; - - /* - * Doubly-linked circular list of all buffers still to be - * flushed before this transaction can be checkpointed. - */ - /* Protected by journal_datalist_lock */ - struct journal_head * t_checkpoint_list; - - /* Doubly-linked circular list of temporary buffers currently - undergoing IO in the log */ - struct journal_head * t_iobuf_list; - - /* Doubly-linked circular list of metadata buffers being - shadowed by log IO. The IO buffers on the iobuf list and the - shadow buffers on this list match each other one for one at - all times. */ - struct journal_head * t_shadow_list; - - /* Doubly-linked circular list of control buffers being written - to the log. */ - struct journal_head * t_log_list; - - /* Number of outstanding updates running on this transaction */ + * flushed before this transaction can be committed [j_list_lock] + */ + struct journal_head *t_sync_datalist; + + /* + * Doubly-linked circular list of all forget buffers (superseded + * buffers which we can un-checkpoint once this transaction commits) + * [j_list_lock] + */ + struct journal_head *t_forget; + + /* + * Doubly-linked circular list of all buffers still to be flushed before + * this transaction can be checkpointed. [j_list_lock] + */ + struct journal_head *t_checkpoint_list; + + /* + * Doubly-linked circular list of temporary buffers currently undergoing + * IO in the log [j_list_lock] + */ + struct journal_head *t_iobuf_list; + + /* + * Doubly-linked circular list of metadata buffers being shadowed by log + * IO. The IO buffers on the iobuf list and the shadow buffers on this + * list match each other one for one at all times. [j_list_lock] + */ + struct journal_head *t_shadow_list; + + /* + * Doubly-linked circular list of control buffers being written to the + * log. [j_list_lock] + */ + struct journal_head *t_log_list; + + /* + * Protects info related to handles + */ + spinlock_t t_handle_lock; + + /* + * Number of outstanding updates running on this transaction + * [t_handle_lock] + */ int t_updates; - /* Number of buffers reserved for use by all handles in this - * transaction handle but not yet modified. */ + /* + * Number of buffers reserved for use by all handles in this transaction + * handle but not yet modified. [t_handle_lock] + */ int t_outstanding_credits; - + /* - * Forward and backward links for the circular list of all - * transactions awaiting checkpoint. + * Forward and backward links for the circular list of all transactions + * awaiting checkpoint. [j_list_lock] */ - /* Protected by journal_datalist_lock */ transaction_t *t_cpnext, *t_cpprev; - /* When will the transaction expire (become due for commit), in - * jiffies ? */ + /* + * When will the transaction expire (become due for commit), in jiffies? + * [no locking] + */ unsigned long t_expires; - /* How many handles used this transaction? */ + /* + * How many handles used this transaction? [t_handle_lock] + */ int t_handle_count; - /* List of registered callback functions for this transaction. - * Called when the transaction is committed. */ + /* + * Protects the callback list + */ + spinlock_t t_jcb_lock; + /* + * List of registered callback functions for this transaction. + * Called when the transaction is committed. [t_jcb_lock] + */ struct list_head t_jcb; }; /** - * struct journal_s - The journal_s type is the concrete type associated with journal_t. + * struct journal_s - The journal_s type is the concrete type associated with + * journal_t. * @j_flags: General journaling state flags - * @j_errno: Is there an outstanding uncleared error on the journal (from a prior abort)? + * @j_errno: Is there an outstanding uncleared error on the journal (from a + * prior abort)? * @j_sb_buffer: First part of superblock buffer * @j_superblock: Second part of superblock buffer * @j_format_version: Version of the superblock format @@ -498,171 +588,232 @@ struct transaction_s * @j_barrier: The barrier lock itself * @j_running_transaction: The current running transaction.. * @j_committing_transaction: the transaction we are pushing to disk - * @j_checkpoint_transactions: a linked circular list of all transactions waiting for checkpointing - * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction to start committing, or for a barrier lock to be released + * @j_checkpoint_transactions: a linked circular list of all transactions + * waiting for checkpointing + * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction + * to start committing, or for a barrier lock to be released * @j_wait_logspace: Wait queue for waiting for checkpointing to complete * @j_wait_done_commit: Wait queue for waiting for commit to complete * @j_wait_checkpoint: Wait queue to trigger checkpointing * @j_wait_commit: Wait queue to trigger commit * @j_wait_updates: Wait queue to wait for updates to complete * @j_checkpoint_sem: Semaphore for locking against concurrent checkpoints - * @j_sem: The main journal lock, used by lock_journal() * @j_head: Journal head - identifies the first unused block in the journal - * @j_tail: Journal tail - identifies the oldest still-used block in the journal. + * @j_tail: Journal tail - identifies the oldest still-used block in the + * journal. * @j_free: Journal free - how many free blocks are there in the journal? * @j_first: The block number of the first usable block * @j_last: The block number one beyond the last usable block * @j_dev: Device where we store the journal * @j_blocksize: blocksize for the location where we store the journal. - * @j_blk_offset: starting block offset for into the device where we store the journal - * @j_fs_dev: Device which holds the client fs. For internal journal this will be equal to j_dev + * @j_blk_offset: starting block offset for into the device where we store the + * journal + * @j_fs_dev: Device which holds the client fs. For internal journal this will + * be equal to j_dev * @j_maxlen: Total maximum capacity of the journal region on disk. - * @j_inode: Optional inode where we store the journal. If present, all journal block numbers are mapped into this inode via bmap(). + * @j_inode: Optional inode where we store the journal. If present, all journal + * block numbers are mapped into this inode via bmap(). * @j_tail_sequence: Sequence number of the oldest transaction in the log * @j_transaction_sequence: Sequence number of the next transaction to grant - * @j_commit_sequence: Sequence number of the most recently committed transaction - * @j_commit_request: Sequence number of the most recent transaction wanting commit + * @j_commit_sequence: Sequence number of the most recently committed + * transaction + * @j_commit_request: Sequence number of the most recent transaction wanting + * commit * @j_uuid: Uuid of client object. * @j_task: Pointer to the current commit thread for this journal - * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a single compound commit transaction - * @j_commit_interval: What is the maximum transaction lifetime before we begin a commit? + * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a + * single compound commit transaction + * @j_commit_interval: What is the maximum transaction lifetime before we begin + * a commit? * @j_commit_timer: The timer used to wakeup the commit thread - * @j_commit_timer_active: Timer flag - * @j_all_journals: Link all journals together - system-wide - * @j_revoke: The revoke table - maintains the list of revoked blocks in the current transaction. - **/ + * @j_revoke: The revoke table - maintains the list of revoked blocks in the + * current transaction. + */ struct journal_s { - /* General journaling state flags */ + /* General journaling state flags [j_state_lock] */ unsigned long j_flags; - /* Is there an outstanding uncleared error on the journal (from */ - /* a prior abort)? */ + /* + * Is there an outstanding uncleared error on the journal (from a prior + * abort)? [j_state_lock] + */ int j_errno; - + /* The superblock buffer */ - struct buffer_head * j_sb_buffer; - journal_superblock_t * j_superblock; + struct buffer_head *j_sb_buffer; + journal_superblock_t *j_superblock; /* Version of the superblock format */ int j_format_version; - /* Number of processes waiting to create a barrier lock */ + /* + * Protect the various scalars in the journal + */ + spinlock_t j_state_lock; + + /* + * Number of processes waiting to create a barrier lock [j_state_lock] + */ int j_barrier_count; - + /* The barrier lock itself */ struct semaphore j_barrier; - - /* Transactions: The current running transaction... */ - transaction_t * j_running_transaction; - - /* ... the transaction we are pushing to disk ... */ - transaction_t * j_committing_transaction; - - /* ... and a linked circular list of all transactions waiting */ - /* for checkpointing. */ - /* Protected by journal_datalist_lock */ - transaction_t * j_checkpoint_transactions; - - /* Wait queue for waiting for a locked transaction to start */ - /* committing, or for a barrier lock to be released */ + + /* + * Transactions: The current running transaction... + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_running_transaction; + + /* + * the transaction we are pushing to disk + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_committing_transaction; + + /* + * ... and a linked circular list of all transactions waiting for + * checkpointing. [j_list_lock] + */ + transaction_t *j_checkpoint_transactions; + + /* + * Wait queue for waiting for a locked transaction to start committing, + * or for a barrier lock to be released + */ wait_queue_head_t j_wait_transaction_locked; - + /* Wait queue for waiting for checkpointing to complete */ wait_queue_head_t j_wait_logspace; - + /* Wait queue for waiting for commit to complete */ wait_queue_head_t j_wait_done_commit; - + /* Wait queue to trigger checkpointing */ wait_queue_head_t j_wait_checkpoint; - + /* Wait queue to trigger commit */ wait_queue_head_t j_wait_commit; - + /* Wait queue to wait for updates to complete */ wait_queue_head_t j_wait_updates; /* Semaphore for locking against concurrent checkpoints */ struct semaphore j_checkpoint_sem; - /* The main journal lock, used by lock_journal() */ - struct semaphore j_sem; - - /* Journal head: identifies the first unused block in the journal. */ + /* + * Journal head: identifies the first unused block in the journal. + * [j_state_lock] + */ unsigned long j_head; - - /* Journal tail: identifies the oldest still-used block in the */ - /* journal. */ + + /* + * Journal tail: identifies the oldest still-used block in the journal. + * [j_state_lock] + */ unsigned long j_tail; - /* Journal free: how many free blocks are there in the journal? */ + /* + * Journal free: how many free blocks are there in the journal? + * [j_state_lock] + */ unsigned long j_free; - /* Journal start and end: the block numbers of the first usable */ - /* block and one beyond the last usable block in the journal. */ - unsigned long j_first, j_last; + /* + * Journal start and end: the block numbers of the first usable block + * and one beyond the last usable block in the journal. [j_state_lock] + */ + unsigned long j_first; + unsigned long j_last; - /* Device, blocksize and starting block offset for the location */ - /* where we store the journal. */ - struct block_device * j_dev; + /* + * Device, blocksize and starting block offset for the location where we + * store the journal. + */ + struct block_device *j_dev; int j_blocksize; unsigned int j_blk_offset; - /* Device which holds the client fs. For internal journal this */ - /* will be equal to j_dev. */ - struct block_device * j_fs_dev; + /* + * Device which holds the client fs. For internal journal this will be + * equal to j_dev. + */ + struct block_device *j_fs_dev; /* Total maximum capacity of the journal region on disk. */ unsigned int j_maxlen; + /* + * Protects the buffer lists and internal buffer state. + */ + spinlock_t j_list_lock; + /* Optional inode where we store the journal. If present, all */ /* journal block numbers are mapped into this inode via */ /* bmap(). */ - struct inode * j_inode; + struct inode *j_inode; - /* Sequence number of the oldest transaction in the log */ + /* + * Sequence number of the oldest transaction in the log [j_state_lock] + */ tid_t j_tail_sequence; - /* Sequence number of the next transaction to grant */ + + /* + * Sequence number of the next transaction to grant [j_state_lock] + */ tid_t j_transaction_sequence; - /* Sequence number of the most recently committed transaction */ + + /* + * Sequence number of the most recently committed transaction + * [j_state_lock]. + */ tid_t j_commit_sequence; - /* Sequence number of the most recent transaction wanting commit */ - tid_t j_commit_request; - /* Journal uuid: identifies the object (filesystem, LVM volume */ - /* etc) backed by this journal. This will eventually be */ - /* replaced by an array of uuids, allowing us to index multiple */ - /* devices within a single journal and to perform atomic updates */ - /* across them. */ + /* + * Sequence number of the most recent transaction wanting commit + * [j_state_lock] + */ + tid_t j_commit_request; + /* + * Journal uuid: identifies the object (filesystem, LVM volume etc) + * backed by this journal. This will eventually be replaced by an array + * of uuids, allowing us to index multiple devices within a single + * journal and to perform atomic updates across them. + */ __u8 j_uuid[16]; /* Pointer to the current commit thread for this journal */ - struct task_struct * j_task; + struct task_struct *j_task; - /* Maximum number of metadata buffers to allow in a single */ - /* compound commit transaction */ + /* + * Maximum number of metadata buffers to allow in a single compound + * commit transaction + */ int j_max_transaction_buffers; - /* What is the maximum transaction lifetime before we begin a */ - /* commit? */ + /* + * What is the maximum transaction lifetime before we begin a commit? + */ unsigned long j_commit_interval; /* The timer used to wakeup the commit thread: */ - struct timer_list * j_commit_timer; - int j_commit_timer_active; + struct timer_list *j_commit_timer; - /* Link all journals together - system-wide */ - struct list_head j_all_journals; - - /* The revoke table: maintains the list of revoked blocks in the */ - /* current transaction. */ + /* + * The revoke table: maintains the list of revoked blocks in the + * current transaction. [j_revoke_lock] + */ + spinlock_t j_revoke_lock; struct jbd_revoke_table_s *j_revoke; + struct jbd_revoke_table_s *j_revoke_table[2]; - /* An opaque pointer to fs-private information. ext3 puts its - * superblock pointer here */ + /* + * An opaque pointer to fs-private information. ext3 puts its + * superblock pointer here + */ void *j_private; }; @@ -681,10 +832,10 @@ struct journal_s */ /* Filing buffers */ +extern void journal_unfile_buffer(journal_t *, struct journal_head *); extern void __journal_unfile_buffer(struct journal_head *); -extern void journal_unfile_buffer(struct journal_head *); extern void __journal_refile_buffer(struct journal_head *); -extern void journal_refile_buffer(struct journal_head *); +extern void journal_refile_buffer(journal_t *, struct journal_head *); extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); extern void __journal_free_buffer(struct journal_head *bh); extern void journal_file_buffer(struct journal_head *, transaction_t *, int); @@ -699,10 +850,8 @@ extern void journal_commit_transaction(journal_t *); /* Checkpoint list management */ int __journal_clean_checkpoint_list(journal_t *journal); -extern void journal_remove_checkpoint(struct journal_head *); -extern void __journal_remove_checkpoint(struct journal_head *); -extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); -extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); +void __journal_remove_checkpoint(struct journal_head *); +void __journal_insert_checkpoint(struct journal_head *, transaction_t *); /* Buffer IO */ extern int @@ -717,34 +866,14 @@ extern void __wait_on_journal (journal_t *); /* * Journal locking. * - * We need to lock the journal during transaction state changes so that - * nobody ever tries to take a handle on the running transaction while - * we are in the middle of moving it to the commit phase. + * We need to lock the journal during transaction state changes so that nobody + * ever tries to take a handle on the running transaction while we are in the + * middle of moving it to the commit phase. j_state_lock does this. * * Note that the locking is completely interrupt unsafe. We never touch * journal structures from interrupts. - * - * In 2.2, the BKL was required for lock_journal. This is no longer - * the case. */ -static inline void lock_journal(journal_t *journal) -{ - down(&journal->j_sem); -} - -/* This returns zero if we acquired the semaphore */ -static inline int try_lock_journal(journal_t * journal) -{ - return down_trylock(&journal->j_sem); -} - -static inline void unlock_journal(journal_t * journal) -{ - up(&journal->j_sem); -} - - static inline handle_t *journal_current_handle(void) { return current->journal_info; @@ -759,12 +888,15 @@ static inline handle_t *journal_current_handle(void) extern handle_t *journal_start(journal_t *, int nblocks); extern int journal_restart (handle_t *, int nblocks); extern int journal_extend (handle_t *, int nblocks); -extern int journal_get_write_access (handle_t *, struct buffer_head *); +extern int journal_get_write_access(handle_t *, struct buffer_head *, + int *credits); extern int journal_get_create_access (handle_t *, struct buffer_head *); -extern int journal_get_undo_access (handle_t *, struct buffer_head *); +extern int journal_get_undo_access(handle_t *, struct buffer_head *, + int *credits); extern int journal_dirty_data (handle_t *, struct buffer_head *); extern int journal_dirty_metadata (handle_t *, struct buffer_head *); -extern void journal_release_buffer (handle_t *, struct buffer_head *); +extern void journal_release_buffer (handle_t *, struct buffer_head *, + int credits); extern void journal_forget (handle_t *, struct buffer_head *); extern void journal_sync_buffer (struct buffer_head *); extern int journal_invalidatepage(journal_t *, @@ -809,11 +941,10 @@ extern int journal_force_commit(journal_t *); /* * journal_head management */ -extern struct journal_head - *journal_add_journal_head(struct buffer_head *bh); -extern void journal_remove_journal_head(struct buffer_head *bh); -extern void __journal_remove_journal_head(struct buffer_head *bh); -extern void journal_unlock_journal_head(struct journal_head *jh); +struct journal_head *journal_add_journal_head(struct buffer_head *bh); +struct journal_head *journal_grab_journal_head(struct buffer_head *bh); +void journal_remove_journal_head(struct buffer_head *bh); +void journal_put_journal_head(struct journal_head *jh); /* * handle management @@ -843,29 +974,30 @@ extern int journal_cancel_revoke(handle_t *, struct journal_head *); extern void journal_write_revoke_records(journal_t *, transaction_t *); /* Recovery revoke support */ -extern int journal_set_revoke(journal_t *, unsigned long, tid_t); -extern int journal_test_revoke(journal_t *, unsigned long, tid_t); -extern void journal_clear_revoke(journal_t *); -extern void journal_brelse_array(struct buffer_head *b[], int n); +extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +extern void journal_clear_revoke(journal_t *); +extern void journal_brelse_array(struct buffer_head *b[], int n); +extern void journal_switch_revoke_table(journal_t *journal); -/* The log thread user interface: +/* + * The log thread user interface: * * Request space in the current transaction, and force transaction commit * transitions on demand. */ -extern int log_space_left (journal_t *); /* Called with journal locked */ -extern tid_t log_start_commit (journal_t *, transaction_t *); -extern int log_wait_commit (journal_t *, tid_t); -extern int log_do_checkpoint (journal_t *, int); +int __log_space_left(journal_t *); /* Called with journal locked */ +int log_start_commit(journal_t *journal, tid_t tid); +int __log_start_commit(journal_t *journal, tid_t tid); +int journal_start_commit(journal_t *journal, tid_t *tid); +int log_wait_commit(journal_t *journal, tid_t tid); +int log_do_checkpoint(journal_t *journal, int nblocks); -extern void log_wait_for_space(journal_t *, int nblocks); +void __log_wait_for_space(journal_t *journal, int nblocks); extern void __journal_drop_transaction(journal_t *, transaction_t *); extern int cleanup_journal_tail(journal_t *); -/* Reduce journal memory usage by flushing */ -extern void shrink_journal_memory(void); - /* Debugging code only: */ #define jbd_ENOSYS() \ @@ -940,50 +1072,6 @@ extern int jbd_blocks_per_page(struct inode *inode); #ifdef __KERNEL__ -extern spinlock_t jh_splice_lock; -/* - * Once `expr1' has been found true, take jh_splice_lock - * and then reevaluate everything. - */ -#define SPLICE_LOCK(expr1, expr2) \ - ({ \ - int ret = (expr1); \ - if (ret) { \ - spin_lock(&jh_splice_lock); \ - ret = (expr1) && (expr2); \ - spin_unlock(&jh_splice_lock); \ - } \ - ret; \ - }) - -/* - * A number of buffer state predicates. They test for - * buffer_jbd() because they are used in core kernel code. - * - * These will be racy on SMP unless we're *sure* that the - * buffer won't be detached from the journalling system - * in parallel. - */ - -/* Return true if the buffer is on journal list `list' */ -static inline int buffer_jlist_eq(struct buffer_head *bh, int list) -{ - return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list); -} - -/* Return true if this bufer is dirty wrt the journal */ -static inline int buffer_jdirty(struct buffer_head *bh) -{ - return buffer_jbd(bh) && buffer_jbddirty(bh); -} - -/* Return true if it's a data buffer which journalling is managing */ -static inline int buffer_jbd_data(struct buffer_head *bh) -{ - return SPLICE_LOCK(buffer_jbd(bh), - bh2jh(bh)->b_jlist == BJ_SyncData); -} - #ifdef CONFIG_SMP #define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock)) #else @@ -1011,7 +1099,6 @@ static inline int buffer_jbd_data(struct buffer_head *bh) #define J_ASSERT(expr) do {} while (0) #define J_ASSERT_BH(bh, expr) do {} while (0) #define buffer_jbd(bh) 0 -#define buffer_jlist_eq(bh, val) 0 #define journal_buffer_journal_lru(bh) 0 #endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */ diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h dissimilarity index 62% index cd77e2fca55..8751663d04c 100644 --- a/include/linux/journal-head.h +++ b/include/linux/journal-head.h @@ -1,70 +1,85 @@ -/* - * include/linux/journal-head.h - * - * buffer_head fields for JBD - * - * 27 May 2001 ANdrew Morton - * Created - pulled out of fs.h - */ - -#ifndef JOURNAL_HEAD_H_INCLUDED -#define JOURNAL_HEAD_H_INCLUDED - -typedef unsigned int tid_t; /* Unique transaction ID */ -typedef struct transaction_s transaction_t; /* Compound transaction type */ -struct buffer_head; - -struct journal_head { -#ifndef CONFIG_JBD_UNIFIED_BUFFERS - /* Points back to our buffer_head. */ - struct buffer_head *b_bh; -#endif - - /* Reference count - see description in journal.c */ - int b_jcount; - - /* Journaling list for this buffer */ - unsigned b_jlist; - - /* Copy of the buffer data frozen for writing to the log. */ - char * b_frozen_data; - - /* Pointer to a saved copy of the buffer containing no - uncommitted deallocation references, so that allocations can - avoid overwriting uncommitted deletes. */ - char * b_committed_data; - - /* Pointer to the compound transaction which owns this buffer's - metadata: either the running transaction or the committing - transaction (if there is one). Only applies to buffers on a - transaction's data or metadata journaling list. */ - /* Protected by journal_datalist_lock */ - transaction_t * b_transaction; - - /* Pointer to the running compound transaction which is - currently modifying the buffer's metadata, if there was - already a transaction committing it when the new transaction - touched it. */ - transaction_t * b_next_transaction; - - /* Doubly-linked list of buffers on a transaction's data, - metadata or forget queue. */ - /* Protected by journal_datalist_lock */ - struct journal_head *b_tnext, *b_tprev; - - /* - * Pointer to the compound transaction against which this buffer - * is checkpointed. Only dirty buffers can be checkpointed. - */ - /* Protected by journal_datalist_lock */ - transaction_t * b_cp_transaction; - - /* - * Doubly-linked list of buffers still remaining to be flushed - * before an old transaction can be checkpointed. - */ - /* Protected by journal_datalist_lock */ - struct journal_head *b_cpnext, *b_cpprev; -}; - -#endif /* JOURNAL_HEAD_H_INCLUDED */ +/* + * include/linux/journal-head.h + * + * buffer_head fields for JBD + * + * 27 May 2001 Andrew Morton + * Created - pulled out of fs.h + */ + +#ifndef JOURNAL_HEAD_H_INCLUDED +#define JOURNAL_HEAD_H_INCLUDED + +typedef unsigned int tid_t; /* Unique transaction ID */ +typedef struct transaction_s transaction_t; /* Compound transaction type */ +struct buffer_head; + +struct journal_head { + /* + * Points back to our buffer_head. [jbd_lock_bh_journal_head()] + */ + struct buffer_head *b_bh; + + /* + * Reference count - see description in journal.c + * [jbd_lock_bh_journal_head()] + */ + int b_jcount; + + /* + * Journalling list for this buffer [jbd_lock_bh_state()] + */ + unsigned b_jlist; + + /* + * Copy of the buffer data frozen for writing to the log. + * [jbd_lock_bh_state()] + */ + char *b_frozen_data; + + /* + * Pointer to a saved copy of the buffer containing no uncommitted + * deallocation references, so that allocations can avoid overwriting + * uncommitted deletes. [jbd_lock_bh_state()] + */ + char *b_committed_data; + + /* + * Pointer to the compound transaction which owns this buffer's + * metadata: either the running transaction or the committing + * transaction (if there is one). Only applies to buffers on a + * transaction's data or metadata journaling list. + * [j_list_lock] [jbd_lock_bh_state()] + */ + transaction_t *b_transaction; + + /* + * Pointer to the running compound transaction which is currently + * modifying the buffer's metadata, if there was already a transaction + * committing it when the new transaction touched it. + * [t_list_lock] [jbd_lock_bh_state()] + */ + transaction_t *b_next_transaction; + + /* + * Doubly-linked list of buffers on a transaction's data, metadata or + * forget queue. [t_list_lock] [jbd_lock_bh_state()] + */ + struct journal_head *b_tnext, *b_tprev; + + /* + * Pointer to the compound transaction against which this buffer + * is checkpointed. Only dirty buffers can be checkpointed. + * [j_list_lock] + */ + transaction_t *b_cp_transaction; + + /* + * Doubly-linked list of buffers still remaining to be flushed + * before an old transaction can be checkpointed. + * [j_list_lock] + */ + struct journal_head *b_cpnext, *b_cpprev; +}; + +#endif /* JOURNAL_HEAD_H_INCLUDED */ diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index 0555d7d0889..4268ed11243 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -270,7 +270,7 @@ extern void fat_clear_inode(struct inode *inode); extern void fat_put_super(struct super_block *sb); int fat_fill_super(struct super_block *sb, void *data, int silent, struct inode_operations *fs_dir_inode_ops, int isvfat); -extern int fat_statfs(struct super_block *sb, struct statfs *buf); +extern int fat_statfs(struct super_block *sb, struct kstatfs *buf); extern void fat_write_inode(struct inode *inode, int wait); extern int fat_notify_change(struct dentry * dentry, struct iattr * attr); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7bed3d24a2e..fba9b5ddec1 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -195,8 +195,14 @@ struct hh_cache int hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); rwlock_t hh_lock; + /* cached hardware header; allow for machine alignment needs. */ - unsigned long hh_data[16/sizeof(unsigned long)]; +#define HH_DATA_MOD 16 +#define HH_DATA_OFF(__len) \ + (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1))) +#define HH_DATA_ALIGN(__len) \ + (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) + unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER)]; }; /* These flag bits are private to the generic network queueing diff --git a/include/linux/netfilter_arp.h b/include/linux/netfilter_arp.h index 4f460b3b0cb..a3f8977f7f1 100644 --- a/include/linux/netfilter_arp.h +++ b/include/linux/netfilter_arp.h @@ -14,6 +14,7 @@ /* ARP Hooks */ #define NF_ARP_IN 0 #define NF_ARP_OUT 1 -#define NF_ARP_NUMHOOKS 2 +#define NF_ARP_FORWARD 2 +#define NF_ARP_NUMHOOKS 3 #endif /* __LINUX_ARP_NETFILTER_H */ diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index c7726a375b3..667e7f223a1 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -69,6 +69,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp); int fh_lock_parent(struct svc_fh *, struct dentry *); int nfsd_racache_init(int); void nfsd_racache_shutdown(void); +int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); int nfsd_setattr(struct svc_rqst *, struct svc_fh *, @@ -111,7 +113,7 @@ int nfsd_truncate(struct svc_rqst *, struct svc_fh *, int nfsd_readdir(struct svc_rqst *, struct svc_fh *, loff_t *, struct readdir_cd *, encode_dent_fn); int nfsd_statfs(struct svc_rqst *, struct svc_fh *, - struct statfs *); + struct kstatfs *); int nfsd_notify_change(struct inode *, struct iattr *); int nfsd_permission(struct svc_export *, struct dentry *, int); @@ -226,6 +228,7 @@ extern struct timeval nfssvc_boot; #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ #define NFSD_LEASE_TIME 60 /* seconds */ +#define NFSD_LAUNDROMAT_MINTIMEOUT 10 /* seconds */ /* * The following attributes are currently not supported by the NFSv4 server: diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 11327bf3860..c9d6de8d350 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -73,14 +73,19 @@ struct nfs4_client { struct list_head cl_idhash; /* hash by cl_clientid.id */ struct list_head cl_strhash; /* hash by cl_name */ struct list_head cl_perclient; /* list: stateowners */ + struct list_head cl_lru; /* tail queue */ struct xdr_netobj cl_name; /* id generated by client */ nfs4_verifier cl_verifier; /* generated by client */ + time_t cl_time; /* time of last lease renewal */ u32 cl_addr; /* client ipaddress */ struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ }; +extern time_t nfs4_laundromat(void); +int nfsd4_renew(clientid_t *clid); + static inline void update_stateid(stateid_t *stateid) { diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h index 970474550bb..0164bd1fc10 100644 --- a/include/linux/nfsd/xdr.h +++ b/include/linux/nfsd/xdr.h @@ -113,7 +113,7 @@ struct nfsd_readdirres { }; struct nfsd_statfsres { - struct statfs stats; + struct kstatfs stats; }; /* diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index df2de40faa2..1240afe79da 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -176,7 +176,7 @@ struct nfsd3_readdirres { struct nfsd3_fsstatres { __u32 status; - struct statfs stats; + struct kstatfs stats; __u32 invarsec; }; diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index e68fb211752..d4fd6bb3ca4 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -200,6 +200,7 @@ extern void get_full_page_state(struct page_state *ret); #define PageChecked(page) test_bit(PG_checked, &(page)->flags) #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) +#define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags) #define PageReserved(page) test_bit(PG_reserved, &(page)->flags) #define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) diff --git a/include/linux/pci.h b/include/linux/pci.h index 1983191d32c..0a2ecb5fd9e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -486,6 +486,13 @@ struct pci_ops { int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); }; +struct pci_raw_ops { + int (*read)(int dom, int bus, int dev, int func, int reg, int len, u32 *val); + int (*write)(int dom, int bus, int dev, int func, int reg, int len, u32 val); +}; + +extern struct pci_raw_ops *raw_pci_ops; + struct pci_bus_region { unsigned long start; unsigned long end; @@ -549,8 +556,8 @@ char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); -extern struct pci_dev *pci_get_dev(struct pci_dev *dev); -extern void pci_put_dev(struct pci_dev *dev); +extern struct pci_dev *pci_dev_get(struct pci_dev *dev); +extern void pci_dev_put(struct pci_dev *dev); extern void pci_remove_bus_device(struct pci_dev *dev); @@ -566,6 +573,10 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); struct pci_bus * pci_find_next_bus(const struct pci_bus *from); +struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from); +struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, + unsigned int ss_vendor, unsigned int ss_device, + struct pci_dev *from); int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val); @@ -688,6 +699,13 @@ static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { return NULL; } +static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from) +{ return NULL; } + +static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device, +unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from) +{ return NULL; } + static inline void pci_set_master(struct pci_dev *dev) { } static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } static inline void pci_disable_device(struct pci_dev *dev) { } @@ -743,6 +761,20 @@ static inline int pci_module_init(struct pci_driver *drv) return rc; } +/* + * PCI domain support. Sometimes called PCI segment (eg by ACPI), + * a PCI domain is defined to be a set of PCI busses which share + * configuration space. + */ +#ifndef CONFIG_PCI_DOMAINS +static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } +static inline int pci_name_bus(char *name, struct pci_bus *bus) +{ + sprintf(name, "%02x", bus->number); + return 0; +} +#endif + #endif /* !CONFIG_PCI */ /* these helpers provide future and backwards compatibility @@ -800,15 +832,5 @@ extern int pci_pci_problems; #define PCIPCI_VSFX 16 #define PCIPCI_ALIMAGIK 32 -/* - * PCI domain support. Sometimes called PCI segment (eg by ACPI), - * a PCI domain is defined to be a set of PCI busses which share - * configuration space. - */ - -#ifndef CONFIG_PCI_DOMAINS -static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -#endif - #endif /* __KERNEL__ */ #endif /* LINUX_PCI_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a8dccc09066..2894e0dd61b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -552,6 +552,7 @@ #define PCI_DEVICE_ID_SI_601 0x0601 #define PCI_DEVICE_ID_SI_620 0x0620 #define PCI_DEVICE_ID_SI_630 0x0630 +#define PCI_DEVICE_ID_SI_633 0x0633 #define PCI_DEVICE_ID_SI_635 0x0635 #define PCI_DEVICE_ID_SI_640 0x0640 #define PCI_DEVICE_ID_SI_645 0x0645 @@ -562,6 +563,7 @@ #define PCI_DEVICE_ID_SI_652 0x0652 #define PCI_DEVICE_ID_SI_655 0x0655 #define PCI_DEVICE_ID_SI_730 0x0730 +#define PCI_DEVICE_ID_SI_733 0x0733 #define PCI_DEVICE_ID_SI_630_VGA 0x6300 #define PCI_DEVICE_ID_SI_730_VGA 0x7300 #define PCI_DEVICE_ID_SI_735 0x0735 @@ -582,7 +584,10 @@ #define PCI_DEVICE_ID_SI_5513 0x5513 #define PCI_DEVICE_ID_SI_5518 0x5518 #define PCI_DEVICE_ID_SI_5571 0x5571 +#define PCI_DEVICE_ID_SI_5581 0x5581 +#define PCI_DEVICE_ID_SI_5582 0x5582 #define PCI_DEVICE_ID_SI_5591 0x5591 +#define PCI_DEVICE_ID_SI_5596 0x5596 #define PCI_DEVICE_ID_SI_5597 0x5597 #define PCI_DEVICE_ID_SI_5598 0x5598 #define PCI_DEVICE_ID_SI_5600 0x5600 @@ -605,6 +610,8 @@ #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A #define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0 +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 #define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b #define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 #define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 diff --git a/include/linux/pnp.h b/include/linux/pnp.h index d0249ab4067..348bb52a716 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -102,22 +102,13 @@ struct pnp_mem { #define PNP_RES_PRIORITY_FUNCTIONAL 2 #define PNP_RES_PRIORITY_INVALID 65535 -struct pnp_resources { +struct pnp_option { unsigned short priority; /* priority */ struct pnp_port *port; /* first port */ struct pnp_irq *irq; /* first IRQ */ struct pnp_dma *dma; /* first DMA */ struct pnp_mem *mem; /* first memory resource */ - struct pnp_dev *dev; /* parent */ - struct pnp_resources *dep; /* dependent resources */ -}; - -struct pnp_rule_table { - int depnum; - struct pnp_port *port[PNP_MAX_PORT]; - struct pnp_irq *irq[PNP_MAX_IRQ]; - struct pnp_dma *dma[PNP_MAX_DMA]; - struct pnp_mem *mem[PNP_MAX_MEM]; + struct pnp_option *next; /* used to chain dependent resources */ }; struct pnp_resource_table { @@ -187,8 +178,6 @@ static inline void pnp_set_card_drvdata (struct pnp_card_link *pcard, void *data struct pnp_dev { struct device dev; /* Driver Model device interface */ unsigned char number; /* used as an index, must be unique */ - int active; - int capabilities; int status; struct list_head global_list; /* node in global list of devices */ @@ -201,11 +190,13 @@ struct pnp_dev { struct pnp_driver * driver; struct pnp_card_link * card_link; - struct pnp_id * id; /* supported EISA IDs*/ - struct pnp_resource_table res; /* contains the currently chosen resources */ - struct pnp_resources * possible; /* a list of possible resources */ - struct pnp_rule_table * rule; /* the current possible resource set */ - int config_mode; /* flags that determine how the device's resources should be configured */ + struct pnp_id * id; /* supported EISA IDs*/ + + int active; + int capabilities; + struct pnp_option * independent; + struct pnp_option * dependent; + struct pnp_resource_table res; void * protocol_data; /* Used to store protocol specific data */ unsigned short regs; /* ISAPnP: supported registers */ @@ -252,11 +243,9 @@ struct pnp_fixup { void (*quirk_function)(struct pnp_dev *dev); /* fixup function */ }; -/* config modes */ -#define PNP_CONFIG_AUTO 0x0001 /* Use the Resource Configuration Engine to determine resource settings */ -#define PNP_CONFIG_MANUAL 0x0002 /* the config has been manually specified */ -#define PNP_CONFIG_FORCE 0x0004 /* disables validity checking */ -#define PNP_CONFIG_INVALID 0x0008 /* If this flag is set, the pnp layer will refuse to activate the device */ +/* config parameters */ +#define PNP_CONFIG_NORMAL 0x0001 +#define PNP_CONFIG_FORCE 0x0002 /* disables validity checking */ /* capabilities */ #define PNP_READ 0x0001 @@ -271,7 +260,7 @@ struct pnp_fixup { ((dev)->capabilities & PNP_WRITE)) #define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \ ((dev)->capabilities & PNP_DISABLE)) -#define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->config_mode & PNP_CONFIG_AUTO) && \ +#define pnp_can_configure(dev) ((!(dev)->active) && \ ((dev)->capabilities & PNP_CONFIGURABLE)) #ifdef CONFIG_ISAPNP @@ -383,7 +372,7 @@ struct pnp_protocol { #if defined(CONFIG_PNP) -/* core */ +/* device management */ int pnp_register_protocol(struct pnp_protocol *protocol); void pnp_unregister_protocol(struct pnp_protocol *protocol); int pnp_add_device(struct pnp_dev *dev); @@ -392,7 +381,7 @@ int pnp_device_attach(struct pnp_dev *pnp_dev); void pnp_device_detach(struct pnp_dev *pnp_dev); extern struct list_head pnp_global; -/* card */ +/* multidevice card support */ int pnp_add_card(struct pnp_card *card); void pnp_remove_card(struct pnp_card *card); int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); @@ -404,41 +393,35 @@ int pnp_register_card_driver(struct pnp_card_driver * drv); void pnp_unregister_card_driver(struct pnp_card_driver * drv); extern struct list_head pnp_cards; -/* resource */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent); -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum); -int pnp_get_max_depnum(struct pnp_dev *dev); -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data); -int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data); -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data); -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data); -void pnp_init_resource_table(struct pnp_resource_table *table); -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule); - -/* manager */ +/* resource management */ +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev); +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority); +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data); +int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data); +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data); +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data); +void pnp_init_resources(struct pnp_resource_table *table); +int pnp_assign_resources(struct pnp_dev *dev, int depnum); +int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); +int pnp_auto_config_dev(struct pnp_dev *dev); +int pnp_validate_config(struct pnp_dev *dev); int pnp_activate_dev(struct pnp_dev *dev); int pnp_disable_dev(struct pnp_dev *dev); void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size); -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); -int pnp_auto_config_dev(struct pnp_dev *dev); - -/* driver */ -int compare_pnp_id(struct pnp_id * pos, const char * id); -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); -int pnp_register_driver(struct pnp_driver *drv); -void pnp_unregister_driver(struct pnp_driver *drv); -/* support */ +/* protocol helpers */ int pnp_is_active(struct pnp_dev * dev); unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev); unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); +int compare_pnp_id(struct pnp_id * pos, const char * id); +int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); +int pnp_register_driver(struct pnp_driver *drv); +void pnp_unregister_driver(struct pnp_driver *drv); #else -/* just in case anyone decides to call these without PnP Support Enabled */ - -/* core */ +/* device management */ static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; } static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } @@ -447,7 +430,7 @@ static inline void pnp_remove_device(struct pnp_dev *dev) { } static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; } -/* card */ +/* multidevice card support */ static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; } static inline void pnp_remove_card(struct pnp_card *card) { ; } static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; } @@ -458,35 +441,31 @@ static inline void pnp_release_card_device(struct pnp_dev * dev) { ; } static inline int pnp_register_card_driver(struct pnp_card_driver * drv) { return -ENODEV; } static inline void pnp_unregister_card_driver(struct pnp_card_driver * drv) { ; } -/* resource */ -static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; } -static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; } -static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline void pnp_init_resource_table(struct pnp_resource_table *table) { ; } -static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { return -ENODEV; } - -/* manager */ -static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; } +/* resource management */ +static inline struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { return NULL; } +static inline struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; } +static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; } +static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; } +static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; } +static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; } +static inline void pnp_init_resources(struct pnp_resource_table *table) { } +static inline int pnp_assign_resources(struct pnp_dev *dev, int depnum) { return -ENODEV; } static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; } static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { } -/* driver */ -static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; } -static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } -static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } - -/* support */ -static inline int pnp_is_active(struct pnp_dev * dev) { return -ENODEV; } +/* protocol helpers */ +static inline int pnp_is_active(struct pnp_dev * dev) { return 0; } static inline unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } static inline unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev) { return NULL; } static inline unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } +static inline int compare_pnp_id(struct pnp_id * pos, const char * id) { return -ENODEV; } +static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } +static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } #endif /* CONFIG_PNP */ diff --git a/include/linux/rmap-locking.h b/include/linux/rmap-locking.h dissimilarity index 60% index 51f6697f379..d4dd60e34e2 100644 --- a/include/linux/rmap-locking.h +++ b/include/linux/rmap-locking.h @@ -1,47 +1,23 @@ -/* - * include/linux/rmap-locking.h - * - * Locking primitives for exclusive access to a page's reverse-mapping - * pte chain. - */ - -#include - -struct pte_chain; -extern kmem_cache_t *pte_chain_cache; - -static inline void pte_chain_lock(struct page *page) -{ - /* - * Assuming the lock is uncontended, this never enters - * the body of the outer loop. If it is contended, then - * within the inner loop a non-atomic test is used to - * busywait with less bus contention for a good time to - * attempt to acquire the lock bit. - */ - preempt_disable(); -#ifdef CONFIG_SMP - while (test_and_set_bit(PG_chainlock, &page->flags)) { - while (test_bit(PG_chainlock, &page->flags)) - cpu_relax(); - } -#endif -} - -static inline void pte_chain_unlock(struct page *page) -{ -#ifdef CONFIG_SMP - smp_mb__before_clear_bit(); - clear_bit(PG_chainlock, &page->flags); -#endif - preempt_enable(); -} - -struct pte_chain *pte_chain_alloc(int gfp_flags); -void __pte_chain_free(struct pte_chain *pte_chain); - -static inline void pte_chain_free(struct pte_chain *pte_chain) -{ - if (pte_chain) - __pte_chain_free(pte_chain); -} +/* + * include/linux/rmap-locking.h + * + * Locking primitives for exclusive access to a page's reverse-mapping + * pte chain. + */ + +#include + +struct pte_chain; +extern kmem_cache_t *pte_chain_cache; + +#define pte_chain_lock(page) bit_spin_lock(PG_chainlock, &page->flags) +#define pte_chain_unlock(page) bit_spin_unlock(PG_chainlock, &page->flags) + +struct pte_chain *pte_chain_alloc(int gfp_flags); +void __pte_chain_free(struct pte_chain *pte_chain); + +static inline void pte_chain_free(struct pte_chain *pte_chain) +{ + if (pte_chain) + __pte_chain_free(pte_chain); +} diff --git a/include/linux/sched.h b/include/linux/sched.h index fb29819901c..5fa14591c73 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -148,10 +148,15 @@ extern void sched_init(void); extern void init_idle(task_t *idle, int cpu); extern void show_state(void); -extern void show_trace(unsigned long *stack); -extern void show_stack(unsigned long *stack); extern void show_regs(struct pt_regs *); +/* + * TASK is a pointer to the task whose backtrace we want to see (or NULL for current + * task), SP is the stack pointer of the first frame that should be shown in the back + * trace (or NULL if the entire call-chain of the task should be shown). + */ +extern void show_stack(struct task_struct *task, unsigned long *sp); + void io_schedule(void); long io_schedule_timeout(long timeout); @@ -478,9 +483,12 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_LESS_THROTTLE 0x01000000 /* Throttle me less: I clena memory */ #ifdef CONFIG_SMP -extern void set_cpus_allowed(task_t *p, unsigned long new_mask); +extern int set_cpus_allowed(task_t *p, unsigned long new_mask); #else -# define set_cpus_allowed(p, new_mask) do { } while (0) +static inline int set_cpus_allowed(task_t *p, unsigned long new_mask) +{ + return 0; +} #endif #ifdef CONFIG_NUMA diff --git a/include/linux/sem.h b/include/linux/sem.h index 38a64f8ea69..2821bc07f64 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h @@ -128,13 +128,11 @@ struct sem_undo { struct sem_undo_list { atomic_t refcnt; spinlock_t lock; - volatile unsigned long add_count; struct sem_undo *proc_list; }; struct sysv_sem { struct sem_undo_list *undo_list; - struct sem_queue *sleep_list; }; asmlinkage long sys_semget (key_t key, int nsems, int semflg); @@ -143,6 +141,8 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg); asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, unsigned nsops, const struct timespec __user *timeout); +void exit_sem(struct task_struct *p); + #endif /* __KERNEL__ */ #endif /* _LINUX_SEM_H */ diff --git a/include/linux/serio.h b/include/linux/serio.h index ae1a7f9bde2..f1c67ff70f2 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -26,7 +26,6 @@ struct serio { void *driver; char *name; char *phys; - int number; unsigned short idbus; unsigned short idvendor; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4367ef3643e..57af37850a4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -802,12 +803,9 @@ static inline void skb_fill_page_desc(struct sk_buff *skb, int i, struct page *p skb_shinfo(skb)->nr_frags = i+1; } -#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \ - BUG(); } while (0) -#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \ - BUG(); } while (0) -#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) \ - BUG(); } while (0) +#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) +#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) +#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) /* * Add data to an sk_buff @@ -836,7 +834,7 @@ static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) SKB_LINEAR_ASSERT(skb); skb->tail += len; skb->len += len; - if (skb->tail>skb->end) + if (unlikely(skb->tail>skb->end)) skb_over_panic(skb, len, current_text_addr()); return tmp; } @@ -861,7 +859,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; skb->len += len; - if (skb->datahead) + if (unlikely(skb->datahead)) skb_under_panic(skb, len, current_text_addr()); return skb->data; } @@ -869,8 +867,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; - if (skb->len < skb->data_len) - BUG(); + BUG_ON(skb->len < skb->data_len); return skb->data += len; } @@ -1127,13 +1124,16 @@ static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len) * If there is no free memory -ENOMEM is returned, otherwise zero * is returned and the old skb data released. */ -int skb_linearize(struct sk_buff *skb, int gfp); +extern int __skb_linearize(struct sk_buff *skb, int gfp); +static inline int __deprecated skb_linearize(struct sk_buff *skb, int gfp) +{ + return __skb_linearize(skb, gfp); +} static inline void *kmap_skb_frag(const skb_frag_t *frag) { #ifdef CONFIG_HIGHMEM - if (in_irq()) - BUG(); + BUG_ON(in_irq()); local_bh_disable(); #endif @@ -1149,9 +1149,9 @@ static inline void kunmap_skb_frag(void *vaddr) } #define skb_queue_walk(queue, skb) \ - for (skb = (queue)->next; \ + for (skb = (queue)->next, prefetch(skb->next); \ (skb != (struct sk_buff *)(queue)); \ - skb = skb->next) + skb = skb->next, prefetch(skb->next)) extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, diff --git a/include/linux/smbno.h b/include/linux/smbno.h index c202e2d6cb8..f99e02d9ffe 100644 --- a/include/linux/smbno.h +++ b/include/linux/smbno.h @@ -347,8 +347,8 @@ #define SMB_MODE_NO_CHANGE 0xFFFFFFFF #define SMB_UID_NO_CHANGE 0xFFFFFFFF #define SMB_GID_NO_CHANGE 0xFFFFFFFF -#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFF -#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFF +#define SMB_TIME_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL +#define SMB_SIZE_NO_CHANGE 0xFFFFFFFFFFFFFFFFULL /* UNIX filetype mappings. */ #define UNIX_TYPE_FILE 0 diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 35837cde0e4..4e2c1973ae6 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -146,13 +146,8 @@ typedef struct { /* * gcc versions before ~2.95 have a nasty bug with empty initializers. */ -#if (__GNUC__ > 2) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { } -#else - typedef struct { int gcc_is_buggy; } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } -#endif +typedef struct { } spinlock_t; +#define SPIN_LOCK_UNLOCKED (spinlock_t) { } /* * If CONFIG_SMP is unset, declare the _raw_* definitions as nops @@ -395,4 +390,74 @@ do { \ extern int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #endif +/* + * bit-based spin_lock() + * + * Don't use this unless you really need to: spin_lock() and spin_unlock() + * are significantly faster. + */ +static inline void bit_spin_lock(int bitnum, unsigned long *addr) +{ + /* + * Assuming the lock is uncontended, this never enters + * the body of the outer loop. If it is contended, then + * within the inner loop a non-atomic test is used to + * busywait with less bus contention for a good time to + * attempt to acquire the lock bit. + */ + preempt_disable(); +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + while (test_and_set_bit(bitnum, addr)) { + while (test_bit(bitnum, addr)) + cpu_relax(); + } +#endif +} + +/* + * Return true if it was acquired + */ +static inline int bit_spin_trylock(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + int ret; + + preempt_disable(); + ret = !test_and_set_bit(bitnum, addr); + if (!ret) + preempt_enable(); + return ret; +#else + preempt_disable(); + return 1; +#endif +} + +/* + * bit-based spin_unlock() + */ +static inline void bit_spin_unlock(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + BUG_ON(!test_bit(bitnum, addr)); + smp_mb__before_clear_bit(); + clear_bit(bitnum, addr); +#endif + preempt_enable(); +} + +/* + * Return true if the lock is held. + */ +static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + return test_bit(bitnum, addr); +#elif defined CONFIG_PREEMPT + return preempt_count(); +#else + return 1; +#endif +} + #endif /* __LINUX_SPINLOCK_H */ diff --git a/include/linux/statfs.h b/include/linux/statfs.h new file mode 100644 index 00000000000..ad83a2bdb82 --- /dev/null +++ b/include/linux/statfs.h @@ -0,0 +1,22 @@ +#ifndef _LINUX_STATFS_H +#define _LINUX_STATFS_H + +#include + +#include + +struct kstatfs { + long f_type; + long f_bsize; + sector_t f_blocks; + sector_t f_bfree; + sector_t f_bavail; + sector_t f_files; + sector_t f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_frsize; + long f_spare[5]; +}; + +#endif diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h index 1d3bccefe95..f8ebf0b4303 100644 --- a/include/linux/sunrpc/cache.h +++ b/include/linux/sunrpc/cache.h @@ -115,6 +115,8 @@ struct cache_deferred_req { struct list_head recent; /* on fifo */ struct cache_head *item; /* cache item we wait on */ time_t recv_time; + void *owner; /* we might need to discard all defered requests + * owned by someone */ void (*revisit)(struct cache_deferred_req *req, int too_many); }; @@ -168,12 +170,14 @@ RTN *FNAME ARGS \ tmp = container_of(*hp, RTN, MEMBER); \ if (TEST) { /* found a match */ \ \ + if (set == 1 && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \ + break; \ + \ atomic_inc(&tmp->MEMBER.refcnt); \ if (set) { \ - if (set!= 2 && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ + if (set == 1 && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ { /* need to swap in new */ \ RTN *t2; \ - if (!new) break; \ \ new->MEMBER.next = tmp->MEMBER.next; \ *hp = &new->MEMBER; \ @@ -242,6 +246,7 @@ RTN *FNAME ARGS \ extern void cache_defer_req(struct cache_req *req, struct cache_head *item); extern void cache_revisit_request(struct cache_head *item); +extern void cache_clean_deferred(void *owner); static inline struct cache_head *cache_get(struct cache_head *h) { diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 09f7d54052e..20773282fad 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -125,7 +125,6 @@ struct svc_rqst { u32 rq_proc; /* procedure number */ u32 rq_prot; /* IP protocol */ unsigned short - rq_userset : 1, /* auth->setuser OK */ rq_secure : 1; /* secure port */ @@ -196,14 +195,14 @@ static inline void svc_pushback_allpages(struct svc_rqst *rqstp) static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp) { - while (rqstp->rq_resused) { + while (rqstp->rq_resused && + rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) { + if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) { rqstp->rq_argpages[rqstp->rq_arghi++] = rqstp->rq_respages[rqstp->rq_resused]; rqstp->rq_respages[rqstp->rq_resused] = NULL; } - if (rqstp->rq_res.pages == &rqstp->rq_respages[rqstp->rq_resused]) - break; } } @@ -218,7 +217,6 @@ static inline void svc_free_allpages(struct svc_rqst *rqstp) } struct svc_deferred_req { - struct svc_serv *serv; u32 prot; /* protocol (UDP or TCP) */ struct sockaddr_in addr; struct svc_sock *svsk; /* where reply must go */ diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 614200d6038..4bc3e22b510 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -72,7 +72,6 @@ struct sys_device { u32 id; struct sysdev_class * cls; struct kobject kobj; - struct list_head entry; }; extern int sys_device_register(struct sys_device *); diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 4e0f6a72860..3a2e7bf3c44 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -219,7 +219,7 @@ struct tcp_opt { __u32 snd_sml; /* Last byte of the most recently transmitted small packet */ __u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ __u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ - + struct tcp_bind_bucket *bind_hash; /* Delayed ACK control data */ struct { __u8 pending; /* ACK is pending */ diff --git a/include/linux/time.h b/include/linux/time.h index 12d0a89a4ee..e739d812825 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -130,7 +130,8 @@ static __inline__ unsigned long timeval_to_jiffies(struct timeval *value) { unsigned long sec = value->tv_sec; - long usec = value->tv_usec + TICK_USEC - 1; + long usec = value->tv_usec + + ((TICK_NSEC + 1000UL/2) / 1000UL) - 1; if (sec >= MAX_SEC_IN_JIFFIES){ sec = MAX_SEC_IN_JIFFIES; diff --git a/include/linux/timex.h b/include/linux/timex.h index 593cdf41150..2b1665d57ad 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -176,7 +176,7 @@ #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((TICK_NSEC + 1000UL/2) / 1000UL) +#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) /* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */ /* a value TUSEC for TICK_USEC (can be set bij adjtimex) */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 67c9989be29..735735d663d 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -492,8 +492,9 @@ extern int usb_disabled(void); */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ -#define URB_NO_DMA_MAP 0x0004 /* urb->*_dma are valid on submit */ -#define URB_ASYNC_UNLINK 0x0008 /* usb_unlink_urb() returns asap */ +#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ +#define URB_NO_SETUP_DMA_MAP 0x0008 /* urb->setup_dma valid on submit */ +#define URB_ASYNC_UNLINK 0x0010 /* usb_unlink_urb() returns asap */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ @@ -531,14 +532,15 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * submission, unlinking, or operation are handled. Different * kinds of URB can use different flags. * @transfer_buffer: This identifies the buffer to (or from) which - * the I/O request will be performed (unless URB_NO_DMA_MAP is set). - * This buffer must be suitable for DMA; allocate it with kmalloc() - * or equivalent. For transfers to "in" endpoints, contents of - * this buffer will be modified. This buffer is used for data + * the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP + * is set). This buffer must be suitable for DMA; allocate it with + * kmalloc() or equivalent. For transfers to "in" endpoints, contents + * of this buffer will be modified. This buffer is used for data * phases of control transfers. - * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device - * driver is saying that it provided this DMA address, which the host - * controller driver should use instead of the transfer_buffer. + * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, + * the device driver is saying that it provided this DMA address, + * which the host controller driver should use in preference to the + * transfer_buffer. * @transfer_buffer_length: How big is transfer_buffer. The transfer may * be broken up into chunks according to the current maximum packet * size for the endpoint, which is a function of the configuration @@ -553,11 +555,10 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * @setup_packet: Only used for control transfers, this points to eight bytes * of setup data. Control transfers always start by sending this data * to the device. Then transfer_buffer is read or written, if needed. - * (Not used when URB_NO_DMA_MAP is set.) - * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device - * driver has provided this DMA address for the setup packet. The - * host controller driver should use this instead of setup_buffer. - * If there is a data phase, its buffer is identified by transfer_dma. + * @setup_dma: For control transfers with URB_NO_SETUP_DMA_MAP set, the + * device driver has provided this DMA address for the setup packet. + * The host controller driver should use this in preference to + * setup_packet. * @start_frame: Returns the initial frame for interrupt or isochronous * transfers. * @number_of_packets: Lists the number of ISO transfer buffers. @@ -589,13 +590,15 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * bounce buffer or talking to an IOMMU), * although they're cheap on commodity x86 and ppc hardware. * - * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which - * tells the host controller driver that no such mapping is needed since - * the device driver is DMA-aware. For example, they might allocate a DMA - * buffer with usb_buffer_alloc(), or call usb_buffer_map(). - * When this transfer flag is provided, host controller drivers will use the - * dma addresses found in the transfer_dma and/or setup_dma fields rather than - * determing a dma address themselves. + * Alternatively, drivers may pass the URB_NO_xxx_DMA_MAP transfer flags, + * which tell the host controller driver that no such mapping is needed since + * the device driver is DMA-aware. For example, a device driver might + * allocate a DMA buffer with usb_buffer_alloc() or call usb_buffer_map(). + * When these transfer flags are provided, host controller drivers will + * attempt to use the dma addresses found in the transfer_dma and/or + * setup_dma fields rather than determining a dma address themselves. (Note + * that transfer_buffer and setup_packet must still be set because not all + * host controllers use DMA, nor do virtual root hubs). * * Initialization: * @@ -614,7 +617,11 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *); * should always terminate with a short packet, even if it means adding an * extra zero length packet. * - * Control URBs must provide a setup_packet. + * Control URBs must provide a setup_packet. The setup_packet and + * transfer_buffer may each be mapped for DMA or not, independently of + * the other. The transfer_flags bits URB_NO_TRANSFER_DMA_MAP and + * URB_NO_SETUP_DMA_MAP indicate which buffers have already been mapped. + * URB_NO_SETUP_DMA_MAP is ignored for non-control URBs. * * Interrupt UBS must provide an interval, saying how often (in milliseconds * or, for highspeed devices, 125 microsecond units) diff --git a/include/linux/vfs.h b/include/linux/vfs.h index b3a58657d76..e701d054140 100644 --- a/include/linux/vfs.h +++ b/include/linux/vfs.h @@ -1,6 +1,6 @@ #ifndef _LINUX_VFS_H #define _LINUX_VFS_H -#include +#include #endif diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h index 02145e59174..235e6c0bc17 100644 --- a/include/net/llc_pdu.h +++ b/include/net/llc_pdu.h @@ -39,8 +39,8 @@ #define LLC_PDU_CMD_RSP_MASK 0x01 #define LLC_PDU_CMD 0 #define LLC_PDU_RSP 1 -#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) -#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) +#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) +#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) /* Get PDU type from 2 lowest-order bits of control field first byte */ #define LLC_PDU_TYPE_I_MASK 0x01 /* 16-bit control field */ @@ -53,18 +53,18 @@ #define LLC_PDU_TYPE_U 3 /* first two bits */ #define LLC_PDU_TYPE_IS_I(pdu) \ - ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 0 : 1) + ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 1 : 0) #define LLC_PDU_TYPE_IS_U(pdu) \ - (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 0 : 1) + (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 1 : 0) #define LLC_PDU_TYPE_IS_S(pdu) \ - (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 0 : 1) + (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 1 : 0) /* U-format PDU control field masks */ #define LLC_U_PF_BIT_MASK 0x10 /* P/F bit mask */ -#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 0 : 1) -#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 0 : 1) +#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 1 : 0) +#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 1 : 0) #define LLC_U_PDU_CMD_MASK 0xEC /* cmd/rsp mask */ #define LLC_U_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) @@ -119,8 +119,8 @@ #define LLC_I_PF_BIT_MASK 0x01 -#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 0 : 1) -#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 0 : 1) +#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 1 : 0) +#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 1 : 0) /* S-PDU supervisory commands and responses */ @@ -136,8 +136,8 @@ #define LLC_2_PDU_RSP_RNR 0x04 /* rx not ready rsp */ #define LLC_S_PF_BIT_MASK 0x01 -#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 0 : 1) -#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 0 : 1) +#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 1 : 0) +#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 1 : 0) #define PDU_SUPV_GET_Nr(pdu) ((pdu->ctrl_2 & 0xFE) >> 1) #define PDU_GET_NEXT_Vr(sn) (++sn & ~LLC_2_SEQ_NBR_MODULO) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index f165b7279e7..b4a576529e4 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -313,6 +313,7 @@ struct sctp_opt { /* What is our base endpointer? */ struct sctp_endpoint *ep; + struct sctp_bind_bucket *bind_hash; /* Various Socket Options. */ __u16 default_stream; __u32 default_ppid; diff --git a/include/net/sock.h b/include/net/sock.h index 1f6a3d49ca7..22801b214d9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -133,7 +133,6 @@ struct sock_common { * @sk_forward_alloc - space allocated forward * @sk_allocation - allocation mode * @sk_sndbuf - size of send buffer in bytes - * @sk_prev - pointer to previous sock in the list this sock is in * @sk_flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings * @sk_no_check - %SO_NO_CHECK setting, wether or not checkup packets * @sk_debug - %SO_DEBUG setting @@ -206,7 +205,6 @@ struct sock { int sk_forward_alloc; unsigned int sk_allocation; int sk_sndbuf; - struct sock *sk_prev; unsigned long sk_flags; char sk_no_check; unsigned char sk_debug; @@ -291,21 +289,53 @@ static __inline__ void sk_node_init(struct hlist_node *node) node->pprev = NULL; } -static __inline__ int sk_del_node_init(struct sock *sk) +static __inline__ void __sk_del_node(struct sock *sk) +{ + __hlist_del(&sk->sk_node); +} + +static __inline__ int __sk_del_node_init(struct sock *sk) { if (sk_hashed(sk)) { - __hlist_del(&sk->sk_node); + __sk_del_node(sk); sk_node_init(&sk->sk_node); return 1; } return 0; } -static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) +static inline void __sock_put(struct sock *sk); + +static __inline__ int sk_del_node_init(struct sock *sk) +{ + int rc = __sk_del_node_init(sk); + + if (rc) { + /* paranoid for a while -acme */ + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + return rc; +} + +static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list) { hlist_add_head(&sk->sk_node, list); } +static inline void sock_hold(struct sock *sk); + +static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) +{ + sock_hold(sk); + __sk_add_node(sk, list); +} + +static __inline__ void __sk_del_bind_node(struct sock *sk) +{ + __hlist_del(&sk->sk_bind_node); +} + static __inline__ void sk_add_bind_node(struct sock *sk, struct hlist_head *list) { diff --git a/include/net/syncppp.h b/include/net/syncppp.h index df5b0aa3001..07214226b4e 100644 --- a/include/net/syncppp.h +++ b/include/net/syncppp.h @@ -48,6 +48,7 @@ struct sppp struct timer_list pp_timer; struct net_device *pp_if; char pp_link_state; /* Link status */ + spinlock_t lock; }; struct ppp_device diff --git a/include/net/tcp.h b/include/net/tcp.h index de9e55910b3..293e1c6f264 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1475,7 +1475,8 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) TCP_INC_STATS(TcpEstabResets); sk->sk_prot->unhash(sk); - if (sk->sk_prev && !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) + if (tcp_sk(sk)->bind_hash && + !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) tcp_put_port(sk); /* fall through */ default: diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h new file mode 100644 index 00000000000..c3bf11473f0 --- /dev/null +++ b/include/scsi/scsi_cmnd.h @@ -0,0 +1,164 @@ +#ifndef _SCSI_SCSI_CMND_H +#define _SCSI_SCSI_CMND_H + +#include +#include + +struct request; +struct scatterlist; +struct scsi_device; +struct scsi_request; + + +/* embedded in scsi_cmnd */ +struct scsi_pointer { + char *ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + dma_addr_t dma_handle; + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; +}; + +struct scsi_cmnd { + int sc_magic; + + struct scsi_device *device; + unsigned short state; + unsigned short owner; + struct scsi_request *sc_request; + + struct list_head list; /* scsi_cmnd participates in queue lists */ + + struct list_head eh_entry; /* entry for the host eh_cmd_q */ + int eh_state; /* Used for state tracking in error handlr */ + int eh_eflags; /* Used by error handlr */ + void (*done) (struct scsi_cmnd *); /* Mid-level done function */ + + /* + * A SCSI Command is assigned a nonzero serial_number when internal_cmnd + * passes it to the driver's queue command function. The serial_number + * is cleared when scsi_done is entered indicating that the command has + * been completed. If a timeout occurs, the serial number at the moment + * of timeout is copied into serial_number_at_timeout. By subsequently + * comparing the serial_number and serial_number_at_timeout fields + * during abort or reset processing, we can detect whether the command + * has already completed. This also detects cases where the command has + * completed and the SCSI Command structure has already being reused + * for another command, so that we can avoid incorrectly aborting or + * resetting the new command. + */ + unsigned long serial_number; + unsigned long serial_number_at_timeout; + + int retries; + int allowed; + int timeout_per_command; + int timeout_total; + int timeout; + + /* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + unsigned volatile char internal_timeout; + + unsigned char cmd_len; + unsigned char old_cmd_len; + unsigned char sc_data_direction; + unsigned char sc_old_data_direction; + + /* These elements define the operation we are about to perform */ +#define MAX_COMMAND_SIZE 16 + unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned request_bufflen; /* Actual request size */ + + struct timer_list eh_timeout; /* Used to time out the command. */ + void *request_buffer; /* Actual requested buffer */ + + /* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[MAX_COMMAND_SIZE]; + unsigned short old_use_sg; /* We save use_sg here when requesting + * sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short abort_reason; /* If the mid-level code requests an + * abort, this is the reason. */ + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than + this amount is transferred */ + unsigned old_underflow; /* save underflow here when reusing the + * command for error handling */ + + unsigned transfersize; /* How much we are guaranteed to + transfer with each SCSI transfer + (ie, between disconnect / + reconnects. Probably == sector + size */ + + int resid; /* Number of bytes requested to be + transferred less actual number + transferred (0 if not supported) */ + + struct request *request; /* The command we are + working on */ + +#define SCSI_SENSE_BUFFERSIZE 64 + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + unsigned flags; + + /* Low-level done function - can be used by low-level driver to point + * to completion function. Not used by mid/upper level code. */ + void (*scsi_done) (struct scsi_cmnd *); + + /* + * The following fields can be written to by the host specific code. + * Everything else should be left alone. + */ + struct scsi_pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char *host_scribble; /* The host adapter is allowed to + * call scsi_malloc and get some memory + * and hang it here. The host adapter + * is also expected to call scsi_free + * to release this memory. (The memory + * obtained by scsi_malloc is guaranteed + * to be at an address < 16Mb). */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + unsigned long pid; /* Process ID, starts at 0 */ +}; + +/* + * These are the values that scsi_cmd->state can take. + */ +#define SCSI_STATE_TIMEOUT 0x1000 +#define SCSI_STATE_FINISHED 0x1001 +#define SCSI_STATE_FAILED 0x1002 +#define SCSI_STATE_QUEUED 0x1003 +#define SCSI_STATE_UNUSED 0x1006 +#define SCSI_STATE_DISCONNECTING 0x1008 +#define SCSI_STATE_INITIALIZING 0x1009 +#define SCSI_STATE_BHQUEUE 0x100a +#define SCSI_STATE_MLQUEUE 0x100b + + +extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int); +extern void scsi_put_command(struct scsi_cmnd *); +extern void scsi_io_completion(struct scsi_cmnd *, int, int); + +#endif /* _SCSI_SCSI_CMND_H */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h new file mode 100644 index 00000000000..d19cd979754 --- /dev/null +++ b/include/scsi/scsi_device.h @@ -0,0 +1,106 @@ +#ifndef _SCSI_SCSI_DEVICE_H +#define _SCSI_SCSI_DEVICE_H + +#include +#include +#include + +struct request_queue; +struct scsi_cmnd; + + +struct scsi_device { + struct class_device sdev_classdev; + + struct list_head siblings; /* list of all devices on this host */ + struct list_head same_target_siblings; /* just the devices sharing same target id */ + struct Scsi_Host *host; + struct request_queue *request_queue; + volatile unsigned short device_busy; /* commands actually active on low-level */ + spinlock_t sdev_lock; /* also the request queue_lock */ + spinlock_t list_lock; + struct list_head cmd_list; /* queue of in use SCSI Command structures */ + struct list_head starved_entry; + struct scsi_cmnd *current_cmnd; /* currently active command */ + unsigned short queue_depth; /* How deep of a queue we want */ + unsigned short last_queue_full_depth; /* These two are used by */ + unsigned short last_queue_full_count; /* scsi_track_queue_full() */ + unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same + jiffie count on our counter, they + could all be from the same event. */ + + unsigned int id, lun, channel; + + unsigned int manufacturer; /* Manufacturer of device, for using + * vendor-specific cmd's */ + unsigned sector_size; /* size in bytes */ + + int access_count; /* Count of open channels/mounts */ + + void *hostdata; /* available to low-level driver */ + char devfs_name[256]; /* devfs junk */ + char type; + char scsi_level; + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + unsigned char * inquiry; /* INQUIRY response data */ + char * vendor; /* [back_compat] point into 'inquiry' ... */ + char * model; /* ... after scan; point to static string */ + char * rev; /* ... "nullnullnullnull" before scan */ + unsigned char current_tag; /* current tag */ + struct scsi_target *sdev_target; /* used only for single_lun */ + + unsigned online:1; + + unsigned writeable:1; + unsigned removable:1; + unsigned changed:1; /* Data invalid due to media change */ + unsigned busy:1; /* Used to prevent races */ + unsigned lockable:1; /* Able to prevent media removal */ + unsigned locked:1; /* Media removal disabled */ + unsigned borken:1; /* Tell the Seagate driver to be + * painfully slow on this device */ + unsigned disconnect:1; /* can disconnect */ + unsigned soft_reset:1; /* Uses soft reset option */ + unsigned sdtr:1; /* Device supports SDTR messages */ + unsigned wdtr:1; /* Device supports WDTR messages */ + unsigned ppr:1; /* Device supports PPR messages */ + unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ + unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags + instead!!! Please fix your driver now!! */ + unsigned simple_tags:1; /* simple queue tag messages are enabled */ + unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ + unsigned single_lun:1; /* Indicates we should only allow I/O to + * one of the luns for the device at a + * time. */ + unsigned was_reset:1; /* There was a bus reset on the bus for + * this device */ + unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN + * because we did a bus reset. */ + unsigned use_10_for_rw:1; /* first try 10-byte read / write */ + unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned no_start_on_add:1; /* do not issue start on add */ + + unsigned int device_blocked; /* Device returned QUEUE_FULL. */ + + unsigned int max_device_blocked; /* what device_blocked counts down from */ +#define SCSI_DEFAULT_DEVICE_BLOCKED 3 + + struct device sdev_driverfs_dev; +}; +#define to_scsi_device(d) \ + container_of(d, struct scsi_device, sdev_driverfs_dev) + +extern struct scsi_device *scsi_add_device(struct Scsi_Host *, + uint, uint, uint); +extern int scsi_remove_device(struct scsi_device *); +extern void scsi_set_device_offline(struct scsi_device *); + +extern int scsi_device_get(struct scsi_device *); +extern void scsi_device_put(struct scsi_device *); + +extern void scsi_adjust_queue_depth(struct scsi_device *, int, int); +extern int scsi_track_queue_full(struct scsi_device *, int); + +extern int scsi_set_medium_removal(struct scsi_device *, char); + +#endif /* _SCSI_SCSI_DEVICE_H */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h new file mode 100644 index 00000000000..9bfb4ac7e43 --- /dev/null +++ b/include/scsi/scsi_eh.h @@ -0,0 +1,21 @@ +#ifndef _SCSI_SCSI_EH_H +#define _SCSI_SCSI_EH_H + +extern void scsi_add_timer(struct scsi_cmnd *, int, + void (*)(struct scsi_cmnd *)); +extern int scsi_delete_timer(struct scsi_cmnd *); +extern void scsi_report_bus_reset(struct Scsi_Host *, int); +extern void scsi_report_device_reset(struct Scsi_Host *, int, int); +extern int scsi_block_when_processing_errors(struct scsi_device *); +extern void scsi_sleep(int); + +/* + * Reset request from external source + */ +#define SCSI_TRY_RESET_DEVICE 1 +#define SCSI_TRY_RESET_BUS 2 +#define SCSI_TRY_RESET_HOST 3 + +extern int scsi_reset_provider(struct scsi_device *, int); + +#endif /* _SCSI_SCSI_EH_H */ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h new file mode 100644 index 00000000000..d92dc75d131 --- /dev/null +++ b/include/scsi/scsi_host.h @@ -0,0 +1,525 @@ +#ifndef _SCSI_SCSI_HOST_H +#define _SCSI_SCSI_HOST_H + +#include +#include +#include + +struct block_device; +struct module; +struct scsi_cmnd; +struct scsi_device; +struct Scsi_Host; +struct scsi_host_cmd_pool; + + +/* + * The various choices mean: + * NONE: Self evident. Host adapter is not capable of scatter-gather. + * ALL: Means that the host adapter module can do scatter-gather, + * and that there is no limit to the size of the table to which + * we scatter/gather data. + * Anything else: Indicates the maximum number of chains that can be + * used in one scatter-gather request. + */ +#define SG_NONE 0 +#define SG_ALL 0xff + + +#define DISABLE_CLUSTERING 0 +#define ENABLE_CLUSTERING 1 + + +struct scsi_host_template { + struct module *module; + const char *name; + + /* + * Used to initialize old-style drivers. For new-style drivers + * just perform all work in your module initialization function. + * + * Status: OBSOLETE + */ + int (* detect)(struct scsi_host_template *); + + /* + * Used as unload callback for hosts with old-style drivers. + * + * Status: OBSOLETE + */ + int (* release)(struct Scsi_Host *); + + /* + * The info function will return whatever useful information the + * developer sees fit. If not provided, then the name field will + * be used instead. + * + * Status: OPTIONAL + */ + const char *(* info)(struct Scsi_Host *); + + /* + * Ioctl interface + * + * Status: OPTIONAL + */ + int (* ioctl)(struct scsi_device *dev, int cmd, void *arg); + + /* + * The queuecommand function is used to queue up a scsi + * command block to the LLDD. When the driver finished + * processing the command the done callback is invoked. + * + * If queuecommand returns 0, then the HBA has accepted the + * command. The done() function must be called on the command + * when the driver has finished with it. (you may call done on the + * command before queuecommand returns, but in this case you + * *must* return 0 from queuecommand). + * + * Queuecommand may also reject the command, in which case it may + * not touch the command and must not call done() for it. + * + * There are two possible rejection returns: + * + * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but + * allow commands to other devices serviced by this host. + * + * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this + * host temporarily. + * + * For compatibility, any other non-zero return is treated the + * same as SCSI_MLQUEUE_HOST_BUSY. + * + * NOTE: "temporarily" means either until the next command for# + * this device/host completes, or a period of time determined by + * I/O pressure in the system if there are no other outstanding + * commands. + * + * STATUS: REQUIRED + */ + int (* queuecommand)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + + /* + * This is an error handling strategy routine. You don't need to + * define one of these if you don't want to - there is a default + * routine that is present that should work in most cases. For those + * driver authors that have the inclination and ability to write their + * own strategy routine, this is where it is specified. Note - the + * strategy routine is *ALWAYS* run in the context of the kernel eh + * thread. Thus you are guaranteed to *NOT* be in an interrupt + * handler when you execute this, and you are also guaranteed to + * *NOT* have any other commands being queued while you are in the + * strategy routine. When you return from this function, operations + * return to normal. + * + * See scsi_error.c scsi_unjam_host for additional comments about + * what this function should and should not be attempting to do. + * + * Status: REQUIRED (at least one of them) + */ + int (* eh_strategy_handler)(struct Scsi_Host *); + int (* eh_abort_handler)(struct scsi_cmnd *); + int (* eh_device_reset_handler)(struct scsi_cmnd *); + int (* eh_bus_reset_handler)(struct scsi_cmnd *); + int (* eh_host_reset_handler)(struct scsi_cmnd *); + + /* + * Old EH handlers, no longer used. Make them warn the user of old + * drivers by using a wrong type + * + * Status: MORE THAN OBSOLETE + */ + int (* abort)(int); + int (* reset)(int, int); + + /* + * Before the mid layer attempts to scan for a new device where none + * currently exists, it will call this entry in your driver. Should + * your driver need to allocate any structs or perform any other init + * items in order to send commands to a currently unused target/lun + * combo, then this is where you can perform those allocations. This + * is specifically so that drivers won't have to perform any kind of + * "is this a new device" checks in their queuecommand routine, + * thereby making the hot path a bit quicker. + * + * Return values: 0 on success, non-0 on failure + * + * Deallocation: If we didn't find any devices at this ID, you will + * get an immediate call to slave_destroy(). If we find something + * here then you will get a call to slave_configure(), then the + * device will be used for however long it is kept around, then when + * the device is removed from the system (or * possibly at reboot + * time), you will then get a call to slave_detach(). This is + * assuming you implement slave_configure and slave_destroy. + * However, if you allocate memory and hang it off the device struct, + * then you must implement the slave_destroy() routine at a minimum + * in order to avoid leaking memory + * each time a device is tore down. + * + * Status: OPTIONAL + */ + int (* slave_alloc)(struct scsi_device *); + + /* + * Once the device has responded to an INQUIRY and we know the + * device is online, we call into the low level driver with the + * struct scsi_device *. If the low level device driver implements + * this function, it *must* perform the task of setting the queue + * depth on the device. All other tasks are optional and depend + * on what the driver supports and various implementation details. + * + * Things currently recommended to be handled at this time include: + * + * 1. Setting the device queue depth. Proper setting of this is + * described in the comments for scsi_adjust_queue_depth. + * 2. Determining if the device supports the various synchronous + * negotiation protocols. The device struct will already have + * responded to INQUIRY and the results of the standard items + * will have been shoved into the various device flag bits, eg. + * device->sdtr will be true if the device supports SDTR messages. + * 3. Allocating command structs that the device will need. + * 4. Setting the default timeout on this device (if needed). + * 5. Anything else the low level driver might want to do on a device + * specific setup basis... + * 6. Return 0 on success, non-0 on error. The device will be marked + * as offline on error so that no access will occur. If you return + * non-0, your slave_detach routine will never get called for this + * device, so don't leave any loose memory hanging around, clean + * up after yourself before returning non-0 + * + * Status: OPTIONAL + */ + int (* slave_configure)(struct scsi_device *); + + /* + * Immediately prior to deallocating the device and after all activity + * has ceased the mid layer calls this point so that the low level + * driver may completely detach itself from the scsi device and vice + * versa. The low level driver is responsible for freeing any memory + * it allocated in the slave_alloc or slave_configure calls. + * + * Status: OPTIONAL + */ + void (* slave_destroy)(struct scsi_device *); + + /* + * This function determines the bios parameters for a given + * harddisk. These tend to be numbers that are made up by + * the host adapter. Parameters: + * size, device, list (heads, sectors, cylinders) + * + * Status: OPTIONAL + */ + int (* bios_param)(struct scsi_device *, struct block_device *, + sector_t, int []); + + /* + * Can be used to export driver statistics and other infos to the + * world outside the kernel ie. userspace and it also provides an + * interface to feed the driver with information. + * + * Status: OBSOLETE + */ + int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); + + /* + * Name of proc directory + */ + char *proc_name; + + /* + * Used to store the procfs directory if a driver implements the + * proc_info method. + */ + struct proc_dir_entry *proc_dir; + + /* + * This determines if we will use a non-interrupt driven + * or an interrupt driven scheme, It is set to the maximum number + * of simultaneous commands a given host adapter will accept. + */ + int can_queue; + + /* + * In many instances, especially where disconnect / reconnect are + * supported, our host also has an ID on the SCSI bus. If this is + * the case, then it must be reserved. Please set this_id to -1 if + * your setup is in single initiator mode, and the host lacks an + * ID. + */ + int this_id; + + /* + * This determines the degree to which the host adapter is capable + * of scatter-gather. + */ + unsigned short sg_tablesize; + + /* + * If the host adapter has limitations beside segment count + */ + unsigned short max_sectors; + + /* + * This specifies "machine infinity" for host templates which don't + * limit the transfer size. Note this limit represents an absolute + * maximum, and may be over the transfer limits allowed for + * individual devices (e.g. 256 for SCSI-1) + */ +#define SCSI_DEFAULT_MAX_SECTORS 1024 + + /* + * True if this host adapter can make good use of linked commands. + * This will allow more than one command to be queued to a given + * unit on a given host. Set this to the maximum number of command + * blocks to be provided for each device. Set this to 1 for one + * command block per lun, 2 for two, etc. Do not set this to 0. + * You should make sure that the host adapter will do the right thing + * before you try setting this above 1. + */ + short cmd_per_lun; + + /* + * present contains counter indicating how many boards of this + * type were found when we did the scan. + */ + unsigned char present; + + /* + * true if this host adapter uses unchecked DMA onto an ISA bus. + */ + unsigned unchecked_isa_dma:1; + + /* + * true if this host adapter can make good use of clustering. + * I originally thought that if the tablesize was large that it + * was a waste of CPU cycles to prepare a cluster list, but + * it works out that the Buslogic is faster if you use a smaller + * number of segments (i.e. use clustering). I guess it is + * inefficient. + */ + unsigned use_clustering:1; + + /* + * True for emulated SCSI host adapters (e.g. ATAPI) + */ + unsigned emulated:1; + + unsigned highmem_io:1; + + /* + * True if the driver wishes to use the generic block layer + * tag queueing functions + */ + unsigned use_blk_tcq:1; + + /* + * Countdown for host blocking with no commands outstanding + */ + unsigned int max_host_blocked; + + /* + * Default value for the blocking. If the queue is empty, + * host_blocked counts down in the request_fn until it restarts + * host operations as zero is reached. + * + * FIXME: This should probably be a value in the template + */ +#define SCSI_DEFAULT_HOST_BLOCKED 7 + + /* + * Pointer to the sysfs class properties for this host + */ + struct class_device_attribute **shost_attrs; + + /* + * Pointer to the SCSI device properties for this host + */ + struct device_attribute **sdev_attrs; + + /* + * List of hosts per template. + * + * This is only for use by scsi_module.c for legacy templates. + * For these access to it is synchronized implicitly by + * module_init/module_exit. + */ + struct list_head legacy_hosts; +}; + +struct Scsi_Host { + struct list_head my_devices; + struct scsi_host_cmd_pool *cmd_pool; + spinlock_t free_list_lock; + struct list_head free_list; /* backup store of cmd structs */ + struct list_head starved_list; + + spinlock_t default_lock; + spinlock_t *host_lock; + + struct list_head eh_cmd_q; + struct task_struct * ehandler; /* Error recovery thread. */ + struct semaphore * eh_wait; /* The error recovery thread waits on + this. */ + struct completion * eh_notify; /* wait for eh to begin or end */ + struct semaphore * eh_action; /* Wait for specific actions on the + host. */ + unsigned int eh_active:1; /* Indicates the eh thread is awake and active if + this is true. */ + unsigned int eh_kill:1; /* set when killing the eh thread */ + wait_queue_head_t host_wait; + struct scsi_host_template *hostt; + volatile unsigned short host_busy; /* commands actually active on low-level */ + volatile unsigned short host_failed; /* commands that failed. */ + + unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ + int resetting; /* if set, it means that last_reset is a valid value */ + unsigned long last_reset; + + /* + * These three parameters can be used to allow for wide scsi, + * and for host adapters that support multiple busses + * The first two should be set to 1 more than the actual max id + * or lun (i.e. 8 for normal systems). + */ + unsigned int max_id; + unsigned int max_lun; + unsigned int max_channel; + + /* + * This is a unique identifier that must be assigned so that we + * have some way of identifying each detected host adapter properly + * and uniquely. For hosts that do not support more than one card + * in the system at one time, this does not need to be set. It is + * initialized to 0 in scsi_register. + */ + unsigned int unique_id; + + /* + * The maximum length of SCSI commands that this host can accept. + * Probably 12 for most host adapters, but could be 16 for others. + * For drivers that don't set this field, a value of 12 is + * assumed. I am leaving this as a number rather than a bit + * because you never know what subsequent SCSI standards might do + * (i.e. could there be a 20 byte or a 24-byte command a few years + * down the road?). + */ + unsigned char max_cmd_len; + + int this_id; + int can_queue; + short cmd_per_lun; + short unsigned int sg_tablesize; + short unsigned int max_sectors; + + unsigned in_recovery:1; + unsigned unchecked_isa_dma:1; + unsigned use_clustering:1; + unsigned highmem_io:1; + unsigned use_blk_tcq:1; + + /* + * Host has requested that no further requests come through for the + * time being. + */ + unsigned host_self_blocked:1; + + /* + * Host uses correct SCSI ordering not PC ordering. The bit is + * set for the minority of drivers whose authors actually read + * the spec ;) + */ + unsigned reverse_ordering:1; + + /* + * Host has rejected a command because it was busy. + */ + unsigned int host_blocked; + + /* + * Value host_blocked counts down from + */ + unsigned int max_host_blocked; + + /* + * Support for sysfs + */ + struct device host_gendev; + struct class_device class_dev; + + /* legacy crap */ + unsigned long base; + unsigned long io_port; + unsigned char n_io_port; + unsigned char dma_channel; + unsigned int irq; + + + /* + * List of hosts per template. + * + * This is only for use by scsi_module.c for legacy templates. + * For these access to it is synchronized implicitly by + * module_init/module_exit. + */ + struct list_head sht_legacy_list; + + /* + * We should ensure that this is aligned, both for better performance + * and also because some compilers (m68k) don't automatically force + * alignment to a long boundary. + */ + unsigned long hostdata[0] /* Used for storage of host specific stuff */ + __attribute__ ((aligned (sizeof(unsigned long)))); +}; +#define dev_to_shost(d) \ + container_of(d, struct Scsi_Host, host_gendev) +#define class_to_shost(d) \ + container_of(d, struct Scsi_Host, class_dev) + +extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); +extern int scsi_add_host(struct Scsi_Host *, struct device *); +extern int scsi_remove_host(struct Scsi_Host *); +extern void scsi_host_get(struct Scsi_Host *); +extern void scsi_host_put(struct Scsi_Host *t); +extern struct Scsi_Host *scsi_host_lookup(unsigned short); + +extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); + +static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) +{ + shost->host_lock = lock; +} + +static inline void scsi_set_device(struct Scsi_Host *shost, + struct device *dev) +{ + shost->host_gendev.parent = dev; +} + +static inline struct device *scsi_get_device(struct Scsi_Host *shost) +{ + return shost->host_gendev.parent; +} + +extern void scsi_sysfs_release_attributes(struct scsi_host_template *); + +extern void scsi_unblock_requests(struct Scsi_Host *); +extern void scsi_block_requests(struct Scsi_Host *); + +/* + * These two functions are used to allocate and free a pseudo device + * which will connect to the host adapter itself rather than any + * physical device. You must deallocate when you are done with the + * thing. This physical pseudo-device isn't real and won't be available + * from any high-level drivers. + */ +extern void scsi_free_host_dev(struct scsi_device *); +extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); + +/* legacy interfaces */ +extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int); +extern void scsi_unregister(struct Scsi_Host *); + +#endif /* _SCSI_SCSI_HOST_H */ diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h new file mode 100644 index 00000000000..17cfe3f71d1 --- /dev/null +++ b/include/scsi/scsi_request.h @@ -0,0 +1,58 @@ +#ifndef _SCSI_SCSI_REQUEST_H +#define _SCSI_SCSI_REQUEST_H + +#include + +struct request; +struct scsi_cmnd; +struct scsi_device; +struct Scsi_Host; + + +/* + * This is essentially a slimmed down version of Scsi_Cmnd. The point of + * having this is that requests that are injected into the queue as result + * of things like ioctls and character devices shouldn't be using a + * Scsi_Cmnd until such a time that the command is actually at the head + * of the queue and being sent to the driver. + */ +struct scsi_request { + int sr_magic; + int sr_result; /* Status code from lower level driver */ + unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + struct Scsi_Host *sr_host; + struct scsi_device *sr_device; + struct scsi_cmnd *sr_command; + struct request *sr_request; /* A copy of the command we are + working on */ + unsigned sr_bufflen; /* Size of data buffer */ + void *sr_buffer; /* Data buffer */ + int sr_allowed; + unsigned char sr_data_direction; + unsigned char sr_cmd_len; + unsigned char sr_cmnd[MAX_COMMAND_SIZE]; + void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ + int sr_timeout_per_command; + unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ + unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ + unsigned sr_underflow; /* Return error if less than + this amount is transferred */ + void *upper_private_data; /* reserved for owner (usually upper + level driver) of this request */ +}; + +extern struct scsi_request *scsi_allocate_request(struct scsi_device *); +extern void scsi_release_request(struct scsi_request *); +extern void scsi_wait_req(struct scsi_request *, const void *cmnd, + void *buffer, unsigned bufflen, + int timeout, int retries); +extern void scsi_do_req(struct scsi_request *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done) (struct scsi_cmnd *), + int timeout, int retries); + +#endif /* _SCSI_SCSI_REQUEST_H */ diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h new file mode 100644 index 00000000000..a0fcc800521 --- /dev/null +++ b/include/scsi/scsi_tcq.h @@ -0,0 +1,94 @@ +#ifndef _SCSI_SCSI_TCQ_H +#define _SCSI_SCSI_TCQ_H + +#include +#include +#include + + +#define MSG_SIMPLE_TAG 0x20 +#define MSG_HEAD_TAG 0x21 +#define MSG_ORDERED_TAG 0x22 + +#define SCSI_NO_TAG (-1) /* identify no tag in use */ + + +/** + * scsi_activate_tcq - turn on tag command queueing + * @SDpnt: device to turn on TCQ for + * @depth: queue depth + * + * Notes: + * Eventually, I hope depth would be the maximum depth + * the device could cope with and the real queue depth + * would be adjustable from 0 to depth. + **/ +static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth) +{ + if (sdev->tagged_supported) { + if (!blk_queue_tagged(sdev->request_queue)) + blk_queue_init_tags(sdev->request_queue, depth); + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); + } +} + +/** + * scsi_deactivate_tcq - turn off tag command queueing + * @SDpnt: device to turn off TCQ for + **/ +static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) +{ + if (blk_queue_tagged(sdev->request_queue)) + blk_queue_free_tags(sdev->request_queue); + scsi_adjust_queue_depth(sdev, 0, depth); +} + +/** + * scsi_populate_tag_msg - place a tag message in a buffer + * @SCpnt: pointer to the Scsi_Cmnd for the tag + * @msg: pointer to the area to place the tag + * + * Notes: + * designed to create the correct type of tag message for the + * particular request. Returns the size of the tag message. + * May return 0 if TCQ is disabled for this device. + **/ +static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) +{ + struct request *req = cmd->request; + + if (blk_rq_tagged(req)) { + if (req->flags & REQ_HARDBARRIER) + *msg++ = MSG_ORDERED_TAG; + else + *msg++ = MSG_SIMPLE_TAG; + *msg++ = req->tag; + return 2; + } + + return 0; +} + +/** + * scsi_find_tag - find a tagged command by device + * @SDpnt: pointer to the ScSI device + * @tag: the tag number + * + * Notes: + * Only works with tags allocated by the generic blk layer. + **/ +static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag) +{ + + struct request *req; + + if (tag != SCSI_NO_TAG) { + req = blk_queue_find_tag(sdev->request_queue, tag); + return req ? (struct scsi_cmnd *)req->special : NULL; + } + + /* single command, look in space */ + return sdev->current_cmnd; +} + +#endif /* _SCSI_SCSI_TCQ_H */ diff --git a/ipc/sem.c b/ipc/sem.c index 991831da7f1..07d9a2e054b 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -214,7 +214,7 @@ static int sem_revalidate(int semid, struct sem_array* sma, int nsems, short flg return -EIDRM; } - if (ipcperms(&sma->sem_perm, flg)) { + if (flg && ipcperms(&sma->sem_perm, flg)) { sem_unlock(smanew); return -EACCES; } @@ -412,7 +412,7 @@ static void freeary (struct sem_array *sma, int id) int size; /* Invalidate the existing undo structures for this semaphore set. - * (They will be freed without any further action in sem_exit() + * (They will be freed without any further action in exit_sem() * or during the next semop.) */ for (un = sma->undo; un; un = un->id_next) @@ -887,106 +887,87 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) return 0; } -static struct sem_undo* freeundos(struct sem_undo* un) +static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) { - struct sem_undo* u; - struct sem_undo** up; - - for(up = ¤t->sysvsem.undo_list->proc_list;(u=*up);up=&u->proc_next) { - if(un==u) { - un=u->proc_next; - *up=un; - kfree(u); - return un; - } - } - printk ("freeundos undo list error id=%d\n", un->semid); - return un->proc_next; -} + struct sem_undo **last, *un; -static inline struct sem_undo *find_undo(int semid) -{ - struct sem_undo *un; - - un = NULL; - if (current->sysvsem.undo_list != NULL) { - un = current->sysvsem.undo_list->proc_list; - } + last = &ulp->proc_list; + un = *last; while(un != NULL) { if(un->semid==semid) break; - if(un->semid==-1) - un=freeundos(un); - else - un=un->proc_next; + if(un->semid==-1) { + *last=un->proc_next; + kfree(un); + } else { + last=&un->proc_next; + } + un=*last; } return un; } -/* returns without sem_lock and semundo list locks on error! */ -static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, int alter) +static struct sem_undo *find_undo(int semid) { - int size, nsems, error; - struct sem_undo *un, *new_un; - struct sem_undo_list *undo_list; - unsigned long saved_add_count; + struct sem_array *sma; + struct sem_undo_list *ulp; + struct sem_undo *un, *new; + int nsems; + int error; + error = get_undo_list(&ulp); + if (error) + return ERR_PTR(error); - nsems = sma->sem_nsems; - saved_add_count = 0; - if (current->sysvsem.undo_list != NULL) - saved_add_count = current->sysvsem.undo_list->add_count; - sem_unlock(sma); + lock_semundo(); + un = lookup_undo(ulp, semid); unlock_semundo(); + if (likely(un!=NULL)) + goto out; - error = get_undo_list(&undo_list); - if (error) - return error; + /* no undo structure around - allocate one. */ + sma = sem_lock(semid); + un = ERR_PTR(-EINVAL); + if(sma==NULL) + goto out; + un = ERR_PTR(-EIDRM); + if (sem_checkid(sma,semid)) + goto out_unlock; + nsems = sma->sem_nsems; + sem_unlock(sma); - size = sizeof(struct sem_undo) + sizeof(short)*nsems; - un = (struct sem_undo *) kmalloc(size, GFP_KERNEL); - if (!un) - return -ENOMEM; + new = (struct sem_undo *) kmalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); + if (!new) + return ERR_PTR(-ENOMEM); + memset(new, 0, sizeof(struct sem_undo) + sizeof(short)*nsems); + new->semadj = (short *) &new[1]; + new->semid = semid; - memset(un, 0, size); lock_semundo(); - error = sem_revalidate(semid, sma, nsems, alter ? S_IWUGO : S_IRUGO); - if(error) { + un = lookup_undo(ulp, semid); + if (un) { unlock_semundo(); - kfree(un); - return error; + kfree(new); + goto out; } - - - /* alloc_undo has just - * released all locks and reacquired them. - * But, another thread may have - * added the semundo we were looking for - * during that time. - * So, we check for it again. - * only initialize and add the new one - * if we don't discover one. - */ - new_un = NULL; - if (current->sysvsem.undo_list->add_count != saved_add_count) - new_un = find_undo(semid); - - if (new_un != NULL) { - if (sma->undo != new_un) - BUG(); - kfree(un); - un = new_un; - } else { - current->sysvsem.undo_list->add_count++; - un->semadj = (short *) &un[1]; - un->semid = semid; - un->proc_next = undo_list->proc_list; - undo_list->proc_list = un; - un->id_next = sma->undo; - sma->undo = un; + error = sem_revalidate(semid, sma, nsems, 0); + if (error) { + sem_unlock(sma); + unlock_semundo(); + kfree(new); + un = ERR_PTR(error); + goto out; } - *unp = un; - return 0; + new->proc_next = ulp->proc_list; + ulp->proc_list = new; + new->id_next = sma->undo; + sma->undo = new; + sem_unlock(sma); + un = new; +out_unlock: + unlock_semundo(); +out: + return un; } asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops) @@ -1002,7 +983,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, struct sembuf fast_sops[SEMOPM_FAST]; struct sembuf* sops = fast_sops, *sop; struct sem_undo *un; - int undos = 0, decrease = 0, alter = 0; + int undos = 0, decrease = 0, alter = 0, max; struct sem_queue queue; unsigned long jiffies_left = 0; @@ -1032,18 +1013,10 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, } jiffies_left = timespec_to_jiffies(&_timeout); } - lock_semundo(); - sma = sem_lock(semid); - error=-EINVAL; - if(sma==NULL) - goto out_semundo_free; - error = -EIDRM; - if (sem_checkid(sma,semid)) - goto out_unlock_semundo_free; - error = -EFBIG; + max = 0; for (sop = sops; sop < sops + nsops; sop++) { - if (sop->sem_num >= sma->sem_nsems) - goto out_unlock_semundo_free; + if (sop->sem_num >= max) + max = sop->sem_num; if (sop->sem_flg & SEM_UNDO) undos++; if (sop->sem_op < 0) @@ -1053,30 +1026,42 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, } alter |= decrease; - error = -EACCES; - if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) - goto out_unlock_semundo_free; - - error = security_sem_semop(sma, sops, nsops, alter); - if (error) - goto out_unlock_semundo_free; - - error = -EACCES; +retry_undos: if (undos) { - /* Make sure we have an undo structure - * for this process and this semaphore set. - */ - un = find_undo(semid); - if (!un) { - error = alloc_undo(sma,&un,semid,alter); - if (error) - goto out_free; - + if (IS_ERR(un)) { + error = PTR_ERR(un); + goto out_free; } } else un = NULL; + sma = sem_lock(semid); + error=-EINVAL; + if(sma==NULL) + goto out_free; + error = -EIDRM; + if (sem_checkid(sma,semid)) + goto out_unlock_free; + /* + * semid identifies are not unique - find_undo may have + * allocated an undo structure, it was invalidated by an RMID + * and now a new array with received the same id. Check and retry. + */ + if (un && un->semid == -1) + goto retry_undos; + error = -EFBIG; + if (max >= sma->sem_nsems) + goto out_unlock_free; + + error = -EACCES; + if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) + goto out_unlock_free; + + error = security_sem_semop(sma, sops, nsops, alter); + if (error) + goto out_unlock_free; + error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0); if (error <= 0) goto update; @@ -1096,28 +1081,24 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); - current->sysvsem.sleep_list = &queue; for (;;) { queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; sem_unlock(sma); - unlock_semundo(); if (timeout) jiffies_left = schedule_timeout(jiffies_left); else schedule(); - lock_semundo(); sma = sem_lock(semid); if(sma==NULL) { if(queue.prev != NULL) BUG(); - current->sysvsem.sleep_list = NULL; error = -EIDRM; - goto out_semundo_free; + goto out_free; } /* * If queue.status == 1 we where woken up and @@ -1139,19 +1120,15 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf *tsops, if (queue.prev) /* got Interrupt */ break; /* Everything done by update_queue */ - current->sysvsem.sleep_list = NULL; - goto out_unlock_semundo_free; + goto out_unlock_free; } } - current->sysvsem.sleep_list = NULL; remove_from_queue(sma,&queue); update: if (alter) update_queue (sma); -out_unlock_semundo_free: +out_unlock_free: sem_unlock(sma); -out_semundo_free: - unlock_semundo(); out_free: if(sops != fast_sops) kfree(sops); @@ -1185,21 +1162,6 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) return 0; } -static inline void __exit_semundo(struct task_struct *tsk) -{ - struct sem_undo_list *undo_list; - - undo_list = tsk->sysvsem.undo_list; - if (!atomic_dec_and_test(&undo_list->refcnt)) - kfree(undo_list); -} - -void exit_semundo(struct task_struct *tsk) -{ - if (tsk->sysvsem.undo_list != NULL) - __exit_semundo(tsk); -} - /* * add semadj values to semaphores, free undo structures. * undo structures are not freed when semaphore arrays are destroyed @@ -1212,44 +1174,29 @@ void exit_semundo(struct task_struct *tsk) * The current implementation does not do so. The POSIX standard * and SVID should be consulted to determine what behavior is mandated. */ -void sem_exit (void) +void exit_sem(struct task_struct *tsk) { - struct sem_queue *q; - struct sem_undo *u, *un = NULL, **up, **unp; - struct sem_array *sma; struct sem_undo_list *undo_list; - int nsems, i; - - lock_kernel(); - - /* If the current process was sleeping for a semaphore, - * remove it from the queue. - */ - if ((q = current->sysvsem.sleep_list)) { - int semid = q->id; - sma = sem_lock(semid); - current->sysvsem.sleep_list = NULL; + struct sem_undo *u, **up; - if (q->prev) { - if(sma==NULL) - BUG(); - remove_from_queue(q->sma,q); - } - if(sma!=NULL) - sem_unlock(sma); - } + undo_list = tsk->sysvsem.undo_list; + if (!undo_list) + return; - undo_list = current->sysvsem.undo_list; - if ((undo_list == NULL) || (atomic_read(&undo_list->refcnt) != 1)) { - unlock_kernel(); + if (!atomic_dec_and_test(&undo_list->refcnt)) return; - } /* There's no need to hold the semundo list lock, as current * is the last task exiting for this undo list. */ for (up = &undo_list->proc_list; (u = *up); *up = u->proc_next, kfree(u)) { - int semid = u->semid; + struct sem_array *sma; + int nsems, i; + struct sem_undo *un, **unp; + int semid; + + semid = u->semid; + if(semid == -1) continue; sma = sem_lock(semid); @@ -1259,15 +1206,14 @@ void sem_exit (void) if (u->semid == -1) goto next_entry; - if (sem_checkid(sma,u->semid)) - goto next_entry; + BUG_ON(sem_checkid(sma,u->semid)); /* remove u from the sma->undo list */ for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) goto found; } - printk ("sem_exit undo list error id=%d\n", u->semid); + printk ("exit_sem undo list error id=%d\n", u->semid); goto next_entry; found: *unp = un->id_next; @@ -1275,10 +1221,12 @@ found: nsems = sma->sem_nsems; for (i = 0; i < nsems; i++) { struct sem * sem = &sma->sem_base[i]; - sem->semval += u->semadj[i]; - if (sem->semval < 0) - sem->semval = 0; /* shouldn't happen */ - sem->sempid = current->pid; + if (u->semadj[i]) { + sem->semval += u->semadj[i]; + if (sem->semval < 0) + sem->semval = 0; /* shouldn't happen */ + sem->sempid = current->pid; + } } sma->sem_otime = get_seconds(); /* maybe some queued-up processes were waiting for this */ @@ -1286,9 +1234,7 @@ found: next_entry: sem_unlock(sma); } - __exit_semundo(current); - - unlock_kernel(); + kfree(undo_list); } #ifdef CONFIG_PROC_FS diff --git a/ipc/util.c b/ipc/util.c index a2f4c3b1c68..b1e76464b85 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -541,17 +541,11 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) return 0; } -void exit_semundo(struct task_struct *tsk) +void exit_sem(struct task_struct *tsk) { return; } - -void sem_exit (void) -{ - return; -} - asmlinkage long sys_semget (key_t key, int nsems, int semflg) { return -ENOSYS; diff --git a/kernel/acct.c b/kernel/acct.c index 9f7cdf9a826..e63095525ac 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -54,6 +54,7 @@ #include #include #include +#include /* sector_div */ /* * These constants control the amount of freespace that suspend and @@ -100,9 +101,11 @@ static void acct_timeout(unsigned long unused) */ static int check_free_space(struct file *file) { - struct statfs sbuf; + struct kstatfs sbuf; int res; int act; + sector_t resume; + sector_t suspend; spin_lock(&acct_globals.lock); res = acct_globals.active; @@ -113,10 +116,15 @@ static int check_free_space(struct file *file) /* May block */ if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf)) return res; + suspend = sbuf.f_blocks * SUSPEND; + resume = sbuf.f_blocks * RESUME; - if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100) + sector_div(suspend, 100); + sector_div(resume, 100); + + if (sbuf.f_bavail <= suspend) act = -1; - else if (sbuf.f_bavail >= RESUME * sbuf.f_blocks / 100) + else if (sbuf.f_bavail >= resume) act = 1; else act = 0; diff --git a/kernel/compat.c b/kernel/compat.c index 8709faa648c..b28e3db9468 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -354,6 +354,8 @@ asmlinkage long compat_sys_getrusage(int who, struct compat_rusage *ru) if (put_compat_rusage(ru, &r)) return -EFAULT; + + return 0; } asmlinkage long diff --git a/kernel/exit.c b/kernel/exit.c index c5b8ec241a8..7dee095b31b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -698,7 +698,7 @@ NORET_TYPE void do_exit(long code) acct_process(code); __exit_mm(tsk); - sem_exit(); + exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); exit_namespace(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index fba722be316..5ef2dca0235 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -39,7 +39,7 @@ #include extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); -extern void exit_semundo(struct task_struct *tsk); +extern void exit_sem(struct task_struct *tsk); /* The idle threads do not count.. * Protected by write_lock_irq(&tasklist_lock) @@ -887,13 +887,11 @@ struct task_struct *copy_process(unsigned long clone_flags, if (retval) goto bad_fork_cleanup_namespace; - if (clone_flags & CLONE_CHILD_SETTID) - p->set_child_tid = child_tidptr; + p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* * Clear TID on mm_release()? */ - if (clone_flags & CLONE_CHILD_CLEARTID) - p->clear_child_tid = child_tidptr; + p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr: NULL; /* * Syscall tracing should be turned off in the child regardless @@ -1034,7 +1032,7 @@ bad_fork_cleanup_fs: bad_fork_cleanup_files: exit_files(p); /* blocking */ bad_fork_cleanup_semundo: - exit_semundo(p); + exit_sem(p); bad_fork_cleanup_security: security_task_free(p); bad_fork_cleanup: diff --git a/kernel/kmod.c b/kernel/kmod.c index d9e4299a876..e011611afb7 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -183,12 +183,15 @@ static int wait_for_helper(void *data) struct subprocess_info *sub_info = data; pid_t pid; - pid = kernel_thread(____call_usermodehelper, sub_info, - CLONE_VFORK | SIGCHLD); + sub_info->retval = 0; + pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD); if (pid < 0) sub_info->retval = pid; else - sys_wait4(pid, (unsigned int *)&sub_info->retval, 0, NULL); + /* We don't have a SIGCHLD signal handler, so this + * always returns -ECHILD, but the important thing is + * that it blocks. */ + sys_wait4(pid, NULL, 0, NULL); complete(sub_info->complete); return 0; @@ -231,8 +234,7 @@ static void __call_usermodehelper(void *data) * (ie. it runs with full root capabilities). * * Must be called from process context. Returns a negative error code - * if program was not execed successfully, or (exitcode << 8 + signal) - * of the application (0 if wait is not set). + * if program was not execed successfully, or 0. */ int call_usermodehelper(char *path, char **argv, char **envp, int wait) { diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 8e7c9206752..cbb2313433c 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -592,7 +592,6 @@ EXPORT_SYMBOL(__tasklet_hi_schedule); /* init task, for moving kthread roots - ought to export a function ?? */ EXPORT_SYMBOL(init_task); -EXPORT_SYMBOL(init_thread_union); EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(find_task_by_pid); @@ -604,5 +603,6 @@ EXPORT_SYMBOL(__per_cpu_offset); /* debug */ EXPORT_SYMBOL(dump_stack); EXPORT_SYMBOL(ptrace_notify); +EXPORT_SYMBOL(console_printk); -EXPORT_SYMBOL(current_kernel_time); +EXPORT_SYMBOL(current_kernel_time); diff --git a/kernel/sched.c b/kernel/sched.c index c603aaa6779..9566cd11de1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1880,10 +1880,6 @@ asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) return -EFAULT; - new_mask &= cpu_online_map; - if (!new_mask) - return -EINVAL; - read_lock(&tasklist_lock); p = find_process_by_pid(pid); @@ -1905,8 +1901,7 @@ asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, !capable(CAP_SYS_NICE)) goto out_unlock; - retval = 0; - set_cpus_allowed(p, new_mask); + retval = set_cpus_allowed(p, new_mask); out_unlock: put_task_struct(p); @@ -2182,10 +2177,7 @@ static void show_task(task_t * p) else printk(" (NOTLB)\n"); - { - extern void show_trace_task(task_t *tsk); - show_trace_task(p); - } + show_stack(p, NULL); } void show_state(void) @@ -2272,17 +2264,14 @@ typedef struct { * task must not exit() & deallocate itself prematurely. The * call is not atomic; no spinlocks may be held. */ -void set_cpus_allowed(task_t *p, unsigned long new_mask) +int set_cpus_allowed(task_t *p, unsigned long new_mask) { unsigned long flags; migration_req_t req; runqueue_t *rq; -#if 0 /* FIXME: Grab cpu_lock, return error on this case. --RR */ - new_mask &= cpu_online_map; - if (!new_mask) - BUG(); -#endif + if (any_online_cpu(new_mask) == NR_CPUS) + return -EINVAL; rq = task_rq_lock(p, &flags); p->cpus_allowed = new_mask; @@ -2292,7 +2281,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) */ if (new_mask & (1UL << task_cpu(p))) { task_rq_unlock(rq, &flags); - return; + return 0; } /* * If the task is not on a runqueue (and not running), then @@ -2301,7 +2290,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) if (!p->array && !task_running(rq, p)) { set_task_cpu(p, any_online_cpu(p->cpus_allowed)); task_rq_unlock(rq, &flags); - return; + return 0; } init_completion(&req.done); req.task = p; @@ -2311,6 +2300,7 @@ void set_cpus_allowed(task_t *p, unsigned long new_mask) wake_up_process(rq->migration_thread); wait_for_completion(&req.done); + return 0; } /* Move (not current) task off this cpu, onto dest cpu. */ diff --git a/kernel/timer.c b/kernel/timer.c index 5136630693b..ad3758c663d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -439,8 +439,8 @@ repeat: /* * Timekeeping variables */ -unsigned long tick_usec = TICK_USEC; /* ACTHZ period (usec) */ -unsigned long tick_nsec = TICK_NSEC; /* USER_HZ period (nsec) */ +unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */ +unsigned long tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */ /* * The current time diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 96883721865..24dcca29de3 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -259,15 +259,40 @@ void flush_workqueue(struct workqueue_struct *wq) } } -struct workqueue_struct *create_workqueue(const char *name) +static int create_workqueue_thread(struct workqueue_struct *wq, + const char *name, + int cpu) { - int ret, cpu, destroy = 0; - struct cpu_workqueue_struct *cwq; startup_t startup; + struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu; + int ret; + + spin_lock_init(&cwq->lock); + cwq->wq = wq; + cwq->thread = NULL; + cwq->insert_sequence = 0; + cwq->remove_sequence = 0; + INIT_LIST_HEAD(&cwq->worklist); + init_waitqueue_head(&cwq->more_work); + init_waitqueue_head(&cwq->work_done); + + init_completion(&startup.done); + startup.cwq = cwq; + startup.name = name; + ret = kernel_thread(worker_thread, &startup, CLONE_FS | CLONE_FILES); + if (ret >= 0) { + wait_for_completion(&startup.done); + BUG_ON(!cwq->thread); + } + return ret; +} + +struct workqueue_struct *create_workqueue(const char *name) +{ + int cpu, destroy = 0; struct workqueue_struct *wq; BUG_ON(strlen(name) > 10); - startup.name = name; wq = kmalloc(sizeof(*wq), GFP_KERNEL); if (!wq) @@ -276,27 +301,8 @@ struct workqueue_struct *create_workqueue(const char *name) for (cpu = 0; cpu < NR_CPUS; cpu++) { if (!cpu_online(cpu)) continue; - cwq = wq->cpu_wq + cpu; - - spin_lock_init(&cwq->lock); - cwq->wq = wq; - cwq->thread = NULL; - cwq->insert_sequence = 0; - cwq->remove_sequence = 0; - INIT_LIST_HEAD(&cwq->worklist); - init_waitqueue_head(&cwq->more_work); - init_waitqueue_head(&cwq->work_done); - - init_completion(&startup.done); - startup.cwq = cwq; - ret = kernel_thread(worker_thread, &startup, - CLONE_FS | CLONE_FILES); - if (ret < 0) + if (create_workqueue_thread(wq, name, cpu) < 0) destroy = 1; - else { - wait_for_completion(&startup.done); - BUG_ON(!cwq->thread); - } } /* * Was there any error during startup? If yes then clean up: @@ -308,28 +314,33 @@ struct workqueue_struct *create_workqueue(const char *name) return wq; } -void destroy_workqueue(struct workqueue_struct *wq) +static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu) { struct cpu_workqueue_struct *cwq; - int cpu; - flush_workqueue(wq); - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (!cpu_online(cpu)) - continue; - cwq = wq->cpu_wq + cpu; - if (!cwq->thread) - continue; - /* - * Initiate an exit and wait for it: - */ + cwq = wq->cpu_wq + cpu; + if (cwq->thread) { + printk("Cleaning up workqueue thread for %i\n", cpu); + /* Initiate an exit and wait for it: */ init_completion(&cwq->exit); + wmb(); /* Thread must see !cwq->thread after completion init */ cwq->thread = NULL; wake_up(&cwq->more_work); wait_for_completion(&cwq->exit); } +} + +void destroy_workqueue(struct workqueue_struct *wq) +{ + int cpu; + + flush_workqueue(wq); + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (cpu_online(cpu)) + cleanup_workqueue_thread(wq, cpu); + } kfree(wq); } diff --git a/lib/kobject.c b/lib/kobject.c index e2378597b98..fb49131f5ff 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -100,6 +100,9 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path, #define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define NUM_ENVP 32 /* number of env pointers */ +static unsigned long sequence_num; +static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED; + static void kset_hotplug(const char *action, struct kset *kset, struct kobject *kobj) { @@ -112,6 +115,7 @@ static void kset_hotplug(const char *action, struct kset *kset, int kobj_path_length; char *kobj_path = NULL; char *name = NULL; + unsigned long seq; /* If the kset has a filter operation, call it. If it returns failure, no hotplug event is required. */ @@ -152,6 +156,13 @@ static void kset_hotplug(const char *action, struct kset *kset, envp [i++] = scratch; scratch += sprintf(scratch, "ACTION=%s", action) + 1; + spin_lock(&sequence_lock); + seq = sequence_num++; + spin_unlock(&sequence_lock); + + envp [i++] = scratch; + scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; + kobj_path_length = get_kobj_path_length (kset, kobj); kobj_path = kmalloc (kobj_path_length, GFP_KERNEL); if (!kobj_path) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 9e54d17adaa..db2e96ea0fd 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -323,7 +323,8 @@ static void wb_kupdate(unsigned long arg) oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100; start_jif = jiffies; next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100; - nr_to_write = ps.nr_dirty + ps.nr_unstable; + nr_to_write = ps.nr_dirty + ps.nr_unstable + + (inodes_stat.nr_inodes - inodes_stat.nr_unused); while (nr_to_write > 0) { wbc.encountered_congestion = 0; wbc.nr_to_write = MAX_WRITEBACK_PAGES; @@ -516,7 +517,9 @@ int __set_page_dirty_nobuffers(struct page *page) list_add(&page->list, &mapping->dirty_pages); } spin_unlock(&mapping->page_lock); - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + if (!PageSwapCache(page)) + __mark_inode_dirty(mapping->host, + I_DIRTY_PAGES); } } return ret; diff --git a/mm/shmem.c b/mm/shmem.c index 8df99f64eb9..73301cee3f4 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1010,7 +1010,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) struct inode *inode = file->f_dentry->d_inode; ops = &shmem_vm_ops; - if (!inode->i_sb || !S_ISREG(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) return -EACCES; update_atime(inode); vma->vm_ops = ops; @@ -1352,7 +1352,7 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos, return desc.error; } -static int shmem_statfs(struct super_block *sb, struct statfs *buf) +static int shmem_statfs(struct super_block *sb, struct kstatfs *buf) { struct shmem_sb_info *sbinfo = SHMEM_SB(sb); diff --git a/mm/slab.c b/mm/slab.c index e236bbbfac2..b625155fd0e 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -475,8 +475,6 @@ static void cache_estimate (unsigned long gfporder, size_t size, *left_over = wastage; } -#if DEBUG - #define slab_error(cachep, msg) __slab_error(__FUNCTION__, cachep, msg) static void __slab_error(const char *function, kmem_cache_t *cachep, char *msg) @@ -486,8 +484,6 @@ static void __slab_error(const char *function, kmem_cache_t *cachep, char *msg) dump_stack(); } -#endif - /* * Start the reap timer running on the target CPU. We run at around 1 to 2Hz. * Add the CPU number into the expiry time to minimize the possibility of the @@ -1307,6 +1303,8 @@ int kmem_cache_shrink(kmem_cache_t *cachep) */ int kmem_cache_destroy (kmem_cache_t * cachep) { + int i; + if (!cachep || in_interrupt()) BUG(); @@ -1319,21 +1317,19 @@ int kmem_cache_destroy (kmem_cache_t * cachep) up(&cache_chain_sem); if (__cache_shrink(cachep)) { - printk(KERN_ERR "kmem_cache_destroy: Can't free all objects %p\n", - cachep); + slab_error(cachep, "Can't free all objects"); down(&cache_chain_sem); list_add(&cachep->next,&cache_chain); up(&cache_chain_sem); return 1; } - { - int i; - for (i = 0; i < NR_CPUS; i++) - kfree(cachep->array[i]); - /* NUMA: free the list3 structures */ - kfree(cachep->lists.shared); - cachep->lists.shared = NULL; - } + + for (i = 0; i < NR_CPUS; i++) + kfree(cachep->array[i]); + + /* NUMA: free the list3 structures */ + kfree(cachep->lists.shared); + cachep->lists.shared = NULL; kmem_cache_free(&cache_cache, cachep); return 0; @@ -1749,8 +1745,10 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, if (!objp) return objp; - if (cachep->flags & SLAB_POISON) + if (cachep->flags & SLAB_POISON) { check_poison_obj(cachep, objp); + poison_obj(cachep, objp, POISON_BEFORE); + } if (cachep->flags & SLAB_STORE_USER) { objlen -= BYTES_PER_WORD; *((void **)(objp+objlen)) = caller; diff --git a/mm/swap_state.c b/mm/swap_state.c index 29198f06fca..708141fb021 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -16,14 +16,6 @@ #include -/* - * swapper_inode doesn't do anything much. It is really only here to - * avoid some special-casing in other parts of the kernel. - */ -static struct inode swapper_inode = { - .i_mapping = &swapper_space, -}; - static struct backing_dev_info swap_backing_dev_info = { .ra_pages = 0, /* No readahead */ .memory_backed = 1, /* Does not contribute to dirty memory */ @@ -38,7 +30,6 @@ struct address_space swapper_space = { .dirty_pages = LIST_HEAD_INIT(swapper_space.dirty_pages), .io_pages = LIST_HEAD_INIT(swapper_space.io_pages), .locked_pages = LIST_HEAD_INIT(swapper_space.locked_pages), - .host = &swapper_inode, .a_ops = &swap_aops, .backing_dev_info = &swap_backing_dev_info, .i_mmap = LIST_HEAD_INIT(swapper_space.i_mmap), diff --git a/net/atm/clip.c b/net/atm/clip.c index 2071c3ad3cd..69443157240 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -140,8 +140,8 @@ static void idle_timer_check(unsigned long dummy) DPRINTK("releasing vcc %p->%p of " "entry %p\n",clip_vcc,clip_vcc->vcc, entry); - atm_async_release_vcc(clip_vcc->vcc, - -ETIMEDOUT); + vcc_release_async(clip_vcc->vcc, + -ETIMEDOUT); } if (entry->vccs || time_before(jiffies, entry->expires)) { diff --git a/net/atm/common.c b/net/atm/common.c index d449fd9aff8..e48d71a09fd 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -239,15 +239,16 @@ int atm_release(struct socket *sock) } -void atm_async_release_vcc(struct atm_vcc *vcc,int reply) +void vcc_release_async(struct atm_vcc *vcc, int reply) { - set_bit(ATM_VF_CLOSE,&vcc->flags); + set_bit(ATM_VF_CLOSE, &vcc->flags); vcc->reply = reply; + vcc->sk->sk_err = -reply; wake_up(&vcc->sleep); } -EXPORT_SYMBOL(atm_async_release_vcc); +EXPORT_SYMBOL(vcc_release_async); static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) @@ -276,8 +277,8 @@ static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) } -static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, - int vci) +static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi, + int vci) { int error; @@ -334,29 +335,26 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, } -static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) +int vcc_connect(struct socket *sock, int itf, short vpi, int vci) { struct atm_dev *dev; - int return_val; - - dev = atm_dev_lookup(itf); - if (!dev) - return_val = -ENODEV; - else { - return_val = atm_do_connect_dev(vcc,dev,vpi,vci); - if (return_val) atm_dev_release(dev); - } - - return return_val; -} + struct atm_vcc *vcc = ATM_SD(sock); + int error; + DPRINTK("vcc_connect (vpi %d, vci %d)\n",vpi,vci); + if (sock->state == SS_CONNECTED) + return -EISCONN; + if (sock->state != SS_UNCONNECTED) + return -EINVAL; + if (!(vpi || vci)) + return -EINVAL; -int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) -{ if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) clear_bit(ATM_VF_PARTIAL,&vcc->flags); - else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; - DPRINTK("atm_connect (TX: cl %d,bw %d-%d,sdu %d; " + else + if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) + return -EINVAL; + DPRINTK("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; " "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, @@ -364,141 +362,135 @@ int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) + return -EBADFD; if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; if (itf != ATM_ITF_ANY) { - int error; - - error = atm_do_connect(vcc,itf,vpi,vci); - if (error) return error; - } - else { - struct atm_dev *dev = NULL; + dev = atm_dev_lookup(itf); + error = __vcc_connect(vcc, dev, vpi, vci); + if (error) { + atm_dev_release(dev); + return error; + } + } else { struct list_head *p, *next; + dev = NULL; spin_lock(&atm_dev_lock); list_for_each_safe(p, next, &atm_devs) { dev = list_entry(p, struct atm_dev, dev_list); atm_dev_hold(dev); spin_unlock(&atm_dev_lock); - if (!atm_do_connect_dev(vcc,dev,vpi,vci)) + if (!__vcc_connect(vcc, dev, vpi, vci)) break; atm_dev_release(dev); dev = NULL; spin_lock(&atm_dev_lock); } spin_unlock(&atm_dev_lock); - if (!dev) return -ENODEV; + if (!dev) + return -ENODEV; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) set_bit(ATM_VF_PARTIAL,&vcc->flags); - return 0; -} - - -int atm_connect(struct socket *sock,int itf,short vpi,int vci) -{ - int error; - - DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci); - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state != SS_UNCONNECTED) return -EINVAL; - if (!(vpi || vci)) return -EINVAL; - error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci); - if (error) return error; if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags)) sock->state = SS_CONNECTED; return 0; } -int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - int total_len, int flags) +int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + int size, int flags) { - DECLARE_WAITQUEUE(wait,current); + struct sock *sk = sock->sk; struct atm_vcc *vcc; struct sk_buff *skb; - int eff_len,error; - void *buff; - int size; + int copied, error = -EINVAL; - if (sock->state != SS_CONNECTED) return -ENOTCONN; - if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP; - if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ - buff = m->msg_iov->iov_base; - size = m->msg_iov->iov_len; + if (sock->state != SS_CONNECTED) + return -ENOTCONN; + if (flags & ~MSG_DONTWAIT) /* only handle MSG_DONTWAIT */ + return -EOPNOTSUPP; vcc = ATM_SD(sock); - add_wait_queue(&vcc->sleep,&wait); - set_current_state(TASK_INTERRUPTIBLE); - error = 1; /* <= 0 is error */ - while (!(skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags)) { - error = vcc->reply; - break; - } - if (!test_bit(ATM_VF_READY,&vcc->flags)) { - error = 0; - break; - } - if (flags & MSG_DONTWAIT) { - error = -EAGAIN; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - error = -ERESTARTSYS; - break; - } + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) + return vcc->reply; + if (!test_bit(ATM_VF_READY, &vcc->flags)) + return 0; + + skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error); + if (!skb) + return error; + + copied = skb->len; + if (copied > size) { + copied = size; + msg->msg_flags |= MSG_TRUNC; } - set_current_state(TASK_RUNNING); - remove_wait_queue(&vcc->sleep,&wait); - if (error <= 0) return error; - sock_recv_timestamp(m, vcc->sk, skb); - eff_len = skb->len > size ? size : skb->len; - if (skb->len > size) /* Not fit ? Report it... */ - m->msg_flags |= MSG_TRUNC; - if (vcc->dev->ops->feedback) - vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, - (unsigned long) buff,eff_len); - DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->sk_rmem_alloc), - skb->truesize); - atm_return(vcc,skb->truesize); - error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; - kfree_skb(skb); - return error ? error : eff_len; + + error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (error) + return error; + sock_recv_timestamp(msg, sk, skb); + if (vcc->dev->ops->feedback) + vcc->dev->ops->feedback(vcc, skb, (unsigned long) skb->data, + (unsigned long) msg->msg_iov->iov_base, copied); + DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->rmem_alloc), skb->truesize); + atm_return(vcc, skb->truesize); + skb_free_datagram(sk, skb); + return copied; } -int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, +int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len) { - DECLARE_WAITQUEUE(wait,current); + struct sock *sk = sock->sk; + DEFINE_WAIT(wait); struct atm_vcc *vcc; struct sk_buff *skb; int eff,error; const void *buff; int size; - if (sock->state != SS_CONNECTED) return -ENOTCONN; - if (m->msg_name) return -EISCONN; - if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ + lock_sock(sk); + if (sock->state != SS_CONNECTED) { + error = -ENOTCONN; + goto out; + } + if (m->msg_name) { + error = -EISCONN; + goto out; + } + if (m->msg_iovlen != 1) { + error = -ENOSYS; /* fix this later @@@ */ + goto out; + } buff = m->msg_iov->iov_base; size = m->msg_iov->iov_len; vcc = ATM_SD(sock); - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags)) - return vcc->reply; - if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE; - if (!size) return 0; - if (size < 0 || size > vcc->qos.txtp.max_sdu) return -EMSGSIZE; + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || + test_bit(ATM_VF_CLOSE, &vcc->flags)) { + error = vcc->reply; + goto out; + } + if (!test_bit(ATM_VF_READY, &vcc->flags)) { + error = -EPIPE; + goto out; + } + if (!size) { + error = 0; + goto out; + } + if (size < 0 || size > vcc->qos.txtp.max_sdu) { + error = -EMSGSIZE; + goto out; + } /* verify_area is done by net/socket.c */ eff = (size+3) & ~3; /* align to word boundary */ - add_wait_queue(&vcc->sleep,&wait); - set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); error = 0; while (!(skb = alloc_tx(vcc,eff))) { if (m->msg_flags & MSG_DONTWAIT) { @@ -506,7 +498,6 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, break; } schedule(); - set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { error = -ERESTARTSYS; break; @@ -520,19 +511,24 @@ int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, error = -EPIPE; break; } + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&vcc->sleep,&wait); - if (error) return error; + finish_wait(&vcc->sleep, &wait); + if (error) + goto out; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; if (copy_from_user(skb_put(skb,size),buff,size)) { kfree_skb(skb); - return -EFAULT; + error = -EFAULT; + goto out; } if (eff != size) memset(skb->data+size,0,eff-size); error = vcc->dev->ops->send(vcc,skb); - return error ? error : size; + error = error ? error : size; +out: + release_sock(sk); + return error; } @@ -563,129 +559,51 @@ unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait) } -static void copy_aal_stats(struct k_atm_aal_stats *from, - struct atm_aal_stats *to) -{ -#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) - __AAL_STAT_ITEMS -#undef __HANDLE_ITEM -} - - -static void subtract_aal_stats(struct k_atm_aal_stats *from, - struct atm_aal_stats *to) -{ -#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i) - __AAL_STAT_ITEMS -#undef __HANDLE_ITEM -} - - -static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) +int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct atm_dev_stats tmp; - int error = 0; - - copy_aal_stats(&dev->stats.aal0,&tmp.aal0); - copy_aal_stats(&dev->stats.aal34,&tmp.aal34); - copy_aal_stats(&dev->stats.aal5,&tmp.aal5); - if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); - if (zero && !error) { - subtract_aal_stats(&dev->stats.aal0,&tmp.aal0); - subtract_aal_stats(&dev->stats.aal34,&tmp.aal34); - subtract_aal_stats(&dev->stats.aal5,&tmp.aal5); - } - return error ? -EFAULT : 0; -} - - -int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) -{ - struct atm_dev *dev; - struct list_head *p; struct atm_vcc *vcc; - int *tmp_buf, *tmp_p; - void *buf; - int error,len,size,number, ret_val; + int error; - ret_val = 0; vcc = ATM_SD(sock); switch (cmd) { case SIOCOUTQ: if (sock->state != SS_CONNECTED || - !test_bit(ATM_VF_READY,&vcc->flags)) { - ret_val = -EINVAL; + !test_bit(ATM_VF_READY, &vcc->flags)) { + error = -EINVAL; goto done; } - ret_val = put_user(vcc->sk->sk_sndbuf - - atomic_read(&vcc->sk->sk_wmem_alloc), - (int *) arg) ? -EFAULT : 0; + error = put_user(vcc->sk->sk_sndbuf - + atomic_read(&vcc->sk->sk_wmem_alloc), + (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: { struct sk_buff *skb; if (sock->state != SS_CONNECTED) { - ret_val = -EINVAL; + error = -EINVAL; goto done; } skb = skb_peek(&vcc->sk->sk_receive_queue); - ret_val = put_user(skb ? skb->len : 0,(int *) arg) - ? -EFAULT : 0; - goto done; - } - case ATM_GETNAMES: - if (get_user(buf, - &((struct atm_iobuf *) arg)->buffer)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(len, - &((struct atm_iobuf *) arg)->length)) { - ret_val = -EFAULT; - goto done; - } - size = 0; - spin_lock(&atm_dev_lock); - list_for_each(p, &atm_devs) - size += sizeof(int); - if (size > len) { - spin_unlock(&atm_dev_lock); - ret_val = -E2BIG; - goto done; - } - tmp_buf = kmalloc(size, GFP_ATOMIC); - if (!tmp_buf) { - spin_unlock(&atm_dev_lock); - ret_val = -ENOMEM; + error = put_user(skb ? skb->len : 0, + (int *) arg) ? -EFAULT : 0; goto done; } - tmp_p = tmp_buf; - list_for_each(p, &atm_devs) { - dev = list_entry(p, struct atm_dev, dev_list); - *tmp_p++ = dev->number; - } - spin_unlock(&atm_dev_lock); - ret_val = ((copy_to_user(buf, tmp_buf, size)) || - put_user(size, &((struct atm_iobuf *) arg)->length) - ) ? -EFAULT : 0; - kfree(tmp_buf); - goto done; case SIOCGSTAMP: /* borrowed from IP */ if (!vcc->sk->sk_stamp.tv_sec) { - ret_val = -ENOENT; + error = -ENOENT; goto done; } - ret_val = copy_to_user((void *)arg, &vcc->sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + error = copy_to_user((void *)arg, &vcc->sk->sk_stamp, + sizeof(struct timeval)) ? -EFAULT : 0; goto done; case ATM_SETSC: printk(KERN_WARNING "ATM_SETSC is obsolete\n"); - ret_val = 0; + error = 0; goto done; case ATMSIGD_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } /* @@ -696,28 +614,28 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) * have the same privledges that /proc/kcore needs */ if (!capable(CAP_SYS_RAWIO)) { - ret_val = -EPERM; + error = -EPERM; goto done; } error = sigd_attach(vcc); - if (!error) sock->state = SS_CONNECTED; - ret_val = error; + if (!error) + sock->state = SS_CONNECTED; goto done; #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) case SIOCMKCLIP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_create(arg); + error = atm_clip_ops->clip_create(arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARPD_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_CLIP_MODULE) @@ -728,48 +646,47 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) error = atm_clip_ops->atm_init_atmarp(vcc); if (!error) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_MKIP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_mkip(vcc, arg); + error = atm_clip_ops->clip_mkip(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_SETENTRY: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_setentry(vcc, arg); + error = atm_clip_ops->clip_setentry(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_ENCAP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_encap(vcc, arg); + error = atm_clip_ops->clip_encap(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) case ATMLEC_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_LANE_MODULE) @@ -781,37 +698,36 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) module_put(atm_lane_ops->owner); if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMLEC_MCAST: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_lane_ops()) { - ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg); + error = atm_lane_ops->mcast_attach(vcc, (int) arg); module_put(atm_lane_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMLEC_DATA: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_lane_ops()) { - ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg); + error = atm_lane_ops->vcc_attach(vcc, (void *) arg); module_put(atm_lane_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) case ATMMPC_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_MPOA_MODULE) @@ -823,63 +739,62 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) module_put(atm_mpoa_ops->owner); if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMMPC_DATA: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_mpoa_ops()) { - ret_val = atm_mpoa_ops->vcc_attach(vcc, arg); + error = atm_mpoa_ops->vcc_attach(vcc, arg); module_put(atm_mpoa_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) case SIOCSIFATMTCP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.attach) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } - fops_get (&atm_tcp_ops); - error = atm_tcp_ops.attach(vcc,(int) arg); - if (error >= 0) sock->state = SS_CONNECTED; - else fops_put (&atm_tcp_ops); - ret_val = error; + fops_get(&atm_tcp_ops); + error = atm_tcp_ops.attach(vcc, (int) arg); + if (error >= 0) + sock->state = SS_CONNECTED; + else + fops_put (&atm_tcp_ops); goto done; case ATMTCP_CREATE: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.create_persistent) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } error = atm_tcp_ops.create_persistent((int) arg); - if (error < 0) fops_put (&atm_tcp_ops); - ret_val = error; + if (error < 0) + fops_put (&atm_tcp_ops); goto done; case ATMTCP_REMOVE: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.remove_persistent) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } error = atm_tcp_ops.remove_persistent((int) arg); - fops_put (&atm_tcp_ops); - ret_val = error; + fops_put(&atm_tcp_ops); goto done; #endif default: @@ -887,182 +802,23 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) } #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) if (pppoatm_ioctl_hook) { - ret_val = pppoatm_ioctl_hook(vcc, cmd, arg); - if (ret_val != -ENOIOCTLCMD) + error = pppoatm_ioctl_hook(vcc, cmd, arg); + if (error != -ENOIOCTLCMD) goto done; } #endif #if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) if (br2684_ioctl_hook) { - ret_val = br2684_ioctl_hook(vcc, cmd, arg); - if (ret_val != -ENOIOCTLCMD) + error = br2684_ioctl_hook(vcc, cmd, arg); + if (error != -ENOIOCTLCMD) goto done; } #endif - if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(len,&((struct atmif_sioc *) arg)->length)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(number,&((struct atmif_sioc *) arg)->number)) { - ret_val = -EFAULT; - goto done; - } - if (!(dev = atm_dev_lookup(number))) { - ret_val = -ENODEV; - goto done; - } - - size = 0; - switch (cmd) { - case ATM_GETTYPE: - size = strlen(dev->type)+1; - if (copy_to_user(buf,dev->type,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_GETESI: - size = ESI_LEN; - if (copy_to_user(buf,dev->esi,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_SETESI: - { - int i; - for (i = 0; i < ESI_LEN; i++) - if (dev->esi[i]) { - ret_val = -EEXIST; - goto done_release; - } - } - /* fall through */ - case ATM_SETESIF: - { - unsigned char esi[ESI_LEN]; - - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - if (copy_from_user(esi,buf,ESI_LEN)) { - ret_val = -EFAULT; - goto done_release; - } - memcpy(dev->esi,esi,ESI_LEN); - ret_val = ESI_LEN; - goto done_release; - } - case ATM_GETSTATZ: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - /* fall through */ - case ATM_GETSTAT: - size = sizeof(struct atm_dev_stats); - error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ); - if (error) { - ret_val = error; - goto done_release; - } - break; - case ATM_GETCIRANGE: - size = sizeof(struct atm_cirange); - if (copy_to_user(buf,&dev->ci_range,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_GETLINKRATE: - size = sizeof(int); - if (copy_to_user(buf,&dev->link_rate,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_RSTADDR: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - atm_reset_addr(dev); - break; - case ATM_ADDADDR: - case ATM_DELADDR: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - { - struct sockaddr_atmsvc addr; - - if (copy_from_user(&addr,buf,sizeof(addr))) { - ret_val = -EFAULT; - goto done_release; - } - if (cmd == ATM_ADDADDR) - ret_val = atm_add_addr(dev,&addr); - else - ret_val = atm_del_addr(dev,&addr); - goto done_release; - } - case ATM_GETADDR: - size = atm_get_addr(dev,buf,len); - if (size < 0) - ret_val = size; - else - /* may return 0, but later on size == 0 means "don't - write the length" */ - ret_val = put_user(size, - &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; - goto done_release; - case ATM_SETLOOP: - if (__ATM_LM_XTRMT((int) (long) buf) && - __ATM_LM_XTLOC((int) (long) buf) > - __ATM_LM_XTRMT((int) (long) buf)) { - ret_val = -EINVAL; - goto done_release; - } - /* fall through */ - case ATM_SETCIRANGE: - case SONET_GETSTATZ: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - /* fall through */ - default: - if (!dev->ops->ioctl) { - ret_val = -EINVAL; - goto done_release; - } - size = dev->ops->ioctl(dev,cmd,buf); - if (size < 0) { - ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size); - goto done_release; - } - } - - if (size) - ret_val = put_user(size,&((struct atmif_sioc *) arg)->length) ? - -EFAULT : 0; - else - ret_val = 0; -done_release: - atm_dev_release(dev); + error = atm_dev_ioctl(cmd, arg); done: - return ret_val; + return error; } @@ -1120,14 +876,16 @@ static int check_qos(struct atm_qos *qos) return check_tp(&qos->rxtp); } - -static int atm_do_setsockopt(struct socket *sock,int level,int optname, - void *optval,int optlen) +int vcc_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) { struct atm_vcc *vcc; unsigned long value; int error; + if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) + return -EINVAL; + vcc = ATM_SD(sock); switch (optname) { case SO_ATMQOS: @@ -1161,10 +919,16 @@ static int atm_do_setsockopt(struct socket *sock,int level,int optname, } -static int atm_do_getsockopt(struct socket *sock,int level,int optname, - void *optval,int optlen) +int vcc_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) { struct atm_vcc *vcc; + int len; + + if (get_user(len, optlen)) + return -EFAULT; + if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) + return -EINVAL; vcc = ATM_SD(sock); switch (optname) { @@ -1195,28 +959,7 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, break; } if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; - return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); -} - - -int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, - int optlen) -{ - if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) - return -EINVAL; - return atm_do_setsockopt(sock,level,optname,optval,optlen); -} - - -int atm_getsockopt(struct socket *sock,int level,int optname, - char *optval,int *optlen) -{ - int len; - - if (get_user(len,optlen)) return -EFAULT; - if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) - return -EINVAL; - return atm_do_getsockopt(sock,level,optname,optval,len); + return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len); } diff --git a/net/atm/common.h b/net/atm/common.h index 4da0547ecd5..e6bf1fccc4c 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -12,19 +12,18 @@ int atm_create(struct socket *sock,int protocol,int family); int atm_release(struct socket *sock); -int atm_connect(struct socket *sock,int itf,short vpi,int vci); -int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - int total_len, int flags); -int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, +int vcc_connect(struct socket *sock, int itf, short vpi, int vci); +int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + int size, int flags); +int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len); unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait); -int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); -int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, - int optlen); -int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, - int *optlen); +int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +int vcc_setsockopt(struct socket *sock, int level, int optname, char *optval, + int optlen); +int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval, + int *optlen); -int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci); void atm_release_vcc_sk(struct sock *sk,int free_sk); void atm_shutdown_dev(struct atm_dev *dev); diff --git a/net/atm/lec.c b/net/atm/lec.c index 35213ce8966..1ee9090ab39 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1079,7 +1079,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) clear_bit(ATM_VF_READY,&entry->vcc->flags); entry->vcc->push(entry->vcc, NULL); #endif - atm_async_release_vcc(entry->vcc, -EPIPE); + vcc_release_async(entry->vcc, -EPIPE); entry->vcc = NULL; } if (entry->recv_vcc) { @@ -1089,7 +1089,7 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) clear_bit(ATM_VF_READY,&entry->recv_vcc->flags); entry->recv_vcc->push(entry->recv_vcc, NULL); #endif - atm_async_release_vcc(entry->recv_vcc, -EPIPE); + vcc_release_async(entry->recv_vcc, -EPIPE); entry->recv_vcc = NULL; } } diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index 0bca7aa6cc0..64ddebb6406 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -212,7 +212,7 @@ static void in_cache_remove_entry(in_cache_entry *entry, client->eg_ops->put(eg_entry); return; } - atm_async_release_vcc(vcc, -EPIPE); + vcc_release_async(vcc, -EPIPE); } return; @@ -447,7 +447,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry, client->in_ops->put(in_entry); return; } - atm_async_release_vcc(vcc, -EPIPE); + vcc_release_async(vcc, -EPIPE); } return; diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 8962ac44d77..4aca98d3ca9 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -31,20 +31,29 @@ static int pvc_shutdown(struct socket *sock,int how) static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len) { + struct sock *sk = sock->sk; struct sockaddr_atmpvc *addr; struct atm_vcc *vcc; + int error; if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; addr = (struct sockaddr_atmpvc *) sockaddr; if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; + lock_sock(sk); vcc = ATM_SD(sock); - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { + error = -EBADFD; + goto out; + } if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) { if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; } - return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, - addr->sap_addr.vci); + error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi, + addr->sap_addr.vci); +out: + release_sock(sk); + return error; } @@ -54,6 +63,31 @@ static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, return pvc_bind(sock,sockaddr,sockaddr_len); } +static int pvc_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = sock->sk; + int error; + + lock_sock(sk); + error = vcc_setsockopt(sock, level, optname, optval, optlen); + release_sock(sk); + return error; +} + + +static int pvc_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + int error; + + lock_sock(sk); + error = vcc_getsockopt(sock, level, optname, optval, optlen); + release_sock(sk); + return error; +} + static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, int *sockaddr_len,int peer) @@ -72,7 +106,7 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, } -static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { +static struct proto_ops pvc_proto_ops = { .family = PF_ATMPVC, .release = atm_release, @@ -82,22 +116,18 @@ static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { .accept = sock_no_accept, .getname = pvc_getname, .poll = atm_poll, - .ioctl = atm_ioctl, + .ioctl = vcc_ioctl, .listen = sock_no_listen, .shutdown = pvc_shutdown, - .setsockopt = atm_setsockopt, - .getsockopt = atm_getsockopt, - .sendmsg = atm_sendmsg, - .recvmsg = atm_recvmsg, + .setsockopt = pvc_setsockopt, + .getsockopt = pvc_getsockopt, + .sendmsg = vcc_sendmsg, + .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; -#include -SOCKOPS_WRAP(pvc_proto, PF_ATMPVC); - - static int pvc_create(struct socket *sock,int protocol) { sock->ops = &pvc_proto_ops; diff --git a/net/atm/resources.c b/net/atm/resources.c index 0f460069b24..877542a4059 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* for barrier */ #include #include @@ -19,6 +20,7 @@ #include "common.h" #include "resources.h" +#include "addr.h" #ifndef NULL @@ -171,6 +173,240 @@ void shutdown_atm_dev(struct atm_dev *dev) atm_dev_deregister(dev); } + +static void copy_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) +{ +#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} + + +static void subtract_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) +{ +#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} + + +static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats *arg, int zero) +{ + struct atm_dev_stats tmp; + int error = 0; + + copy_aal_stats(&dev->stats.aal0, &tmp.aal0); + copy_aal_stats(&dev->stats.aal34, &tmp.aal34); + copy_aal_stats(&dev->stats.aal5, &tmp.aal5); + if (arg) + error = copy_to_user(arg, &tmp, sizeof(tmp)); + if (zero && !error) { + subtract_aal_stats(&dev->stats.aal0, &tmp.aal0); + subtract_aal_stats(&dev->stats.aal34, &tmp.aal34); + subtract_aal_stats(&dev->stats.aal5, &tmp.aal5); + } + return error ? -EFAULT : 0; +} + + +int atm_dev_ioctl(unsigned int cmd, unsigned long arg) +{ + void *buf; + int error, len, number, size = 0; + struct atm_dev *dev; + struct list_head *p; + int *tmp_buf, *tmp_p; + + switch (cmd) { + case ATM_GETNAMES: + if (get_user(buf, &((struct atm_iobuf *) arg)->buffer)) + return -EFAULT; + if (get_user(len, &((struct atm_iobuf *) arg)->length)) + return -EFAULT; + spin_lock(&atm_dev_lock); + list_for_each(p, &atm_devs) + size += sizeof(int); + if (size > len) { + spin_unlock(&atm_dev_lock); + return -E2BIG; + } + tmp_buf = kmalloc(size, GFP_ATOMIC); + if (!tmp_buf) { + spin_unlock(&atm_dev_lock); + return -ENOMEM; + } + tmp_p = tmp_buf; + list_for_each(p, &atm_devs) { + dev = list_entry(p, struct atm_dev, dev_list); + *tmp_p++ = dev->number; + } + spin_unlock(&atm_dev_lock); + error = ((copy_to_user(buf, tmp_buf, size)) || + put_user(size, &((struct atm_iobuf *) arg)->length)) + ? -EFAULT : 0; + kfree(tmp_buf); + return error; + default: + break; + } + + if (get_user(buf, &((struct atmif_sioc *) arg)->arg)) + return -EFAULT; + if (get_user(len, &((struct atmif_sioc *) arg)->length)) + return -EFAULT; + if (get_user(number, &((struct atmif_sioc *) arg)->number)) + return -EFAULT; + + if (!(dev = atm_dev_lookup(number))) + return -ENODEV; + + switch (cmd) { + case ATM_GETTYPE: + size = strlen(dev->type) + 1; + if (copy_to_user(buf, dev->type, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETESI: + size = ESI_LEN; + if (copy_to_user(buf, dev->esi, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_SETESI: + { + int i; + + for (i = 0; i < ESI_LEN; i++) + if (dev->esi[i]) { + error = -EEXIST; + goto done; + } + } + /* fall through */ + case ATM_SETESIF: + { + unsigned char esi[ESI_LEN]; + + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + if (copy_from_user(esi, buf, ESI_LEN)) { + error = -EFAULT; + goto done; + } + memcpy(dev->esi, esi, ESI_LEN); + error = ESI_LEN; + goto done; + } + case ATM_GETSTATZ: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + case ATM_GETSTAT: + size = sizeof(struct atm_dev_stats); + error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); + if (error) + goto done; + break; + case ATM_GETCIRANGE: + size = sizeof(struct atm_cirange); + if (copy_to_user(buf, &dev->ci_range, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETLINKRATE: + size = sizeof(int); + if (copy_to_user(buf, &dev->link_rate, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_RSTADDR: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + atm_reset_addr(dev); + break; + case ATM_ADDADDR: + case ATM_DELADDR: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + { + struct sockaddr_atmsvc addr; + + if (copy_from_user(&addr, buf, sizeof(addr))) { + error = -EFAULT; + goto done; + } + if (cmd == ATM_ADDADDR) + error = atm_add_addr(dev, &addr); + else + error = atm_del_addr(dev, &addr); + goto done; + } + case ATM_GETADDR: + error = atm_get_addr(dev, buf, len); + if (error < 0) + goto done; + size = error; + /* may return 0, but later on size == 0 means "don't + write the length" */ + error = put_user(size, &((struct atmif_sioc *) arg)->length) + ? -EFAULT : 0; + goto done; + case ATM_SETLOOP: + if (__ATM_LM_XTRMT((int) (long) buf) && + __ATM_LM_XTLOC((int) (long) buf) > + __ATM_LM_XTRMT((int) (long) buf)) { + error = -EINVAL; + goto done; + } + /* fall through */ + case ATM_SETCIRANGE: + case SONET_GETSTATZ: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + default: + if (!dev->ops->ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->ioctl(dev, cmd, buf); + if (size < 0) { + error = (size == -ENOIOCTLCMD ? -EINVAL : size); + goto done; + } + } + + if (size) + error = put_user(size, &((struct atmif_sioc *) arg)->length) + ? -EFAULT : 0; + else + error = 0; +done: + atm_dev_release(dev); + return error; +} + + struct sock *alloc_atm_vcc_sk(int family) { struct sock *sk; diff --git a/net/atm/resources.h b/net/atm/resources.h index 9c7dc3cf13e..b4135b47d20 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -16,6 +16,7 @@ extern spinlock_t atm_dev_lock; struct sock *alloc_atm_vcc_sk(int family); void free_atm_vcc_sk(struct sock *sk); +int atm_dev_ioctl(unsigned int cmd, unsigned long arg); #ifdef CONFIG_PROC_FS diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 9849062cea2..6d4f21c80e1 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -124,14 +124,16 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; + vcc->sk->sk_err = -msg->reply; break; case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; DPRINTK("as_indicate!!!\n"); + lock_sock(vcc->sk); if (vcc->sk->sk_ack_backlog == vcc->sk->sk_max_ack_backlog) { sigd_enq(0,as_reject,vcc,NULL,NULL); - return 0; + goto as_indicate_complete; } vcc->sk->sk_ack_backlog++; skb_queue_tail(&vcc->sk->sk_receive_queue, skb); @@ -140,11 +142,14 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb) &vcc->sleep); vcc->callback(vcc); } +as_indicate_complete: + release_sock(vcc->sk); return 0; case as_close: set_bit(ATM_VF_RELEASED,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; + vcc->sk->sk_err = -msg->reply; break; case as_modify: modify_qos(vcc,msg); @@ -202,6 +207,7 @@ static void purge_vccs(struct atm_vcc *vcc) !test_bit(ATM_VF_META,&vcc->flags)) { set_bit(ATM_VF_RELEASED,&vcc->flags); vcc->reply = -EUNATCH; + vcc->sk->sk_err = EUNATCH; wake_up(&vcc->sleep); } vcc = vcc->next; diff --git a/net/atm/svc.c b/net/atm/svc.c index f1401b6a20f..13d7aa3d0e6 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -59,18 +59,18 @@ static int svc_shutdown(struct socket *sock,int how) static void svc_disconnect(struct atm_vcc *vcc) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); struct sk_buff *skb; DPRINTK("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ @@ -107,80 +107,138 @@ static int svc_release(struct socket *sock) static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct sockaddr_atmsvc *addr; struct atm_vcc *vcc; + int error; - if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state != SS_UNCONNECTED) return -EINVAL; + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) + return -EINVAL; + lock_sock(sk); + if (sock->state == SS_CONNECTED) { + error = -EISCONN; + goto out; + } + if (sock->state != SS_UNCONNECTED) { + error = -EINVAL; + goto out; + } vcc = ATM_SD(sock); - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + if (test_bit(ATM_VF_SESSION, &vcc->flags)) { + error = -EINVAL; + goto out; + } addr = (struct sockaddr_atmsvc *) sockaddr; - if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; + if (addr->sas_family != AF_ATMSVC) { + error = -EAFNOSUPPORT; + goto out; + } clear_bit(ATM_VF_BOUND,&vcc->flags); /* failing rebind will kill old binding */ /* @@@ check memory (de)allocation on rebind */ - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) { + error = -EBADFD; + goto out; + } vcc->local = *addr; vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */ - if (!sigd) return -EUNATCH; - if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags); - return vcc->reply; + if (!sigd) { + error = -EUNATCH; + goto out; + } + if (!vcc->reply) + set_bit(ATM_VF_BOUND,&vcc->flags); + error = vcc->reply; +out: + release_sock(sk); + return error; } static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len,int flags) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct sockaddr_atmsvc *addr; struct atm_vcc *vcc = ATM_SD(sock); int error; DPRINTK("svc_connect %p\n",vcc); - if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state == SS_CONNECTING) { - if (vcc->reply == WAITING) return -EALREADY; - sock->state = SS_UNCONNECTED; - if (vcc->reply) return vcc->reply; + lock_sock(sk); + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { + error = -EINVAL; + goto out; } - else { - int error; - if (sock->state != SS_UNCONNECTED) return -EINVAL; - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + switch (sock->state) { + default: + error = -EINVAL; + goto out; + case SS_CONNECTED: + error = -EISCONN; + goto out; + case SS_CONNECTING: + if (vcc->reply == WAITING) { + error = -EALREADY; + goto out; + } + sock->state = SS_UNCONNECTED; + if (vcc->reply) { + error = vcc->reply; + goto out; + } + break; + case SS_UNCONNECTED: + if (test_bit(ATM_VF_SESSION, &vcc->flags)) { + error = -EINVAL; + goto out; + } addr = (struct sockaddr_atmsvc *) sockaddr; - if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (addr->sas_family != AF_ATMSVC) { + error = -EAFNOSUPPORT; + goto out; + } + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { + error = -EBADFD; + goto out; + } if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || - vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) - return -EINVAL; + vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { + error = -EINVAL; + goto out; + } if (!vcc->qos.txtp.traffic_class && - !vcc->qos.rxtp.traffic_class) return -EINVAL; + !vcc->qos.rxtp.traffic_class) { + error = -EINVAL; + goto out; + } vcc->remote = *addr; vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); if (flags & O_NONBLOCK) { - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); sock->state = SS_CONNECTING; - return -EINPROGRESS; + error = -EINPROGRESS; + goto out; } error = 0; while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_INTERRUPTIBLE); schedule(); - if (!signal_pending(current)) continue; + if (!signal_pending(current)) { + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); + continue; + } DPRINTK("*ABORT*\n"); /* * This is tricky: @@ -196,13 +254,13 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, */ sigd_enq(vcc,as_close,NULL,NULL,NULL); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } if (!vcc->reply) while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } clear_bit(ATM_VF_REGIS,&vcc->flags); @@ -212,10 +270,17 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, error = -EINTR; break; } - remove_wait_queue(&vcc->sleep,&wait); - if (error) return error; - if (!sigd) return -EUNATCH; - if (vcc->reply) return vcc->reply; + finish_wait(&vcc->sleep, &wait); + if (error) + goto out; + if (!sigd) { + error = -EUNATCH; + goto out; + } + if (vcc->reply) { + error = vcc->reply; + goto out; + } } /* * Not supported yet @@ -228,56 +293,73 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, /* * #endif */ - if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) + if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci))) sock->state = SS_CONNECTED; else (void) svc_disconnect(vcc); +out: + release_sock(sk); return error; } static int svc_listen(struct socket *sock,int backlog) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct atm_vcc *vcc = ATM_SD(sock); + int error; DPRINTK("svc_listen %p\n",vcc); + lock_sock(sk); /* let server handle listen on unbound sockets */ - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + if (test_bit(ATM_VF_SESSION,&vcc->flags)) { + error = -EINVAL; + goto out; + } vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); + } + finish_wait(&vcc->sleep, &wait); + if (!sigd) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&vcc->sleep,&wait); - if (!sigd) return -EUNATCH; set_bit(ATM_VF_LISTEN,&vcc->flags); vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; - return vcc->reply; + error = vcc->reply; +out: + release_sock(sk); + return error; } static int svc_accept(struct socket *sock,struct socket *newsock,int flags) { + struct sock *sk = sock->sk; struct sk_buff *skb; struct atmsvc_msg *msg; struct atm_vcc *old_vcc = ATM_SD(sock); struct atm_vcc *new_vcc; int error; + lock_sock(sk); + error = svc_create(newsock,0); if (error) - return error; + goto out; new_vcc = ATM_SD(newsock); DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); - add_wait_queue(&old_vcc->sleep,&wait); + prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE); while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) && sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; @@ -289,46 +371,63 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) error = -EAGAIN; break; } - set_current_state(TASK_INTERRUPTIBLE); + release_sock(sk); schedule(); + lock_sock(sk); if (signal_pending(current)) { error = -ERESTARTSYS; break; } + prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE); + } + finish_wait(&old_vcc->sleep, &wait); + if (error) + goto out; + if (!skb) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&old_vcc->sleep,&wait); - if (error) return error; - if (!skb) return -EUNATCH; msg = (struct atmsvc_msg *) skb->data; new_vcc->qos = msg->qos; set_bit(ATM_VF_HASQOS,&new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; - error = atm_connect(newsock,msg->pvc.sap_addr.itf, - msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); + error = vcc_connect(newsock, msg->pvc.sap_addr.itf, + msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci); dev_kfree_skb(skb); old_vcc->sk->sk_ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); - return error == -EAGAIN ? -EBUSY : error; + error = error == -EAGAIN ? -EBUSY : error; + goto out; } /* wait should be short, so we ignore the non-blocking flag */ new_vcc->reply = WAITING; - add_wait_queue(&new_vcc->sleep,&wait); + prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); while (new_vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + release_sock(sk); schedule(); + lock_sock(sk); + prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); + } + finish_wait(&new_vcc->sleep, &wait); + if (!sigd) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&new_vcc->sleep,&wait); - if (!sigd) return -EUNATCH; if (!new_vcc->reply) break; - if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; + if (new_vcc->reply != -ERESTARTSYS) { + error = new_vcc->reply; + goto out; + } } newsock->state = SS_CONNECTED; - return 0; +out: + release_sock(sk); + return error; } @@ -347,17 +446,17 @@ static int svc_getname(struct socket *sock,struct sockaddr *sockaddr, int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); 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); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); if (!sigd) return -EUNATCH; return vcc->reply; } @@ -366,33 +465,57 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) static int svc_setsockopt(struct socket *sock,int level,int optname, char *optval,int optlen) { + struct sock *sk = sock->sk; struct atm_vcc *vcc; + int error = 0; if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP || - optlen != sizeof(struct atm_sap)) - return atm_setsockopt(sock,level,optname,optval,optlen); + optlen != sizeof(struct atm_sap)) { + error = vcc_setsockopt(sock, level, optname, optval, optlen); + goto out; + } vcc = ATM_SD(sock); - if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT; - set_bit(ATM_VF_HASSAP,&vcc->flags); - return 0; + if (copy_from_user(&vcc->sap, optval, optlen)) { + error = -EFAULT; + goto out; + } + set_bit(ATM_VF_HASSAP, &vcc->flags); +out: + release_sock(sk); + return error; } static int svc_getsockopt(struct socket *sock,int level,int optname, char *optval,int *optlen) { - int len; - - if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) - return atm_getsockopt(sock,level,optname,optval,optlen); - if (get_user(len,optlen)) return -EFAULT; - if (len != sizeof(struct atm_sap)) return -EINVAL; - return copy_to_user(optval,&ATM_SD(sock)->sap,sizeof(struct atm_sap)) ? - -EFAULT : 0; + struct sock *sk = sock->sk; + int error = 0, len; + + lock_sock(sk); + if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) { + error = vcc_getsockopt(sock, level, optname, optval, optlen); + goto out; + } + if (get_user(len, optlen)) { + error = -EFAULT; + goto out; + } + if (len != sizeof(struct atm_sap)) { + error = -EINVAL; + goto out; + } + if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) { + error = -EFAULT; + goto out; + } +out: + release_sock(sk); + return error; } -static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { +static struct proto_ops svc_proto_ops = { .family = PF_ATMSVC, .release = svc_release, @@ -402,21 +525,18 @@ static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { .accept = svc_accept, .getname = svc_getname, .poll = atm_poll, - .ioctl = atm_ioctl, + .ioctl = vcc_ioctl, .listen = svc_listen, .shutdown = svc_shutdown, .setsockopt = svc_setsockopt, .getsockopt = svc_getsockopt, - .sendmsg = atm_sendmsg, - .recvmsg = atm_recvmsg, + .sendmsg = vcc_sendmsg, + .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; -#include -SOCKOPS_WRAP(svc_proto, PF_ATMSVC); - static int svc_create(struct socket *sock,int protocol) { int error; diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 9ccdd809ea9..cb1d68d4c98 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -143,15 +143,13 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *sk) { write_lock_bh(&l->lock); sk_add_node(sk, &l->head); - sock_hold(sk); write_unlock_bh(&l->lock); } void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk) { write_lock_bh(&l->lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&l->lock); } diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 607a6358198..f2a9517511e 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -304,31 +305,36 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, return NF_ACCEPT; } - /* PF_BRIDGE/FORWARD *************************************************/ static int br_nf_forward_finish(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct net_device *in; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif - if (nf_bridge->mask & BRNF_PKT_TYPE) { - skb->pkt_type = PACKET_OTHERHOST; - nf_bridge->mask ^= BRNF_PKT_TYPE; + if (skb->protocol == __constant_htons(ETH_P_IP)) { + in = nf_bridge->physindev; + if (nf_bridge->mask & BRNF_PKT_TYPE) { + skb->pkt_type = PACKET_OTHERHOST; + nf_bridge->mask ^= BRNF_PKT_TYPE; + } + } else { + in = *((struct net_device **)(skb->cb)); } - NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, nf_bridge->physindev, + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, skb->dev, br_forward_finish, 1); - return 0; } -/* This is the 'purely bridged' case. We pass the packet to +/* This is the 'purely bridged' case. For IP, we pass the packet to * netfilter with indev and outdev set to the bridge device, * but we are still able to filter on the 'real' indev/outdev - * because of the ipt_physdev.c module. + * because of the ipt_physdev.c module. For ARP, indev and outdev are the + * bridge ports. */ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, @@ -337,24 +343,33 @@ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, struct sk_buff *skb = *pskb; struct nf_bridge_info *nf_bridge; - if (skb->protocol != __constant_htons(ETH_P_IP)) + if (skb->protocol != __constant_htons(ETH_P_IP) && + skb->protocol != __constant_htons(ETH_P_ARP)) return NF_ACCEPT; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif + if (skb->protocol == __constant_htons(ETH_P_IP)) { + nf_bridge = skb->nf_bridge; + if (skb->pkt_type == PACKET_OTHERHOST) { + skb->pkt_type = PACKET_HOST; + nf_bridge->mask |= BRNF_PKT_TYPE; + } - nf_bridge = skb->nf_bridge; - if (skb->pkt_type == PACKET_OTHERHOST) { - skb->pkt_type = PACKET_HOST; - nf_bridge->mask |= BRNF_PKT_TYPE; - } + /* The physdev module checks on this */ + nf_bridge->mask |= BRNF_BRIDGED; + nf_bridge->physoutdev = skb->dev; - nf_bridge->mask |= BRNF_BRIDGED; /* The physdev module checks on this */ - nf_bridge->physoutdev = skb->dev; + NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in), + bridge_parent(out), br_nf_forward_finish); + } else { + struct net_device **d = (struct net_device **)(skb->cb); - NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(nf_bridge->physindev), - bridge_parent(skb->dev), br_nf_forward_finish); + *d = (struct net_device *)in; + NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, + (struct net_device *)out, br_nf_forward_finish); + } return NF_STOLEN; } diff --git a/net/core/dev.c b/net/core/dev.c index f61808deadd..f885a30411b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1018,6 +1018,66 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) #define illegal_highdma(dev, skb) (0) #endif +extern void skb_release_data(struct sk_buff *); + +/* Keep head the same: replace data */ +int __skb_linearize(struct sk_buff *skb, int gfp_mask) +{ + unsigned int size; + u8 *data; + long offset; + struct skb_shared_info *ninfo; + int headerlen = skb->data - skb->head; + int expand = (skb->tail + skb->data_len) - skb->end; + + if (skb_shared(skb)) + BUG(); + + if (expand <= 0) + expand = 0; + + size = skb->end - skb->head + expand; + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (!data) + return -ENOMEM; + + /* Copy entire thing */ + if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) + BUG(); + + /* Set up shinfo */ + ninfo = (struct skb_shared_info*)(data + size); + atomic_set(&ninfo->dataref, 1); + ninfo->tso_size = skb_shinfo(skb)->tso_size; + ninfo->tso_segs = skb_shinfo(skb)->tso_segs; + ninfo->nr_frags = 0; + ninfo->frag_list = NULL; + + /* Offset between the two in bytes */ + offset = data - skb->head; + + /* Free old data. */ + skb_release_data(skb); + + skb->head = data; + skb->end = data + size; + + /* Set up new pointers */ + skb->h.raw += offset; + skb->nh.raw += offset; + skb->mac.raw += offset; + skb->tail += offset; + skb->data += offset; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; + + skb->tail += skb->data_len; + skb->data_len = 0; + return 0; +} + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1039,7 +1099,7 @@ int dev_queue_xmit(struct sk_buff *skb) if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && - skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* Fragmented skb is linearized if device does not support SG, @@ -1048,7 +1108,7 @@ int dev_queue_xmit(struct sk_buff *skb) */ if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* If packet is not checksummed and device does not support @@ -1356,7 +1416,7 @@ static int deliver_to_old_ones(struct packet_type *pt, if (!skb) goto out; } - if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC)) + if (skb_is_nonlinear(skb) && __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree; #ifdef CONFIG_SMP diff --git a/net/core/flow.c b/net/core/flow.c index 35c6058d22f..87a5b21694c 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -301,7 +300,8 @@ void flow_cache_flush(void) local_bh_disable(); smp_call_function(flow_cache_flush_per_cpu, &info, 1, 0); - flow_cache_flush_tasklet((unsigned long)&info); + if (test_bit(smp_processor_id(), &info.cpumap)) + flow_cache_flush_tasklet((unsigned long)&info); local_bh_enable(); wait_for_completion(&info.completion); @@ -309,13 +309,11 @@ void flow_cache_flush(void) up(&flow_flush_sem); } -static void __devinit flow_cache_cpu_online(int cpu) +static int __devinit flow_cache_cpu_prepare(int cpu) { struct tasklet_struct *tasklet; unsigned long order; - flow_hash_rnd_recalc(cpu) = 1; - for (order = 0; (PAGE_SIZE << order) < (sizeof(struct flow_cache_entry *)*flow_hash_size); @@ -325,15 +323,28 @@ static void __devinit flow_cache_cpu_online(int cpu) flow_table(cpu) = (struct flow_cache_entry **) __get_free_pages(GFP_KERNEL, order); + if (!flow_table(cpu)) + return NOTIFY_BAD; + memset(flow_table(cpu), 0, PAGE_SIZE << order); + flow_hash_rnd_recalc(cpu) = 1; + flow_count(cpu) = 0; + tasklet = flow_flush_tasklet(cpu); tasklet_init(tasklet, flow_cache_flush_tasklet, 0); + return NOTIFY_OK; +} + +static int __devinit flow_cache_cpu_online(int cpu) +{ down(&flow_cache_cpu_sem); set_bit(cpu, &flow_cache_cpu_map); flow_cache_cpu_count++; up(&flow_cache_cpu_sem); + + return NOTIFY_OK; } static int __devinit flow_cache_cpu_notify(struct notifier_block *self, @@ -342,7 +353,10 @@ static int __devinit flow_cache_cpu_notify(struct notifier_block *self, unsigned long cpu = (unsigned long)cpu; switch (action) { case CPU_UP_PREPARE: - flow_cache_cpu_online(cpu); + return flow_cache_cpu_prepare(cpu); + break; + case CPU_ONLINE: + return flow_cache_cpu_online(cpu); break; } return NOTIFY_OK; @@ -354,6 +368,8 @@ static struct notifier_block __devinitdata flow_cache_cpu_nb = { static int __init flow_cache_init(void) { + int i; + flow_cachep = kmem_cache_create("flow_cache", sizeof(struct flow_cache_entry), 0, SLAB_HWCACHE_ALIGN, @@ -371,8 +387,15 @@ static int __init flow_cache_init(void) flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; add_timer(&flow_hash_rnd_timer); - flow_cache_cpu_online(smp_processor_id()); register_cpu_notifier(&flow_cache_cpu_nb); + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (flow_cache_cpu_prepare(i) == NOTIFY_OK && + flow_cache_cpu_online(i) == NOTIFY_OK) + continue; + panic("NET: failed to initialise flow cache hash table\n"); + } return 0; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index efdc436b2f0..ef7095747c8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -181,7 +181,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) skb_get(list); } -static void skb_release_data(struct sk_buff *skb) +void skb_release_data(struct sk_buff *skb) { if (!skb->cloned || atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { @@ -412,64 +412,6 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask) return n; } -/* Keep head the same: replace data */ -int skb_linearize(struct sk_buff *skb, int gfp_mask) -{ - unsigned int size; - u8 *data; - long offset; - struct skb_shared_info *ninfo; - int headerlen = skb->data - skb->head; - int expand = (skb->tail + skb->data_len) - skb->end; - - if (skb_shared(skb)) - BUG(); - - if (expand <= 0) - expand = 0; - - size = skb->end - skb->head + expand; - size = SKB_DATA_ALIGN(size); - data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); - if (!data) - return -ENOMEM; - - /* Copy entire thing */ - if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) - BUG(); - - /* Set up shinfo */ - ninfo = (struct skb_shared_info*)(data + size); - atomic_set(&ninfo->dataref, 1); - ninfo->tso_size = skb_shinfo(skb)->tso_size; - ninfo->tso_segs = skb_shinfo(skb)->tso_segs; - ninfo->nr_frags = 0; - ninfo->frag_list = NULL; - - /* Offset between the two in bytes */ - offset = data - skb->head; - - /* Free old data. */ - skb_release_data(skb); - - skb->head = data; - skb->end = data + size; - - /* Set up new pointers */ - skb->h.raw += offset; - skb->nh.raw += offset; - skb->mac.raw += offset; - skb->tail += offset; - skb->data += offset; - - /* We are no longer a clone, even if we were. */ - skb->cloned = 0; - - skb->tail += skb->data_len; - skb->data_len = 0; - return 0; -} - /** * pskb_copy - create copy of an sk_buff with private head. diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 84f16652b3f..318740b029d 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -276,7 +276,7 @@ static void dn_rehash_sock(struct sock *sk) return; write_lock_bh(&dn_hash_lock); - hlist_del(&sk->sk_node); + sk_del_node_init(sk); DN_SK(sk)->addrloc = 0; list = listen_hash(&DN_SK(sk)->addr); sk_add_node(sk, list); diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index 029ed34ca3f..dd6e87b206e 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -96,8 +96,7 @@ struct ec_cb static void econet_remove_socket(struct hlist_head *list, struct sock *sk) { write_lock_bh(&econet_lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&econet_lock); } @@ -105,7 +104,6 @@ static void econet_insert_socket(struct hlist_head *list, struct sock *sk) { write_lock_bh(&econet_lock); sk_add_node(sk, list); - sock_hold(sk); write_unlock_bh(&econet_lock); } diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 80e2b037985..bf49e394665 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -216,9 +216,12 @@ int eth_header_parse(struct sk_buff *skb, unsigned char *haddr) int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; struct net_device *dev = neigh->dev; + eth = (struct ethhdr*) + (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -235,5 +238,6 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f9959c4e932..1324b4e97d8 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -623,15 +623,20 @@ int arp_process(struct sk_buff *skb) int addr_type; struct neighbour *n; - /* arp_rcv below verifies the ARP header, verifies the device - * is ARP'able, and linearizes the SKB (if needed). + /* arp_rcv below verifies the ARP header and verifies the device + * is ARP'able. */ if (in_dev == NULL) goto out; + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + + (2 * sizeof(u32))))) + goto out; + arp = skb->nh.arph; - arp_ptr= (unsigned char *)(arp+1); switch (dev_type) { default: @@ -693,6 +698,7 @@ int arp_process(struct sk_buff *skb) /* * Extract fields */ + arp_ptr= (unsigned char *)(arp+1); sha = arp_ptr; arp_ptr += dev->addr_len; memcpy(&sip, arp_ptr, 4); @@ -841,11 +847,6 @@ int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out_of_mem; - if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) - goto freeskb; - } - return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); freeskb: diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 680ab028ad6..140f01415d3 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -178,7 +178,7 @@ static void igmp_gq_start_timer(struct in_device *in_dev) in_dev->mr_gq_running = 1; if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2)) - atomic_inc(&in_dev->refcnt); + in_dev_hold(in_dev); } static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) @@ -186,7 +186,7 @@ static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) int tv = net_random() % delay; if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2)) - atomic_inc(&in_dev->refcnt); + in_dev_hold(in_dev); } static void igmp_mod_timer(struct ip_mc_list *im, int max_delay) @@ -387,8 +387,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, if (type == IGMPV3_ALLOW_NEW_SOURCES || type == IGMPV3_BLOCK_OLD_SOURCES) return skb; - if (pmc->crcount || isquery) + if (pmc->crcount || isquery) { + /* make sure we have room for group header and at + * least one source. + */ + if (skb && AVAILABLE(skb) < sizeof(struct igmpv3_grec)+ + sizeof(__u32)) { + igmpv3_sendpack(skb); + skb = 0; /* add_grhead will get a new one */ + } skb = add_grhead(skb, pmc, type, &pgr); + } return skb; } pih = skb ? (struct igmpv3_report *)skb->h.igmph : 0; @@ -661,6 +670,7 @@ static void igmp_gq_timer_expire(unsigned long data) in_dev->mr_gq_running = 0; igmpv3_send_report(in_dev, 0); + __in_dev_put(in_dev); } static void igmp_ifc_timer_expire(unsigned long data) @@ -672,6 +682,7 @@ static void igmp_ifc_timer_expire(unsigned long data) in_dev->mr_ifc_count--; igmp_ifc_start_timer(in_dev, IGMP_Unsolicited_Report_Interval); } + __in_dev_put(in_dev); } static void igmp_ifc_event(struct in_device *in_dev) @@ -773,7 +784,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih, /* cancel the interface change timer */ in_dev->mr_ifc_count = 0; if (del_timer(&in_dev->mr_ifc_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); /* clear deleted report items */ igmpv3_clear_delrec(in_dev); } else if (len < 12) { @@ -1188,10 +1199,10 @@ void ip_mc_down(struct in_device *in_dev) #ifdef CONFIG_IP_MULTICAST in_dev->mr_ifc_count = 0; if (del_timer(&in_dev->mr_ifc_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); in_dev->mr_gq_running = 0; if (del_timer(&in_dev->mr_gq_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); #endif for (i=in_dev->mc_list; i; i=i->next) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 765c13b96d6..7a736073666 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -193,8 +193,11 @@ static inline int ip_finish_output2(struct sk_buff *skb) #endif /*CONFIG_NETFILTER_DEBUG*/ if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 751a5f550a2..aa964484841 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -247,14 +247,16 @@ unsigned int arpt_do_table(struct sk_buff **pskb, { static const char nulldevname[IFNAMSIZ] = { 0 }; unsigned int verdict = NF_DROP; - struct arphdr *arp = (*pskb)->nh.arph; + struct arphdr *arp; int hotdrop = 0; struct arpt_entry *e, *back; const char *indev, *outdev; void *table_base; - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) + + (2 * (*pskb)->dev->addr_len) + + (2 * sizeof(u32))))) return NF_DROP; indev = in ? in->name : nulldevname; @@ -267,6 +269,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb, e = get_entry(table_base, table->private->hook_entry[hook]); back = get_entry(table_base, table->private->underflow[hook]); + arp = (*pskb)->nh.arph; do { if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) { struct arpt_entry_target *t; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 3387279f690..2404ad53a71 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -8,7 +8,8 @@ #include #include -#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT)) +#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ + (1 << NF_ARP_FORWARD)) /* Standard entry. */ struct arpt_standard @@ -32,15 +33,17 @@ struct arpt_error static struct { struct arpt_replace repl; - struct arpt_standard entries[2]; + struct arpt_standard entries[3]; struct arpt_error term; } initial_table __initdata -= { { "filter", FILTER_VALID_HOOKS, 3, - sizeof(struct arpt_standard) * 2 + sizeof(struct arpt_error), += { { "filter", FILTER_VALID_HOOKS, 4, + sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard) }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard), }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, 0, NULL, { } }, { /* ARP_IN */ @@ -84,6 +87,27 @@ static struct { 0, 0 }, { } }, { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } + }, + /* ARP_FORWARD */ + { + { + { + { 0 }, { 0 }, { 0 }, { 0 }, + 0, 0, + { { 0, }, { 0, } }, + { { 0, }, { 0, } }, + 0, 0, + 0, 0, + 0, 0, + "", "", { 0 }, { 0 }, + 0, 0 + }, + sizeof(struct arpt_entry), + sizeof(struct arpt_standard), + 0, + { 0, 0 }, { } }, + { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } } }, /* ERROR */ @@ -142,35 +166,34 @@ static struct nf_hook_ops arpt_ops[] = { .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_OUT, - } + }, + { + .hook = arpt_hook, + .owner = THIS_MODULE, + .pf = NF_ARP, + .hooknum = NF_ARP_FORWARD, + }, }; static int __init init(void) { - int ret; + int ret, i; /* Register table */ ret = arpt_register_table(&packet_filter); if (ret < 0) return ret; - /* Register hooks */ - ret = nf_register_hook(&arpt_ops[0]); - if (ret < 0) - goto cleanup_table; - - ret = nf_register_hook(&arpt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) + if ((ret = nf_register_hook(&arpt_ops[i])) < 0) + goto cleanup_hooks; return ret; -cleanup_hook0: - nf_unregister_hook(&arpt_ops[0]); +cleanup_hooks: + while (--i >= 0) + nf_unregister_hook(&arpt_ops[i]); -cleanup_table: arpt_unregister_table(&packet_filter); - return ret; } @@ -178,7 +201,7 @@ static void __exit fini(void) { unsigned int i; - for (i = 0; i < sizeof(arpt_ops)/sizeof(struct nf_hook_ops); i++) + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) nf_unregister_hook(&arpt_ops[i]); arpt_unregister_table(&packet_filter); diff --git a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c index fcd424bd73b..3f8faff13dc 100644 --- a/net/ipv4/netfilter/ipt_MIRROR.c +++ b/net/ipv4/netfilter/ipt_MIRROR.c @@ -90,8 +90,11 @@ static void ip_direct_send(struct sk_buff *skb) struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); hh->hh_output(skb); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 218c304ee5a..5451b13a51e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -91,17 +91,14 @@ static void raw_v4_hash(struct sock *sk) write_lock_bh(&raw_v4_lock); sk_add_node(sk, head); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); write_unlock_bh(&raw_v4_lock); } static void raw_v4_unhash(struct sock *sk) { write_lock_bh(&raw_v4_lock); - if (sk_del_node_init(sk)) { + if (sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); - } write_unlock_bh(&raw_v4_lock); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 619c4ce05f1..0c8ac243188 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1909,7 +1909,7 @@ void tcp_destroy_sock(struct sock *sk) BUG_TRAP(sk_unhashed(sk)); /* If it has not 0 inet_sk(sk)->num, it must be bound */ - BUG_TRAP(!inet_sk(sk)->num || sk->sk_prev); + BUG_TRAP(!inet_sk(sk)->num || tcp_sk(sk)->bind_hash); #ifdef TCP_DEBUG if (sk->sk_zapped) { @@ -2164,7 +2164,7 @@ int tcp_disconnect(struct sock *sk, int flags) tcp_sack_reset(tp); __sk_dst_reset(sk); - BUG_TRAP(!inet->num || sk->sk_prev); + BUG_TRAP(!inet->num || tp->bind_hash); sk->sk_error_report(sk); return err; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ab2a3977c84..1a74f72df31 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -156,9 +156,9 @@ static __inline__ void __tcp_inherit_port(struct sock *sk, struct sock *child) struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *)sk->sk_prev; + tb = tcp_sk(sk)->bind_hash; sk_add_bind_node(child, &tb->owners); - child->sk_prev = (struct sock *)tb; + tcp_sk(child)->bind_hash = tb; spin_unlock(&head->lock); } @@ -174,7 +174,7 @@ void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, { inet_sk(sk)->num = snum; sk_add_bind_node(sk, &tb->owners); - sk->sk_prev = (struct sock *)tb; + tcp_sk(sk)->bind_hash = tb; } static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) @@ -279,9 +279,9 @@ tb_not_found: (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) tb->fastreuse = 0; success: - if (!sk->sk_prev) + if (!tcp_sk(sk)->bind_hash) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->sk_prev == (struct sock *)tb); + BUG_TRAP(tcp_sk(sk)->bind_hash == tb); ret = 0; fail_unlock: @@ -301,9 +301,9 @@ static void __tcp_put_port(struct sock *sk) struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *)sk->sk_prev; - __hlist_del(&sk->sk_bind_node); - sk->sk_prev = NULL; + tb = tcp_sk(sk)->bind_hash; + __sk_del_bind_node(sk); + tcp_sk(sk)->bind_hash = NULL; inet->num = 0; tcp_bucket_destroy(tb); spin_unlock(&head->lock); @@ -359,7 +359,7 @@ static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible) lock = &tcp_ehash[sk->sk_hashent].lock; write_lock(lock); } - sk_add_node(sk, list); + __sk_add_node(sk, list); sock_prot_inc_use(sk->sk_prot); write_unlock(lock); if (listen_possible && sk->sk_state == TCP_LISTEN) @@ -392,7 +392,7 @@ void tcp_unhash(struct sock *sk) write_lock_bh(&head->lock); } - if (sk_del_node_init(sk)) + if (__sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); write_unlock_bh(lock); @@ -608,7 +608,7 @@ unique: inet->sport = htons(lport); sk->sk_hashent = hash; BUG_TRAP(sk_unhashed(sk)); - sk_add_node(sk, &head->chain); + __sk_add_node(sk, &head->chain); sock_prot_inc_use(sk->sk_prot); write_unlock(&head->lock); @@ -730,7 +730,7 @@ ok: } head = &tcp_bhash[tcp_bhashfn(snum)]; - tb = (struct tcp_bind_bucket *)sk->sk_prev; + tb = tcp_sk(sk)->bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { __tcp_v4_hash(sk, 0); @@ -2101,7 +2101,7 @@ static int tcp_v4_destroy_sock(struct sock *sk) __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if (sk->sk_prev) + if (tp->bind_hash) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index b0a6d0f166e..8bfbf511f7b 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -301,15 +301,15 @@ static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) */ bhead = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)]; spin_lock(&bhead->lock); - tw->tw_tb = (struct tcp_bind_bucket *)sk->sk_prev; - BUG_TRAP(sk->sk_prev); + tw->tw_tb = tcp_sk(sk)->bind_hash; + BUG_TRAP(tcp_sk(sk)->bind_hash); tw_add_bind_node(tw, &tw->tw_tb->owners); spin_unlock(&bhead->lock); write_lock(&ehead->lock); /* Step 2: Remove SK from established hash. */ - if (sk_del_node_init(sk)) + if (__sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); /* Step 3: Hash TW into TIMEWAIT half of established hash table. */ @@ -620,7 +620,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, /* SANITY */ sk_node_init(&newsk->sk_node); - newsk->sk_prev = NULL; + tcp_sk(newsk)->bind_hash = NULL; /* Clone the TCP header template */ inet_sk(newsk)->dport = req->rmt_port; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d3522962842..5b32fe89bea 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -189,7 +189,6 @@ gotit: sk_add_node(sk, h); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); } write_unlock_bh(&udp_hash_lock); return 0; @@ -210,7 +209,6 @@ static void udp_v4_unhash(struct sock *sk) if (sk_del_node_init(sk)) { inet_sk(sk)->num = 0; sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); } write_unlock_bh(&udp_hash_lock); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9700faf3e8b..5cfc70535e3 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -613,12 +613,6 @@ static int icmpv6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: - if (skb_is_nonlinear(skb) && - skb_linearize(skb, GFP_ATOMIC) != 0) { - kfree_skb(skb); - return 0; - } - ndisc_rcv(skb); break; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9b17cafeab3..0eb4d60f9da 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -76,8 +76,11 @@ static inline int ip6_output_finish(struct sk_buff *skb) struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 472e2a86f17..58dfe07c6b4 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -230,8 +230,6 @@ ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt) dev->init = ip6ip6_tnl_dev_init; memcpy(&t->parms, p, sizeof (*p)); t->parms.name[IFNAMSIZ - 1] = '\0'; - if (t->parms.hop_limit > 255) - t->parms.hop_limit = -1; strcpy(dev->name, t->parms.name); if (!dev->name[0]) { int i = 0; @@ -952,7 +950,7 @@ ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) ipv6_addr_copy(&t->parms.laddr, &p->laddr); ipv6_addr_copy(&t->parms.raddr, &p->raddr); t->parms.flags = p->flags; - t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1); + t->parms.hop_limit = p->hop_limit; t->parms.encap_limit = p->encap_limit; t->parms.flowinfo = p->flowinfo; ip6ip6_tnl_link_config(t); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 243aa2f6a5c..d9d5d289bb2 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -930,7 +930,7 @@ static void mld_gq_start_timer(struct inet6_dev *idev) idev->mc_gq_running = 1; if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2)) - atomic_inc(&idev->refcnt); + in6_dev_hold(idev); } static void mld_ifc_start_timer(struct inet6_dev *idev, int delay) @@ -938,7 +938,7 @@ static void mld_ifc_start_timer(struct inet6_dev *idev, int delay) int tv = net_random() % delay; if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2)) - atomic_inc(&idev->refcnt); + in6_dev_hold(idev); } /* @@ -1037,7 +1037,7 @@ int igmp6_event_query(struct sk_buff *skb) /* cancel the interface change timer */ idev->mc_ifc_count = 0; if (del_timer(&idev->mc_ifc_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); /* clear deleted report items */ mld_clear_delrec(idev); } else if (len >= 28) { @@ -1321,8 +1321,17 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, if (type == MLD2_ALLOW_NEW_SOURCES || type == MLD2_BLOCK_OLD_SOURCES) return skb; - if (pmc->mca_crcount || isquery) + if (pmc->mca_crcount || isquery) { + /* make sure we have room for group header and at + * least one source. + */ + if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+ + sizeof(struct in6_addr)) { + mld_sendpack(skb); + skb = 0; /* add_grhead will get a new one */ + } skb = add_grhead(skb, pmc, type, &pgr); + } return skb; } pmr = skb ? (struct mld2_report *)skb->h.raw : 0; @@ -1895,6 +1904,7 @@ static void mld_gq_timer_expire(unsigned long data) idev->mc_gq_running = 0; mld_send_report(idev, 0); + __in6_dev_put(idev); } static void mld_ifc_timer_expire(unsigned long data) @@ -1907,6 +1917,7 @@ static void mld_ifc_timer_expire(unsigned long data) if (idev->mc_ifc_count) mld_ifc_start_timer(idev, idev->mc_maxdelay); } + __in6_dev_put(idev); } static void mld_ifc_event(struct inet6_dev *idev) @@ -1945,10 +1956,10 @@ void ipv6_mc_down(struct inet6_dev *idev) read_lock_bh(&idev->lock); idev->mc_ifc_count = 0; if (del_timer(&idev->mc_ifc_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); idev->mc_gq_running = 0; if (del_timer(&idev->mc_gq_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); for (i = idev->mc_list; i; i=i->next) igmp6_group_dropped(i); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index aab59050a6c..1c582945bac 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -714,12 +714,6 @@ void ndisc_recv_ns(struct sk_buff *skb) struct inet6_ifaddr *ifp; struct neighbour *neigh; - if (skb->len < sizeof(struct nd_msg)) { - if (net_ratelimit()) - printk(KERN_WARNING "ICMP NS: packet too short\n"); - return; - } - if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) { if (net_ratelimit()) printk(KERN_WARNING "ICMP NS: target address is multicast\n"); @@ -1410,7 +1404,12 @@ static void pndisc_redo(struct sk_buff *skb) int ndisc_rcv(struct sk_buff *skb) { - struct nd_msg *msg = (struct nd_msg *) skb->h.raw; + struct nd_msg *msg; + + if (!pskb_may_pull(skb, skb->len)) + return 0; + + msg = (struct nd_msg *) skb->h.raw; __skb_push(skb, skb->data-skb->h.raw); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index f4c4490b0ac..03ecad3c350 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -64,17 +64,14 @@ static void raw_v6_hash(struct sock *sk) write_lock_bh(&raw_v6_lock); sk_add_node(sk, list); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); write_unlock_bh(&raw_v6_lock); } static void raw_v6_unhash(struct sock *sk) { write_lock_bh(&raw_v6_lock); - if (sk_del_node_init(sk)) { + if (sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); - } write_unlock_bh(&raw_v6_lock); } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 71ca875f7e7..b5d18871ecd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -225,9 +225,9 @@ tb_not_found: tb->fastreuse = 0; success: - if (!sk->sk_prev) + if (!tcp_sk(sk)->bind_hash) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->sk_prev == (struct sock *)tb); + BUG_TRAP(tcp_sk(sk)->bind_hash == tb); ret = 0; fail_unlock: @@ -1947,7 +1947,7 @@ static int tcp_v6_destroy_sock(struct sock *sk) __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if (sk->sk_prev) + if (tcp_sk(sk)->bind_hash) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 26fca3d7d4a..e797bd8f691 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -160,7 +160,6 @@ gotit: if (sk_unhashed(sk)) { sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); } write_unlock_bh(&udp_hash_lock); return 0; @@ -181,7 +180,6 @@ static void udp_v6_unhash(struct sock *sk) if (sk_del_node_init(sk)) { inet_sk(sk)->num = 0; sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); } write_unlock_bh(&udp_hash_lock); } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index a13091a7414..0220f6e4549 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -60,8 +60,16 @@ __xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *pol read_lock_bh(&policy->lock); for (dst = policy->bundles; dst; dst = dst->next) { struct xfrm_dst *xdst = (struct xfrm_dst*)dst; - if (!ipv6_addr_cmp(&xdst->u.rt6.rt6i_dst.addr, &fl->fl6_dst) && - !ipv6_addr_cmp(&xdst->u.rt6.rt6i_src.addr, &fl->fl6_src) && + struct in6_addr fl_dst_prefix, fl_src_prefix; + + ipv6_addr_prefix(&fl_dst_prefix, + &fl->fl6_dst, + xdst->u.rt6.rt6i_dst.plen); + ipv6_addr_prefix(&fl_src_prefix, + &fl->fl6_src, + xdst->u.rt6.rt6i_src.plen); + if (!ipv6_addr_cmp(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && + !ipv6_addr_cmp(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && __xfrm6_bundle_ok(xdst, fl)) { dst_clone(dst); break; @@ -133,7 +141,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int dst_prev->child = &rt->u.dst; for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; - x->u.rt.fl = *fl; dst_prev->dev = rt->u.dst.dev; if (rt->u.dst.dev) @@ -157,6 +164,8 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int x->u.rt6.rt6i_node = rt0->rt6i_node; x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); + x->u.rt6.rt6i_dst = rt0->rt6i_dst; + x->u.rt6.rt6i_src = rt0->rt6i_src; header_len -= x->u.dst.xfrm->props.header_len; trailer_len -= x->u.dst.xfrm->props.trailer_len; } diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 25aa0bcc57b..f2150caae0c 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -142,7 +142,6 @@ static void ipx_remove_socket(struct sock *sk) spin_lock_bh(&intrfc->if_sklist_lock); sk_del_node_init(sk); spin_unlock_bh(&intrfc->if_sklist_lock); - sock_put(sk); ipxitf_put(intrfc); out: return; @@ -229,7 +228,6 @@ unlock: static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) { ipxitf_hold(intrfc); - sock_hold(sk); spin_lock_bh(&intrfc->if_sklist_lock); ipx_sk(sk)->intrfc = intrfc; sk_add_node(sk, &intrfc->if_sklist); @@ -269,7 +267,7 @@ static struct sock *ipxitf_find_socket(struct ipx_interface *intrfc, #ifdef CONFIG_IPX_INTERN static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, - unsigned char *node, + unsigned char *ipx_node, unsigned short port) { struct sock *s; @@ -282,7 +280,7 @@ static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, struct ipx_opt *ipxs = ipx_sk(s); if (ipxs->port == port && - !memcmp(node, ipxs->node, IPX_NODE_LEN)) + !memcmp(ipx_node, ipxs->node, IPX_NODE_LEN)) goto found; } s = NULL; diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 743abb29c16..5092abb62d5 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -231,7 +231,7 @@ static void __irda_task_delete(struct irda_task *task) void irda_task_delete(struct irda_task *task) { /* Unregister task */ - hashbin_remove(tasks, (int) task, NULL); + hashbin_remove(tasks, (long) task, NULL); __irda_task_delete(task); } @@ -345,7 +345,7 @@ struct irda_task *irda_task_execute(void *instance, init_timer(&task->timer); /* Register task */ - hashbin_insert(tasks, (irda_queue_t *) task, (int) task, NULL); + hashbin_insert(tasks, (irda_queue_t *) task, (long) task, NULL); /* No time to waste, so lets get going! */ ret = irda_task_kick(task); diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index 45dc5b03c16..05458c3d4a5 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -33,8 +33,8 @@ irnet_post_event(irnet_socket * ap, { int index; /* In the log */ - DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n", - (unsigned int) ap, event, daddr, name); + DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", + ap, event, daddr, name); /* Protect this section via spinlock. * Note : as we are the only event producer, we only need to exclude @@ -100,7 +100,7 @@ irnet_open_tsap(irnet_socket * self) { notify_t notify; /* Callback structure */ - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); @@ -125,8 +125,8 @@ irnet_open_tsap(irnet_socket * self) /* Remember which TSAP selector we actually got */ self->stsap_sel = self->tsap->stsap_sel; - DEXIT(IRDA_SR_TRACE, " - tsap=0x%X, sel=0x%X\n", - (unsigned int) self->tsap, self->stsap_sel); + DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", + self->tsap, self->stsap_sel); return 0; } @@ -151,7 +151,7 @@ irnet_ias_to_tsap(irnet_socket * self, { __u8 dtsap_sel = 0; /* TSAP we are looking for */ - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* By default, no error */ self->errno = 0; @@ -231,7 +231,7 @@ irnet_ias_to_tsap(irnet_socket * self, static inline int irnet_find_lsap_sel(irnet_socket * self) { - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* This should not happen */ DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); @@ -268,7 +268,7 @@ irnet_connect_tsap(irnet_socket * self) { int err; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Open a local TSAP (an IrTTP instance) */ err = irnet_open_tsap(self); @@ -369,7 +369,7 @@ irnet_discover_daddr_and_lsap_sel(irnet_socket * self) { int ret; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, @@ -382,8 +382,8 @@ irnet_discover_daddr_and_lsap_sel(irnet_socket * self) clear_bit(0, &self->ttp_connect); DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); } - DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n", - (unsigned int) self->discoveries, self->disco_number); + DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", + self->discoveries, self->disco_number); /* Start with the first discovery */ self->disco_index = -1; @@ -426,7 +426,7 @@ irnet_dname_to_daddr(irnet_socket * self) int number; /* Number of nodes in the log */ int i; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&number, 0xffff, @@ -474,7 +474,7 @@ irnet_dname_to_daddr(irnet_socket * self) int irda_irnet_create(irnet_socket * self) { - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); self->magic = IRNET_MAGIC; /* Paranoia */ @@ -518,7 +518,7 @@ irda_irnet_connect(irnet_socket * self) { int err; - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); /* Check if we are already trying to connect. * Because irda_irnet_connect() can be called directly by pppd plus @@ -585,7 +585,7 @@ irda_irnet_connect(irnet_socket * self) void irda_irnet_destroy(irnet_socket * self) { - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); if(self == NULL) return; @@ -676,7 +676,7 @@ irnet_daddr_to_dname(irnet_socket * self) int number; /* Number of nodes in the log */ int i; - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&number, 0xffff, @@ -722,7 +722,7 @@ irnet_find_socket(irnet_socket * self) irnet_socket * new = (irnet_socket *) NULL; int err; - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Get the addresses of the requester */ self->daddr = irttp_get_daddr(self->tsap); @@ -741,8 +741,8 @@ irnet_find_socket(irnet_socket * self) new = (irnet_socket *) hashbin_find(irnet_server.list, 0, self->rname); if(new) - DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches rname ``%s''.\n", - (unsigned int) new, new->rname); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", + new, new->rname); } /* If no name matches, try to find an socket by the destination address */ @@ -758,8 +758,8 @@ irnet_find_socket(irnet_socket * self) if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) { /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches daddr %#08x.\n", - (unsigned int) new, self->daddr); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", + new, self->daddr); break; } new = (irnet_socket *) hashbin_get_next(irnet_server.list); @@ -777,8 +777,8 @@ irnet_find_socket(irnet_socket * self) (new->rname[0] == '\0') && (new->ppp_open)) { /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%X is free.\n", - (unsigned int) new); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", + new); break; } new = (irnet_socket *) hashbin_get_next(irnet_server.list); @@ -788,7 +788,7 @@ irnet_find_socket(irnet_socket * self) /* Spin lock end */ spin_unlock_bh(&irnet_server.spinlock); - DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new); + DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); return new; } @@ -806,8 +806,8 @@ irnet_connect_socket(irnet_socket * server, __u32 max_sdu_size, __u8 max_header_size) { - DENTER(IRDA_SERV_TRACE, "(server=0x%X, new=0x%X)\n", - (unsigned int) server, (unsigned int) new); + DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", + server, new); /* Now attach up the new socket */ new->tsap = irttp_dup(server->tsap, new); @@ -878,7 +878,7 @@ static inline void irnet_disconnect_server(irnet_socket * self, struct sk_buff *skb) { - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Put the received packet in the black hole */ kfree_skb(skb); @@ -1010,8 +1010,8 @@ irnet_data_indication(void * instance, unsigned char * p; int code = 0; - DENTER(IRDA_TCB_TRACE, "(self/ap=0x%X, skb=0x%X)\n", - (unsigned int) ap,(unsigned int) skb); + DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", + ap, skb); DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); /* Check is ppp is ready to receive our packet */ @@ -1081,7 +1081,7 @@ irnet_disconnect_indication(void * instance, int test_open; int test_connect; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); /* Don't care about it, but let's not leak it */ @@ -1171,7 +1171,7 @@ irnet_connect_confirm(void * instance, { irnet_socket * self = (irnet_socket *) instance; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); /* Check if socket is closing down (via irda_irnet_destroy()) */ if(! test_bit(0, &self->ttp_connect)) @@ -1237,7 +1237,7 @@ irnet_flow_indication(void * instance, irnet_socket * self = (irnet_socket *) instance; LOCAL_FLOW oldflow = self->tx_flow; - DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow); + DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); /* Update our state */ self->tx_flow = flow; @@ -1278,7 +1278,7 @@ irnet_status_indication(void * instance, { irnet_socket * self = (irnet_socket *) instance; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); /* We can only get this event if we are connected */ @@ -1320,9 +1320,9 @@ irnet_connect_indication(void * instance, irnet_socket * server = &irnet_server.s; irnet_socket * new = (irnet_socket *) NULL; - DENTER(IRDA_TCB_TRACE, "(server=0x%X)\n", (unsigned int) server); + DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) instance); + "Invalid instance (0x%p) !!!\n", instance); DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); /* Try to find the most appropriate IrNET socket */ @@ -1466,7 +1466,7 @@ irnet_getvalue_confirm(int result, { irnet_socket * self = (irnet_socket *) priv; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) @@ -1530,7 +1530,7 @@ irnet_discovervalue_confirm(int result, irnet_socket * self = (irnet_socket *) priv; __u8 dtsap_sel; /* TSAP we are looking for */ - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) @@ -1583,8 +1583,8 @@ irnet_discovervalue_confirm(int result, self->iriap = NULL; /* No more items : remove the log and signal termination */ - DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%X)\n", - (unsigned int) self->discoveries); + DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", + self->discoveries); if(self->discoveries != NULL) { /* Cleanup our copy of the discovery log */ @@ -1643,9 +1643,9 @@ irnet_discovery_indication(discinfo_t * discovery, { irnet_socket * self = &irnet_server.s; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) priv); + "Invalid instance (0x%p) !!!\n", priv); DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", discovery->info); @@ -1674,9 +1674,9 @@ irnet_expiry_indication(discinfo_t * expiry, { irnet_socket * self = &irnet_server.s; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) priv); + "Invalid instance (0x%p) !!!\n", priv); DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", expiry->info); diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c index 187871a4208..b724fb08722 100644 --- a/net/irda/irnet/irnet_ppp.c +++ b/net/irda/irnet/irnet_ppp.c @@ -43,7 +43,7 @@ irnet_ctrl_write(irnet_socket * ap, char * next; /* Next command to process */ int length; /* Length of current command */ - DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count); + DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); /* Check for overflow... */ DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM, @@ -58,7 +58,7 @@ irnet_ctrl_write(irnet_socket * ap, /* Safe terminate the string */ command[count] = '\0'; - DEBUG(CTRL_INFO, "Command line received is ``%s'' (%d).\n", + DEBUG(CTRL_INFO, "Command line received is ``%s'' (%Zd).\n", command, count); /* Check every commands in the command line */ @@ -184,8 +184,8 @@ irnet_read_discovery_log(irnet_socket * ap, { int done_event = 0; - DENTER(CTRL_TRACE, "(ap=0x%X, event=0x%X)\n", - (unsigned int) ap, (unsigned int) event); + DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n", + ap, event); /* Test if we have some work to do or we have already finished */ if(ap->disco_number == -1) @@ -205,8 +205,8 @@ irnet_read_discovery_log(irnet_socket * ap, /* Check if the we got some results */ if(ap->discoveries == NULL) ap->disco_number = -1; - DEBUG(CTRL_INFO, "Got the log (0x%X), size is %d\n", - (unsigned int) ap->discoveries, ap->disco_number); + DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n", + ap->discoveries, ap->disco_number); } /* Check if we have more item to dump */ @@ -232,8 +232,8 @@ irnet_read_discovery_log(irnet_socket * ap, if(ap->disco_index >= ap->disco_number) { /* No more items : remove the log and signal termination */ - DEBUG(CTRL_INFO, "Cleaning up log (0x%X)\n", - (unsigned int) ap->discoveries); + DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n", + ap->discoveries); if(ap->discoveries != NULL) { /* Cleanup our copy of the discovery log */ @@ -261,7 +261,7 @@ irnet_ctrl_read(irnet_socket * ap, char event[64]; /* Max event is 61 char */ ssize_t ret = 0; - DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count); + DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); /* Check if we can write an event out in one go */ DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n"); @@ -307,7 +307,7 @@ irnet_ctrl_read(irnet_socket * ap, if(ret != 0) { /* No, return the error code */ - DEXIT(CTRL_TRACE, " - ret %d\n", ret); + DEXIT(CTRL_TRACE, " - ret %Zd\n", ret); return ret; } @@ -402,7 +402,7 @@ irnet_ctrl_poll(irnet_socket * ap, { unsigned int mask; - DENTER(CTRL_TRACE, "(ap=0x%X)\n", (unsigned int) ap); + DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap); poll_wait(file, &irnet_events.rwait, wait); mask = POLLOUT | POLLWRNORM; @@ -439,7 +439,7 @@ dev_irnet_open(struct inode * inode, struct irnet_socket * ap; int err; - DENTER(FS_TRACE, "(file=0x%X)\n", (unsigned int) file); + DENTER(FS_TRACE, "(file=0x%p)\n", file); #ifdef SECURE_DEVIRNET /* This could (should?) be enforced by the permissions on /dev/irnet. */ @@ -482,7 +482,7 @@ dev_irnet_open(struct inode * inode, /* Put our stuff where we will be able to find it later */ file->private_data = ap; - DEXIT(FS_TRACE, " - ap=0x%X\n", (unsigned int) ap); + DEXIT(FS_TRACE, " - ap=0x%p\n", ap); return 0; } @@ -498,8 +498,8 @@ dev_irnet_close(struct inode * inode, { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n", - (unsigned int) file, (unsigned int) ap); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n"); /* Detach ourselves */ @@ -535,8 +535,8 @@ dev_irnet_write(struct file * file, { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n", - (unsigned int) file, (unsigned int) ap, count); + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", + file, ap, count); DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); /* If we are connected to ppp_generic, let it handle the job */ @@ -559,8 +559,8 @@ dev_irnet_read(struct file * file, { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n", - (unsigned int) file, (unsigned int) ap, count); + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", + file, ap, count); DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); /* If we are connected to ppp_generic, let it handle the job */ @@ -581,8 +581,8 @@ dev_irnet_poll(struct file * file, irnet_socket * ap = (struct irnet_socket *) file->private_data; unsigned int mask; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n", - (unsigned int) file, (unsigned int) ap); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); mask = POLLOUT | POLLWRNORM; DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n"); @@ -611,8 +611,8 @@ dev_irnet_ioctl(struct inode * inode, int err; int val; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X, cmd=0x%X)\n", - (unsigned int) file, (unsigned int) ap, cmd); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n", + file, ap, cmd); /* Basic checks... */ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); @@ -777,8 +777,8 @@ irnet_prepare_skb(irnet_socket * ap, int islcp; /* Protocol == LCP */ int needaddr; /* Need PPP address */ - DENTER(PPP_TRACE, "(ap=0x%X, skb=0x%X)\n", - (unsigned int) ap, (unsigned int) skb); + DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n", + ap, skb); /* Extract PPP protocol from the frame */ data = skb->data; @@ -845,8 +845,8 @@ ppp_irnet_send(struct ppp_channel * chan, irnet_socket * self = (struct irnet_socket *) chan->private; int ret; - DENTER(PPP_TRACE, "(channel=0x%X, ap/self=0x%X)\n", - (unsigned int) chan, (unsigned int) self); + DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n", + chan, self); /* Check if things are somewhat valid... */ DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); @@ -949,8 +949,8 @@ ppp_irnet_ioctl(struct ppp_channel * chan, int val; u32 accm[8]; - DENTER(PPP_TRACE, "(channel=0x%X, ap=0x%X, cmd=0x%X)\n", - (unsigned int) chan, (unsigned int) ap, cmd); + DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n", + chan, ap, cmd); /* Basic checks... */ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); diff --git a/net/irda/irttp.c b/net/irda/irttp.c index bb51edc7d99..cc9069395d9 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -1408,7 +1408,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); /* Find the old instance */ - if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) { + if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) { IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __FUNCTION__); spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; diff --git a/net/key/af_key.c b/net/key/af_key.c index 7963ce20815..9833536c08c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -115,15 +115,13 @@ static void pfkey_insert(struct sock *sk) { pfkey_table_grab(); sk_add_node(sk, &pfkey_table); - sock_hold(sk); pfkey_table_ungrab(); } static void pfkey_remove(struct sock *sk) { pfkey_table_grab(); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); pfkey_table_ungrab(); } diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 08ee90b3fed..d7f35bf275a 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -102,13 +102,13 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) if (ev->type == LLC_CONN_EV_TYPE_PDU) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM) { reason = LLC_DISC_REASON_RX_DM_RSP_PDU; rc = 0; - } else if (!LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + } else if (LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC) { reason = LLC_DISC_REASON_RX_DISC_CMD_PDU; rc = 0; @@ -146,13 +146,13 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) switch (ev->type) { case LLC_CONN_EV_TYPE_PDU: - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) { reason = LLC_RESET_REASON_LOCAL; rc = 0; - } else if (!LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + } else if (LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) { reason = LLC_RESET_REASON_REMOTE; rc = 0; @@ -198,9 +198,9 @@ int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk, { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf) + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf) llc_conn_ac_clear_remote_busy(sk, skb); return 0; } @@ -310,7 +310,7 @@ int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb) struct llc_opt *llc = llc_sk(sk); llc->rx_pdu_hdr = *((u32 *)pdu); - if (!LLC_PDU_IS_CMD(pdu)) + if (LLC_PDU_IS_CMD(pdu)) llc_pdu_decode_pf_bit(skb, &f_bit); else f_bit = 0; @@ -1228,7 +1228,7 @@ int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_IS_RSP(pdu)) { u8 f_bit; llc_pdu_decode_pf_bit(skb, &f_bit); diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c index 883e550afe2..77d630de218 100644 --- a/net/llc/llc_c_ev.c +++ b/net/llc/llc_c_ev.c @@ -170,7 +170,7 @@ int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1; } @@ -178,7 +178,7 @@ int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1; } @@ -186,7 +186,7 @@ int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1; } @@ -195,8 +195,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && + LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -205,8 +205,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && + LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -217,8 +217,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk, u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && ns != vr && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -229,8 +229,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk, u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && ns != vr && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -240,7 +240,7 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, struct llc_pdu_sn * pdu = llc_pdu_sn_hdr(skb); u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + u16 rc = LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", @@ -253,8 +253,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -262,8 +262,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -272,7 +272,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -283,8 +283,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk, u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -295,8 +295,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk, u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -307,7 +307,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk, u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -317,7 +317,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + u16 rc = LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", @@ -329,8 +329,8 @@ int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; } @@ -338,8 +338,8 @@ int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; } @@ -347,8 +347,8 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -356,8 +356,8 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -365,7 +365,7 @@ int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -373,8 +373,8 @@ int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; } @@ -382,8 +382,8 @@ int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; } @@ -391,8 +391,8 @@ int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; } @@ -400,8 +400,8 @@ int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; } @@ -409,8 +409,8 @@ int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; } @@ -418,8 +418,8 @@ int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; } @@ -428,8 +428,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } @@ -438,8 +438,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } @@ -447,7 +447,7 @@ int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1; } @@ -455,7 +455,7 @@ int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1; } @@ -464,11 +464,11 @@ int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_1(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_1(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu) && !LLC_U_PF_IS_1(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PF_IS_1(pdu)) rc = 0; } return rc; @@ -479,15 +479,15 @@ int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_0(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_0(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: - if (!LLC_U_PF_IS_0(pdu)) + if (LLC_U_PF_IS_0(pdu)) rc = 0; break; } @@ -500,10 +500,10 @@ int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: @@ -519,16 +519,16 @@ int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_1(pdu)) + if (LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_1(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_RSP(pdu)) { case LLC_2_PDU_RSP_UA: case LLC_2_PDU_RSP_DM: case LLC_2_PDU_RSP_FRMR: - if (!LLC_U_PF_IS_1(pdu)) + if (LLC_U_PF_IS_1(pdu)) rc = 0; break; } @@ -541,10 +541,10 @@ int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_RSP(pdu)) { case LLC_2_PDU_RSP_UA: case LLC_2_PDU_RSP_DM: @@ -562,9 +562,9 @@ int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct sk_buff *skb) u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: @@ -585,8 +585,8 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, u8 vs = llc_sk(sk)->vS; u8 nr = LLC_I_GET_NR(pdu); - if (!LLC_PDU_IS_CMD(pdu) && - (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && + if (LLC_PDU_IS_CMD(pdu) && + (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", __FUNCTION__, llc_sk(sk)->state, vs, nr); @@ -603,8 +603,8 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, u8 vs = llc_sk(sk)->vS; u8 nr = LLC_I_GET_NR(pdu); - if (!LLC_PDU_IS_RSP(pdu) && - (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && + if (LLC_PDU_IS_RSP(pdu) && + (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { rc = 0; dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index ccc2143f353..3fbb3fe4512 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -356,7 +356,7 @@ static void llc_conn_send_pdus(struct sock *sk) while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_TYPE_IS_I(pdu) && + if (LLC_PDU_TYPE_IS_I(pdu) && !(skb->dev->flags & IFF_LOOPBACK)) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); diff --git a/net/llc/llc_evnt.c b/net/llc/llc_evnt.c index 654650f5a4f..3ff47997522 100644 --- a/net/llc/llc_evnt.c +++ b/net/llc/llc_evnt.c @@ -68,8 +68,8 @@ int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station, struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_CMD(pdu) && /* command PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_CMD(pdu) && /* command PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap ? 0 : 1; /* NULL DSAP value */ } @@ -81,8 +81,8 @@ int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station, struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_RSP(pdu) && /* response PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_RSP(pdu) && /* response PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap && /* NULL DSAP value */ !station->xid_r_count ? 0 : 1; @@ -95,8 +95,8 @@ int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station, struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_RSP(pdu) && /* response PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_RSP(pdu) && /* response PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap && /* NULL DSAP value */ station->xid_r_count == 1 ? 0 : 1; @@ -109,8 +109,8 @@ int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station, struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_CMD(pdu) && /* command PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_CMD(pdu) && /* command PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && !pdu->dsap ? 0 : 1; /* NULL DSAP */ } diff --git a/net/llc/llc_s_ev.c b/net/llc/llc_s_ev.c index 949ade26806..a74d2a1d658 100644 --- a/net/llc/llc_s_ev.c +++ b/net/llc/llc_s_ev.c @@ -33,8 +33,8 @@ int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb) struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1; } @@ -62,8 +62,8 @@ int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb) struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; } @@ -72,8 +72,8 @@ int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct sk_buff *skb) struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; } @@ -91,8 +91,8 @@ int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb) struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; } @@ -101,8 +101,8 @@ int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct sk_buff *skb) struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; } diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 70e9b324d06..e15f2ef6e6d 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -35,7 +35,6 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) write_lock_bh(&sap->sk_list.lock); llc_sk(sk)->sap = sap; sk_add_node(sk, &sap->sk_list.list); - sock_hold(sk); write_unlock_bh(&sap->sk_list.lock); } @@ -50,8 +49,7 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) { write_lock_bh(&sap->sk_list.lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&sap->sk_list.lock); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 253724f330a..54d88de80e2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -193,7 +193,6 @@ static int netlink_insert(struct sock *sk, u32 pid) if (nlk_sk(sk)->pid == 0) { nlk_sk(sk)->pid = pid; sk_add_node(sk, &nl_table[sk->sk_protocol]); - sock_hold(sk); err = 0; } } @@ -204,8 +203,7 @@ static int netlink_insert(struct sock *sk, u32 pid) static void netlink_remove(struct sock *sk) { netlink_table_grab(); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); netlink_table_ungrab(); } diff --git a/net/netsyms.c b/net/netsyms.c index 5ad7714b21e..091305e3d87 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -148,7 +148,7 @@ EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); -EXPORT_SYMBOL(skb_linearize); +EXPORT_SYMBOL(__skb_linearize); EXPORT_SYMBOL(skb_checksum); EXPORT_SYMBOL(skb_checksum_help); EXPORT_SYMBOL(skb_recv_datagram); @@ -563,6 +563,7 @@ EXPORT_SYMBOL(register_netdevice); EXPORT_SYMBOL(unregister_netdevice); EXPORT_SYMBOL(synchronize_net); EXPORT_SYMBOL(netdev_state_change); +EXPORT_SYMBOL(netdev_boot_setup_check); EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_get_by_flags); EXPORT_SYMBOL(__dev_get_by_flags); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 21fa669fd24..5867ffa99ac 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -758,8 +758,7 @@ static int packet_release(struct socket *sock) return 0; write_lock_bh(&packet_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&packet_sklist_lock); /* @@ -984,7 +983,6 @@ static int packet_create(struct socket *sock, int protocol) write_lock_bh(&packet_sklist_lock); sk_add_node(sk, &packet_sklist); - sock_hold(sk); write_unlock_bh(&packet_sklist_lock); return(0); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 20bb98d47b7..ef4ea4452c5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -9,6 +9,8 @@ * Authors: Martin Devera, * * Credits (in time order) for older HTB versions: + * Stef Coene + * HTB support at LARTC mailing list * Ondrej Kraus, * found missing INIT_QDISC(htb) * Vladimir Smelhaus, Aamer Akhter, Bert Hubert @@ -19,7 +21,7 @@ * created test case so that I was able to fix nasty bug * and many others. thanks. * - * $Id: sch_htb.c,v 1.17 2003/01/29 09:22:18 devik Exp devik $ + * $Id: sch_htb.c,v 1.20 2003/06/18 19:55:49 devik Exp devik $ */ #include #include @@ -71,7 +73,7 @@ #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x3000a /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x3000c /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" @@ -217,6 +219,9 @@ struct htb_sched /* time of nearest event per level (row) */ unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; + /* cached value of jiffies in dequeue */ + unsigned long jiffies; + /* whether we hit non-work conserving class during this dequeue; we use */ int nwc_hit; /* this to disable mindelay complaint in dequeue */ @@ -336,7 +341,7 @@ static void htb_next_rb_node(struct rb_node **n); static void htb_debug_dump (struct htb_sched *q) { int i,p; - printk(KERN_DEBUG "htb*g j=%lu\n",jiffies); + printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies); /* rows */ for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) { printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]); @@ -419,8 +424,8 @@ static void htb_add_to_wait_tree (struct htb_sched *q, if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit()) printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint); #endif - cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay); - if (cl->pq_key == jiffies) + cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); + if (cl->pq_key == q->jiffies) cl->pq_key++; /* update the nearest event cache */ @@ -587,7 +592,7 @@ htb_class_mode(struct htb_class *cl,long *diff) long toks; if ((toks = (cl->ctokens + *diff)) < ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : #endif 0)) { @@ -595,7 +600,7 @@ htb_class_mode(struct htb_class *cl,long *diff) return HTB_CANT_SEND; } if ((toks = (cl->tokens + *diff)) >= ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode == HTB_CAN_SEND ? -cl->buffer : #endif 0)) @@ -798,7 +803,7 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -841,6 +846,7 @@ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl, * * Scans event queue for pending events and applies them. Returns jiffies to * next pending event (0 for no event in pq). + * Note: Aplied are events whose have cl->pq_key <= jiffies. */ static long htb_do_events(struct htb_sched *q,int level) { @@ -855,9 +861,9 @@ static long htb_do_events(struct htb_sched *q,int level) while (p->rb_left) p = p->rb_left; cl = rb_entry(p, struct htb_class, pq_node); - if (cl->pq_key - (jiffies+1) < 0x80000000) { - HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - jiffies); - return cl->pq_key - jiffies; + if (cl->pq_key - (q->jiffies+1) < 0x80000000) { + HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); + return cl->pq_key - q->jiffies; } htb_safe_rb_erase(p,q->wait_pq+level); diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0); @@ -868,7 +874,7 @@ static long htb_do_events(struct htb_sched *q,int level) cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -975,7 +981,8 @@ static void htb_delay_by(struct Qdisc *sch,long delay) printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); delay = 5*HZ; } - mod_timer(&q->timer, jiffies + delay); + /* why don't use jiffies here ? because expires can be in past */ + mod_timer(&q->timer, q->jiffies + delay); sch->flags |= TCQ_F_THROTTLED; sch->stats.overlimits++; HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay); @@ -991,6 +998,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) int evs_used = 0; #endif + q->jiffies = jiffies; HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue), sch->q.qlen); @@ -1010,14 +1018,14 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) /* common case optimization - skip event handler quickly */ int m; long delay; - if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { + if (q->jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { delay = htb_do_events(q,level); - q->near_ev_cache[level] += delay ? delay : HZ; + q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); #ifdef HTB_DEBUG evs_used++; #endif } else - delay = q->near_ev_cache[level] - jiffies; + delay = q->near_ev_cache[level] - q->jiffies; if (delay && min_delay > delay) min_delay = delay; @@ -1036,8 +1044,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) #ifdef HTB_DEBUG if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) { if (min_delay == LONG_MAX) { - printk(KERN_ERR "HTB: dequeue bug (%d), report it please !\n", - evs_used); + printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n", + evs_used,q->jiffies,jiffies); htb_debug_dump(q); } else printk(KERN_WARNING "HTB: mindelay=%ld, some class has " @@ -1046,7 +1054,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) #endif htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay); fin: - HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb); + HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb); return skb; } @@ -1409,7 +1417,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch); hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]); - HTB_DBG(0,1,"htb_chg cl=%p, clid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); + HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]); ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); if (!rtab || !ctab) goto failure; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 2f5c5084f8a..0fda841d742 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -209,7 +209,7 @@ void sctp_endpoint_destroy(struct sctp_endpoint *ep) sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ - if (ep->base.sk->sk_prev) + if (sctp_sk(ep->base.sk)->bind_hash) sctp_put_port(ep->base.sk); /* Give up our hold on the sock. */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 8051d24e8a2..aabf9450a35 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -3078,9 +3078,9 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) */ success: inet_sk(sk)->num = snum; - if (!sk->sk_prev) { + if (!sctp_sk(sk)->bind_hash) { sk_add_bind_node(sk, &pp->sk_list); - sk->sk_prev = (struct sock *) pp; + sctp_sk(sk)->bind_hash = pp; } ret = 0; @@ -3328,7 +3328,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( /* Caller must hold hashbucket lock for this tb with local BH disabled */ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) { - if (!hlist_empty(&pp->sk_list)) { + if (hlist_empty(&pp->sk_list)) { if (pp->next) pp->next->pprev = pp->pprev; *(pp->pprev) = pp->next; @@ -3345,9 +3345,9 @@ static __inline__ void __sctp_put_port(struct sock *sk) struct sctp_bind_bucket *pp; sctp_spin_lock(&head->lock); - pp = (struct sctp_bind_bucket *)sk->sk_prev; - hlist_del(&sk->sk_bind_node); - sk->sk_prev = NULL; + pp = sctp_sk(sk)->bind_hash; + __sk_del_bind_node(sk); + sctp_sk(sk)->bind_hash = NULL; inet_sk(sk)->num = 0; sctp_bucket_destroy(pp); sctp_spin_unlock(&head->lock); diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 9a8c6b39f18..aa85c0b5e25 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -310,14 +310,17 @@ int cache_clean(void) cp = & current_detail->hash_table[current_index]; ch = *cp; for (; ch; cp= & ch->next, ch= *cp) { - if (atomic_read(&ch->refcnt)) - continue; - if (ch->expiry_time < get_seconds() - || ch->last_refresh < current_detail->flush_time - ) - break; if (current_detail->nextcheck > ch->expiry_time) current_detail->nextcheck = ch->expiry_time+1; + if (ch->expiry_time >= get_seconds() + && ch->last_refresh >= current_detail->flush_time + ) + continue; + if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) + queue_loose(current_detail, ch); + + if (atomic_read(&ch->refcnt)) + continue; } if (ch) { cache_get(ch); @@ -467,6 +470,31 @@ void cache_revisit_request(struct cache_head *item) } } +void cache_clean_deferred(void *owner) +{ + struct cache_deferred_req *dreq, *tmp; + struct list_head pending; + + + INIT_LIST_HEAD(&pending); + spin_lock(&cache_defer_lock); + + list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { + if (dreq->owner == owner) { + list_del(&dreq->hash); + list_move(&dreq->recent, &pending); + cache_defer_cnt--; + } + } + spin_unlock(&cache_defer_lock); + + while (!list_empty(&pending)) { + dreq = list_entry(pending.next, struct cache_deferred_req, recent); + list_del_init(&dreq->recent); + dreq->revisit(dreq, 1); + } +} + /* * communicate with user-space * diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index d9ccb6d1db0..79ebf10e03d 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -969,6 +970,8 @@ rpciod(void *ptr) flush_signals(current); } __rpc_schedule(); + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); if (++rounds >= 64) { /* safeguard */ schedule(); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index beadf395b86..686d5cbdb7a 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -98,6 +98,8 @@ svc_destroy(struct svc_serv *serv) sk_list); svc_delete_socket(svsk); } + + cache_clean_deferred(serv); /* Unregister service with the portmapper */ svc_register(serv, 0, 0); diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 3397f58011e..1aee12c44c9 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -195,12 +195,12 @@ static int ip_map_parse(struct cache_detail *cd, ipm.m_addr.s_addr = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); ipm.h.flags = 0; - if (dom) + if (dom) { ipm.m_client = container_of(dom, struct unix_domain, h); - else + ipm.m_add_change = ipm.m_client->addr_changes; + } else set_bit(CACHE_NEGATIVE, &ipm.h.flags); ipm.h.expiry_time = expiry; - ipm.m_add_change = ipm.m_client->addr_changes; ipmp = ip_map_lookup(&ipm, 1); if (ipmp) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index f1230fdafa9..dc645b5dd41 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -681,8 +681,17 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused) dprintk("svc: socket %p TCP (listen) state change %d\n", sk, sk->sk_state); - if (sk->sk_state != TCP_ESTABLISHED) { - /* Aborted connection, SYN_RECV or whatever... */ + if (sk->sk_state != TCP_LISTEN) { + /* + * This callback may called twice when a new connection + * is established as a child socket inherits everything + * from a parent LISTEN socket. + * 1) data_ready method of the parent socket will be called + * when one of child sockets become ESTABLISHED. + * 2) data_ready method of the child socket may be called + * when it receives data before the socket is accepted. + * In case of 2, we should ignore it silently. + */ goto out; } if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { @@ -1060,6 +1069,8 @@ svc_tcp_init(struct svc_sock *svsk) set_bit(SK_CHNGBUF, &svsk->sk_flags); set_bit(SK_DATA, &svsk->sk_flags); + if (sk->sk_state != TCP_ESTABLISHED) + set_bit(SK_CLOSE, &svsk->sk_flags); } } @@ -1211,7 +1222,6 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) } rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; - rqstp->rq_userset = 0; rqstp->rq_chandle.defer = svc_defer; if (serv->sv_stats) @@ -1443,7 +1453,7 @@ svc_makesock(struct svc_serv *serv, int protocol, unsigned short port) static void svc_revisit(struct cache_deferred_req *dreq, int too_many) { struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle); - struct svc_serv *serv = dr->serv; + struct svc_serv *serv = dreq->owner; struct svc_sock *svsk; if (too_many) { @@ -1481,7 +1491,7 @@ svc_defer(struct cache_req *req) if (dr == NULL) return NULL; - dr->serv = rqstp->rq_server; + dr->handle.owner = rqstp->rq_server; dr->prot = rqstp->rq_prot; dr->addr = rqstp->rq_addr; dr->argslen = rqstp->rq_arg.len >> 2; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f697a573a54..64b97aec031 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -211,15 +211,13 @@ static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) static void __unix_remove_socket(struct sock *sk) { - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); } static void __unix_insert_socket(struct hlist_head *list, struct sock *sk) { BUG_TRAP(sk_unhashed(sk)); sk_add_node(sk, list); - sock_hold(sk); } static inline void unix_remove_socket(struct sock *sk) diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 2e3c9615a1d..4f49aa6edf0 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -982,8 +982,7 @@ static int wanpipe_release(struct socket *sock) set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); @@ -1143,8 +1142,7 @@ static void wanpipe_kill_sock_timer (unsigned long data) } write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); @@ -1206,8 +1204,7 @@ static void wanpipe_kill_sock_accept (struct sock *sk) * appropriate locks */ write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(init)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); sk->sk_socket = NULL; @@ -1536,7 +1533,6 @@ static int wanpipe_create(struct socket *sock, int protocol) set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_add_node(sk, &wanpipe_sklist); - sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); @@ -2434,7 +2430,6 @@ static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_add_node(newsk, &wanpipe_sklist); - sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5a83561ab53..5d0a21917be 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -154,8 +154,7 @@ int x25_addr_aton(unsigned char *p, struct x25_address *called_addr, static void x25_remove_socket(struct sock *sk) { write_lock_bh(&x25_list_lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&x25_list_lock); } @@ -219,7 +218,6 @@ static void x25_insert_socket(struct sock *sk) { write_lock_bh(&x25_list_lock); sk_add_node(sk, &x25_list); - sock_hold(sk); write_unlock_bh(&x25_list_lock); } diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 8f8afaa113c..12286986855 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -492,7 +492,7 @@ static void conf(struct menu *menu) switch (type) { case 'm': if (single_menu_mode) - submenu->data = (void *) !submenu->data; + submenu->data = (void *) (long) !submenu->data; else conf(submenu); break; diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 10f782d8fd1..7540dc2a9bc 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2070,7 +2070,7 @@ static void snd_korg1212_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *b snd_iprintf(buffer, korg1212->card->longname); snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1); snd_iprintf(buffer, "\nGeneral settings\n"); - snd_iprintf(buffer, " period size: %d bytes\n", K1212_PERIOD_BYTES); + snd_iprintf(buffer, " period size: %Zd bytes\n", K1212_PERIOD_BYTES); snd_iprintf(buffer, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] ); snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens ); snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens ); @@ -2336,7 +2336,7 @@ static int __devinit snd_korg1212_create(snd_card_t * card, struct pci_dev *pci, korg1212->sharedBufferPhy = (unsigned long)phys_addr; if (korg1212->sharedBufferPtr == NULL) { - snd_printk(KERN_ERR "can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer)); + snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer)); return -ENOMEM; } @@ -2385,9 +2385,12 @@ static int __devinit snd_korg1212_create(snd_card_t * card, struct pci_dev *pci, korg1212->dspCodeSize = sizeof (dspCode); - korg1212->VolumeTablePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->volumeData; - korg1212->RoutingTablePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->routeData; - korg1212->AdatTimeCodePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->AdatTimeCode; + korg1212->VolumeTablePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, volumeData); + korg1212->RoutingTablePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, routeData); + korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, AdatTimeCode); korg1212->dspMemPtr = snd_malloc_pci_pages(korg1212->pci, korg1212->dspCodeSize, &phys_addr); korg1212->dspMemPhy = (u32)phys_addr; diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 6f17ea0c1fd..361dc0e7949 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -56,7 +56,7 @@ static void cpio_trailer(void) const char *name = "TRAILER!!!"; sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ 0, /* ino */ 0, /* mode */ @@ -87,7 +87,7 @@ static void cpio_mkdir(const char *name, unsigned int mode, time_t mtime = time(NULL); sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ S_IFDIR | mode, /* mode */ @@ -119,7 +119,7 @@ static void cpio_mknod(const char *name, unsigned int mode, mode |= S_IFCHR; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */ @@ -176,7 +176,7 @@ void cpio_mkfile(const char *filename, const char *location, } sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */ -- 2.11.4.GIT