From 9af6f6e4860e86507da2d470dd6a3bee34bf58c2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:27:18 -0500 Subject: [PATCH] Import 2.3.18pre1 --- CREDITS | 10 - Documentation/Configure.help | 21 +- Documentation/atm.txt | 4 + Documentation/ioctl-number.txt | 156 +- Makefile | 3 +- arch/alpha/kernel/smp.c | 2 +- arch/arm/kernel/dma-dummy.c | 3 +- arch/arm/kernel/dma.c | 2 +- arch/arm/kernel/leds-footbridge.c | 2 +- arch/arm/kernel/traps.c | 2 +- arch/arm/nwfpe/fpmodule.c | 2 +- arch/i386/defconfig | 6 + arch/i386/kernel/apm.c | 99 +- arch/i386/kernel/bios32.c | 36 +- arch/i386/kernel/traps.c | 18 +- arch/m68k/hp300/ints.c | 2 +- arch/m68k/sun3/config.c | 6 +- arch/m68k/sun3/idprom.c | 6 +- arch/m68k/sun3/prom/init.c | 2 +- arch/m68k/sun3/sbus.c | 2 +- arch/mips/jazz/io.c | 2 +- arch/mips/sni/io.c | 2 +- arch/ppc/Makefile | 4 + arch/ppc/boot/Makefile | 5 + arch/ppc/boot/head.S | 5 +- arch/ppc/config.in | 3 +- arch/{i386/defconfig => ppc/gemini_defconfig} | 269 +-- arch/ppc/kernel/Makefile | 2 +- arch/ppc/kernel/entry.S | 8 +- arch/ppc/kernel/gemini_pci.c | 9 +- arch/ppc/kernel/gemini_setup.c | 3 + arch/ppc/kernel/hashtable.S | 10 +- arch/ppc/kernel/head.S | 206 +- arch/ppc/kernel/idle.c | 8 +- arch/ppc/kernel/irq.c | 3 +- arch/ppc/kernel/misc.S | 15 - arch/ppc/kernel/pci.c | 44 +- arch/ppc/kernel/ppc_ksyms.c | 2 +- arch/ppc/kernel/prom.c | 11 +- arch/ppc/kernel/setup.c | 5 +- arch/ppc/kernel/smp.c | 33 +- arch/ppc/kernel/syscalls.c | 1 + arch/ppc/lib/locks.c | 2 +- arch/ppc/mm/init.c | 37 +- arch/sh/kernel/traps.c | 2 +- arch/sparc/kernel/irq.c | 2 +- arch/sparc/kernel/setup.c | 2 +- arch/sparc/kernel/smp.c | 2 +- arch/sparc/kernel/sparc_ksyms.c | 2 +- arch/sparc/kernel/sun4d_irq.c | 2 +- arch/sparc/kernel/sun4d_smp.c | 2 +- arch/sparc/kernel/sun4m_smp.c | 2 +- arch/sparc/lib/debuglocks.c | 2 +- arch/sparc/mm/init.c | 4 +- arch/sparc/mm/io-unit.c | 2 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc64/config.in | 5 +- arch/sparc64/defconfig | 6 + arch/sparc64/kernel/cpu.c | 4 +- arch/sparc64/kernel/ebus.c | 51 +- arch/sparc64/kernel/entry.S | 93 +- arch/sparc64/kernel/pci.c | 55 +- arch/sparc64/kernel/pci_common.c | 15 +- arch/sparc64/kernel/pci_impl.h | 12 +- arch/sparc64/kernel/pci_psycho.c | 14 +- arch/sparc64/kernel/pci_sabre.c | 15 +- arch/sparc64/kernel/power.c | 2 +- arch/sparc64/kernel/signal.c | 4 +- arch/sparc64/kernel/smp.c | 2 +- arch/sparc64/kernel/sparc64_ksyms.c | 5 +- arch/sparc64/kernel/traps.c | 120 +- arch/sparc64/kernel/ttable.S | 6 +- arch/sparc64/lib/PeeCeeI.c | 139 +- arch/sparc64/lib/debuglocks.c | 2 +- arch/sparc64/mm/init.c | 4 +- arch/sparc64/prom/misc.c | 50 +- arch/sparc64/prom/p1275.c | 8 +- arch/sparc64/solaris/timod.c | 2 +- drivers/atm/Config.in | 2 + drivers/atm/Makefile | 20 +- drivers/atm/ambassador.c | 252 +-- drivers/atm/ambassador.h | 20 +- drivers/atm/atmtcp.c | 147 +- drivers/atm/eni.c | 17 +- drivers/atm/horizon.c | 251 ++- drivers/atm/horizon.h | 13 +- drivers/atm/nicstar.c | 48 +- drivers/atm/nicstar.c.old_skb | 2883 ------------------------- drivers/atm/suni.c | 17 +- drivers/atm/zatm.c | 7 +- drivers/block/DAC960.c | 2 +- drivers/block/cpqarray.c | 2 +- drivers/block/ll_rw_blk.c | 2 +- drivers/block/paride/paride.c | 2 +- drivers/block/paride/pcd.c | 2 +- drivers/block/paride/pd.c | 2 +- drivers/block/paride/pf.c | 2 +- drivers/char/Config.in | 7 + drivers/char/Makefile | 5 + drivers/char/adbmouse.c | 16 +- drivers/char/buz.c | 2 +- drivers/char/cyclades.c | 3 +- drivers/char/drm/Makefile | 27 + drivers/char/drm/README.drm | 39 + drivers/char/drm/auth.c | 161 ++ drivers/char/drm/bufs.c | 527 +++++ drivers/char/drm/context.c | 308 +++ drivers/char/drm/dma.c | 530 +++++ drivers/char/drm/drawable.c | 50 + drivers/char/drm/drm.h | 277 +++ drivers/char/drm/drmP.h | 584 +++++ drivers/char/drm/fops.c | 204 ++ drivers/char/drm/gamma_dma.c | 802 +++++++ drivers/char/drm/gamma_drv.c | 525 +++++ drivers/char/drm/gamma_drv.h | 58 + drivers/char/drm/init.c | 99 + drivers/char/drm/ioctl.c | 91 + drivers/char/drm/lists.c | 252 +++ drivers/char/drm/lock.c | 227 ++ drivers/char/drm/memory.c | 320 +++ drivers/char/drm/proc.c | 568 +++++ drivers/char/drm/sigio.c | 82 + drivers/char/drm/vm.c | 264 +++ drivers/char/i2c-parport.c | 2 +- drivers/char/joystick/joystick.c | 2 +- drivers/char/mem.c | 4 + drivers/char/pc_keyb.c | 2 +- drivers/char/q40_keyb.c | 2 +- drivers/i2o/i2o_config.c | 2 +- drivers/i2o/i2o_core.c | 2 +- drivers/i2o/i2o_lan.c | 2 +- drivers/i2o/i2o_proc.c | 2 +- drivers/macintosh/macserial.c | 49 +- drivers/macintosh/mediabay.c | 16 +- drivers/net/3c501.c | 2 +- drivers/net/3c507.c | 2 +- drivers/net/3c509.c | 2 +- drivers/net/3c59x.c | 11 + drivers/net/8390.c | 20 +- drivers/net/Config.in | 5 + drivers/net/Makefile | 15 +- drivers/net/Space.c | 4 + drivers/net/cosa.c | 2 +- drivers/net/de4x5.c | 2 +- drivers/net/eepro.c | 2 +- drivers/net/eepro100.c | 6 +- drivers/net/eexpress.c | 2 +- drivers/net/fc/iph5526.c | 2 +- drivers/net/ibmtr.c | 2 +- drivers/net/irda/irport.c | 2 +- drivers/net/ne2k-pci.c | 25 +- drivers/net/pcmcia/Config.in | 13 + drivers/net/pcmcia/Makefile | 32 + drivers/net/pcmcia/pcnet_cs.c | 1359 ++++++++++++ drivers/net/pcmcia/ray_cs.c | 2327 ++++++++++++++++++++ drivers/net/pcmcia/ray_cs.h | 60 + drivers/net/pcmcia/rayctl.h | 725 +++++++ drivers/net/plip.c | 2 +- drivers/net/ppp_generic.c | 2 +- drivers/net/rtl8139.c | 18 +- drivers/net/starfire.c | 1431 ++++++++++++ drivers/net/sun3lance.c | 4 +- drivers/net/sunhme.c | 66 +- drivers/net/z85230.c | 2 +- drivers/parport/init.c | 6 +- drivers/parport/parport_sunbpp.c | 295 +-- drivers/parport/share.c | 2 +- drivers/pci/pci.c | 29 + drivers/pci/setup.c | 1 - drivers/pcmcia/cs.c | 12 +- drivers/pcmcia/i82365.c | 46 +- drivers/sbus/char/Config.in | 1 + drivers/sbus/char/Makefile | 8 + drivers/sbus/char/pcikbd.c | 2 +- drivers/sbus/char/rtc.c | 6 +- drivers/sbus/char/sab82532.c | 4 +- drivers/sbus/char/su.c | 4 +- drivers/sbus/char/sunserial.c | 12 +- drivers/sbus/char/uctrl.c | 155 ++ drivers/sbus/char/zs.c | 4 +- drivers/sbus/sbus.c | 8 +- drivers/scsi/53c7,8xx.c | 2 +- drivers/scsi/53c7xx.c | 2 +- drivers/scsi/AM53C974.c | 2 +- drivers/scsi/BusLogic.c | 2 +- drivers/scsi/NCR5380.c | 2 +- drivers/scsi/NCR53c406a.c | 2 +- drivers/scsi/a2091.c | 2 +- drivers/scsi/a3000.c | 2 +- drivers/scsi/advansys.c | 19 +- drivers/scsi/aha1542.c | 2 +- drivers/scsi/aic7xxx.c | 2 +- drivers/scsi/atp870u.c | 2 +- drivers/scsi/eata.c | 2 +- drivers/scsi/eata_dma.c | 2 +- drivers/scsi/eata_pio.c | 2 +- drivers/scsi/esp.c | 2 +- drivers/scsi/fd_mcs.c | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/gdth.c | 2 +- drivers/scsi/gvp11.c | 2 +- drivers/scsi/ibmmca.c | 2 +- drivers/scsi/in2000.h | 2 +- drivers/scsi/ini9100u.c | 2 +- drivers/scsi/inia100.c | 2 +- drivers/scsi/ips.c | 2 +- drivers/scsi/mac53c94.c | 2 +- drivers/scsi/megaraid.c | 2 +- drivers/scsi/mesh.c | 2 +- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/pci2000.c | 2 +- drivers/scsi/pci2220i.c | 2 +- drivers/scsi/psi240i.c | 2 +- drivers/scsi/qlogicfas.c | 2 +- drivers/scsi/qlogicfc.c | 7 +- drivers/scsi/qlogicisp.c | 2 +- drivers/scsi/qlogicpti.c | 2 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/st.c | 2 +- drivers/scsi/sym53c416.c | 2 +- drivers/scsi/sym53c8xx.c | 2 +- drivers/scsi/tmscsim.c | 4 +- drivers/scsi/u14-34f.c | 2 +- drivers/scsi/ultrastor.c | 2 +- drivers/scsi/wd7000.c | 2 +- drivers/sgi/char/ds1286.c | 2 +- drivers/sound/cmpci.c | 2 +- drivers/sound/es1370.c | 2 +- drivers/sound/es1371.c | 2 +- drivers/sound/esssolo1.c | 2 +- drivers/sound/maestro.c | 2 +- drivers/sound/msnd.c | 2 +- drivers/sound/sonicvibes.c | 2 +- drivers/sound/vwsnd.c | 2 +- drivers/usb/acm.c | 4 +- drivers/usb/cpia.c | 2 +- drivers/usb/ezusb.c | 2 +- drivers/usb/hp_scanner.c | 2 +- drivers/usb/hub.c | 2 +- drivers/usb/keyboard.c | 61 +- drivers/usb/mouse.c | 3 +- drivers/usb/ohci-hcd.c | 410 ++-- drivers/usb/ohci-hcd.h | 5 +- drivers/usb/ohci-root-hub.c | 9 +- drivers/usb/ohci.c | 2 +- drivers/usb/printer.c | 3 +- drivers/usb/uhci.c | 17 +- drivers/usb/usb.c | 2 +- drivers/usb/usb.h | 4 +- drivers/usb/usb_scsi.c | 3 +- drivers/usb/usb_scsi_debug.c | 3 +- drivers/video/Config.in | 3 + drivers/video/Makefile | 14 + drivers/video/atyfb.c | 872 +++++++- drivers/video/matroxfb.c | 2 +- drivers/video/p9100fb.c | 24 +- drivers/video/sbusfb.c | 3 +- fs/binfmt_misc.c | 2 +- fs/pipe.c | 45 +- fs/udf/file.c | 7 +- fs/udf/super.c | 2 +- fs/udf/udfend.h | 4 + include/asm-alpha/dma.h | 2 +- include/asm-alpha/hardirq.h | 2 +- include/asm-alpha/pgtable.h | 2 +- include/asm-alpha/smplock.h | 2 +- include/asm-alpha/spinlock.h | 98 - include/asm-arm/dma.h | 2 +- include/asm-arm/semaphore.h | 2 +- include/asm-arm/smplock.h | 2 +- include/asm-arm/spinlock.h | 122 +- include/asm-generic/smplock.h | 2 +- include/asm-i386/dma.h | 2 +- include/asm-i386/semaphore.h | 2 +- include/asm-i386/smplock.h | 2 +- include/asm-i386/spinlock.h | 334 +-- include/asm-m68k/semaphore.h | 2 +- include/asm-m68k/smplock.h | 2 +- include/asm-m68k/spinlock.h | 78 +- include/asm-mips/dma.h | 2 +- include/asm-mips/semaphore.h | 2 +- include/asm-mips/smplock.h | 2 +- include/asm-mips/spinlock.h | 85 +- include/asm-ppc/dma.h | 2 +- include/asm-ppc/gemini.h | 1 + include/asm-ppc/gemini_serial.h | 10 +- include/asm-ppc/init.h | 3 +- include/asm-ppc/keyboard.h | 26 +- include/asm-ppc/machdep.h | 5 +- include/asm-ppc/pci.h | 10 + include/asm-ppc/semaphore.h | 6 +- include/asm-ppc/serial.h | 129 +- include/asm-ppc/smplock.h | 2 +- include/asm-ppc/softirq.h | 16 +- include/asm-ppc/spinlock.h | 229 +- include/asm-ppc/system.h | 6 +- include/asm-sh/bugs.h | 2 +- include/asm-sh/semaphore.h | 3 +- include/asm-sh/spinlock.h | 114 +- include/asm-sparc/dma.h | 2 +- include/asm-sparc/hardirq.h | 2 +- include/asm-sparc/io-unit.h | 2 +- include/asm-sparc/mostek.h | 8 +- include/asm-sparc/pci.h | 10 + include/asm-sparc/pgtable.h | 2 +- include/asm-sparc/sigcontext.h | 31 +- include/asm-sparc/signal.h | 6 +- include/asm-sparc/smplock.h | 2 +- include/asm-sparc/spinlock.h | 53 - include/asm-sparc/system.h | 5 +- include/asm-sparc64/dma.h | 4 +- include/asm-sparc64/hardirq.h | 2 +- include/asm-sparc64/io.h | 81 +- include/asm-sparc64/iommu.h | 2 +- include/asm-sparc64/irq.h | 3 +- include/asm-sparc64/mmu_context.h | 2 +- include/asm-sparc64/oplib.h | 6 +- include/asm-sparc64/pbm.h | 2 +- include/asm-sparc64/pci.h | 44 + include/asm-sparc64/reg.h | 3 +- include/asm-sparc64/sigcontext.h | 82 +- include/asm-sparc64/signal.h | 20 +- include/asm-sparc64/smplock.h | 2 +- include/asm-sparc64/spinlock.h | 84 - include/asm-sparc64/system.h | 8 +- include/asm-sparc64/ttable.h | 9 +- include/linux/arequipa.h | 63 - include/linux/atm.h | 15 +- include/linux/atm_tcp.h | 32 +- include/linux/atmdev.h | 25 +- include/linux/blk.h | 3 +- include/linux/cyclomx.h | 2 +- include/linux/hdlcdrv.h | 2 +- include/linux/netfilter.h | 25 +- include/linux/parport.h | 4 +- include/linux/pci.h | 1 + include/linux/sched.h | 2 +- include/linux/skbuff.h | 2 +- include/linux/socket.h | 4 + include/{asm-sh => linux}/spinlock.h | 44 +- include/linux/sysctl.h | 3 +- include/linux/tqueue.h | 2 +- include/linux/wait.h | 2 +- include/net/atmclip.h | 3 +- include/net/irda/irda_device.h | 3 +- include/net/irda/irqueue.h | 2 +- include/net/irda/irttp.h | 2 +- include/net/sock.h | 5 + include/net/tcp.h | 33 +- kernel/dma.c | 2 +- kernel/resource.c | 3 +- net/Config.in | 1 - net/atm/Makefile | 9 +- net/atm/addr.c | 3 +- net/atm/atm_misc.c | 22 +- net/atm/clip.c | 21 +- net/atm/common.c | 50 +- net/atm/lec.c | 39 +- net/atm/lec.h | 2 +- net/atm/mpc.h | 4 +- net/atm/proc.c | 58 - net/atm/pvc.c | 23 +- net/atm/raw.c | 6 +- net/atm/svc.c | 4 +- net/atm/tunable.h | 7 - net/core/netfilter.c | 97 +- net/core/sock.c | 2 +- net/decnet/dn_fib.c | 2 +- net/decnet/dn_neigh.c | 2 +- net/decnet/dn_timer.c | 2 +- net/econet/econet.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv4/ip_output.c | 11 +- net/ipv4/ip_sockglue.c | 18 +- net/ipv4/sysctl_net_ipv4.c | 5 +- net/ipv4/tcp.c | 64 +- net/ipv4/tcp_input.c | 4 +- net/ipv4/tcp_ipv4.c | 4 +- net/ipv4/tcp_output.c | 8 +- net/ipv4/tcp_timer.c | 27 +- net/irda/irda_device.c | 2 +- net/sched/sch_atm.c | 2 +- net/unix/af_unix.c | 2 +- 384 files changed, 16391 insertions(+), 6091 deletions(-) copy arch/{i386/defconfig => ppc/gemini_defconfig} (58%) delete mode 100644 drivers/atm/nicstar.c.old_skb create mode 100644 drivers/char/drm/Makefile create mode 100644 drivers/char/drm/README.drm create mode 100644 drivers/char/drm/auth.c create mode 100644 drivers/char/drm/bufs.c create mode 100644 drivers/char/drm/context.c create mode 100644 drivers/char/drm/dma.c create mode 100644 drivers/char/drm/drawable.c create mode 100644 drivers/char/drm/drm.h create mode 100644 drivers/char/drm/drmP.h create mode 100644 drivers/char/drm/fops.c create mode 100644 drivers/char/drm/gamma_dma.c create mode 100644 drivers/char/drm/gamma_drv.c create mode 100644 drivers/char/drm/gamma_drv.h create mode 100644 drivers/char/drm/init.c create mode 100644 drivers/char/drm/ioctl.c create mode 100644 drivers/char/drm/lists.c create mode 100644 drivers/char/drm/lock.c create mode 100644 drivers/char/drm/memory.c create mode 100644 drivers/char/drm/proc.c create mode 100644 drivers/char/drm/sigio.c create mode 100644 drivers/char/drm/vm.c create mode 100644 drivers/net/pcmcia/Config.in create mode 100644 drivers/net/pcmcia/Makefile create mode 100644 drivers/net/pcmcia/pcnet_cs.c create mode 100644 drivers/net/pcmcia/ray_cs.c create mode 100644 drivers/net/pcmcia/ray_cs.h create mode 100644 drivers/net/pcmcia/rayctl.h create mode 100644 drivers/net/starfire.c create mode 100644 drivers/sbus/char/uctrl.c rewrite include/asm-arm/spinlock.h (98%) rewrite include/asm-i386/spinlock.h (66%) rewrite include/asm-m68k/spinlock.h (97%) rewrite include/asm-mips/spinlock.h (94%) create mode 100644 include/asm-ppc/pci.h rewrite include/asm-ppc/spinlock.h (61%) rewrite include/asm-sh/spinlock.h (97%) create mode 100644 include/asm-sparc/pci.h create mode 100644 include/asm-sparc64/pci.h delete mode 100644 include/linux/arequipa.h copy include/{asm-sh => linux}/spinlock.h (83%) diff --git a/CREDITS b/CREDITS index 820a3cc3a..dcc37e698 100644 --- a/CREDITS +++ b/CREDITS @@ -1031,16 +1031,6 @@ S: ul. Matemblewska 1B/10 S: 80-283 Gdansk S: Poland -N: Dave Jones -E: dave@powertweak.com -W: http://linux.powertweak.com -D: Centaur/IDT Winchip/Winchip 2 tweaks -D: Misc clean ups and other random hacking. -S: 40, Heol Edward Lewis, -S: Gelligaer, Hengoed, -S: Mid Glamorgan, CF82 8EJ, -S: Wales, United Kingdom - N: Bernhard Kaindl E: bkaindl@netway.at E: edv@bartelt.via.at diff --git a/Documentation/Configure.help b/Documentation/Configure.help index ec1239296..6be67e5b4 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -3578,8 +3578,8 @@ CONFIG_NETLINK_DEV Asynchronous Transfer Mode (ATM) CONFIG_ATM Kernel support for ATM. Note that you need a set of user-space programs - to actually make use of ATM. See http://lrcwww.epfl.ch/linux-atm/ for - further details. + to actually make use of ATM. See Documentation/atm.txt for further + details. Classical IP over ATM CONFIG_ATM_CLIP @@ -3609,12 +3609,6 @@ CONFIG_ATM_MPOA subnetwork boundaries. These shortcut connections bypass routers enhancing overall network performance. - -Application REQUested IP over ATM -CONFIG_AREQUIPA - Arequipa is a mechanism to create ATM connections under application - control for IP traffic. See RFC2170 for details. - ATM over TCP CONFIG_ATM_TCP ATM over TCP driver. Useful mainly for development and for experiments. @@ -11284,6 +11278,17 @@ CONFIG_VIDEO_DEV whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Direct Rendering Manager (XFree86 DRI support) +CONFIG_DRM + Kernel-level support for the Direct Rendering Infrastructure (DRI) + introduced in XFree86 4.x. These modules provide support for + synchronization, security, and DMA transfers. Select the module that + provides support for your graphics card. + +3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support) +CONFIG_DRM_GAMMA + Choose M here if you have a 3dlabs GMX 2000 graphics card. + AIMSlab RadioTrack (aka RadioReveal) support CONFIG_RADIO_RTRACK Choose Y here if you have one of these FM radio cards, and then fill diff --git a/Documentation/atm.txt b/Documentation/atm.txt index adf93bb8c..2fc1b5a60 100644 --- a/Documentation/atm.txt +++ b/Documentation/atm.txt @@ -2,3 +2,7 @@ In order to use anything but the most primitive functions of ATM, several user-mode programs are required to assist the kernel. These programs and related material can be found via the ATM on Linux Web page at http://icawww1.epfl.ch/linux-atm/ + +If you encounter problems with ATM, please report them on the ATM +on Linux mailing list. Subscription information, archives, etc., +can be found on http://icawww1.epfl.ch/linux-atm/ diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 15012b8e8..cc9e3704b 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -1,37 +1,41 @@ Ioctl Numbers -18 Feb 1998 -Michael Chastain +2 September 1999 +Michael Elizabeth Chastain If you are adding new ioctl's to the kernel, you should use the _IO macros defined in : _IO an ioctl with no parameters - _IOW an ioctl with write parameters (from user's point of view) - _IOR an ioctl with read parameters (from user's point of view) + _IOW an ioctl with write parameters (copy_from_user) + _IOR an ioctl with read parameters (copy_to_user) _IOWR an ioctl with both write and read parameters. -'Write' and 'read' are from the user's point of view. This is like the -system calls 'write' and 'read'. For example, a SET_FOO ioctl would be -_IOW, although the kernel would actually read data from user space; a -GET_FOO ioctl would be _IOR, although the kernel would actually write +'Write' and 'read' are from the user's point of view, just like the +system calls 'write' and 'read'. For example, a SET_FOO ioctl would +be _IOW, although the kernel would actually read data from user space; +a GET_FOO ioctl would be _IOR, although the kernel would actually write data to user space. The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter -or number from the table below. If you are writing a driver for a new -device and need a letter, pick an unused letter. You can register the -letter by patching this file and submitting the patch to Linus Torvalds. -Or you can e-mail me at and I'll register one for you. +or number from the table below. Because of the large number of drivers, +many drivers share a partial letter with other drivers. + +If you are writing a driver for a new device and need a letter, pick an +unused block with enough room for expansion: 32 to 256 ioctl commands. +You can register the block by patching this file and submitting the +patch to Linus Torvalds. Or you can e-mail me at and +I'll register one for you. The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number to distinguish ioctls from each other. The third argument is the size of the structure going into the kernel or coming out of the kernel. -Some devices use their major number as the identifier; this is not -recommended. Some devices are even more irregular and don't follow -the convention at all. +Some devices use their major number as the identifier; this is OK, as +long as it is unique. Some devices are irregular and don't follow any +convention at all. -Following the convention is good because: +Following this convention is good because: (1) Keeping the ioctl's globally unique helps error checking: if a program calls an ioctl on the wrong device, it will get an @@ -44,92 +48,124 @@ Following the convention is good because: numbers are unique. (4) People looking for ioctls can grep for them more easily when - the convention is used to define the ioctl numbers. + this convention is used to define the ioctl numbers. (5) When following the convention, the driver code can use generic - code to call verify_area to validate parameters. + code to copy the parameters between user and kernel space. -This table lists ioctls visible from user land for Linux/i386. It is -current to Linux 2.1.15. +This table lists ioctls visible from user land for Linux/i386. It contains +most drivers up to 2.3.14, but I know I am missing some. Code Seq# Include File Comments ======================================================== -0x00 01-02 linux/fs.h conflict! -0x00 01-04 scsi/scsi_ioctl.h conflict! +0x00 00-1F linux/fs.h conflict! +0x00 00-1F scsi/scsi_ioctl.h conflict! +0x00 00-1F linux/fb.h conflict! +0x00 00-1F linux/wavefront.h conflict! 0x02 all linux/fd.h 0x03 all linux/hdreg.h 0x04 all linux/umsdos_fs.h 0x06 all linux/lp.h 0x09 all linux/md.h 0x12 all linux/fs.h -0x20 all linux/cm206.h + linux/blkpg.h +0x20 all drivers/cdrom/cm206.h 0x22 all scsi/sg.h -'A' all linux/apm_bios.h +'1' 00-1F PPS kit from Ulrich Windl + +'8' all SNP8023 advanced NIC card + +'A' 00-1F linux/apm_bios.h +'B' C0-FF advanced bbus + 'C' all linux/soundcard.h 'F' all linux/fb.h 'I' all linux/isdn.h +'J' 00-1F drivers/scsi/gdth_ioctl.h 'K' all linux/kd.h -'L' all linux/loop.h -'M' all linux/soundcard.h +'L' 00-1F linux/loop.h +'L' E0-FF linux/ppdd.h encrypted disk device driver + +'M' all linux/soundcard.h conflict! +'M' 00-1F linux/isicom.h conflict! 'P' all linux/soundcard.h 'Q' all linux/soundcard.h -'R' all linux/random.h -'S' 00-7F linux/cdrom.h -'S' 80-81 scsi/scsi_ioctl.h -'S' 82-FF scsi/scsi.h +'R' 00-1F linux/random.h +'S' all linux/cdrom.h conflict! +'S' 80-81 scsi/scsi_ioctl.h conflict! +'S' 82-FF scsi/scsi.h conflict! 'T' all linux/soundcard.h conflict! 'T' all asm-i386/ioctls.h conflict! -'U' all linux/drivers/usb/usb.h +'U' all linux/drivers/usb/usb.h 'V' all linux/vt.h -'W' 00-1F linux/router.h conflict [Please reallocate] -'W' 00-1F linux/watchdog.h -'W' 20-27 linux/octal-relay.h in development -'W' 28-2F linux/iso16-relay.h in development +'W' 00-1F linux/watchdog.h conflict! +'W' 00-1F linux/wanrouter.h conflict! 'Y' all linux/cyclades.h -'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html -'b' 00-FF bit3 vme host bridge in development: +'a' all ATM on linux + +'b' 00-FF bit3 vme host bridge -'c' all linux/comstats.h -'f' all linux/ext2_fs.h +'c' 00-7F linux/comstats.h conflict! +'c' 00-7F linux/coda.h conflict! +'d' 00-1F linux/devfs_fs.h conflict! +'d' 00-DF linux/video_decoder.h conflict! +'d' F0-FF linux/digi1.h +'e' all linux/digi1.h conflict! +'e' 00-1F linux/video_encoder.h conflict! +'e' 00-1F net/irda/irtty.h conflict! +'f' 00-1F linux/ext2_fs.h +'i' 00-3F linux/i2o.h 'j' 00-3F linux/joystick.h -'k' all asm-sparc/kbio.h, asm-sparc64/kbio.h -'l' 00-3F linux/tcfs_fs.h in development: +'k' all asm-sparc/kbio.h + asm-sparc64/kbio.h +'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system 'm' all linux/mtio.h conflict! 'm' all linux/soundcard.h conflict! +'m' all linux/synclink.h conflict! +'m' 00-1F net/irda/irmod.h conflict! 'n' all linux/ncp_fs.h 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h -'p' 80-9F user-space parport in development: - -'r' all linux/msdos_fs.h +'p' 80-9F user-space parport + +'q' 00-1F linux/videotext.h conflict! +'q' 80-FF Internet PhoneJACK, Internet LineJACK + +'r' 00-1F linux/msdos_fs.h 's' all linux/cdk.h 't' 00-7F linux/if_ppp.h 't' 80-8F linux/isdn_ppp.h -'u' all linux/smb_fs.h -'v' all linux/ext2_fs.h -'w' all CERN SCI driver in development -'z' 00-3F CAN bus card in development: +'u' 00-1F linux/smb_fs.h +'v' 00-1F linux/ext2_fs.h conflict! +'v' all linux/videodev.h conflict! +'w' all CERN SCI driver +'z' 00-3F CAN bus card -'z' 40-7F CAN bas card in development: +'z' 40-7F CAN bus card -0x89 00-0F asm-i386/sockios.h -0x89 10-DF linux/sockios.h +0x80 00-1F linux/fb.h +0x89 00-06 asm-i386/sockios.h +0x89 0B-DF linux/sockios.h 0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range 0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range 0x8B all linux/wireless.h -0x8C 00-3F WiNRADiO driver in development: +0x8C 00-3F WiNRADiO driver -0x90 00 linux/sbpcd.h +0x90 00 drivers/cdrom/sbpcd.h 0x93 60-7F linux/auto_fs.h -0x99 00-0F 537-Addinboard driver in development: - -0xA0 all Small Device Project in development: - +0x99 00-0F 537-Addinboard driver + +0xA0 all linux/sdp/sdp.h Industrial Device Project + +0xA3 00-1F Philips SAA7146 dirver in development: + 0xA3 80-8F Port ACL in development: -0xA3 90-9F DoubleTalk driver in development: - -0xAB 00-06 Network block device +0xA3 90-9F linux/dtlk.h +0xAB 00-1F linux/nbd.h +0xAC 00-1F linux/raw.h 0xAD 00 Netfilter device in development: +0xB0 all RATIO devices in development: + diff --git a/Makefile b/Makefile index 0a0975bb5..73f09a186 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 17 +SUBLEVEL = 18 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -148,6 +148,7 @@ endif ifdef CONFIG_PCMCIA DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o +DRIVERS := $(DRIVERS) drivers/net/pcmcia/pcmcia_net.o endif ifdef CONFIG_DIO diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index fd4e5466b..e35dd7c7e 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm/kernel/dma-dummy.c b/arch/arm/kernel/dma-dummy.c index 404fc49d3..7efc85363 100644 --- a/arch/arm/kernel/dma-dummy.c +++ b/arch/arm/kernel/dma-dummy.c @@ -8,8 +8,7 @@ */ #include #include - -#include +#include spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 5e6c57aba..7d1a11cd5 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -19,13 +19,13 @@ #include #include #include +#include #include #include #include #include #include -#include /* A note on resource allocation: diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c index 54b6723bd..6b4cb001b 100644 --- a/arch/arm/kernel/leds-footbridge.c +++ b/arch/arm/kernel/leds-footbridge.c @@ -21,10 +21,10 @@ #include #include #include +#include #include #include -#include #include #define LED_STATE_ENABLED 1 diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index f5bb5ee56..9f9e6934f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -16,11 +16,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c index a8857664e..de28e39f5 100644 --- a/arch/arm/nwfpe/fpmodule.c +++ b/arch/arm/nwfpe/fpmodule.c @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include -#include #include #include /* XXX */ diff --git a/arch/i386/defconfig b/arch/i386/defconfig index e3af88fd9..50b12d5f9 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -257,6 +257,7 @@ CONFIG_EEXPRESS_PRO100=y # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set # CONFIG_PPP is not set @@ -281,6 +282,11 @@ CONFIG_EEXPRESS_PRO100=y # CONFIG_X25_ASY is not set # +# PCMCIA network devices +# +CONFIG_PCMCIA_RAYCS=m + +# # Amateur Radio support # # CONFIG_HAMRADIO is not set diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index a79778989..3bafdfcfc 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -983,40 +983,27 @@ static void check_events(void) } } -/* - * This is the APM thread main loop. - */ -static void apm_mainloop(void) +static void apm_event_handler(void) { - DECLARE_WAITQUEUE(wait, current); - apm_enabled = 1; + static int pending_count = 0; - add_wait_queue(&apm_waitqueue, &wait); - for (;;) { - static int pending_count = 0; + if (((standbys_pending > 0) || (suspends_pending > 0)) + && (apm_bios_info.version > 0x100) + && (pending_count-- <= 0)) { int err; + pending_count = 4; - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(APM_CHECK_TIMEOUT); - - if (((standbys_pending > 0) || (suspends_pending > 0)) - && (apm_bios_info.version > 0x100) - && (pending_count-- <= 0)) { - pending_count = 4; - - err = apm_set_power_state(APM_STATE_BUSY); - if (err) - apm_error("busy", err); - } - - if (!(((standbys_pending > 0) || (suspends_pending > 0)) - && (apm_bios_info.version == 0x100))) - check_events(); + err = apm_set_power_state(APM_STATE_BUSY); + if (err) + apm_error("busy", err); } + + if (!(((standbys_pending > 0) || (suspends_pending > 0)) + && (apm_bios_info.version == 0x100))) + check_events(); } -/* Called from cpu_idle, must make sure apm_enabled. */ -int apm_do_idle(void) +static int apm_do_idle(void) { #ifdef CONFIG_APM_CPU_IDLE u32 dummy; @@ -1027,30 +1014,74 @@ int apm_do_idle(void) if (apm_bios_call_simple(0x5305, 0, 0, &dummy)) return 0; +#ifdef ALWAYS_CALL_BUSY + clock_slowed = 1; +#else clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0; +#endif return 1; #else return 0; #endif } -/* Called from cpu_idle, must make sure apm_enabled. */ -void apm_do_busy(void) +static void apm_do_busy(void) { #ifdef CONFIG_APM_CPU_IDLE u32 dummy; - if (apm_enabled -#ifndef ALWAYS_CALL_BUSY - && clock_slowed -#endif - ) { + if (clock_slowed) { (void) apm_bios_call_simple(0x5306, 0, 0, &dummy); clock_slowed = 0; } #endif } +/* + * This is the APM thread main loop. + * + * Check whether we're the only running process to + * decide if we should just power down. + * + * Do this by checking the runqueue: if we're the + * only one, then the current process run_list will + * have both prev and next pointing to the same + * entry (the true idle process) + */ +#define system_idle() (current->run_list.next == current->run_list.prev) + +static void apm_mainloop(void) +{ + DECLARE_WAITQUEUE(wait, current); + apm_enabled = 1; + + add_wait_queue(&apm_waitqueue, &wait); + current->state = TASK_INTERRUPTIBLE; + for (;;) { + /* Nothing to do, just sleep for the timeout */ + schedule_timeout(APM_CHECK_TIMEOUT); + + /* + * Ok, check all events, check for idle (and mark us sleeping + * so as not to count towards the load average).. + */ + current->state = TASK_INTERRUPTIBLE; + apm_event_handler(); + if (!system_idle()) + continue; + if (apm_do_idle()) { + unsigned long start = jiffies; + do { + apm_do_idle(); + if (jiffies - start > APM_CHECK_TIMEOUT) + break; + } while (system_idle()); + apm_do_busy(); + apm_event_handler(); + } + } +} + static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index e8e2ca6a3..f0c63c938 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -88,13 +88,13 @@ #include #include #include +#include #include #include #include #include #include -#include #undef DEBUG @@ -760,36 +760,6 @@ static void __init pcibios_sort(void) #endif /* - * Assign new address to PCI resource. We hope our resource information - * is complete. On the PC, we don't re-assign resources unless we are - * forced to do so. - * - * Expects start=0, end=size-1, flags=resource type. - */ - -int __init pcibios_assign_resource(struct pci_dev *dev, int i) -{ - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; - - if (!pr) - return -EINVAL; - if (r->flags & IORESOURCE_IO) { - if (size > 0x100) - return -EFBIG; - if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) - return -EBUSY; - } else { - if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) - return -EBUSY; - } - if (i < 6) - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start); - return 0; -} - -/* * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it. */ @@ -824,7 +794,7 @@ static void __init pcibios_fixup_io_addr(struct pci_dev *dev, int idx) r->start = 0; r->end = size - 1; - if (pcibios_assign_resource(dev, idx)) { + if (pci_assign_resource(dev, idx)) { printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name); return; } @@ -852,7 +822,7 @@ static void __init pcibios_fixup_rom_addr(struct pci_dev *dev) r->start = 0; r->end = rom_size - 1; - if (pcibios_assign_resource(dev, PCI_ROM_RESOURCE)) + if (pci_assign_resource(dev, PCI_ROM_RESOURCE)) printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n", dev->name, rom_size); else { diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index b6b13f3bd..f3e6f75aa 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef CONFIG_MCA #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -357,11 +357,17 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) unsigned int condition; struct task_struct *tsk = current; + __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + + /* Mask out spurious debug traps due to lazy DR7 setting */ + if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { + if (!tsk->thread.debugreg[7]) + goto clear_dr7; + } + if (regs->eflags & VM_MASK) goto debug_vm86; - __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); - /* Mask out spurious TF errors due to lazy TF clearing */ if (condition & DR_STEP) { /* @@ -377,12 +383,6 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) goto clear_TF; } - /* Mask out spurious debug traps due to lazy DR7 setting */ - if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { - if (!tsk->thread.debugreg[7]) - goto clear_dr7; - } - /* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */ if ((regs->xcs & 3) == 0) goto clear_dr7; diff --git a/arch/m68k/hp300/ints.c b/arch/m68k/hp300/ints.c index 4eebf9584..497400575 100644 --- a/arch/m68k/hp300/ints.c +++ b/arch/m68k/hp300/ints.c @@ -15,13 +15,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include "ints.h" /* Each ipl has a linked list of interrupt service routines. diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index d9477f205..05fbdea8d 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -57,7 +57,7 @@ extern unsigned long sun_serial_setup(unsigned long memory_start); volatile char* clock_va; extern unsigned char* sun3_intreg; -__initfunc(void sun3_init(void)) +void __init sun3_init(void) { unsigned char enable_register; int i; @@ -106,7 +106,7 @@ static void sun3_reboot (void) prom_reboot ("vmlinux"); } -__initfunc(void config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p)) +void __init config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p) { printk("ARCH: SUN3\n"); idprom_init(); @@ -141,7 +141,7 @@ __initfunc(void config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p *start_mem_p = sun_serial_setup(*start_mem_p); } -__initfunc(void sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +void __init sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { sun3_disable_interrupts(); intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE); diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c index d71a6acd4..3b2c99d45 100644 --- a/arch/m68k/sun3/idprom.c +++ b/arch/m68k/sun3/idprom.c @@ -54,7 +54,7 @@ struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { //{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } }; -__initfunc(static void display_system_type(unsigned char machtype)) +static void __init display_system_type(unsigned char machtype) { register int i; @@ -92,7 +92,7 @@ void sun3_get_model(unsigned char* model) /* Calculate the IDPROM checksum (xor of the data bytes). */ -__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) +static unsigned char __init calc_idprom_cksum(struct idprom *idprom) { unsigned char cksum, i, *ptr = (unsigned char *)idprom; @@ -103,7 +103,7 @@ __initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) } /* Create a local IDPROM copy, verify integrity, and display information. */ -__initfunc(void idprom_init(void)) +void __init idprom_init(void) { prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer)); diff --git a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c index 3cc6c3c55..3922eff55 100644 --- a/arch/m68k/sun3/prom/init.c +++ b/arch/m68k/sun3/prom/init.c @@ -30,7 +30,7 @@ struct linux_nodeops *prom_nodeops; extern void prom_meminit(void); extern void prom_ranges_init(void); -__initfunc(void prom_init(struct linux_romvec *rp)) +void __init prom_init(struct linux_romvec *rp) { #if CONFIG_AP1000 extern struct linux_romvec *ap_prom_init(void); diff --git a/arch/m68k/sun3/sbus.c b/arch/m68k/sun3/sbus.c index d1960642c..ae2d99e2c 100644 --- a/arch/m68k/sun3/sbus.c +++ b/arch/m68k/sun3/sbus.c @@ -12,7 +12,7 @@ #include #include -__initfunc(void sbus_init(void)) +void __init sbus_init(void) { } diff --git a/arch/mips/jazz/io.c b/arch/mips/jazz/io.c index a151b99fe..ae0c8483b 100644 --- a/arch/mips/jazz/io.c +++ b/arch/mips/jazz/io.c @@ -8,10 +8,10 @@ * Copyright (C) 1997 by Ralf Baechle. */ #include +#include #include #include #include -#include #include /* diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c index 1e14ebfcc..1b57e9bc4 100644 --- a/arch/mips/sni/io.c +++ b/arch/mips/sni/io.c @@ -7,10 +7,10 @@ * Low level I/O functions for SNI. */ #include +#include #include #include #include -#include #include /* diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index ec00baa58..9977db204 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -106,6 +106,10 @@ endif @$(MAKECHRPBOOT) $@ endif +gemini_config: + rm -f .config arch/ppc/defconfig + ln -s gemini_defconfig arch/ppc/defconfig + pmac_config: rm -f .config arch/ppc/defconfig ln -s pmac_defconfig arch/ppc/defconfig diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index ca39c7ee0..9e637aa7b 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -75,7 +75,10 @@ zImage: zvmlinux mkprep sImage ./mkprep -pbp zvmlinux zImage sImage: ../../../vmlinux +ifdef CONFIG_GEMINI $(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage +else +endif zImage.initrd: zvmlinux.initrd mkprep ./mkprep -pbp zvmlinux.initrd zImage.initrd @@ -108,7 +111,9 @@ mkprep : mkprep.c znetboot : zImage cp zImage $(TFTPIMAGE) +ifdef CONFIG_GEMINI cp sImage /tftpboot/ +endif znetboot.initrd : zImage.initrd cp zImage.initrd $(TFTPIMAGE) diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S index 59e6f2f26..79377a2ac 100644 --- a/arch/ppc/boot/head.S +++ b/arch/ppc/boot/head.S @@ -6,7 +6,7 @@ .text /* - * $Id: head.S,v 1.32 1999/08/12 19:51:12 cort Exp $ + * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $ * * Boot loader philosophy: * ROM loads us to some arbitrary location @@ -125,10 +125,11 @@ start_ldr: * get start address of kernel code which is stored as a coff * entry. see boot/head.S -- Cort */ - li r9,0x0 + li r9,0x4 mtlr r9 lis r10,0xdeadc0de@h ori r10,r10,0xdeadc0de@l + li r9,0 stw r10,0(r9) /* * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2 diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 871e7e470..5d2d2165a 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.102 1999/08/30 10:06:53 davem Exp $ +# $Id: config.in,v 1.103 1999/09/01 19:04:44 cort Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -17,6 +17,7 @@ choice 'Machine Type' \ PReP/MTX CONFIG_PREP \ CHRP CONFIG_CHRP \ PowerMac/PReP/CHRP CONFIG_ALL_PPC \ + Gemini CONFIG_GEMINI \ APUS CONFIG_APUS \ MBX CONFIG_MBX" PowerMac diff --git a/arch/i386/defconfig b/arch/ppc/gemini_defconfig similarity index 58% copy from arch/i386/defconfig copy to arch/ppc/gemini_defconfig index e3af88fd9..f0f5dc3f6 100644 --- a/arch/i386/defconfig +++ b/arch/ppc/gemini_defconfig @@ -1,121 +1,65 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # -CONFIG_X86=y -CONFIG_ISA=y # -# Code maturity level options +# Platform support # -# CONFIG_EXPERIMENTAL is not set - -# -# Processor type and features -# -# CONFIG_M386 is not set -# CONFIG_M486 is not set -# CONFIG_M586 is not set -# CONFIG_M586TSC is not set -CONFIG_M686=y -CONFIG_X86_WP_WORKS_OK=y -CONFIG_X86_INVLPG=y -CONFIG_X86_BSWAP=y -CONFIG_X86_POPAD_OK=y -CONFIG_X86_TSC=y -CONFIG_X86_GOOD_APIC=y -CONFIG_1GB=y -# CONFIG_2GB is not set -# CONFIG_MATH_EMULATION is not set -# CONFIG_MTRR is not set -CONFIG_SMP=y - -# -# Loadable module support -# -CONFIG_MODULES=y -# CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_PPC=y +CONFIG_6xx=y +# CONFIG_PPC64 is not set +# CONFIG_8xx is not set +# CONFIG_PMAC is not set +# CONFIG_PREP is not set +# CONFIG_CHRP is not set +# CONFIG_ALL_PPC is not set +CONFIG_GEMINI=y +# CONFIG_APUS is not set +# CONFIG_MBX is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_6xx=y # # General setup # -# CONFIG_BIGMEM is not set -CONFIG_NET=y +CONFIG_EXPERIMENTAL=y +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y CONFIG_PCI=y -# CONFIG_PCI_GOBIOS is not set -# CONFIG_PCI_GODIRECT is not set -CONFIG_PCI_GOANY=y -CONFIG_PCI_BIOS=y -CONFIG_PCI_DIRECT=y -# CONFIG_MCA is not set -# CONFIG_VISWS is not set -CONFIG_X86_IO_APIC=y -CONFIG_X86_LOCAL_APIC=y - -# -# PCMCIA/Cardbus support -# -CONFIG_PCMCIA=y -CONFIG_CARDBUS=y +CONFIG_NET=y +CONFIG_SYSCTL=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set # CONFIG_PARPORT is not set -# CONFIG_APM is not set - -# -# I2O device support -# -# CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_FB is not set +# CONFIG_PMAC_PBOOK is not set +CONFIG_MAC_KEYBOARD=y +# CONFIG_MAC_FLOPPY is not set +# CONFIG_MAC_SERIAL is not set +# CONFIG_PROC_DEVICETREE is not set +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set +# CONFIG_MOTOROLA_HOTSWAP is not set # # Plug and Play configuration # -CONFIG_PNP=y -CONFIG_ISAPNP=y +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # -CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_IDECD_SLOTS is not set -# CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set -CONFIG_BLK_DEV_CMD640=y -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -CONFIG_BLK_DEV_RZ1000=y -CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_BLK_DEV_IDEDMA_PCI is not set -# CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_AEC6210 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_BLK_DEV_HPT366 is not set -CONFIG_BLK_DEV_PIIX=y -# CONFIG_BLK_DEV_SIS5513 is not set -# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set +# CONFIG_BLK_DEV_HD_ONLY is not set # CONFIG_BLK_CPQ_DA is not set - -# -# Additional Block Devices -# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -123,7 +67,7 @@ CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_XD is not set CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set -CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set # @@ -131,48 +75,53 @@ CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set -# CONFIG_SYN_COOKIES is not set - -# -# (it is safe to leave these untouched) -# +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y +CONFIG_SYN_COOKIES=y CONFIG_SKB_LARGE=y - -# -# -# +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set # -# SCSI support +# QoS and/or fair queueing # -CONFIG_SCSI=y +# CONFIG_NET_SCHED is not set # -# SCSI support type (disk, tape, CD-ROM) +# SCSI support # +CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set -# CONFIG_BLK_DEV_SR is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -205,12 +154,13 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set +# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set @@ -223,6 +173,9 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_MESH is not set +# CONFIG_SCSI_MAC53C94 is not set # # Network device support @@ -233,32 +186,17 @@ CONFIG_NETDEVICES=y # ARCnet devices # # CONFIG_ARCNET is not set -CONFIG_DUMMY=m +# CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set # # Ethernet (10 or 100Mbit) # -CONFIG_NET_ETHERNET=y -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -# CONFIG_PCNET32 is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set -# CONFIG_DEC_ELCP is not set -# CONFIG_DGRS is not set -CONFIG_EEXPRESS_PRO100=y -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_NET_POCKET is not set +# CONFIG_NET_ETHERNET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set @@ -268,6 +206,8 @@ CONFIG_EEXPRESS_PRO100=y # # CONFIG_TR is not set # CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set # # Wan interfaces @@ -276,9 +216,6 @@ CONFIG_EEXPRESS_PRO100=y # CONFIG_COSA is not set # CONFIG_SEALEVEL_4021 is not set # CONFIG_DLCI is not set -# CONFIG_WAN_DRIVERS is not set -# CONFIG_LAPBETHER is not set -# CONFIG_X25_ASY is not set # # Amateur Radio support @@ -286,11 +223,6 @@ CONFIG_EEXPRESS_PRO100=y # CONFIG_HAMRADIO is not set # -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # ISDN subsystem # # CONFIG_ISDN is not set @@ -301,12 +233,17 @@ CONFIG_EEXPRESS_PRO100=y # CONFIG_CD_NO_IDESCSI is not set # +# Console drivers +# + +# # Character devices # CONFIG_VT=y CONFIG_VT_CONSOLE=y +CONFIG_PC_KEYB=y CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set +CONFIG_SERIAL_CONSOLE=y # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y @@ -315,14 +252,18 @@ CONFIG_UNIX98_PTY_COUNT=256 # # Mice # -# CONFIG_BUSMOUSE is not set +CONFIG_BUSMOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_LOGIBUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y -CONFIG_82C710_MOUSE=y +# CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set # CONFIG_QIC02_TAPE is not set # CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set +CONFIG_NVRAM=y # CONFIG_RTC is not set # @@ -349,28 +290,26 @@ CONFIG_82C710_MOUSE=y # CONFIG_USB is not set # -# Misc devices -# - -# # Filesystems # # CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set @@ -380,11 +319,10 @@ CONFIG_EXT2_FS=y # Network File Systems # # CONFIG_CODA_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set @@ -392,6 +330,7 @@ CONFIG_LOCKD=y # Partition Types # # CONFIG_PARTITION_ADVANCED is not set +CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y # CONFIG_BSD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set @@ -401,12 +340,6 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS is not set # -# Console drivers -# -CONFIG_VGA_CONSOLE=y -# CONFIG_VIDEO_SELECT is not set - -# # Sound # # CONFIG_SOUND is not set @@ -414,4 +347,6 @@ CONFIG_VGA_CONSOLE=y # # Kernel hacking # -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 8eadd7b19..a177a3642 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -69,7 +69,7 @@ find_name : find_name.c $(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c checks: checks.c - $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c + $(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 17e1eac6d..abff78bc3 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/entry.S * - * $Id: entry.S,v 1.2 1999/08/23 02:53:16 paulus Exp $ + * $Id: entry.S,v 1.3 1999/09/05 11:56:26 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -291,14 +291,12 @@ ret_from_syscall: .globl ret_from_except ret_from_except: 0: mfmsr r30 /* Disable interrupts */ - li r3,0 - ori r3,r3,MSR_EE - andc r30,r30,r3 + rlwinm r30,r30,0,17,15 /* clear MSR_EE */ SYNC /* Some chip revs need this... */ mtmsr r30 SYNC lwz r5,_MSR(r1) - and. r5,r5,r4 + andi. r5,r5,MSR_EE beq 2f 3: lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) diff --git a/arch/ppc/kernel/gemini_pci.c b/arch/ppc/kernel/gemini_pci.c index 60d6523c2..89ed43501 100644 --- a/arch/ppc/kernel/gemini_pci.c +++ b/arch/ppc/kernel/gemini_pci.c @@ -152,7 +152,7 @@ static unsigned int mem_base = FIRST_MEM_ADDR; -static __init void layout_dev( struct pci_dev *dev ) +__init void layout_dev( struct pci_dev *dev ) { int i; struct pci_bus *bus; @@ -225,7 +225,7 @@ static __init void layout_dev( struct pci_dev *dev ) (cmd|PCI_COMMAND_MASTER)); } -static __init void layout_bus( struct pci_bus *bus ) +__init void layout_bus( struct pci_bus *bus ) { struct pci_dev *dev; @@ -246,13 +246,10 @@ void __init gemini_pcibios_fixup(void) { struct pci_bus *bus; unsigned long orig_mem_base, orig_io_base; - + orig_mem_base = pci_mem_base; orig_io_base = pci_io_base; - for( bus = &pci_root; bus; bus = bus->children ) - layout_bus( bus ); - pci_mem_base = orig_mem_base; pci_io_base = orig_io_base; } diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c index 0f0222a6b..4af02958a 100644 --- a/arch/ppc/kernel/gemini_setup.c +++ b/arch/ppc/kernel/gemini_setup.c @@ -480,6 +480,8 @@ void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { void chrp_do_IRQ(struct pt_regs *, int, int); + void layout_bus( struct pci_bus * ); + gemini_setup_pci_ptrs(); ISA_DMA_THRESHOLD = 0; @@ -521,4 +523,5 @@ void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, #ifdef CONFIG_MAGIC_SYSRQ ppc_md.ppc_kbd_sysrq_xlate = NULL; #endif + ppc_md.pcibios_fixup_bus = layout_bus; } diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S index 8c02d02b5..74f00ce10 100644 --- a/arch/ppc/kernel/hashtable.S +++ b/arch/ppc/kernel/hashtable.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/hashtable.S * - * $Id: hashtable.S,v 1.2 1999/08/23 02:53:17 paulus Exp $ + * $Id: hashtable.S,v 1.3 1999/09/05 11:56:27 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -318,11 +318,14 @@ hash_page_out: eieio blr + .data .globl hash_table_lock hash_table_lock: .long 0 -#endif + .text +#endif /* __SMP__ */ +/* next_slot is assumed to be within the first 32kB of physical RAM */ next_slot: .long 0 @@ -467,9 +470,8 @@ _GLOBAL(flush_hash_page) #ifdef __SMP__ tlbsync sync - lis r3,hash_table_lock@h li r0,0 - stw r0,hash_table_lock@l(r3) + stw r0,0(r9) /* clear hash_table_lock */ mtmsr r10 SYNC #endif diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 84db06916..9a0ee6346 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.142 1999/08/23 02:53:18 paulus Exp $ + * $Id: head.S,v 1.143 1999/09/05 11:56:28 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -143,6 +143,7 @@ __start: mr r27,r7 li r24,0 /* cpu # */ bl prom_init + #ifdef CONFIG_APUS /* On APUS the __va/__pa constants need to be set to the correct * values before continuing. @@ -150,15 +151,14 @@ __start: mr r4,r30 bl fix_mem_constants #endif - .globl __secondary_start -__secondary_start: + /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely * call OF any more. */ lis r11,KERNELBASE@h -#ifndef CONFIG_PPC64 +#ifndef CONFIG_PPC64xxx mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpi 0,r9,1 @@ -189,8 +189,15 @@ __secondary_start: * allow secondary cpus to get at all of ram in early bootup * since their init_task may be up there -- Cort */ +#if 0 oris r18,r8,0x10000000@h oris r21,r11,(KERNELBASE+0x10000000)@h +#else + lis r18,0x9000 + ori r18,r18,0x12 + lis r21,0x9000 + ori r21,r21,0x7fe +#endif mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ mtspr DBAT1U,r21 /* bit in upper BAT register */ mtspr IBAT1L,r18 @@ -330,7 +337,7 @@ label: \ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge) #else STD_EXCEPTION(0x100, Reset, UnknownException) -#endif +#endif /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) @@ -982,11 +989,6 @@ fix_mem_constants: #endif #ifdef CONFIG_SMP - .globl __secondary_start_psurge -__secondary_start_psurge: - li r24,1 /* cpu # */ - b __secondary_start - .globl __secondary_hold __secondary_hold: /* tell the master we're here */ @@ -1008,15 +1010,59 @@ __secondary_hold: mtlr r5 mr r24,r3 /* cpu # */ blr + + .globl __secondary_start_psurge +__secondary_start_psurge: + li r24,1 /* cpu # */ + /* we come in here with IR=0 and DR=1, and DBAT 0 + set to map the 0xf0000000 - 0xffffffff region */ + mfmsr r0 + rlwinm r0,r0,0,28,26 /* clear DR (0x10) */ + sync + mtmsr r0 + isync + + .globl __secondary_start +__secondary_start: + bl enable_caches + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + tophys(r2,r2) + slwi r24,r24,2 /* get current_set[cpu#] */ + lwzx r2,r2,r24 + + /* stack */ + addi r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD + li r0,0 + tophys(r3,r1) + stw r0,0(r3) + + /* load up the MMU */ + bl load_up_mmu + + /* ptr to phys current thread */ + tophys(r4,r2) + addi r4,r4,THREAD /* phys address of our thread_struct */ + mtspr SPRG3,r4 + li r3,0 + mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ + + /* enable MMU and jump to start_secondary */ + li r4,MSR_KERNEL + lis r3,start_secondary@h + ori r3,r3,start_secondary@l + mtspr SRR0,r3 + mtspr SRR1,r4 + rfi + #endif /* CONFIG_SMP */ - + /* - * This is where the main kernel code starts. + * Enable caches and 604-specific features if necessary. */ -start_here: - /* - * Enable caches and 604-specific features if necessary. - */ +enable_caches: mfspr r9,PVR rlwinm r9,r9,16,16,31 cmpi 0,r9,1 @@ -1044,25 +1090,57 @@ start_here: bne 2,5f ori r11,r11,HID0_BTCD 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ -4: -#ifdef __SMP__ - /* if we're the second cpu stack and r2 are different - * and we want to not clear the bss -- Cort */ - lis r5,first_cpu_booted@h - ori r5,r5,first_cpu_booted@l - lwz r5,0(r5) - cmpi 0,r5,0 - beq 99f +4: blr + +/* + * Load stuff into the MMU. Intended to be called with + * IR=0 and DR=0. + */ +load_up_mmu: + /* Load the SDR1 register (hash table base & size) */ + lis r6,_SDR1@ha + tophys(r6,r6) +#ifdef CONFIG_PPC64 + ld r6,_SDR1@l(r6) + mtspr SDR1,r6 + /* clear the v bit in the ASR so we can + * behave as if we have segment registers + * -- Cort + */ + clrldi r6,r6,63 + mtasr r6 +#else + lwz r6,_SDR1@l(r6) + mtspr SDR1,r6 +#endif /* CONFIG_PPC64 */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,1 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b +/* Load the BAT registers with the values set up by MMU_init. + MMU_init takes care of whether we're on a 601 or not. */ + mfpvr r3 + srwi r3,r3,16 + cmpwi r3,1 + lis r3,BATS@ha + addi r3,r3,BATS@l + tophys(r3,r3) + LOAD_BAT(0,r3,r4,r5) + LOAD_BAT(1,r3,r4,r5) + LOAD_BAT(2,r3,r4,r5) + LOAD_BAT(3,r3,r4,r5) + blr + +/* + * This is where the main kernel code starts. + */ +start_here: + bl enable_caches - /* get current */ - lis r2,current_set@h - ori r2,r2,current_set@l - slwi r24,r24,2 /* cpu # to current_set[cpu#] */ - add r2,r2,r24 - lwz r2,0(r2) - b 10f -99: -#endif /* __SMP__ */ /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l @@ -1081,9 +1159,6 @@ start_here: 3: stwu r0,4(r8) bdnz 3b 2: -#ifdef __SMP__ -10: -#endif /* __SMP__ */ /* stack */ addi r1,r2,TASK_UNION_SIZE li r0,0 @@ -1104,12 +1179,6 @@ start_here: * for SDR1 (hash table pointer) and the segment registers * and change to using our exception vectors. */ - lis r6,_SDR1@ha -#ifdef CONFIG_PPC64 - ld r6,_SDR1@l(r6) -#else - lwz r6,_SDR1@l(r6) -#endif lis r4,2f@h ori r4,r4,2f@l tophys(r4,r4) @@ -1126,42 +1195,7 @@ start_here: tlbsync /* ... on all CPUs */ sync #endif - mtspr SDR1,r6 -#ifdef CONFIG_PPC64 - /* clear the v bit in the ASR so we can - * behave as if we have segment registers - * -- Cort - */ - clrldi r6,r6,63 - mtasr r6 -#endif /* CONFIG_PPC64 */ - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,1 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b -/* Load the BAT registers with the values set up by MMU_init. - MMU_init takes care of whether we're on a 601 or not. */ - mfpvr r3 - srwi r3,r3,16 - cmpwi r3,1 - lis r3,BATS@ha - addi r3,r3,BATS@l - tophys(r3,r3) -#ifdef CONFIG_PPC64 - LOAD_BAT(0,r3,r4,r5) - LOAD_BAT(1,r3,r4,r5) - LOAD_BAT(2,r3,r4,r5) - LOAD_BAT(3,r3,r4,r5) -#else /* CONFIG_PPC64 */ - LOAD_BAT(0,r3,r4,r5) - LOAD_BAT(1,r3,r4,r5) - LOAD_BAT(2,r3,r4,r5) - LOAD_BAT(3,r3,r4,r5) -#endif /* CONFIG_PPC64 */ + bl load_up_mmu /* Set up for using our exception vectors */ /* ptr to phys current thread */ @@ -1174,20 +1208,6 @@ start_here: li r4,MSR_KERNEL lis r3,start_kernel@h ori r3,r3,start_kernel@l -#ifdef __SMP__ - /* the second time through here we go to - * start_secondary(). -- Cort - */ - lis r5,first_cpu_booted@h - ori r5,r5,first_cpu_booted@l - tophys(r5,r5) - lwz r5,0(r5) - cmpi 0,r5,0 - beq 10f - lis r3,start_secondary@h - ori r3,r3,start_secondary@l -10: -#endif /* __SMP__ */ mtspr SRR0,r3 mtspr SRR1,r4 rfi /* enable MMU and jump to start_kernel */ diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 7335df7e4..f8f59440c 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.65 1999/08/03 19:16:19 cort Exp $ + * $Id: idle.c,v 1.66 1999/09/05 11:56:30 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -45,7 +45,7 @@ unsigned long zeropage_hits; /* # zero'd pages request that we've done */ unsigned long zeropage_calls; /* # zero'd pages request that've been made */ unsigned long zerototal; /* # pages zero'd over time */ -int idled(void *unused) +int idled(void) { /* endless loop with no priority at all */ current->priority = 0; @@ -73,9 +73,9 @@ int idled(void *unused) * SMP entry into the idle task - calls the same thing as the * non-smp versions. -- Cort */ -int cpu_idle(void *unused) +int cpu_idle() { - idled(unused); + idled(); return 0; } diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index e6213a8a6..eece8308a 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -1,5 +1,5 @@ /* - * $Id: irq.c,v 1.108 1999/07/23 01:55:44 davem Exp $ + * $Id: irq.c,v 1.109 1999/09/05 11:56:31 paulus Exp $ * * arch/ppc/kernel/irq.c * @@ -31,6 +31,7 @@ #include #include +#include #include #include #include diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index dcaa860de..c4bed05e9 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -45,13 +45,7 @@ _GLOBAL(reloc_offset) mtlr r0 blr -/* - * Disable interrupts - * rc = _disable_interrupts() - */ -_GLOBAL(_disable_interrupts) _GLOBAL(__cli) -_GLOBAL(_hard_cli) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ li r4,0 /* Need [unsigned] value of MSR_EE */ @@ -61,16 +55,7 @@ _GLOBAL(_hard_cli) mtmsr r0 /* Update machine state */ blr /* Done */ -/* - * Enable interrupts - * _enable_interrupts(int state) - * turns on interrupts if state = 1. - */ -_GLOBAL(_enable_interrupts) - cmpi 0,r3,0 /* turning them on? */ - beqlr /* nothing to do if state == 0 */ _GLOBAL(__sti) -_GLOBAL(_hard_sti) lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index da8dcfe28..2ed0f4a5b 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.56 1999/08/31 15:42:37 cort Exp $ + * $Id: pci.c,v 1.60 1999/09/08 03:04:07 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -22,6 +22,8 @@ #include "pci.h" +static void __init pcibios_claim_resources(struct pci_bus *); + unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; unsigned long pci_dram_offset = 0; @@ -68,17 +70,46 @@ struct pci_ops generic_pci_ops = void __init pcibios_init(void) { printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = ~0L; pci_scan_bus(0, &generic_pci_ops, NULL); - + pcibios_claim_resources(pci_root); + if ( ppc_md.pcibios_fixup ) + ppc_md.pcibios_fixup(); } -void __init pcibios_fixup(void) +static void __init pcibios_claim_resources(struct pci_bus *bus) { - ppc_md.pcibios_fixup(); + struct pci_dev *dev; + int idx; + + while (bus) + { + for (dev=bus->devices; dev; dev=dev->sibling) + { + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) + { + struct resource *r = &dev->resource[idx]; + struct resource *pr; + if (!r->start) + continue; + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) + { + printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); + /* We probably should disable the region, shouldn't we? */ + } + } + } + if (bus->children) + pcibios_claim_resources(bus->children); + bus = bus->next; + } } void __init pcibios_fixup_bus(struct pci_bus *bus) { + if ( ppc_md.pcibios_fixup_bus ) + ppc_md.pcibios_fixup_bus(bus); } char __init *pcibios_setup(char *str) @@ -110,3 +141,8 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev) } } #endif + +int pcibios_assign_resource(struct pci_dev *pdev, int resource) +{ + return 0; +} diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 27b6d3efc..61806f1af 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 04acd80fb..a7859ca9a 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.70 1999/08/25 21:26:08 cort Exp $ + * $Id: prom.c,v 1.73 1999/09/05 11:56:32 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -16,9 +16,10 @@ #include #include #include +#include +#include #include -#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include /* * Properties whose value is longer than this get excluded from our @@ -281,6 +283,11 @@ prom_init(int r3, int r4, prom_entry pp) int l; char *p, *d; +#ifdef CONFIG_GEMINI + gemini_prom_init(); + return; +#endif /* CONFIG_GEMINI */ + /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) return; diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index a211b3291..8015b8d30 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * $Id: setup.c,v 1.146 1999/08/31 06:54:08 davem Exp $ + * $Id: setup.c,v 1.148 1999/09/05 11:56:34 paulus Exp $ * Common prep/pmac/chrp boot and setup code. */ @@ -279,9 +279,11 @@ int get_cpuinfo(char *buffer) for ( s = 0; (s < i) && cpu_node->next ; s++, cpu_node = cpu_node->next ) /* nothing */ ; +#if 0 /* SMP Pmacs don't have all cpu nodes -- Cort */ if ( s != i ) printk("get_cpuinfo(): ran out of " "cpu nodes.\n"); +#endif } fp = (int *) get_property(cpu_node, "clock-frequency", NULL); if ( !fp ) break; @@ -343,7 +345,6 @@ unsigned long __init identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { - #ifdef __SMP__ if ( first_cpu_booted ) return 0; #endif /* __SMP__ */ diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index bf56cc3e2..3d2fb057f 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.61 1999/08/24 22:06:26 cort Exp $ + * $Id: smp.c,v 1.62 1999/09/05 11:56:34 paulus Exp $ * * Smp support for ppc. * @@ -21,13 +21,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -253,16 +253,18 @@ void __init smp_boot_cpus(void) /* let other processors know to not do certain initialization */ first_cpu_booted = 1; smp_num_cpus = 1; - + smp_store_cpu_info(0); + /* * assume for now that the first cpu booted is * cpu 0, the master -- Cort */ cpu_callin_map[0] = 1; - smp_store_cpu_info(0); active_kernel_processor = 0; current->processor = 0; + init_idle(); + for (i = 0; i < NR_CPUS; i++) { prof_counter[i] = 1; prof_multiplier[i] = 1; @@ -304,12 +306,21 @@ void __init smp_boot_cpus(void) for ( i = 1 ; i < cpu_nr; i++ ) { int c; + struct pt_regs regs; + struct task_struct *idle; /* create a process for the processor */ - kernel_thread(start_secondary, NULL, CLONE_PID); - p = init_tasks[i]; - if ( !p ) - panic("No idle task for secondary processor\n"); + /* we don't care about the values in regs since we'll + never reschedule the forked task. */ + if (do_fork(CLONE_VM|CLONE_PID, 0, ®s) < 0) + panic("failed fork for CPU %d", i); + p = init_task.prev_task; + if (!p) + panic("No idle task for CPU %d", i); + del_from_runqueue(p); + unhash_process(p); + init_tasks[i] = p; + p->processor = i; p->has_cpu = 1; current_set[i] = p; @@ -329,6 +340,7 @@ void __init smp_boot_cpus(void) eieio(); /* interrupt secondary to begin executing code */ out_be32(PSURGE_INTR, ~0); + udelay(1); out_be32(PSURGE_INTR, 0); break; case _MACH_chrp: @@ -385,6 +397,7 @@ void __init smp_commence(void) /* * Lets the callin's below out of their loop. */ + wmb(); smp_commenced = 1; } @@ -394,8 +407,10 @@ void __init initialize_secondary(void) } /* Activate a secondary processor. */ -asmlinkage int __init start_secondary(void *unused) +int __init start_secondary(void *unused) { + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; smp_callin(); return cpu_idle(NULL); } diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 571b36391..30bed889b 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -37,6 +37,7 @@ #include #include +#include void check_bugs(void) diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index 4e1a17c55..d6b56dc5f 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -10,9 +10,9 @@ #include #include #include +#include #include #include -#include #include #define DEBUG_LOCKS 1 diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 369da71b9..20296b4e2 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.180 1999/08/31 06:54:13 davem Exp $ + * $Id: init.c,v 1.183 1999/09/05 19:29:44 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -90,8 +90,7 @@ extern unsigned long *find_end_of_memory(void); unsigned long *mbx_find_end_of_memory(void); #endif /* CONFIG_MBX */ static void mapin_ram(void); -void map_page(struct task_struct *, unsigned long va, - unsigned long pa, int flags); +void map_page(unsigned long va, unsigned long pa, int flags); extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); @@ -436,7 +435,7 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) */ for (i = 0; i < size; i += PAGE_SIZE) - map_page(&init_task, v+i, p+i, flags); + map_page(v+i, p+i, flags); out: return (void *) (v + (addr & ~PAGE_MASK)); } @@ -472,13 +471,19 @@ unsigned long iopa(unsigned long addr) } void -map_page(struct task_struct *tsk, unsigned long va, - unsigned long pa, int flags) +map_page(unsigned long va, unsigned long pa, int flags) { - pte_t * pte; - - pte = pte_alloc(pmd_offset(pgd_offset_k(va), va), va); - set_pte(pte, mk_pte_phys(pa, __pgprot(flags))); + pmd_t *pd, oldpd; + pte_t *pg; + + /* Use upper 10 bits of VA to index the first level map */ + pd = pmd_offset(pgd_offset_k(va), va); + oldpd = *pd; + /* Use middle 10 bits of VA to index the second-level map */ + pg = pte_alloc(pd, va); + if (pmd_none(oldpd) && mem_init_done) + set_pgdir(va, *(pgd_t *)pd); + set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); flush_hash_page(0, va); } @@ -856,7 +861,6 @@ static void __init mapin_ram(void) RAM_PAGE); } } - v = KERNELBASE; for (i = 0; i < phys_mem.n_regions; ++i) { p = phys_mem.regions[i].address; @@ -868,11 +872,11 @@ static void __init mapin_ram(void) /* On the powerpc, no user access forces R/W kernel access */ f |= _PAGE_USER; - map_page(&init_task, v, p, f); + map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } - } + } #else /* CONFIG_8xx */ @@ -895,7 +899,7 @@ static void __init mapin_ram(void) */ if ((char *) v < _stext || (char *) v >= etext) f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; - map_page(&init_task, v, p, f); + map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; } @@ -960,6 +964,11 @@ void __init free_initmem(void) FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; + case _MACH_gemini: + FREESEC(__apus_begin,__apus_end,num_apus_pages); + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; } if ( !have_of ) diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 2e75d3604..3d3cba23c 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -19,11 +19,11 @@ #include #include #include +#include #include #include #include -#include #include static inline void console_verbose(void) diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 3074778e8..adec38c8b 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index a55ace705..06fa837e2 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index fdc9d49df..e611cd828 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 804126994..3fbc29fb1 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 298167a2d..828cb5d89 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index a749f760e..b52cd08a8 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index ba774557f..b9990ce0d 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c index fec57d331..b362895ee 100644 --- a/arch/sparc/lib/debuglocks.c +++ b/arch/sparc/lib/debuglocks.c @@ -8,9 +8,9 @@ #include #include #include /* For NR_CPUS */ +#include #include #include -#include /* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */ #ifdef SPIN_LOCK_DEBUG diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 24075d4c1..69c69d212 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.68 1999/08/31 06:54:32 davem Exp $ +/* $Id: init.c,v 1.69 1999/09/06 22:56:17 ecd Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -379,4 +379,6 @@ void si_meminfo(struct sysinfo *val) } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; + val->totalbig = 0; + val->freebig = 0; } diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index fbb362bf0..7ba2718c2 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -8,12 +8,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include /* #define IOUNIT_DEBUG */ diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 1cde37cca..10f452636 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include /* Now the cpu specific definitions. */ #include diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index 2650b24b6..cf8af1a78 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.77 1999/08/31 12:49:42 davem Exp $ +# $Id: config.in,v 1.78 1999/09/06 01:17:28 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -204,6 +204,9 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'PCI NE2000 support' CONFIG_NE2K_PCI + tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi # bool 'FDDI driver support' CONFIG_FDDI diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index e07cc1eb6..53a69e509 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -71,6 +71,7 @@ CONFIG_OBP_FLASH=m # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_AURORA=m +# CONFIG_TADPOLE_TS102_UCTRL is not set CONFIG_APM_RTC_IS_GMT=y # CONFIG_RTC is not set @@ -257,6 +258,9 @@ CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m CONFIG_VORTEX=m +CONFIG_RTL8139=m +CONFIG_NE2K_PCI=m +CONFIG_EEXPRESS_PRO100=m CONFIG_ADAPTEC_STARFIRE=m # @@ -286,6 +290,8 @@ CONFIG_VFAT_FS=m CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set +CONFIG_UDF_FS=m +# CONFIG_UDF_RW is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set CONFIG_HPFS_FS=m diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 81302224f..dbcc0d45f 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c @@ -33,7 +33,7 @@ struct cpu_fp_info linux_sparc_fpu[] = { { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, - { 0x17, 0x13, 0, "UltraSparc III integrated FPU"}, + { 0x17, 0x14, 0, "UltraSparc III integrated FPU"}, }; #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) @@ -43,7 +43,7 @@ struct cpu_iu_info linux_sparc_chips[] = { { 0x22, 0x10, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x12, "TI UltraSparc IIi"}, - { 0x17, 0x13, "TI UltraSparc III (Cheetah)"}, /* A guess... */ + { 0x17, 0x14, "TI UltraSparc III (Cheetah)"}, /* A guess... */ }; #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 71695a956..0b3d16007 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.42 1999/08/31 09:12:31 davem Exp $ +/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -77,7 +77,7 @@ void __init ebus_intmap_match(struct linux_ebus *ebus, } void __init fill_ebus_child(int node, struct linux_prom_registers *preg, - struct linux_ebus_child *dev) + struct linux_ebus_child *dev, int non_standard_regs) { int regs[PROMREG_MAX]; int irqs[PROMREG_MAX]; @@ -85,22 +85,34 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg, dev->prom_node = node; prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); - printk("(%s)", dev->prom_name); + printk(" (%s)", dev->prom_name); len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); dev->num_addrs = len / sizeof(regs[0]); - for (i = 0; i < dev->num_addrs; i++) { - int rnum = regs[i]; - if (rnum >= dev->parent->num_addrs) { - prom_printf("UGH: property for %s was %d, need < %d\n", - dev->prom_name, len, dev->parent->num_addrs); - panic(__FUNCTION__); + if (non_standard_regs) { + /* This is to handle reg properties which are not + * in the parent relative format. One example are + * children of the i2c device on CompactPCI systems. + * + * So, for such devices we just record the property + * raw in the child resources. + */ + for (i = 0; i < dev->num_addrs; i++) + dev->resource[i].start = regs[i]; + } else { + for (i = 0; i < dev->num_addrs; i++) { + int rnum = regs[i]; + if (rnum >= dev->parent->num_addrs) { + prom_printf("UGH: property for %s was %d, need < %d\n", + dev->prom_name, len, dev->parent->num_addrs); + panic(__FUNCTION__); + } + dev->resource[i].start = dev->parent->resource[i].start; + dev->resource[i].end = dev->parent->resource[i].end; + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; } - dev->resource[i].start = dev->parent->resource[i].start; - dev->resource[i].end = dev->parent->resource[i].end; - dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dev->prom_name; } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -133,6 +145,13 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg, } } +static int __init child_regs_nonstandard(struct linux_ebus_device *dev) +{ + if (!strcmp(dev->prom_name, "i2c")) + return 1; + return 0; +} + void __init fill_ebus_device(int node, struct linux_ebus_device *dev) { struct linux_prom_registers regs[PROMREG_MAX]; @@ -188,7 +207,8 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev) child->next = 0; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], child); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); while ((node = prom_getsibling(node))) { child->next = ebus_alloc(sizeof(struct linux_ebus_child)); @@ -197,7 +217,8 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev) child->next = 0; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], child); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); } } printk("]"); diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index e6f7a423f..fbd64a507 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.106 1999/08/02 08:39:34 davem Exp $ +/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -478,6 +478,97 @@ __do_instruction_access_exception: ba,pt %xcc, rtrap clr %l6 + /* This is the trap handler entry point for ECC correctable + * errors. They are corrected, but we listen for the trap + * so that the event can be logged. + * + * Disrupting errors are either: + * 1) single-bit ECC errors during UDB reads to system + * memory + * 2) data parity errors during write-back events + * + * As far as I can make out from the manual, the CEE trap + * is only for correctable errors during memory read + * accesses by the front-end of the processor. + * + * The code below is only for trap level 1 CEE events, + * as it is the only situation where we can safely record + * and log. For trap level >1 we just clear the CE bit + * in the AFSR and return. + */ + + /* Our trap handling infrastructure allows us to preserve + * two 64-bit values during etrap for arguments to + * subsequent C code. Therefore we encode the information + * as follows: + * + * value 1) Full 64-bits of AFAR + * value 2) Low 33-bits of AFSR, then bits 33-->42 + * are UDBL error status and bits 43-->52 + * are UDBH error status + */ + .align 64 + .globl cee_trap +cee_trap: + ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR + ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR + sllx %g1, 31, %g1 ! Clear reserved bits + srlx %g1, 31, %g1 ! in AFSR + + /* NOTE: UltraSparc-I/II have high and low UDB error + * registers, corresponding to the two UDB units + * present on those chips. UltraSparc-IIi only + * has a single UDB, called "SDB" in the manual. + * For IIi the upper UDB register always reads + * as zero so for our purposes things will just + * work with the checks below. + */ + ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status + andcc %g3, (1 << 8), %g4 ! Check CE bit + sllx %g3, (64 - 10), %g3 ! Clear reserved bits + srlx %g3, (64 - 10), %g3 ! in UDB-Low error status + + sllx %g3, (33 + 0), %g3 ! Shift up to encoding area + or %g1, %g3, %g1 ! Or it in + be,pn %xcc, 1f ! Branch if CE bit was clear + nop + stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL + membar #Sync ! Synchronize ASI stores +1: mov 0x18, %g5 ! Addr of UDB-High error status + ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it + + andcc %g3, (1 << 8), %g4 ! Check CE bit + sllx %g3, (64 - 10), %g3 ! Clear reserved bits + srlx %g3, (64 - 10), %g3 ! in UDB-High error status + sllx %g3, (33 + 10), %g3 ! Shift up to encoding area + or %g1, %g3, %g1 ! Or it in + be,pn %xcc, 1f ! Branch if CE bit was clear + nop + nop + + stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH + membar #Sync ! Synchronize ASI stores +1: mov 1, %g5 ! AFSR CE bit is + sllx %g5, 20, %g5 ! bit 20 + stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR + membar #Sync ! Synchronize ASI stores + sllx %g2, (64 - 41), %g2 ! Clear reserved bits + srlx %g2, (64 - 41), %g2 ! in latched AFAR + + andn %g2, 0x0f, %g2 ! Finish resv bit clearing + mov %g1, %g4 ! Move AFSR+UDB* into save reg + mov %g2, %g5 ! Move AFAR into save reg + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o0 + + mov %l5, %o1 + call cee_log + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + ba,a,pt %xcc, rtrap_clr_l6 + .globl __do_privact __do_privact: mov TLB_SFSR, %g3 diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index feb56ef4b..1776e6d7e 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.1 1999/08/30 10:00:42 davem Exp $ +/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -20,45 +20,9 @@ #include #include -/* This is the base address of IOMMU translated space - * on PCI bus segments. This means that any PCI address - * greater than or equal this value will be translated - * into a physical address and transferred on the system - * bus. Any address less than it will be considered a - * PCI peer-to-peer transaction. For example, given a - * value of 0x80000000: - * - * If a PCI device bus masters the address 0x80001000 - * then then PCI controller's IOMMU will take the offset - * portion (0x1000) and translate that into a physical - * address. The data transfer will be performed to/from - * that physical address on the system bus. - * - * If the PCI device bus masters the address 0x00002000 - * then the PCI controller will not do anything, it will - * proceed as a PCI peer-to-peer transfer. - * - * This all stems from the fact that PCI drivers in Linux are - * not conscious of DMA mappings to the extent they need to - * be for systems like Sparc64 and Alpha which have IOMMU's. - * Plans are already in the works to fix this. So what we do - * at the moment is linearly map all of physical ram with the - * IOMMU in consistant mode, thus providing the illusion of - * a simplistic linear DMA mapping scheme to the drivers. - * This, while it works, is bad for performance (streaming - * DMA is not used) and limits the amount of total memory we - * can support (2GB on Psycho, 512MB on Sabre/APB). - */ -unsigned long pci_dvma_offset = 0x00000000UL; - -/* Given a valid PCI dma address (ie. >= pci_dvma_addset) this - * mask will give you the offset into the DMA space of a - * PCI bus. - */ -unsigned long pci_dvma_mask = 0xffffffffUL; - unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_memspace_mask = 0xffffffffUL; #ifndef CONFIG_PCI /* A "nop" PCI implementation. */ @@ -123,7 +87,9 @@ static struct { void (*init)(int); } pci_controller_table[] = { { "SUNW,sabre", sabre_init }, - { "SUNW,psycho", psycho_init } + { "pci108e,a000", sabre_init }, + { "SUNW,psycho", psycho_init }, + { "pci108e,8000", psycho_init } }; #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ sizeof(pci_controller_table[0])) @@ -164,6 +130,12 @@ static void pci_controller_probe(void) namebuf, sizeof(namebuf)); if (len > 0) pci_controller_init(namebuf, len, node); + else { + len = prom_getproperty(node, "compatible", + namebuf, sizeof(namebuf)); + if (len > 0) + pci_controller_init(namebuf, len, node); + } node = prom_getsibling(node); if (!node) break; @@ -230,6 +202,11 @@ void pcibios_fixup_bus(struct pci_bus *pbus) { } +int pcibios_assign_resource(struct pci_dev *pdev, int resource) +{ + return 0; +} + char * __init pcibios_setup(char *str) { if (!strcmp(str, "onboardfirst")) { diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 411851a7c..a3600df9c 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.2 1999/08/31 09:12:33 davem Exp $ +/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -21,6 +21,19 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm, { int node; + /* + * Return the PBM's PROM node in case we are it's PCI device, + * as the PBM's reg property is different to standard PCI reg + * properties. We would delete this device entry otherwise, + * which confuses XFree86's device probing... + */ + if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) && + (pdev->vendor == PCI_VENDOR_ID_SUN) && + (pdev->device == PCI_DEVICE_ID_SUN_PBM)) { + *nregs = 0; + return bus_prom_node; + } + node = prom_getchild(bus_prom_node); while (node != 0) { int err = prom_getproperty(node, "reg", diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h index 83281842e..0ce565b4f 100644 --- a/arch/sparc64/kernel/pci_impl.h +++ b/arch/sparc64/kernel/pci_impl.h @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.1 1999/08/30 10:00:44 davem Exp $ +/* $Id: pci_impl.h,v 1.2 1999/09/05 04:58:05 davem Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -8,7 +8,7 @@ #define PCI_IMPL_H #include -#include +#include #include extern spinlock_t pci_controller_lock; @@ -35,12 +35,12 @@ extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_p extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); /* IOMMU/DVMA initialization. */ -extern unsigned long pci_dvma_offset; -extern unsigned long pci_dvma_mask; #define PCI_DVMA_HASH_NONE ~0UL -static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr) +static __inline__ void set_dvma_hash(unsigned long dvma_offset, + unsigned long paddr, + unsigned long daddr) { - unsigned long dvma_addr = pci_dvma_offset + daddr; + unsigned long dvma_addr = dvma_offset + daddr; unsigned long vaddr = (unsigned long)__va(paddr); pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 7b2d1ed25..1afe5a67b 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.2 1999/08/31 09:12:34 davem Exp $ +/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1312,7 +1312,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize) (paddr & IOPTE_PAGE)); if (!(n & 0xff)) - set_dvma_hash(paddr, (n << 16)); + set_dvma_hash(0x80000000, paddr, (n << 16)); if (++n > (tsbsize * 1024)) goto out; @@ -1338,17 +1338,14 @@ out: switch(tsbsize) { case 8: p->iommu.page_table_map_base = 0xe0000000; - pci_dvma_mask = 0x1fffffffUL; control |= PSYCHO_IOMMU_TSBSZ_8K; break; case 16: p->iommu.page_table_map_base = 0xc0000000; - pci_dvma_mask = 0x3fffffffUL; control |= PSYCHO_IOMMU_TSBSZ_16K; break; case 32: p->iommu.page_table_map_base = 0x80000000; - pci_dvma_mask = 0x7fffffffUL; control |= PSYCHO_IOMMU_TSBSZ_32K; break; default: @@ -1594,9 +1591,14 @@ void __init psycho_init(int node) p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE; printk("PSYCHO: PCI config space at %016lx\n", p->config_space); + /* + * Psycho's PCI MEM space is mapped to a 2GB aligned area, so + * we need to adjust our MEM space mask. + */ + pci_memspace_mask = 0x7fffffffUL; + psycho_controller_hwinit(p); - pci_dvma_offset = 0x80000000UL; psycho_iommu_init(p, 32); is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 2b1d44a43..46a9b31cf 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.1 1999/08/30 10:00:32 davem Exp $ +/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1121,7 +1121,8 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) sabre_register_error_handlers(p); } -static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize) +static void __init sabre_iommu_init(struct pci_controller_info *p, + int tsbsize, unsigned long dvma_offset) { struct linux_mlist_p1275 *mlist; unsigned long tsbbase, i, n, order; @@ -1142,7 +1143,6 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize) for(order = 0;; order++) if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) break; - tsbbase = __get_free_pages(GFP_DMA, order); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); @@ -1200,8 +1200,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize) (paddr & IOPTE_PAGE)); if (!(n & 0xff)) - set_dvma_hash(paddr, (n << 16)); - + set_dvma_hash(dvma_offset, paddr, (n << 16)); if (++n > (tsbsize * 1024)) goto out; @@ -1225,15 +1224,12 @@ out: control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); switch(tsbsize) { case 8: - pci_dvma_mask = 0x1fffffffUL; control |= IOMMU_TSBSZ_8K; break; case 16: - pci_dvma_mask = 0x3fffffffUL; control |= IOMMU_TSBSZ_16K; break; case 32: - pci_dvma_mask = 0x7fffffffUL; control |= IOMMU_TSBSZ_32K; break; default: @@ -1463,8 +1459,7 @@ void __init sabre_init(int pnode) prom_halt(); } - pci_dvma_offset = vdma[0]; - sabre_iommu_init(p, tsbsize); + sabre_iommu_init(p, tsbsize, vdma[0]); printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 8c58e21f3..831011128 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -1,4 +1,4 @@ -/* $Id: power.c,v 1.2 1999/08/31 04:39:38 davem Exp $ +/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $ * power.c: Power management driver. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 74263295b..672e83493 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.44 1999/08/04 07:04:13 jj Exp $ +/* $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -228,7 +228,7 @@ do_sigsegv: struct rt_signal_frame { struct sparc_stackf ss; - siginfo_t info; + siginfo_t info; struct pt_regs regs; __siginfo_fpu_t * fpu_save; stack_t stack; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c312db206..d1adeb2c7 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index d917979a8..e57b8d6f7 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.62 1999/08/06 01:42:48 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -190,10 +190,9 @@ EXPORT_SYMBOL(dma_chain); #endif #if CONFIG_PCI EXPORT_SYMBOL(ebus_chain); -EXPORT_SYMBOL(pci_dvma_offset); -EXPORT_SYMBOL(pci_dvma_mask); EXPORT_SYMBOL(pci_dvma_v2p_hash); EXPORT_SYMBOL(pci_dvma_p2v_hash); +EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 8f784a7bf..f4f2287df 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.61 1999/07/30 09:35:32 davem Exp $ +/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -395,6 +395,124 @@ void do_iae(struct pt_regs *regs) unlock_kernel(); } +static char ecc_syndrome_table[] = { + 0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49, + 0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a, + 0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48, + 0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c, + 0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48, + 0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29, + 0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b, + 0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48, + 0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48, + 0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e, + 0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b, + 0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48, + 0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36, + 0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48, + 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48, + 0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b, + 0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48, + 0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b, + 0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32, + 0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48, + 0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b, + 0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48, + 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48, + 0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b, + 0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49, + 0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48, + 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48, + 0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b, + 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48, + 0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b, + 0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b, + 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a +}; + +/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status + * in the following format. The AFAR is left as is, with + * reserved bits cleared, and is a raw 40-bit physical + * address. + */ +#define CE_STATUS_UDBH_UE (1UL << (43 + 9)) +#define CE_STATUS_UDBH_CE (1UL << (43 + 8)) +#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43) +#define CE_STATUS_UDBH_SHIFT 43 +#define CE_STATUS_UDBL_UE (1UL << (33 + 9)) +#define CE_STATUS_UDBL_CE (1UL << (33 + 8)) +#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33) +#define CE_STATUS_UDBL_SHIFT 33 +#define CE_STATUS_AFSR_MASK (0x1ffffffffUL) +#define CE_STATUS_AFSR_ME (1UL << 32) +#define CE_STATUS_AFSR_PRIV (1UL << 31) +#define CE_STATUS_AFSR_ISAP (1UL << 30) +#define CE_STATUS_AFSR_ETP (1UL << 29) +#define CE_STATUS_AFSR_IVUE (1UL << 28) +#define CE_STATUS_AFSR_TO (1UL << 27) +#define CE_STATUS_AFSR_BERR (1UL << 26) +#define CE_STATUS_AFSR_LDP (1UL << 25) +#define CE_STATUS_AFSR_CP (1UL << 24) +#define CE_STATUS_AFSR_WP (1UL << 23) +#define CE_STATUS_AFSR_EDP (1UL << 22) +#define CE_STATUS_AFSR_UE (1UL << 21) +#define CE_STATUS_AFSR_CE (1UL << 20) +#define CE_STATUS_AFSR_ETS (0xfUL << 16) +#define CE_STATUS_AFSR_ETS_SHIFT 16 +#define CE_STATUS_AFSR_PSYND (0xffffUL << 0) +#define CE_STATUS_AFSR_PSYND_SHIFT 0 + +/* Layout of Ecache TAG Parity Syndrome of AFSR */ +#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */ +#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */ +#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */ +#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */ + +static char *syndrome_unknown = ""; + +asmlinkage void cee_log(unsigned long ce_status, + unsigned long afar, + struct pt_regs *regs) +{ + char memmod_str[64]; + char *p; + unsigned short scode, udb_reg; + + printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " + "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", + smp_processor_id(), + (ce_status & CE_STATUS_AFSR_MASK), + afar, + ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL), + ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL)); + + udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL); + if (udb_reg & (1 << 8)) { + scode = ecc_syndrome_table[udb_reg & 0xff]; + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) + p = syndrome_unknown; + else + p = memmod_str; + printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] " + "Memory Module \"%s\"\n", + smp_processor_id(), scode, p); + } + + udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); + if (udb_reg & (1 << 8)) { + scode = ecc_syndrome_table[udb_reg & 0xff]; + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) + p = syndrome_unknown; + else + p = memmod_str; + printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] " + "Memory Module \"%s\"\n", + smp_processor_id(), scode, p); + } +} + void do_fpe_common(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) { diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 3a9fdf4d2..b378756c0 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $ +/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -57,7 +57,7 @@ tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) tl0_ivec: TRAP_IVEC tl0_paw: TRAP(do_paw) tl0_vaw: TRAP(do_vaw) -tl0_cee: TRAP(do_cee) +tl0_cee: TRAP_NOSAVE(cee_trap) tl0_iamiss: #include "itlb_base.S" tl0_damiss: @@ -202,7 +202,7 @@ tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) -tl1_cee: TRAPTL1(do_cee_tl1) +tl1_cee: TRAPTL1_CEE tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) tl1_damiss: #include "dtlb_backend.S" diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c index 6677f581a..56c005dfe 100644 --- a/arch/sparc64/lib/PeeCeeI.c +++ b/arch/sparc64/lib/PeeCeeI.c @@ -1,4 +1,4 @@ -/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $ +/* $Id: PeeCeeI.c,v 1.4 1999/09/06 01:17:35 davem Exp $ * PeeCeeI.c: The emerging standard... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -9,6 +9,7 @@ #ifdef CONFIG_PCI #include +#include void outsb(unsigned long addr, const void *src, unsigned long count) { @@ -21,25 +22,29 @@ void outsb(unsigned long addr, const void *src, unsigned long count) void outsw(unsigned long addr, const void *src, unsigned long count) { if(count) { - const u16 *ps = src; - const u32 *pi; + u16 *ps = (u16 *)src; + u32 *pi; if(((u64)src) & 0x2) { - outw(*ps++, addr); + u16 val = le16_to_cpup(ps); + outw(val, addr); + ps++; count--; } - pi = (const u32 *)ps; + pi = (u32 *)ps; while(count >= 2) { - u32 w; + u32 w = le32_to_cpup(pi); - w = *pi++; + pi++; + outw(w >> 0, addr); outw(w >> 16, addr); - outw(w, addr); count -= 2; } - ps = (const u16 *)pi; - if(count) - outw(*ps, addr); + ps = (u16 *)pi; + if(count) { + u16 val = le16_to_cpup(ps); + outw(val, addr); + } } } @@ -47,60 +52,71 @@ void outsl(unsigned long addr, const void *src, unsigned long count) { if(count) { if((((u64)src) & 0x3) == 0) { - const u32 *p = src; - while(count--) - outl(*p++, addr); + u32 *p = (u32 *)src; + while(count--) { + u32 val = cpu_to_le32p(p); + outl(val, addr); + p++; + } } else { - const u8 *pb; - const u16 *ps = src; + u8 *pb; + u16 *ps = (u16 *)src; u32 l = 0, l2; - const u32 *pi; + u32 *pi; switch(((u64)src) & 0x3) { case 0x2: count -= 1; - l = *ps++; - pi = (const u32 *)ps; + l = cpu_to_le16p(ps) << 16; + ps++; + pi = (u32 *)ps; while(count--) { - l2 = *pi++; - outl(((l <<16) | (l2 >> 16)), addr); + l2 = cpu_to_le32p(pi); + pi++; + outl(((l >> 16) | (l2 << 16)), addr); l = l2; } - ps = (const u16 *)pi; - outl(((l << 16) | (*ps >> 16)), addr); + ps = (u16 *)pi; + l2 = cpu_to_le16p(ps); + outl(((l >> 16) | (l2 << 16)), addr); break; case 0x1: count -= 1; - pb = src; - l = (*pb++ << 16); - ps = (const u16 *)pb; - l |= *ps++; - pi = (const u32 *)ps; + pb = (u8 *)src; + l = (*pb++ << 8); + ps = (u16 *)pb; + l2 = cpu_to_le16p(ps); + ps++; + l |= (l2 << 16); + pi = (u32 *)ps; while(count--) { - l2 = *pi++; - outl(((l << 8) | (l2 >> 24)), addr); + l2 = cpu_to_le32p(pi); + pi++; + outl(((l >> 8) | (l2 << 24)), addr); l = l2; } - pb = (const u8 *)pi; - outl(((l << 8) | (*pb >> 24)), addr); + pb = (u8 *)pi; + outl(((l >> 8) | (*pb << 24)), addr); break; case 0x3: count -= 1; - pb = src; - l = (*pb++ >> 24); - pi = (const u32 *)pb; + pb = (u8 *)src; + l = (*pb++ << 24); + pi = (u32 *)pb; while(count--) { - l2 = *pi++; - outl(((l << 24) | (l2 >> 8)), addr); + l2 = cpu_to_le32p(pi); + pi++; + outl(((l >> 24) | (l2 << 8)), addr); l = l2; } - ps = (const u16 *)pi; - l2 = (*ps++ << 16); - pb = (const u8 *)ps; - l2 |= (*pb << 8); - outl(((l << 24) | (l2 >> 8)), addr); + ps = (u16 *)pi; + l2 = cpu_to_le16p(ps); + ps++; + pb = (u8 *)ps; + l2 |= (*pb << 16); + outl(((l >> 24) | (l2 << 8)), addr); break; } } @@ -122,7 +138,7 @@ void insb(unsigned long addr, void *dst, unsigned long count) w = (inb(addr) << 24); w |= (inb(addr) << 16); w |= (inb(addr) << 8); - w |= inb(addr); + w |= (inb(addr) << 0); *pi++ = w; count -= 4; } @@ -139,21 +155,21 @@ void insw(unsigned long addr, void *dst, unsigned long count) u32 *pi; if(((unsigned long)ps) & 0x2) { - *ps++ = inw(addr); + *ps++ = le16_to_cpu(inw(addr)); count--; } pi = (u32 *)ps; while(count >= 2) { u32 w; - w = (inw(addr) << 16); - w |= inw(addr); + w = (le16_to_cpu(inw(addr)) << 16); + w |= (le16_to_cpu(inw(addr)) << 0); *pi++ = w; count -= 2; } ps = (u16 *)pi; if(count) - *ps = inw(addr); + *ps = le16_to_cpu(inw(addr)); } } @@ -163,7 +179,7 @@ void insl(unsigned long addr, void *dst, unsigned long count) if((((unsigned long)dst) & 0x3) == 0) { u32 *pi = dst; while(count--) - *pi++ = inl(addr); + *pi++ = le32_to_cpu(inl(addr)); } else { u32 l = 0, l2, *pi; u16 *ps; @@ -173,47 +189,48 @@ void insl(unsigned long addr, void *dst, unsigned long count) case 0x2: ps = dst; count -= 1; - l = inl(addr); - *ps++ = (l >> 16); + l = le32_to_cpu(inl(addr)); + *ps++ = l; pi = (u32 *)ps; while(count--) { - l2 = inl(addr); + l2 = le32_to_cpu(inl(addr)); *pi++ = (l << 16) | (l2 >> 16); l = l2; } ps = (u16 *)pi; - *ps = (l << 16); + *ps = l; break; case 0x1: pb = dst; count -= 1; - *pb++ = (l >> 24); + l = le32_to_cpu(inl(addr)); + *pb++ = l >> 24; ps = (u16 *)pb; - *ps++ = (l >> 8); + *ps++ = ((l >> 8) & 0xffff); pi = (u32 *)ps; while(count--) { - l2 = inl(addr); - *pi++ = ((l << 24) | (l2 >> 8)); + l2 = le32_to_cpu(inl(addr)); + *pi++ = (l << 24) | (l2 >> 8); l = l2; } pb = (u8 *)pi; - *pb = (l >> 8); + *pb = l; break; case 0x3: pb = (u8 *)dst; count -= 1; - l = inl(addr); + l = le32_to_cpu(inl(addr)); *pb++ = l >> 24; pi = (u32 *)pb; while(count--) { - l2 = inl(addr); - *pi++ = ((l >> 24) | (l2 << 8)); + l2 = le32_to_cpu(inl(addr)); + *pi++ = (l << 8) | (l2 >> 24); l = l2; } ps = (u16 *)pi; - *ps++ = l >> 8; + *ps++ = ((l >> 8) & 0xffff); pb = (u8 *)ps; *pb = l; break; diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c index 69286c4b7..6bdcbb3cc 100644 --- a/arch/sparc64/lib/debuglocks.c +++ b/arch/sparc64/lib/debuglocks.c @@ -6,8 +6,8 @@ #include #include +#include #include -#include #ifdef __SMP__ diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 9992e3293..c1d8d24ae 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.134 1999/08/31 06:54:58 davem Exp $ +/* $Id: init.c,v 1.135 1999/09/06 22:55:10 ecd Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -1477,4 +1477,6 @@ void si_meminfo(struct sysinfo *val) } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; + val->totalbig = 0; + val->freebig = 0; } diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 83af773df..2a45a4bb5 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.14 1998/12/18 10:01:59 davem Exp $ +/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -125,15 +125,37 @@ void prom_set_trap_table(unsigned long tba) /* This is only used internally below. */ static int prom_get_mmu_ihandle(void) { - int node; - int ret; + static int mmu_ihandle_cache = 0; + int node, ret; + + if (mmu_ihandle_cache != 0) + return mmu_ihandle_cache; node = prom_finddevice("/chosen"); ret = prom_getint(node, "mmu"); - if(ret == -1 || ret == 0) { - prom_printf("PROMLIB: Fatal error, cannot get mmu ihandle.\n"); - prom_halt(); - } + if(ret == -1 || ret == 0) + mmu_ihandle_cache = -1; + else + mmu_ihandle_cache = ret; + + return ret; +} + +static int prom_get_memory_ihandle(void) +{ + static int memory_ihandle_cache = 0; + int node, ret; + + if (memory_ihandle_cache != 0) + return memory_ihandle_cache; + + node = prom_finddevice("/chosen"); + ret = prom_getint(node, "memory"); + if (ret == -1 || ret == 0) + memory_ihandle_cache = -1; + else + memory_ihandle_cache = ret; + return ret; } @@ -197,12 +219,18 @@ unsigned long prom_retain(char *name, * etched into the motherboard next to the SIMM slot * in question. */ -int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi, +int prom_getunumber(int syndrome_code, + unsigned long phys_addr, char *buf, int buflen) { - return p1275_cmd("SUNW,get-unumber", - (P1275_ARG(2, P1275_ARG_OUT_BUF) | P1275_INOUT(4, 1)), - phys_lo, phys_hi, buf, buflen); + return p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_OUT_BUF) | + P1275_ARG(5, P1275_ARG_IN_64B) | + P1275_INOUT(8, 2)), + "SUNW,get-unumber", prom_get_memory_ihandle(), + buflen, buf, P1275_SIZE(buflen), + 0, phys_addr, syndrome_code); } /* Power management extensions. */ diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index 3afd992e0..8ddb5aec3 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.16 1999/08/02 12:05:57 jj Exp $ +/* $Id: p1275.c,v 1.17 1999/08/31 19:25:43 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -9,13 +9,13 @@ #include #include #include +#include #include #include #include #include #include -#include struct { long prom_callback; /* 0x00 */ @@ -321,6 +321,10 @@ long p1275_cmd (char *service, long fmt, ...) p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break; + case P1275_ARG_IN_64B: + p1275buf.prom_args[i + 3] = + va_arg(list, unsigned long); + break; case P1275_ARG_IN_STRING: strcpy (p, va_arg(list, char *)); p1275buf.prom_args[i + 3] = (unsigned long)p; diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index e94b73cc9..5ee6df467 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -1,4 +1,4 @@ -/* $Id: timod.c,v 1.3 1999/08/02 12:06:01 jj Exp $ +/* $Id: timod.c,v 1.4 1999/09/01 08:07:47 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in index eba528548..af401ed29 100644 --- a/drivers/atm/Config.in +++ b/drivers/atm/Config.in @@ -1,6 +1,7 @@ # # ATM device configuration # +mainmenu_option next_comment comment 'ATM drivers' if [ "$CONFIG_INET" = "y" ]; then tristate 'ATM over TCP' CONFIG_ATM_TCP y @@ -43,3 +44,4 @@ if [ "$CONFIG_PCI" = "y" ]; then bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG fi fi +endmenu diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index c1802c861..bdb3eb54c 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -12,19 +12,21 @@ include ../../.config ifeq ($(CONFIG_ATM_ENI),y) L_OBJS += eni.o -LX_OBJS += suni.o +NEED_SUNI_LX = suni.o else ifeq ($(CONFIG_ATM_ENI),m) M_OBJS += eni.o - MX_OBJS += suni.o + NEED_SUNI_MX = suni.o endif endif ifeq ($(CONFIG_ATM_ZATM),y) -LX_OBJS += zatm.o uPD98402.o +L_OBJS += zatm.o +LX_OBJS += uPD98402.o else ifeq ($(CONFIG_ATM_ZATM),m) - MX_OBJS += zatm.o uPD98402.o + M_OBJS += zatm.o + MX_OBJS += uPD98402.o endif endif @@ -39,13 +41,13 @@ endif ifeq ($(CONFIG_ATM_NICSTAR),y) L_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) - LX_OBJS += suni.o + NEED_SUNI_LX = suni.o endif else ifeq ($(CONFIG_ATM_NICSTAR),m) M_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) - MX_OBJS += suni.o + NEED_SUNI_MX = suni.o endif endif endif @@ -66,6 +68,12 @@ else endif endif +ifeq ($(NEED_SUNI_LX),) + MX_OBJS += $(NEED_SUNI_MX) +else + LX_OBJS += $(NEED_SUNI_LX) +endif + ifeq ($(CONFIG_ATM_TCP),y) L_OBJS += atmtcp.o else diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 940654995..5664f0ea2 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -20,11 +20,6 @@ system and in the file COPYING in the Linux kernel source. */ -/* - IMPORTANT NOTE: Madge Networks does not license the microcode for - this driver under the GPL. See the .data file for the licence. -*/ - /* * dedicated to the memory of Graham Gordon 1971-1998 * */ #include @@ -44,7 +39,7 @@ #define maintainer_string "Giuliano Procida at Madge Networks " #define description_string "Madge ATM Ambassador driver" -#define version_string "1.1" +#define version_string "1.2" static inline void __init show_version (void) { printk ("%s version %s\n", description_string, version_string); @@ -122,11 +117,11 @@ static inline void __init show_version (void) { The queue pairs work as follows: one queue is for supply to the adapter, items in it are pending and are owned by the adapter; the - other is the for return from the adapter, items in it have been - dealt with by the adapter. The host adds items to the supply (TX - descriptors and free RX buffer descriptors) and removes items from - the return (TX and RX completions). The adapter deals with out of - order completions. + other is the queue for return from the adapter, items in it have + been dealt with by the adapter. The host adds items to the supply + (TX descriptors and free RX buffer descriptors) and removes items + from the return (TX and RX completions). The adapter deals with out + of order completions. Interrupts (card to host) and the doorbell (host to card) are used for signalling. @@ -170,25 +165,26 @@ static inline void __init show_version (void) { delay/spacing = latency = (20+2)/3 = 7 (buffers) (rounding up) - The 20us delay assumes that there is no need to touch disk; if we - need touch disk to get buffers we are going to drop frames anyway. - + The 20us delay assumes that there is no need to sleep; if we need to + sleep to get buffers we are going to drop frames anyway. + In fact, each pool should have enough buffers to support the simultaneous reassembly of a separate frame on each VC and cope with - the case in which large frames arrive with round robin cell arrivals - on each VC. - + the case in which frames complete in round robin cell fashion on + each VC. + Only one frame can complete at each cell arrival, so if "n" VCs are open, the worst case is to have them all complete frames together followed by all starting new frames together. - min number of buffers = n + delay/spacing + desired number of buffers = n + delay/spacing These are the extreme requirements, however, they are "n+k" for some "k" so we have only the constant to choose. This is the argument - rx_lats which current defaults at 3. + rx_lats which current defaults to 7. - Actually, "n ? n+k : 0" is better and this is what is implemented. + Actually, "n ? n+k : 0" is better and this is what is implemented, + subject to the limit given by the pool size. 4. Driver locking @@ -202,7 +198,7 @@ static inline void __init show_version (void) { and close functions. There are three reasons for a lock: 1. we need to do atomic rate reservation and release (not used yet), 2. Opening sometimes involves two adapter commands which must not be separated - by another command on the same VC, 3. the changes in RX pool size + by another command on the same VC, 3. the changes to RX pool size must be atomic. The lock needs to work over context switches, so we use a semaphore. @@ -229,12 +225,12 @@ static inline void __init show_version (void) { The PLX likes to prefetch; if reading up to 4 u32 past the end of each TX fragment is not a problem, then TX can be made to go a little faster by passing a flag at init that disables a prefetch - workaround. We do not pass this flag. + workaround. We do not pass this flag. (new microcode only) Now we: - . Note that skb_alloc rounds up size to a 16byte boundary. - . Ensure all areas must not traverse 4MB boundaries. - . Ensure all areas must not start at a E00000xx bus address. + . Note that alloc_skb rounds up size to a 16byte boundary. + . Ensure all areas do not traverse 4MB boundaries. + . Ensure all areas do not start at a E00000xx bus address. (I cannot be certain, but this may always hold with Linux) . Make all failures cause a loud message. . Discard non-conforming SKBs (causes TX failure or RX fill delay). @@ -321,13 +317,15 @@ static unsigned short debug = 0; static unsigned int cmds = 8; static unsigned int txs = 32; static unsigned int rxs[NUM_RX_POOLS] = { 64, 64, 64, 64 }; -static unsigned int rxs_bs[NUM_RX_POOLS] = { 2500, 5000, 10000, 20000 }; +static unsigned int rxs_bs[NUM_RX_POOLS] = { 4080, 12240, 36720, 65535 }; static unsigned int rx_lats = 7; static unsigned char pci_lat = 0; /********** access to adapter **********/ -static inline void wr_mem (const amb_dev * dev, u32 * addr, u32 data) { +static const amb_mem * const mem = 0; + +static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) { u32 be = cpu_to_be32 (data); PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x b[%08x]", addr, data, be); #ifdef AMB_MMIO @@ -337,7 +335,7 @@ static inline void wr_mem (const amb_dev * dev, u32 * addr, u32 data) { #endif } -static inline u32 rd_mem (const amb_dev * dev, u32 * addr) { +static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) { #ifdef AMB_MMIO u32 be = dev->membase[addr - (u32 *) 0]; #else @@ -499,7 +497,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) { } else { // someone fix this (message), please! - PRINTD (DBG_INFO|DBG_RX, "dropped thanks to atm_charge (vc %hu)", vc); + PRINTD (DBG_INFO|DBG_RX, "dropped thanks to atm_charge (vc %hu, truesize %u)", vc, skb->truesize); // drop stats incremented in atm_charge } @@ -755,7 +753,7 @@ static inline void drain_rx_pool (amb_dev * dev, unsigned char pool) { if (rxq->pending > rxq->buffers_wanted) { command cmd; cmd.request = cpu_to_be32 (SRB_FLUSH_BUFFER_Q); - cmd.args.flush.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT); + cmd.args.flush.flags = cpu_to_be32 (pool << SRB_POOL_SHIFT); while (command_do (dev, &cmd)) schedule(); /* the pool may also be emptied via the interrupt handler */ @@ -792,7 +790,7 @@ static inline void fill_rx_pool (amb_dev * dev, unsigned char pool, int priority rxq = &dev->rxq[pool]; while (rxq->pending < rxq->maximum && rxq->pending < rxq->buffers_wanted) { - struct sk_buff * skb = alloc_skb (rxq->buffer_size + RX_FUDGE, priority); + struct sk_buff * skb = alloc_skb (rxq->buffer_size, priority); if (!skb) { PRINTD (DBG_SKB|DBG_POOL, "failed to allocate skb for RX pool %hu", pool); return; @@ -880,11 +878,9 @@ static void interrupt_handler (int irq, void * dev_id, struct pt_regs * pt_regs) while (irq_ok_old != irq_ok && irq_ok < 100) { unsigned char pool; -#ifdef DEBUG_AMBASSADOR - u32 ints = rd_mem (dev, &mem->interrupt); -#endif + PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", + rd_mem (dev, &mem->interrupt), irq_ok); wr_mem (dev, &mem->interrupt, -1); - PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", ints, irq_ok); irq_ok_old = irq_ok; for (pool = 0; pool < NUM_RX_POOLS; ++pool) while (!rx_take (dev, pool)) @@ -970,9 +966,9 @@ static void dont_panic (amb_dev * dev) { /********** make rate (not quite as much fun as Horizon) **********/ static unsigned int make_rate (unsigned int rate, rounding r, - u16 * bits, unsigned int * actual) { - unsigned char exp = 0; /* silence gcc */ - unsigned int man = 0; + u16 * bits, unsigned int * actual) { + unsigned char exp = -1; // hush gcc + unsigned int man = -1; // hush gcc PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate); @@ -987,12 +983,20 @@ static unsigned int make_rate (unsigned int rate, rounding r, // find position of top bit, this gives e // remove top bit and shift (rounding if feeling clever) by 9-e - // XXX fix me to work with larger ints - // ucode bug: please don't set bit 14! 0 not representable - if (rate) { - // non-zero rate + if (rate > 0xffc00000U) { + // larger than largest representable rate + + if (r == round_up) { + return -EINVAL; + } else { + exp = 31; + man = 511; + } + + } else if (rate) { + // representable rate exp = 31; man = rate; @@ -1007,13 +1011,14 @@ static unsigned int make_rate (unsigned int rate, rounding r, // rate = (2^31+(man-2^31))*2^(exp-31) // rate = (1+(man-2^31)/2^31)*2^exp man = man<<1; + man &= 0xffffffffU; // a nop on 32-bit systems // rate = (1+man/2^32)*2^exp // exp is in the range 0 to 31, man is in the range 0 to 2^32-1 // time to lose significance... we want m in the range 0 to 2^9-1 // rounding presents a minor problem... we first decide which way - // we are rounding (based on given rounding direction and the bits - // of the mantissa that are to be discarded). + // we are rounding (based on given rounding direction and possibly + // the bits of the mantissa that are to be discarded). switch (r) { case round_down: { @@ -1026,13 +1031,9 @@ static unsigned int make_rate (unsigned int rate, rounding r, if (man & (-1>>9)) { man = (man>>(32-9)) + 1; if (man == (1<<9)) { - // check for round up outside of range - if (exp == 31) { - return -EINVAL; - } else { - man = 0; - exp += 1; - } + // no need to check for round up outside of range + man = 0; + exp += 1; } } else { man = (man>>(32-9)); @@ -1043,14 +1044,10 @@ static unsigned int make_rate (unsigned int rate, rounding r, // check msb that we are discarding if (man & (1<<(32-9-1))) { man = (man>>(32-9)) + 1; - // if rounding up would go out of range, just stay at top if (man == (1<<9)) { - if (exp == 31) { - man -= 1; - } else { - man = 0; - exp += 1; - } + // no need to check for round up outside of range + man = 0; + exp += 1; } } else { man = (man>>(32-9)); @@ -1060,19 +1057,13 @@ static unsigned int make_rate (unsigned int rate, rounding r, } } else { - // zero rate + // zero rate - not representable - switch (r) { - case round_up: { - break; - } - case round_down: { - return -EINVAL; - break; - } - case round_nearest: { - break; - } + if (r == round_down) { + return -EINVAL; + } else { + exp = 0; + man = 0; } } @@ -1104,18 +1095,17 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { struct atm_trafprm * txtp; struct atm_trafprm * rxtp; u16 tx_rate_bits; - u16 tx_vc_bits = 0; /* silence gcc */ - u16 tx_frame_bits = 0; - // int pcr; + u16 tx_vc_bits = -1; // hush gcc + u16 tx_frame_bits = -1; // hush gcc amb_dev * dev = AMB_DEV(atm_vcc->dev); amb_vcc * vcc; - unsigned char pool = -1; // compiler warning + unsigned char pool = -1; // hush gcc PRINTD (DBG_FLOW|DBG_VCC, "amb_open %x %x", vpi, vci); +#ifdef ATM_VPI_UNSPEC // UNSPEC is deprecated, remove this code eventually -#if defined ATM_VPI_UNSPEC if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); return -EINVAL; @@ -1250,25 +1240,23 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { // RXer on the channel already, just modify rate... cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE); cmd.args.modify_rate.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.modify_rate.rate = cpu_to_be16 (tx_rate_bits); + cmd.args.modify_rate.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT); while (command_do (dev, &cmd)) schedule(); // ... and TX flags, preserving the RX pool cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.modify_flags.flags = cpu_to_be16 - ((AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT) | tx_vc_bits); + cmd.args.modify_flags.flags = cpu_to_be32 + ( (AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT) + | (tx_vc_bits << SRB_FLAGS_SHIFT) ); while (command_do (dev, &cmd)) schedule(); } else { // no RXer on the channel, just open (with pool zero) cmd.request = cpu_to_be32 (SRB_OPEN_VC); cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.open.flags = cpu_to_be16 (tx_vc_bits); - cmd.args.open.rate = cpu_to_be16 (tx_rate_bits); + cmd.args.open.flags = cpu_to_be32 (tx_vc_bits << SRB_FLAGS_SHIFT); + cmd.args.open.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT); while (command_do (dev, &cmd)) schedule(); } @@ -1282,7 +1270,6 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { vcc->rx_info.pool = pool; down (&dev->vcc_sf); - /* grow RX buffer pool */ if (!dev->rxq[pool].buffers_wanted) dev->rxq[pool].buffers_wanted = rx_lats; @@ -1294,16 +1281,15 @@ static int amb_open (struct atm_vcc * atm_vcc, short vpi, int vci) { // switch (from pool zero) to this pool, preserving the TX bits cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.modify_flags.flags = cpu_to_be16 - ((pool << SRB_POOL_SHIFT) | dev->txer[vci].tx_vc_bits); + cmd.args.modify_flags.flags = cpu_to_be32 + ( (pool << SRB_POOL_SHIFT) + | (dev->txer[vci].tx_vc_bits << SRB_FLAGS_SHIFT) ); } else { // no TXer on the channel, open the VC (with no rate info) cmd.request = cpu_to_be32 (SRB_OPEN_VC); cmd.args.open.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used in the next two (BE nightmare continues) - cmd.args.open.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT); - cmd.args.open.rate = cpu_to_be16 (0); + cmd.args.open.flags = cpu_to_be32 (pool << SRB_POOL_SHIFT); + cmd.args.open.rate = cpu_to_be32 (0); } while (command_do (dev, &cmd)) schedule(); @@ -1344,8 +1330,7 @@ static void amb_close (struct atm_vcc * atm_vcc) { // RXer still on the channel, just modify rate... XXX not really needed cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE); cmd.args.modify_rate.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.modify_rate.rate = cpu_to_be16 (0); + cmd.args.modify_rate.rate = cpu_to_be32 (0); // ... and clear TX rate flags (XXX to stop RM cell output?), preserving RX pool } else { // no RXer on the channel, close channel @@ -1370,8 +1355,8 @@ static void amb_close (struct atm_vcc * atm_vcc) { // TXer still on the channel, just go to pool zero XXX not really needed cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS); cmd.args.modify_flags.vc = cpu_to_be32 (vci); // vpi 0 - // only lower 16 bits used (BE nightmare continues) - cmd.args.modify_flags.flags = cpu_to_be16 (dev->txer[vci].tx_vc_bits); + cmd.args.modify_flags.flags = cpu_to_be32 + (dev->txer[vci].tx_vc_bits << SRB_FLAGS_SHIFT); } else { // no TXer on the channel, close the VC cmd.request = cpu_to_be32 (SRB_CLOSE_VC); @@ -1392,7 +1377,6 @@ static void amb_close (struct atm_vcc * atm_vcc) { dev->rxq[pool].buffers_wanted = 0; drain_rx_pool (dev, pool); } - up (&dev->vcc_sf); } @@ -1674,8 +1658,8 @@ static const struct atmdev_ops amb_ops = { amb_open, amb_close, NULL, // no amb_ioctl, - NULL, // amb_getsockopt, - NULL, // amb_setsockopt, + NULL, // no amb_getsockopt, + NULL, // no amb_setsockopt, amb_send, amb_sg_send, NULL, // no send_oam - not in fact used yet @@ -1718,8 +1702,9 @@ static void do_housekeeping (unsigned long arg) { /********** creation of communication queues **********/ -static int create_queues (amb_dev * dev, unsigned int cmds, unsigned int txs, - unsigned int * rxs, unsigned int * rx_buffer_sizes) { +static int __init create_queues (amb_dev * dev, unsigned int cmds, + unsigned int txs, unsigned int * rxs, + unsigned int * rx_buffer_sizes) { unsigned char pool; size_t total = 0; void * memory; @@ -1848,8 +1833,8 @@ static void destroy_queues (amb_dev * dev) { /********** basic loader commands and error handling **********/ -static int do_loader_command (const amb_dev * dev, loader_command cmd, - volatile loader_block * lb) { +static int __init do_loader_command (const amb_dev * dev, loader_command cmd, + volatile loader_block * lb) { // centisecond timeouts - guessing away here unsigned int command_timeouts [] = { @@ -1865,8 +1850,7 @@ static int do_loader_command (const amb_dev * dev, loader_command cmd, [adap_run_in_iram] = 1, [adap_end_download] = 1 }; - -#if 0 /* unused */ + unsigned int command_successes [] = { [host_memory_test] = COMMAND_PASSED_TEST, [read_adapter_memory] = COMMAND_READ_DATA_OK, @@ -1880,11 +1864,14 @@ static int do_loader_command (const amb_dev * dev, loader_command cmd, [adap_run_in_iram] = COMMAND_COMPLETE, [adap_end_download] = COMMAND_COMPLETE }; -#endif - int decode_loader_error (u32 result) { + int decode_loader_result (loader_command cmd, u32 result) { int res; const char * msg; + + if (result == command_successes[cmd]) + return 0; + switch (result) { case BAD_COMMAND: res = -EINVAL; @@ -1937,12 +1924,12 @@ static int do_loader_command (const amb_dev * dev, loader_command cmd, default: res = -EINVAL; msg = "unknown error"; - PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_error got %d=%x !", + PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_result got %d=%x !", result, result); break; } - if (res) - PRINTK (KERN_ERR, "%s", msg); + + PRINTK (KERN_ERR, "%s", msg); return res; } @@ -1967,7 +1954,7 @@ static int do_loader_command (const amb_dev * dev, loader_command cmd, timeout = command_timeouts[cmd] * HZ/100; - while (!lb->result || lb->result == be32_to_cpu (COMMAND_IN_PROGRESS)) + while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS)) if (timeout) { timeout = schedule_timeout (timeout); } else { @@ -1991,25 +1978,14 @@ static int do_loader_command (const amb_dev * dev, loader_command cmd, } return 0; } else { - return decode_loader_error (be32_to_cpu (lb->result)); + return decode_loader_result (cmd, be32_to_cpu (lb->result)); } -#if 0 - if ((res != COMMAND_PASSED_TEST) && - (res != COMMAND_READ_DATA_OK) && - (res != COMMAND_WRITE_DATA_OK) && - (res != COMMAND_COMPLETE)) { - PRINTD (DBG_LOAD|DBG_ERR"startup cmd %d failed with error %08x", - cmd, res); - dump_registers (dev); - return -EIO; - } -#endif } /* loader: determine loader version */ -static int get_loader_version (const amb_dev * dev, u32 * version) { +static int __init get_loader_version (const amb_dev * dev, u32 * version) { loader_block lb; int res; @@ -2025,8 +2001,8 @@ static int get_loader_version (const amb_dev * dev, u32 * version) { /* loader: read or verify memory data blocks */ -static int loader_write (const amb_dev * dev, const u32 * data, - u32 address, unsigned int count) { +static int __init loader_write (const amb_dev * dev, const u32 * data, + u32 address, unsigned int count) { unsigned int i; loader_block lb; transfer_block * tb = &lb.payload.transfer; @@ -2042,8 +2018,8 @@ static int loader_write (const amb_dev * dev, const u32 * data, return do_loader_command (dev, write_adapter_memory, &lb); } -static int loader_verify (const amb_dev * dev, const u32 * data, - u32 address, unsigned int count) { +static int __init loader_verify (const amb_dev * dev, const u32 * data, + u32 address, unsigned int count) { unsigned int i; loader_block lb; transfer_block * tb = &lb.payload.transfer; @@ -2065,7 +2041,7 @@ static int loader_verify (const amb_dev * dev, const u32 * data, return res; } -static int loader_start (const amb_dev * dev, u32 address) { +static int __init loader_start (const amb_dev * dev, u32 address) { loader_block lb; PRINTD (DBG_FLOW|DBG_LOAD, "loader_start"); @@ -2139,7 +2115,7 @@ static int amb_reset (amb_dev * dev, int diags) { /********** transfer and start the microcode **********/ -static int ucode_init (amb_dev * dev) { +static int __init ucode_init (amb_dev * dev) { unsigned int i = 0; unsigned int total = 0; const u32 * pointer = ucode_data; @@ -2185,7 +2161,7 @@ static int ucode_init (amb_dev * dev) { /********** give adapter parameters **********/ -static int amb_talk (amb_dev * dev) { +static int __init amb_talk (amb_dev * dev) { adap_talk_block a; unsigned char pool; unsigned long timeout; @@ -2238,7 +2214,7 @@ static int amb_talk (amb_dev * dev) { } // get microcode version -static void amb_ucode_version (amb_dev * dev) { +static void __init amb_ucode_version (amb_dev * dev) { u32 major; u32 minor; command cmd; @@ -2251,11 +2227,11 @@ static void amb_ucode_version (amb_dev * dev) { } // get end station address -static void amb_esi (amb_dev * dev, u8 * esi) { +static void __init amb_esi (amb_dev * dev, u8 * esi) { u32 lower4; u16 upper2; command cmd; - + // swap bits within byte to get Ethernet ordering u8 bit_swap (u8 byte) { const u8 swap[] = { @@ -2266,14 +2242,14 @@ static void amb_esi (amb_dev * dev, u8 * esi) { }; return ((swap[byte & 0xf]<<4) | swap[byte>>4]); } - + cmd.request = cpu_to_be32 (SRB_GET_BIA); while (command_do (dev, &cmd)) schedule(); lower4 = be32_to_cpu (cmd.args.bia.lower4); upper2 = be32_to_cpu (cmd.args.bia.upper2); PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2); - + if (esi) { unsigned int i; @@ -2292,7 +2268,7 @@ static void amb_esi (amb_dev * dev, u8 * esi) { return; } -static int amb_init (amb_dev * dev) { +static int __init amb_init (amb_dev * dev) { u32 version; /* enable adapter doorbell */ @@ -2381,8 +2357,8 @@ static int __init amb_probe (void) { #endif // semaphore for txer/rxer modifications - we cannot use a - // spinlock as the critical region needs to process switches - init_MUTEX(&dev->vcc_sf); + // spinlock as the critical region needs to switch processes + init_MUTEX (&dev->vcc_sf); // queue manipulation spinlocks; we want atomic reads and // writes to the queue descriptors (handles IRQ and SMP) // consider replacing "int pending" -> "atomic_t available" @@ -2619,8 +2595,6 @@ void cleanup_module (void) { int __init amb_detect (void) { int devs; - PRINTD (DBG_FLOW|DBG_INIT, "init_module"); - // sanity check - cast needed as printk does not support %Zu if (sizeof(amb_mem) != 4*16 + 4*12) { PRINTK (KERN_ERR, "Fix amb_mem (is %lu words).", diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h index c9742a7e9..93e458644 100644 --- a/drivers/atm/ambassador.h +++ b/drivers/atm/ambassador.h @@ -20,11 +20,6 @@ system and in the file COPYING in the Linux kernel source. */ -/* - IMPORTANT NOTE: Madge Networks does not license the microcode for - this driver under the GPL. See the .data file for the licence. -*/ - #ifndef AMBASSADOR_H #define AMBASSADOR_H @@ -117,9 +112,6 @@ // minimum RX buffers required to cope with replenishing delay #define MIN_RX_BUFFERS 1 -// RX buffer tailroom to cope with writing too much -#define RX_FUDGE 3 - // minimum PCI latency we will tolerate (32 IS TOO SMALL) #define MIN_PCI_LATENCY 64 // 255 @@ -217,7 +209,9 @@ /* RxPool2: 0x0040 */ /* RxPool3: 0x0060 */ -#define SRB_POOL_SHIFT 5 +#define SRB_RATE_SHIFT 16 +#define SRB_POOL_SHIFT (SRB_FLAGS_SHIFT+5) +#define SRB_FLAGS_SHIFT 16 #define SRB_STOP_TASKING 19 #define SRB_START_TASKING 20 @@ -339,8 +333,6 @@ typedef struct { u32 reset_control; } amb_mem; -#define mem ((amb_mem *)0) - /* IRQ (card to host) and doorbell (host to card) enable bits */ #define AMB_INTERRUPT_BITS 0x00030000 #define AMB_DOORBELL_BITS 0x00000300 @@ -435,12 +427,10 @@ typedef struct { typedef struct { u32 handle; - // really? what about a BE host? u16 vc; u16 next_descriptor_length; u32 next_descriptor; #ifdef AMB_NEW_MICROCODE - // BE host? u8 cpcs_uu; u8 cpi; u16 pad; @@ -463,7 +453,6 @@ typedef union { /* this "points" to the sequence of fragments and trailer */ typedef struct { - // what about a BE host? u16 vc; u16 tx_descr_length; u32 tx_descr_addr; @@ -483,7 +472,6 @@ typedef struct { typedef struct { u32 handle; - // what about a BE host? u16 vc; u16 lec_id; // unused u16 status; @@ -526,7 +514,6 @@ typedef struct { u32 buffer_size; /* size of host buffer */ } rec_struct[NUM_RX_POOLS]; #ifdef AMB_NEW_MICROCODE - // BE? u16 init_flags; u16 talk_block_spare; #endif @@ -538,7 +525,6 @@ typedef struct { GET_SUNI_STATS */ typedef struct { - // what about a BE host? u8 racp_chcs; u8 racp_uhcs; u16 spare; diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 869b67ca2..edd2ea1cc 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -1,13 +1,13 @@ /* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ -/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */ #include +#include #include #include #include -#include "../../net/atm/tunable.h" /* @@@ fix this */ #include "../../net/atm/protocols.h" /* @@@ fix this */ @@ -26,6 +26,75 @@ struct atmtcp_dev_data { #define MAX_VCI_BITS 16 +/* + * Hairy code ahead: the control VCC may be closed while we're still + * waiting for an answer, so we need to re-validate out_vcc every once + * in a while. + */ + + +static int atmtcp_send_control(struct atm_vcc *vcc,int type, + const struct atmtcp_control *msg,unsigned short flag) +{ + struct atm_vcc *out_vcc; + struct sk_buff *skb; + struct atmtcp_control *new_msg; + unsigned short old_flags; + + out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; + if (!out_vcc) return -EUNATCH; + skb = alloc_skb(sizeof(*msg),GFP_KERNEL); + if (!skb) return -ENOMEM; + mb(); + out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; + if (!out_vcc) { + dev_kfree_skb(skb); + return -EUNATCH; + } + atm_force_charge(out_vcc,skb->truesize); + new_msg = (struct atmtcp_control *) skb_put(skb,sizeof(*new_msg)); + *new_msg = *msg; + new_msg->hdr.length = ATMTCP_HDR_MAGIC; + new_msg->type = type; + new_msg->vcc = (unsigned long) vcc; + old_flags = vcc->flags; + out_vcc->push(out_vcc,skb); + while (!((vcc->flags ^ old_flags) & flag)) { + mb(); + out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; + if (!out_vcc) return -EUNATCH; + sleep_on(&vcc->sleep); + + } + return 0; +} + + +static int atmtcp_recv_control(const struct atmtcp_control *msg) +{ + struct atm_vcc *vcc = (struct atm_vcc *) msg->vcc; + + vcc->vpi = msg->addr.sap_addr.vpi; + vcc->vci = msg->addr.sap_addr.vci; + vcc->qos = msg->qos; + vcc->reply = msg->result; + switch (msg->type) { + case ATMTCP_CTRL_OPEN: + vcc->flags ^= ATM_VF_READY; + break; + case ATMTCP_CTRL_CLOSE: + vcc->flags ^= ATM_VF_ADDR; + break; + default: + printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n", + msg->type); + return -EINVAL; + } + wake_up(&vcc->sleep); + return 0; +} + + static void atmtcp_v_dev_close(struct atm_dev *dev) { MOD_DEC_USE_COUNT; @@ -34,21 +103,38 @@ static void atmtcp_v_dev_close(struct atm_dev *dev) static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci) { + struct atmtcp_control msg; int error; - error = atm_find_ci(vcc,&vpi,&vci); + memset(&msg,0,sizeof(msg)); + msg.addr.sap_family = AF_ATMPVC; + msg.hdr.vpi = htons(vpi); + msg.addr.sap_addr.vpi = vpi; + msg.hdr.vci = htons(vci); + msg.addr.sap_addr.vci = vci; + error = atm_find_ci(vcc,&msg.addr.sap_addr.vpi,&msg.addr.sap_addr.vci); if (error) return error; - vcc->vpi = vpi; - vcc->vci = vci; if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; - vcc->flags |= ATM_VF_ADDR | ATM_VF_READY; - return 0; + msg.type = ATMTCP_CTRL_OPEN; + msg.qos = vcc->qos; + vcc->flags |= ATM_VF_ADDR; + vcc->flags &= ~ATM_VF_READY; /* just in case ... */ + error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY); + if (error) return error; + return vcc->reply; } static void atmtcp_v_close(struct atm_vcc *vcc) { - vcc->flags &= ~(ATM_VF_READY | ATM_VF_ADDR); + struct atmtcp_control msg; + + memset(&msg,0,sizeof(msg)); + msg.addr.sap_family = AF_ATMPVC; + msg.addr.sap_addr.vpi = vcc->vpi; + msg.addr.sap_addr.vci = vcc->vci; + vcc->flags &= ~ATM_VF_READY; + (void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR); } @@ -89,12 +175,7 @@ static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) return -ENOLINK; } size = skb->len+sizeof(struct atmtcp_hdr); - if (!atm_charge(out_vcc,atm_pdu2truesize(size))) new_skb = NULL; - else { - new_skb = alloc_skb(size,GFP_ATOMIC); - if (!new_skb) - atm_return(out_vcc,atm_pdu2truesize(size)); - } + new_skb = atm_alloc_charge(out_vcc,size,GFP_ATOMIC); if (!new_skb) { if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); @@ -128,14 +209,18 @@ static void atmtcp_c_close(struct atm_vcc *vcc) { struct atm_dev *atmtcp_dev; struct atmtcp_dev_data *dev_data; + struct atm_vcc *walk; atmtcp_dev = (struct atm_dev *) vcc->dev_data; dev_data = PRIV(atmtcp_dev); dev_data->vcc = NULL; if (dev_data->persist) return; + PRIV(atmtcp_dev) = NULL; kfree(dev_data); shutdown_atm_dev(atmtcp_dev); vcc->dev_data = NULL; + for (walk = atmtcp_dev->vccs; walk; walk = walk->next) + wake_up(&walk->sleep); } @@ -145,37 +230,38 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) struct atmtcp_hdr *hdr; struct atm_vcc *out_vcc; struct sk_buff *new_skb; + int result = 0; if (!skb->len) return 0; dev = vcc->dev_data; - hdr = (void *) skb->data; + hdr = (struct atmtcp_hdr *) skb->data; + if (hdr->length == ATMTCP_HDR_MAGIC) { + result = atmtcp_recv_control( + (struct atmtcp_control *) skb->data); + goto done; + } for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next) if (out_vcc->vpi == ntohs(hdr->vpi) && out_vcc->vci == ntohs(hdr->vci) && out_vcc->qos.rxtp.traffic_class != ATM_NONE) break; if (!out_vcc) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); vcc->stats->tx_err++; - return 0; + goto done; } skb_pull(skb,sizeof(struct atmtcp_hdr)); - if (!atm_charge(out_vcc,atm_pdu2truesize(skb->len))) new_skb = NULL; - else { - new_skb = alloc_skb(skb->len,GFP_KERNEL); - if (!new_skb) atm_return(out_vcc,atm_pdu2truesize(skb->len)); - } + new_skb = atm_alloc_charge(out_vcc,skb->len,GFP_KERNEL); if (!new_skb) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return -ENOBUFS; + result = -ENOBUFS; + goto done; } + new_skb->stamp = xtime; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); + out_vcc->push(out_vcc,new_skb); +done: if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); - out_vcc->push(out_vcc,new_skb); - return 0; + return result; } @@ -323,8 +409,12 @@ int init_module(void) return 0; } + void cleanup_module(void) { + atm_tcp_ops.attach = NULL; + atm_tcp_ops.create_persistent = NULL; + atm_tcp_ops.remove_persistent = NULL; } #else @@ -336,4 +426,3 @@ struct atm_tcp_ops atm_tcp_ops = { }; #endif - diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index e333faab1..18c7cb35f 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -522,11 +522,7 @@ static int rx_aal0(struct atm_vcc *vcc) else { length = ATM_CELL_SIZE-1; /* no HEC */ } - if (!length || !atm_charge(vcc,atm_pdu2truesize(length))) skb = NULL; - else { - skb = alloc_skb(length,GFP_ATOMIC); - if (!skb) atm_return(vcc,atm_pdu2truesize(length)); - } + skb = length ? atm_alloc_charge(vcc,length,GFP_ATOMIC) : NULL; if (!skb) { discard(vcc,length >> 2); return 0; @@ -596,16 +592,7 @@ static int rx_aal5(struct atm_vcc *vcc) vcc->stats->rx_err++; } } - if (!eff || !atm_charge(vcc,atm_pdu2truesize(eff << 2))) skb = NULL; - else { - skb = alloc_skb(eff << 2,GFP_ATOMIC); - if (!skb) { - EVENT("peek reject (eff << 2=%ld)\n",eff << 2,0); - DPRINTK(DEV_LABEL "(itf %d): peek reject for %ld " - "bytes\n",vcc->dev->number,eff << 2); - atm_return(vcc,atm_pdu2truesize(eff << 2)); - } - } + skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL; if (!skb) { discard(vcc,size); return 0; diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 3a6538bcc..17a6b418f 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -50,9 +50,9 @@ #define maintainer_string "Giuliano Procida at Madge Networks " #define description_string "Madge ATM Horizon [Ultra] driver" -#define version_string "1.1" +#define version_string "1.2" -static void __init show_version (void) { +static inline void __init show_version (void) { printk ("%s version %s\n", description_string, version_string); } @@ -86,7 +86,7 @@ static void __init show_version (void) { The driver is only known to work with SONET and UTP Horizon Ultra cards at 155Mb/s. However, code is in place to deal with both the - original Horizon and 35Mb/s. + original Horizon and 25Mb/s operation. There are two revisions of the Horizon ASIC: the original and the Ultra. Details of hardware bugs are in section III. @@ -127,15 +127,15 @@ static void __init show_version (void) { 3. Initialisation - The card is reset and then put into a know state. The physical layer - is configured for normal operation at the appropriate speed; in the - case of the 155 cards, the framer is initialised with line-based - timing; the internal RAM is zeroed and the allocation of buffers for - RX and TX is made; the Burnt In Address is read and copied to the - ATM ESI; various policy settings for RX (VPI bits, unknown VCs, oam - cells) are made. Ideally all policy items should be configurable at - module load (if not actually on-demand), however, only the vpi vs - vci bit allocation can be specified at insmod. + The card is reset and then put into a known state. The physical + layer is configured for normal operation at the appropriate speed; + in the case of the 155 cards, the framer is initialised with + line-based timing; the internal RAM is zeroed and the allocation of + buffers for RX and TX is made; the Burnt In Address is read and + copied to the ATM ESI; various policy settings for RX (VPI bits, + unknown VCs, oam cells) are made. Ideally all policy items should be + configurable at module load (if not actually on-demand), however, + only the vpi vs vci bit allocation can be specified at insmod. 4. Shutdown @@ -152,12 +152,12 @@ static void __init show_version (void) { the following items they make up the traffic specification. struct atm_trafprm { - unsigned char traffic_class; traffic class (ATM_UBR, ...) - int max_pcr; maximum PCR in cells per second - int pcr; desired PCR in cells per second - int min_pcr; minimum PCR in cells per second - int max_cdv; maximum CDV in microseconds - int max_sdu; maximum SDU in bytes + unsigned char traffic_class; traffic class (ATM_UBR, ...) + int max_pcr; maximum PCR in cells per second + int pcr; desired PCR in cells per second + int min_pcr; minimum PCR in cells per second + int max_cdv; maximum CDV in microseconds + int max_sdu; maximum SDU in bytes }; Note that these denote bandwidth available not bandwidth used; the @@ -206,30 +206,31 @@ static void __init show_version (void) { AAL types are: - ATM_NO_AAL AAL not specified - ATM_AAL0 "raw" ATM cells - ATM_AAL1 AAL1 (CBR) - ATM_AAL2 AAL2 (VBR) - ATM_AAL34 AAL3/4 (data) - ATM_AAL5 AAL5 (data) - ATM_SAAL signaling AAL + ATM_NO_AAL AAL not specified + ATM_AAL0 "raw" ATM cells + ATM_AAL1 AAL1 (CBR) + ATM_AAL2 AAL2 (VBR) + ATM_AAL34 AAL3/4 (data) + ATM_AAL5 AAL5 (data) + ATM_SAAL signaling AAL The Horizon has support for AAL frame types: 0, 3/4 and 5. However, it does not implement AAL 3/4 SAR and it has a different notion of "raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are supported by this driver. - The Horizon has (TX) support for ABR (including UBR), VBR and CBR. - Each TX channel has a bucket (containing up to 31 cell units) and - two timers (PCR and SCR) associated with it that can be used to - govern cell emissions and host notification (in the case of - ABR). The timers may either be disabled or may be set to any of 240 - values (determined by the clock crystal, a fixed (?) per-device - divider, a configurable divider and a configurable timer preload - value). + The Horizon has limited support for ABR (including UBR), VBR and + CBR. Each TX channel has a bucket (containing up to 31 cell units) + and two timers (PCR and SCR) associated with it that can be used to + govern cell emissions and host notification (in the case of ABR this + is presumably so that RM cells may be emitted at appropriate times). + The timers may either be disabled or may be set to any of 240 values + (determined by the clock crystal, a fixed (?) per-device divider, a + configurable divider and a configurable timer preload value). - At the moment only UBR and CBR are supported by the driver. This is - due to my not understanding ATM Linux VBR or Horizon's VBR support. + At the moment only UBR and CBR are supported by the driver. VBR will + be supported as soon as ATM for Linux supports it. ABR support is + very unlikely as RM cell handling is completely up to the driver. 1. TX (TX channel setup and TX transfer) @@ -305,7 +306,7 @@ static void __init show_version (void) { in the TX direction on the original Horizon. More complicated solutions are likely to hurt my brain. - 3. Loss of buffer on close VC + 2. Loss of buffer on close VC When a VC is being closed, the buffer associated with it is not returned to the pool. The host must store the reference to this @@ -314,7 +315,7 @@ static void __init show_version (void) { The host intervention currently consists of stacking such a buffer pointer at VC close and checking the stack at VC open. - 4. Failure to close a VC + 3. Failure to close a VC If a VC is currently receiving a frame then closing the VC may fail and the frame continues to be received. @@ -322,7 +323,7 @@ static void __init show_version (void) { The solution is to make sure any received frames are flushed when ready. This is currently done just before the solution to 3. - 5. PCI bus (original Horizon only, fixed in Ultra) + 4. PCI bus (original Horizon only, fixed in Ultra) Reading from the data port prior to initialisation will hang the PCI bus. Just don't do that then! We don't. @@ -388,10 +389,9 @@ static inline void rds_regb (const hrz_dev * dev, unsigned char reg, void * addr insb (dev->iobase + reg, addr, len); } -/* Read / Write to a given address in Horizon buffer memory. */ -// Interrupts must be disabled between the address register and data port -// accesses as these must form an atomic operation. - +/* Read / Write to a given address in Horizon buffer memory. + Interrupts must be disabled between the address register and data + port accesses as these must form an atomic operation. */ static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) { // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr); wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); @@ -401,7 +401,7 @@ static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) { static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) { // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr); wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); - return rd_regl(dev, MEMORY_PORT_OFF); + return rd_regl (dev, MEMORY_PORT_OFF); } static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) { @@ -511,7 +511,7 @@ static inline void dump_framer (hrz_dev * dev) { /* RX channels are 10 bit integers, these fns are quite paranoid */ -static inline int channel_to_vpci (const u16 channel, short * vpi, int * vci) { +static inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) { unsigned short vci_bits = 10 - vpi_bits; if ((channel & RX_CHANNEL_MASK) == channel) { *vci = channel & ((~0)<mem_lock, flags); wr_mem (dev, &rx_desc->wr_buf_type, - buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME); + buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME); if (buf_ptr != RX_CHANNEL_IDLE) wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr); spin_unlock_irqrestore (&dev->mem_lock, flags); - // rxer->rate = make_rate (qos->peak_cells); + // rxer->rate = make_rate (qos->peak_cells); PRINTD (DBG_FLOW, "hrz_open_rx ok"); @@ -1340,12 +1340,12 @@ static inline void rx_data_av_handler (hrz_dev * dev) { if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { - + struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC); + // If everyone has to call atm_pdu2... why isn't it part of // atm_charge? B'cos some people already have skb->truesize! - if (atm_charge (atm_vcc, atm_pdu2truesize (rx_len))) { - - struct sk_buff * skb = alloc_skb (rx_len, GFP_ATOMIC); + // WA: well. even if they think they do, they might not ... :-) + if (skb) { // remember this so we can push it later dev->rx_skb = skb; @@ -1369,15 +1369,8 @@ static inline void rx_data_av_handler (hrz_dev * dev) { return; } else { - PRINTD (DBG_SKB|DBG_WARN, "failed to get skb"); - atm_vcc->stats->rx_drop++; + PRINTD (DBG_INFO, "failed to get skb"); } - - } else { - // someone fix this (message), please! - PRINTD (DBG_INFO, "dropped thanks to atm_charge"); - // drop stats incremented in atm_charge - } } else { PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel); @@ -1385,7 +1378,7 @@ static inline void rx_data_av_handler (hrz_dev * dev) { } } else { - PRINTK (KERN_WARNING, "dropped over-size frame"); + PRINTK (KERN_WARNING, "dropped over-size frame"); // do we count this? } @@ -1573,7 +1566,7 @@ static inline short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { vcc->tx_pcr_bits); #if 0 - if (a vbr channel) { + if (vcc->tx_xbr_bits == VBR_RATE_TYPE) { // SCR timer update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS, vcc->tx_scr_bits); @@ -1584,9 +1577,9 @@ static inline short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { // ... and fullness update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS, - vcc->tx_bucket_bits); + vcc->tx_bucket_bits); } -#endif +#endif // Initialise the read and write buffer pointers rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK; @@ -1723,7 +1716,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { free_buffers, buffers_required); // what is the appropriate delay? implement a timeout? (depending on line speed?) // mdelay (1); - // what happens if kill (current_pid, SIGKILL) ? + // what happens if we kill (current_pid, SIGKILL) ? schedule(); if (++spin_count > 1000) { PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d", @@ -1743,7 +1736,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel) if (dev->tx_channel_record[tx_channel] == channel) { PRINTD (DBG_TX, "vc already on channel: hit"); - break; + break; } if (tx_channel == TX_CHANS) { PRINTD (DBG_TX, "vc already on channel: miss"); @@ -1802,7 +1795,7 @@ static int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { /********** reset a card **********/ -static void __init hrz_reset_card (const hrz_dev * dev) { +static void __init hrz_reset (const hrz_dev * dev) { u32 control_0_reg = rd_regl (dev, CONTROL_0_REG); // why not set RESET_HORIZON to one and wait for the card to @@ -1813,7 +1806,7 @@ static void __init hrz_reset_card (const hrz_dev * dev) { control_0_reg = rd_regl (dev, CONTROL_0_REG); // old reset code retained: - wr_regl (dev, CONTROL_0_REG, control_0_reg | + wr_regl (dev, CONTROL_0_REG, control_0_reg | RESET_ATM | RESET_RX | RESET_TX | RESET_HOST); // just guessing here udelay (1000); @@ -1821,18 +1814,6 @@ static void __init hrz_reset_card (const hrz_dev * dev) { wr_regl (dev, CONTROL_0_REG, control_0_reg); } -/********** shutdown a card **********/ - -#ifdef MODULE - -static void hrz_shutdown (const hrz_dev * dev) { - hrz_reset_card (dev); - - GREEN_LED_OFF(dev); -} - -#endif - /********** read the burnt in address **********/ static u16 __init read_bia (const hrz_dev * dev, u16 addr) { @@ -1931,7 +1912,7 @@ static int __init hrz_init (hrz_dev * dev) { // Reset the card to get everything in a known state printk (" reset"); - hrz_reset_card (dev); + hrz_reset (dev); // Clear all the buffer memory @@ -2105,9 +2086,9 @@ static int __init hrz_init (hrz_dev * dev) { for (i=0; i < ESI_LEN; ++i) { if (i % 2 == 0) - b = read_bia (dev, i/2 + 2); + b = read_bia (dev, i/2 + 2); else - b = b >> 8; + b = b >> 8; esi[i] = b & 0xFF; printk ("%02x", esi[i]); } @@ -2199,8 +2180,8 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { hrz_vcc * vccp; // allocated late PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci); +#ifdef ATM_VPI_UNSPEC // UNSPEC is deprecated, remove this code eventually -#if defined ATM_VPI_UNSPEC if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); return -EINVAL; @@ -2215,7 +2196,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { } PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci); - error = vpci_to_channel (&channel, vpi, vci); + error = vpivci_to_channel (&channel, vpi, vci); if (error) { PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci); return error; @@ -2459,7 +2440,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { // slight race (no locking) here so we may get -EAGAIN // later; the greedy bastards would deserve it :) PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); - pcr = dev->tx_avail; + pcr = dev->rx_avail; } else if (pcr < 0) { pcr = -pcr; } @@ -2472,14 +2453,15 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { } break; } +#if 0 case ATM_VBR: { - // int scr = atm_scr_goal (txtp); + // int scr = atm_scr_goal (rxtp); int scr = 1<<16; // just for fun if (!scr) { // slight race (no locking) here so we may get -EAGAIN // later; the greedy bastards would deserve it :) PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); - scr = dev->tx_avail; + scr = dev->rx_avail; } else if (scr < 0) { scr = -scr; } @@ -2492,6 +2474,7 @@ static int hrz_open (struct atm_vcc * atm_vcc, short vpi, int vci) { } break; } +#endif default: { PRINTD (DBG_QOS, "unsupported RX traffic class"); return -EINVAL; @@ -2632,8 +2615,10 @@ static void hrz_close (struct atm_vcc * atm_vcc) { MOD_DEC_USE_COUNT; } +#if 0 static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, void *optval, int optlen) { + hrz_dev * dev = HRZ_DEV(atm_vcc->dev); PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt"); switch (level) { case SOL_SOCKET: @@ -2655,6 +2640,7 @@ static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, void *optval, int optlen) { + hrz_dev * dev = HRZ_DEV(atm_vcc->dev); PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt"); switch (level) { case SOL_SOCKET: @@ -2673,6 +2659,7 @@ static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, } return -EINVAL; } +#endif static int hrz_sg_send (struct atm_vcc * atm_vcc, unsigned long start, @@ -2722,15 +2709,15 @@ static int hrz_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) { /* more diagnostics here? */ #if 0 - { - // VBR temporary diags + if (!left--) { + unsigned int count = sprintf (page, "vbr buckets:"); unsigned int i; - for (i = 0; i < TX_CHANS; ++i) { - if (!left--) - return sprintf (page, "bucket %u: %u/%u\n", i, + for (i = 0; i < TX_CHANS; ++i) + count += sprintf (page, " %u/%u", query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS), query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS)); - } + count += sprintf (page+count, ".\n"); + return count; } #endif @@ -2760,8 +2747,8 @@ static const struct atmdev_ops hrz_ops = { hrz_open, hrz_close, NULL, // no hrz_ioctl - hrz_getsockopt, - hrz_setsockopt, + NULL, // hrz_getsockopt, + NULL, // hrz_setsockopt, hrz_send, hrz_sg_send, NULL, // no send_oam - not in fact used yet @@ -2811,10 +2798,10 @@ static int __init hrz_probe (void) { // grab IRQ and install handler - move this someplace more sensible if (request_irq (irq, - interrupt_handler, - SA_SHIRQ, /* irqflags guess */ - DEV_LABEL, /* name guess */ - dev)) { + interrupt_handler, + SA_SHIRQ, /* irqflags guess */ + DEV_LABEL, /* name guess */ + dev)) { PRINTD (DBG_WARN, "request IRQ failed!"); // free_irq is at "endif" } else { @@ -2824,20 +2811,20 @@ static int __init hrz_probe (void) { dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0); if (!(dev->atm_dev)) { - PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); + PRINTD (DBG_ERR, "failed to register Madge ATM adapter"); } else { unsigned char lat; - PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", + PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; - dev->pci_dev = pci_dev; - - /* XXX DEV_LABEL is a guess */ - request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL); + dev->atm_dev->dev_data = (void *) dev; + dev->pci_dev = pci_dev; + + /* XXX DEV_LABEL is a guess */ + request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL); - // enable bus master accesses - pci_set_master (pci_dev); + // enable bus master accesses + pci_set_master (pci_dev); // frobnicate latency (upwards, usually) pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat); @@ -2851,9 +2838,9 @@ static int __init hrz_probe (void) { pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); } - dev->iobase = iobase; - dev->irq = irq; - dev->membase = membase; + dev->iobase = iobase; + dev->irq = irq; + dev->membase = membase; dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0]; dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1]; @@ -2882,13 +2869,13 @@ static int __init hrz_probe (void) { } dev->flags = 0; - + // Allocate cell rates and remember ASIC version // Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 // Copper: (WRONG) we want 6 into the above, close to 25Mb/s // Copper: (plagarise!) 25600000/8/270*260/53 - n/53 - if (hrz_init (dev)) { + if (hrz_init (dev)) { // to be really pedantic, this should be ATM_OC3c_PCR dev->tx_avail = ATM_OC3_PCR; dev->rx_avail = ATM_OC3_PCR; @@ -2906,21 +2893,25 @@ static int __init hrz_probe (void) { // writes to adapter memory (handles IRQ and SMP) spin_lock_init (&dev->mem_lock); - init_waitqueue_head(&dev->tx_queue); - - // vpi in 0..4, vci in 6..10 - dev->atm_dev->ci_range.vpi_bits = vpi_bits; - dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; - - // update count and linked list +#if LINUX_VERSION_CODE >= 0x20303 + init_waitqueue_head (&dev->tx_queue); +#else + dev->tx_queue = 0; +#endif + + // vpi in 0..4, vci in 6..10 + dev->atm_dev->ci_range.vpi_bits = vpi_bits; + dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; + + // update count and linked list ++devs; - dev->prev = hrz_devs; - hrz_devs = dev; + dev->prev = hrz_devs; + hrz_devs = dev; // success - continue; - - /* not currently reached */ - atm_dev_deregister (dev->atm_dev); + continue; + + /* not currently reached */ + atm_dev_deregister (dev->atm_dev); } /* atm_dev_register */ free_irq (irq, dev); } /* request_irq */ @@ -2943,11 +2934,11 @@ static void __init hrz_check_args (void) { if (max_tx_size > TX_AAL5_LIMIT) PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu", - max_tx_size = TX_AAL5_LIMIT); + max_tx_size = TX_AAL5_LIMIT); if (max_rx_size > RX_AAL5_LIMIT) PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu", - max_rx_size = RX_AAL5_LIMIT); + max_rx_size = RX_AAL5_LIMIT); return; } @@ -3016,7 +3007,7 @@ void cleanup_module (void) { hrz_devs = dev->prev; PRINTD (DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); - hrz_shutdown (dev); + hrz_reset (dev); atm_dev_deregister (dev->atm_dev); free_irq (dev->irq, dev); release_region (dev->iobase, HRZ_IO_EXTENT); diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h index f05f44115..be5e5c726 100644 --- a/drivers/atm/horizon.h +++ b/drivers/atm/horizon.h @@ -32,6 +32,9 @@ #include +#include + + #ifdef CONFIG_ATM_HORIZON_DEBUG #define DEBUG_HORIZON #endif @@ -41,7 +44,7 @@ #ifndef PCI_VENDOR_ID_MADGE #define PCI_VENDOR_ID_MADGE 0x10B6 #endif -#ifndef PCI_VENDOR_ID_MADGE_HORIZON +#ifndef PCI_DEVICE_ID_MADGE_HORIZON #define PCI_DEVICE_ID_MADGE_HORIZON 0x1000 #endif @@ -375,8 +378,6 @@ typedef struct MEMMAP { #define memmap ((MEMMAP *)0) -#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0) - /* end horizon specific bits */ typedef enum { @@ -423,7 +424,11 @@ struct hrz_dev { unsigned int tx_regions; // number of remaining regions spinlock_t mem_lock; +#if LINUX_VERSION_CODE >= 0x20303 wait_queue_head_t tx_queue; +#else + struct wait_queue * tx_queue; +#endif u8 irq; u8 flags; @@ -466,6 +471,8 @@ typedef struct hrz_dev hrz_dev; /* macros for use later */ +#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0) + #define INTERESTING_INTERRUPTS \ (RX_DATA_AV | RX_DISABLED | TX_BUS_MASTER_COMPLETE | RX_BUS_MASTER_COMPLETE) diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 895071d4e..97c768ace 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -252,8 +252,7 @@ int init_module(void) #endif /* PHY_LOOPBACK */ XPRINTK("nicstar: init_module() returned.\n"); - ns_timer.next = NULL; - ns_timer.prev = NULL; + init_timer(&ns_timer); ns_timer.expires = jiffies + NS_POLL_PERIOD; ns_timer.data = 0UL; ns_timer.function = ns_poll; @@ -383,6 +382,11 @@ int __init nicstar_detect(void) #endif /* PHY_LOOPBACK */ XPRINTK("nicstar: init_module() returned.\n"); + init_timer(&ns_timer); + ns_timer.expires = jiffies + NS_POLL_PERIOD; + ns_timer.data = 0UL; + ns_timer.function = ns_poll; + add_timer(&ns_timer); return i; } @@ -845,21 +849,6 @@ static int ns_init_card(int i, struct pci_dev *pcidev) ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; card->efbie = 1; - writel(NS_CFG_RXPATH | - NS_CFG_SMBUFSIZE | - NS_CFG_LGBUFSIZE | - NS_CFG_EFBIE | - NS_CFG_RSQSIZE | - NS_CFG_VPIBITS | - ns_cfg_rctsize | - NS_CFG_RXINT_NODELAY | - NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ - NS_CFG_RSQAFIE | - NS_CFG_TXEN | - NS_CFG_TXIE | - NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ - NS_CFG_PHYIE, - card->membase + CFG); /* Register device */ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL); @@ -884,6 +873,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev) card->atmdev->ci_range.vci_bits = card->vcibits; card->atmdev->link_rate = card->max_pcr; + card->atmdev->phy = NULL; #ifdef CONFIG_ATM_NICSTAR_USE_SUNI if (card->max_pcr == ATM_OC3_PCR) { suni_init(card->atmdev); @@ -896,6 +886,22 @@ static int ns_init_card(int i, struct pci_dev *pcidev) if (card->atmdev->phy && card->atmdev->phy->start) card->atmdev->phy->start(card->atmdev); + writel(NS_CFG_RXPATH | + NS_CFG_SMBUFSIZE | + NS_CFG_LGBUFSIZE | + NS_CFG_EFBIE | + NS_CFG_RSQSIZE | + NS_CFG_VPIBITS | + ns_cfg_rctsize | + NS_CFG_RXINT_NODELAY | + NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ + NS_CFG_RSQAFIE | + NS_CFG_TXEN | + NS_CFG_TXIE | + NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ + NS_CFG_PHYIE, + card->membase + CFG); + num_cards++; return error; @@ -1132,10 +1138,10 @@ static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, save_flags(flags); cli(); while (CMD_BUSY(card)); - writel(handle1, card->membase + DR0); - writel(addr1, card->membase + DR1); - writel(handle2, card->membase + DR2); writel(addr2, card->membase + DR3); + writel(handle2, card->membase + DR2); + writel(addr1, card->membase + DR1); + writel(handle1, card->membase + DR0); writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD); restore_flags(flags); @@ -3010,7 +3016,7 @@ static short ns_h2i(char c) { if (c >= '0' && c <= '9') return (short) (c - '0'); - if (c >= 'A' && c <= 'A') + if (c >= 'A' && c <= 'F') return (short) (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (short) (c - 'a' + 10); diff --git a/drivers/atm/nicstar.c.old_skb b/drivers/atm/nicstar.c.old_skb deleted file mode 100644 index f4c946d0b..000000000 --- a/drivers/atm/nicstar.c.old_skb +++ /dev/null @@ -1,2883 +0,0 @@ -/****************************************************************************** - * - * nicstar.c - * - * Device driver supporting CBR for NICStAR based cards. - * - * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. - * It was taken from the frle-0.22 device driver. - * As the file doesn't have a copyright notice, in the file - * nicstarmac.copyright I put the copyright notice from the - * frle-0.22 device driver. - * Some code is based on the nicstar driver by M. Welsh. - * - * Author: Rui Prior - * - * (C) INESC 1998 - * - ******************************************************************************/ - - -/* Header files ***************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nicstar.h" -#include "nicstarmac.h" - - -/* Additional code ************************************************************/ - -#include "nicstarmac.c" - - -/* Configurable parameters ****************************************************/ - -#undef PHY_LOOPBACK -#undef TX_DEBUG -#undef RX_DEBUG -#undef GENERAL_DEBUG -#undef EXTRA_DEBUG - -#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know - you're going to use only raw ATM */ - - -/* Do not touch these *********************************************************/ - -#ifdef TX_DEBUG -#define TXPRINTK(args...) printk(args) -#else -#define TXPRINTK(args...) -#endif /* TX_DEBUG */ - -#ifdef RX_DEBUG -#define RXPRINTK(args...) printk(args) -#else -#define RXPRINTK(args...) -#endif /* RX_DEBUG */ - -#ifdef GENERAL_DEBUG -#define PRINTK(args...) printk(args) -#else -#define PRINTK(args...) -#endif /* GENERAL_DEBUG */ - -#ifdef EXTRA_DEBUG -#define XPRINTK(args...) printk(args) -#else -#define XPRINTK(args...) -#endif /* EXTRA_DEBUG */ - - -/* Macros *********************************************************************/ - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) - -#define NS_DELAY mdelay(1) - -#define ALIGN_ADDRESS(addr, alignment) \ - ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1)) - -#undef CEIL(d) - - -/* Version definition *********************************************************/ -/* -#include -char kernel_version[] = UTS_RELEASE; -*/ - -/* Function declarations ******************************************************/ - -static u32 ns_read_sram(ns_dev *card, u32 sram_address); -static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count); -static int ns_init_card(int i, struct pci_dev *pcidev); -static void ns_init_card_error(ns_dev *card, int error); -static scq_info *get_scq(int size, u32 scd); -static void free_scq(scq_info *scq, struct atm_vcc *vcc); -static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, - u32 handle2, u32 addr2); -static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs); -static int ns_open(struct atm_vcc *vcc, short vpi, int vci); -static void ns_close(struct atm_vcc *vcc); -static void fill_tst(ns_dev *card, int n, vc_map *vc); -static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, - struct sk_buff *skb); -static void process_tsq(ns_dev *card); -static void drain_scq(ns_dev *card, scq_info *scq, int pos); -static void process_rsq(ns_dev *card); -static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe); -#ifdef NS_USE_DESTRUCTORS -static void ns_sb_destructor(struct sk_buff *sb); -static void ns_lb_destructor(struct sk_buff *lb); -static void ns_hb_destructor(struct sk_buff *hb); -#endif /* NS_USE_DESTRUCTORS */ -static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb); -static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count); -static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb); -static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb); -static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb); -static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page); -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg); -static void which_list(ns_dev *card, struct sk_buff *skb); -static void ns_poll(unsigned long arg); - - -/* Global variables ***********************************************************/ - -static struct ns_dev *cards[NS_MAX_CARDS]; -static unsigned num_cards = 0; -static struct atmdev_ops atm_ops = -{ - NULL, /* dev_close */ - ns_open, /* open */ - ns_close, /* close */ - ns_ioctl, /* ioctl */ - NULL, /* getsockopt */ - NULL, /* setsockopt */ - ns_send, /* send */ - NULL, /* sg_send */ - NULL, /* send_oam */ - NULL, /* phy_put */ - NULL, /* phy_get */ - NULL, /* feedback */ - NULL, /* change_qos */ - NULL, /* free_rx_skb */ - ns_proc_read /* proc_read */ -}; -static struct timer_list ns_timer; - - -/* Functions*******************************************************************/ - -#ifdef MODULE - -int init_module(void) -{ - int i; - unsigned error = 0; /* Initialized to remove compile warning */ - struct pci_dev *pcidev; - - XPRINTK("nicstar: init_module() called.\n"); - if(!pci_present()) - { - printk("nicstar: no PCI subsystem found.\n"); - return -EIO; - } - - for(i = 0; i < NS_MAX_CARDS; i++) - cards[i] = NULL; - - pcidev = NULL; - for(i = 0; i < NS_MAX_CARDS; i++) - { - if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, - PCI_DEVICE_ID_IDT_IDT77201, - pcidev)) == NULL) - break; - - error = ns_init_card(i, pcidev); - if (error) - i--; /* Try to find another card but don't increment index */ - } - - if (i == 0) - { - if (!error) - { - printk("nicstar: no cards found.\n"); - return -ENXIO; - } - else - return -EIO; - } - TXPRINTK("nicstar: TX debug enabled.\n"); - RXPRINTK("nicstar: RX debug enabled.\n"); - PRINTK("nicstar: General debug enabled.\n"); -#ifdef PHY_LOOPBACK - printk("nicstar: using PHY loopback.\n"); -#endif /* PHY_LOOPBACK */ - XPRINTK("nicstar: init_module() returned.\n"); - - ns_timer.next = NULL; - ns_timer.prev = NULL; - ns_timer.expires = jiffies + NS_POLL_PERIOD; - ns_timer.data = 0UL; - ns_timer.function = ns_poll; - add_timer(&ns_timer); - return 0; -} - - - -void cleanup_module(void) -{ - int i, j; - unsigned short pci_command; - ns_dev *card; - struct sk_buff *hb; - struct sk_buff *iovb; - struct sk_buff *lb; - struct sk_buff *sb; - - XPRINTK("nicstar: cleanup_module() called.\n"); - - if (MOD_IN_USE) - printk("nicstar: module in use, remove delayed.\n"); - - del_timer(&ns_timer); - - for (i = 0; i < NS_MAX_CARDS; i++) - { - if (cards[i] == NULL) - continue; - - card = cards[i]; - - /* Stop everything */ - writel(0x00000000, card->membase + CFG); - - /* De-register device */ - atm_dev_deregister(card->atmdev); - - /* Disable memory mapping and busmastering */ - if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command) != 0) - { - printk("nicstar%d: can't read PCI_COMMAND.\n", i); - } - pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command) != 0) - { - printk("nicstar%d: can't write PCI_COMMAND.\n", i); - } - - /* Free up resources */ - j = 0; - PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); - while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) - { - kfree_skb(hb); - j++; - } - PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); - j = 0; - PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count); - while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) - { - kfree_skb(iovb); - j++; - } - PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); - while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - kfree_skb(lb); - while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - kfree_skb(sb); - free_scq(card->scq0, NULL); - for (j = 0; j < NS_FRSCD_NUM; j++) - { - if (card->scd2vc[j] != NULL) - free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); - } - kfree(card->rsq.org); - kfree(card->tsq.org); - free_irq(card->pcidev->irq, card); - iounmap((void *) card->membase); - kfree(card); - - } - XPRINTK("nicstar: cleanup_module() returned.\n"); -} - - -#else - -__initfunc(int nicstar_detect(void)) -{ - int i; - unsigned error = 0; /* Initialized to remove compile warning */ - struct pci_dev *pcidev; - - if(!pci_present()) - { - printk("nicstar: no PCI subsystem found.\n"); - return -EIO; - } - - for(i = 0; i < NS_MAX_CARDS; i++) - cards[i] = NULL; - - pcidev = NULL; - for(i = 0; i < NS_MAX_CARDS; i++) - { - if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT, - PCI_DEVICE_ID_IDT_IDT77201, - pcidev)) == NULL) - break; - - error = ns_init_card(i, pcidev); - if (error) - i--; /* Try to find another card but don't increment index */ - } - - if (i == 0 && error) - return -EIO; - - TXPRINTK("nicstar: TX debug enabled.\n"); - RXPRINTK("nicstar: RX debug enabled.\n"); - PRINTK("nicstar: General debug enabled.\n"); -#ifdef PHY_LOOPBACK - printk("nicstar: using PHY loopback.\n"); -#endif /* PHY_LOOPBACK */ - XPRINTK("nicstar: init_module() returned.\n"); - - return i; -} - - -#endif /* MODULE */ - - -static u32 ns_read_sram(ns_dev *card, u32 sram_address) -{ - unsigned long flags; - u32 data; - sram_address <<= 2; - sram_address &= 0x0007FFFC; /* address must be dword aligned */ - sram_address |= 0x50000000; /* SRAM read command */ - save_flags(flags); cli(); - while (CMD_BUSY(card)); - writel(sram_address, card->membase + CMD); - while (CMD_BUSY(card)); - data = readl(card->membase + DR0); - restore_flags(flags); - return data; -} - - - -static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count) -{ - unsigned long flags; - int i, c; - count--; /* count range now is 0..3 instead of 1..4 */ - c = count; - c <<= 2; /* to use increments of 4 */ - save_flags(flags); cli(); - while (CMD_BUSY(card)); - for (i = 0; i <= c; i += 4) - writel(*(value++), card->membase + i); - /* Note: DR# registers are the first 4 dwords in nicstar's memspace, - so card->membase + DR0 == card->membase */ - sram_address <<= 2; - sram_address &= 0x0007FFFC; - sram_address |= (0x40000000 | count); - writel(sram_address, card->membase + CMD); - restore_flags(flags); -} - - -static int ns_init_card(int i, struct pci_dev *pcidev) -{ - int j; - struct ns_dev *card; - unsigned short pci_command; - unsigned char pci_latency; - unsigned error; - u32 data; - u32 u32d[4]; - u32 ns_cfg_rctsize; - int bcount; - - error = 0; - - if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) - { - printk("nicstar%d: can't allocate memory for device structure.\n", i); - error = 2; - ns_init_card_error(card, error); - return error; - } - cards[i] = card; - - card->index = i; - card->pcidev = pcidev; - card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK); - card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE); - if (card->membase == (u32) (NULL)) - { - printk("nicstar%d: can't ioremap() membase.\n",i); - error = 3; - ns_init_card_error(card, error); - return error; - } - PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase); - - if (pci_read_config_word(pcidev, PCI_COMMAND, &pci_command) != 0) - { - printk("nicstar%d: can't read PCI_COMMAND.\n", i); - error = 4; - ns_init_card_error(card, error); - return error; - } - pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - if (pci_write_config_word(pcidev, PCI_COMMAND, pci_command) != 0) - { - printk("nicstar%d: can't write PCI_COMMAND.\n", i); - error = 5; - ns_init_card_error(card, error); - return error; - } - - if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) - { - printk("nicstar%d: can't read PCI latency timer.\n", i); - error = 6; - ns_init_card_error(card, error); - return error; - } - if (pci_latency < NS_PCI_LATENCY) - { - PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); - for (j = 1; j < 4; j++) - { - if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0); - break; - } - if (j == 10) - { - printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY); - error = 7; - ns_init_card_error(card, error); - return error; - } - } - - /* Clear timer overflow */ - data = readl(card->membase + STAT); - if (data & NS_STAT_TMROF) - writel(NS_STAT_TMROF, card->membase + STAT); - - /* Software reset */ - writel(NS_CFG_SWRST, card->membase + CFG); - NS_DELAY; - writel(0x00000000, card->membase + CFG); - - /* PHY reset */ - writel(0x00000008, card->membase + GP); - NS_DELAY; - writel(0x00000001, card->membase + GP); - NS_DELAY; - while (CMD_BUSY(card)); - writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ - NS_DELAY; - - /* Detect PHY type */ - while (CMD_BUSY(card)); - writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); - while (CMD_BUSY(card)); - data = readl(card->membase + DR0); - if (data == 0x00000009) - { - printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); - card->max_pcr = IDT_25_PCR; - while(CMD_BUSY(card)); - writel(0x00000008, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); - /* Clear an eventual pending interrupt */ - writel(NS_STAT_SFBQF, card->membase + STAT); -#ifdef PHY_LOOPBACK - while(CMD_BUSY(card)); - writel(0x00000022, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); -#endif /* PHY_LOOPBACK */ - } - else if (data == 0x00000030) - { - printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); - card->max_pcr = ATM_OC3_PCR; -#ifdef PHY_LOOPBACK - while(CMD_BUSY(card)); - writel(0x00000002, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); -#endif /* PHY_LOOPBACK */ - } - else - { - printk("nicstar%d: can't determine PHY type.\n", i); - error = 8; - ns_init_card_error(card, error); - return error; - } - writel(0x00000000, card->membase + GP); - - /* Determine SRAM size */ - data = 0x76543210; - ns_write_sram(card, 0x1C003, &data, 1); - data = 0x89ABCDEF; - ns_write_sram(card, 0x14003, &data, 1); - if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && - ns_read_sram(card, 0x1C003) == 0x76543210) - card->sram_size = 128; - else - card->sram_size = 32; - PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); - - card->rct_size = NS_MAX_RCTSIZE; - -#if (NS_MAX_RCTSIZE == 4096) - if (card->sram_size == 128) - printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i); -#elif (NS_MAX_RCTSIZE == 16384) - if (card->sram_size == 32) - { - printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i); - card->rct_size = 4096; - } -#else -#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c -#endif - - card->vpibits = NS_VPIBITS; - if (card->rct_size == 4096) - card->vcibits = 12 - NS_VPIBITS; - else /* card->rct_size == 16384 */ - card->vcibits = 14 - NS_VPIBITS; - -#ifdef ESI_FROM_EPROM - /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ - nicstar_init_eprom(card->membase); -#endif /* ESI_FROM_EPROM */ - - if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT, "nicstar", card) != 0) - { - printk("nicstar%d: can't allocate IRQ.\n", i); - error = 9; - ns_init_card_error(card, error); - return error; - } - - /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ - writel(0x00000000, card->membase + VPM); - - /* Initialize TSQ */ - card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL); - if (card->tsq.org == NULL) - { - printk("nicstar%d: can't allocate TSQ.\n", i); - error = 10; - ns_init_card_error(card, error); - return error; - } - card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT); - card->tsq.next = card->tsq.base; - card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); - for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) - ns_tsi_init(card->tsq.base + j); - writel(0x00000000, card->membase + TSQH); - writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB); - PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base, - (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB)); - - /* Initialize RSQ */ - card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL); - if (card->rsq.org == NULL) - { - printk("nicstar%d: can't allocate RSQ.\n", i); - error = 11; - ns_init_card_error(card, error); - return error; - } - card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT); - card->rsq.next = card->rsq.base; - card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); - for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) - ns_rsqe_init(card->rsq.base + j); - writel(0x00000000, card->membase + RSQH); - writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB); - PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base); - - /* Initialize SCQ0, the only VBR SCQ used */ - card->scq1 = (scq_info *) NULL; - card->scq2 = (scq_info *) NULL; - card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); - if (card->scq0 == (scq_info *) NULL) - { - printk("nicstar%d: can't get SCQ0.\n", i); - error = 12; - ns_init_card_error(card, error); - return error; - } - u32d[0] = (u32) virt_to_bus(card->scq0->base); - u32d[1] = (u32) 0x00000000; - u32d[2] = (u32) 0xffffffff; - u32d[3] = (u32) 0x00000000; - ns_write_sram(card, NS_VRSCD0, u32d, 4); - ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ - ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ - card->scq0->scd = NS_VRSCD0; - PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base); - - /* Initialize TSTs */ - card->tst_addr = NS_TST0; - card->tst_free_entries = NS_TST_NUM_ENTRIES; - data = NS_TST_OPCODE_VARIABLE; - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - ns_write_sram(card, NS_TST0 + j, &data, 1); - data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); - ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - ns_write_sram(card, NS_TST1 + j, &data, 1); - data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); - ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - card->tste2vc[j] = NULL; - writel(NS_TST0 << 2, card->membase + TSTB); - - - /* Initialize RCT. AAL type is set on opening the VC. */ -#ifdef RCQ_SUPPORT - u32d[0] = NS_RCTE_RAWCELLINTEN; -#else - u32d[0] = 0x00000000; -#endif RCQ_SUPPORT - u32d[1] = 0x00000000; - u32d[2] = 0x00000000; - u32d[3] = 0xFFFFFFFF; - for (j = 0; j < card->rct_size; j++) - ns_write_sram(card, j * 4, u32d, 4); - - memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map)); - - for (j = 0; j < NS_FRSCD_NUM; j++) - card->scd2vc[j] = NULL; - - /* Initialize buffer levels */ - card->sbnr.min = MIN_SB; - card->sbnr.init = NUM_SB; - card->sbnr.max = MAX_SB; - card->lbnr.min = MIN_LB; - card->lbnr.init = NUM_LB; - card->lbnr.max = MAX_LB; - card->iovnr.min = MIN_IOVB; - card->iovnr.init = NUM_IOVB; - card->iovnr.max = MAX_IOVB; - card->hbnr.min = MIN_HB; - card->hbnr.init = NUM_HB; - card->hbnr.max = MAX_HB; - - card->sm_handle = 0x00000000; - card->sm_addr = 0x00000000; - card->lg_handle = 0x00000000; - card->lg_addr = 0x00000000; - - card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ - - /* Allocate small buffers */ - skb_queue_head_init(&card->sbpool.queue); - card->sbpool.count = 0; /* Not used */ - for (j = 0; j < NUM_SB; j++) - { - struct sk_buff *sb; - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); - if (sb == NULL) - { - printk("nicstar%d: can't allocate %dth of %d small buffers.\n", - i, j, NUM_SB); - error = 13; - ns_init_card_error(card, error); - return error; - } - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); - } - /* Test for strange behaviour which leads to crashes */ - if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) - { - printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", - i, j, bcount); - error = 13; - ns_init_card_error(card, error); - return error; - } - - - /* Allocate large buffers */ - skb_queue_head_init(&card->lbpool.queue); - card->lbpool.count = 0; /* Not used */ - for (j = 0; j < NUM_LB; j++) - { - struct sk_buff *lb; - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); - if (lb == NULL) - { - printk("nicstar%d: can't allocate %dth of %d large buffers.\n", - i, j, NUM_LB); - error = 14; - ns_init_card_error(card, error); - return error; - } - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); - /* Due to the implementation of push_rxbufs() this is 1, not 0 */ - if (j == 1) - { - card->rcbuf = lb; - card->rawch = (u32) virt_to_bus(lb->data); - } - } - /* Test for strange behaviour which leads to crashes */ - if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) - { - printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", - i, j, bcount); - error = 14; - ns_init_card_error(card, error); - return error; - } - - - /* Allocate iovec buffers */ - skb_queue_head_init(&card->iovpool.queue); - card->iovpool.count = 0; - for (j = 0; j < NUM_IOVB; j++) - { - struct sk_buff *iovb; - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); - if (iovb == NULL) - { - printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", - i, j, NUM_IOVB); - error = 15; - ns_init_card_error(card, error); - return error; - } - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - } - - - /* Pre-allocate some huge buffers */ - skb_queue_head_init(&card->hbpool.queue); - card->hbpool.count = 0; - for (j = 0; j < NUM_HB; j++) - { - struct sk_buff *hb; - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); - if (hb == NULL) - { - printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", - i, j, NUM_HB); - error = 16; - ns_init_card_error(card, error); - return error; - } - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - } - - card->in_handler = 0; - card->in_poll = 0; - card->intcnt = 0; - - /* Configure NICStAR */ - if (card->rct_size == 4096) - ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; - else /* (card->rct_size == 16384) */ - ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; - - card->efbie = 1; - writel(NS_CFG_RXPATH | - NS_CFG_SMBUFSIZE | - NS_CFG_LGBUFSIZE | - NS_CFG_EFBIE | - NS_CFG_RSQSIZE | - NS_CFG_VPIBITS | - ns_cfg_rctsize | - NS_CFG_RXINT_NODELAY | - NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ - NS_CFG_RSQAFIE | - NS_CFG_TXEN | - NS_CFG_TXIE | - NS_CFG_TSQFIE_OPT, /* Only enabled if ENABLE_TSQFIE */ - card->membase + CFG); - - /* Register device */ - card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL); - if (card->atmdev == NULL) - { - printk("nicstar%d: can't register device.\n", i); - error = 17; - ns_init_card_error(card, error); - return error; - } - -#ifdef ESI_FROM_EPROM - nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, - card->atmdev->esi, 6); - printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, - card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], - card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); -#else - card->atmdev->esi[0] = NS_ESI0; - card->atmdev->esi[1] = NS_ESI1; - card->atmdev->esi[2] = NS_ESI2; - card->atmdev->esi[3] = NS_ESI3; - card->atmdev->esi[4] = NS_ESI4; - card->atmdev->esi[5] = NS_ESI5; -#endif /* ESI_FROM_EPROM */ - - card->atmdev->dev_data = card; - card->atmdev->ci_range.vpi_bits = card->vpibits; - card->atmdev->ci_range.vci_bits = card->vcibits; - - num_cards++; - - return error; -} - - - -static void ns_init_card_error(ns_dev *card, int error) -{ - if (error >= 17) - { - writel(0x00000000, card->membase + CFG); - } - if (error >= 16) - { - struct sk_buff *hb; - while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) - kfree_skb(hb); - } - if (error >= 15) - { - struct sk_buff *iovb; - while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) - kfree_skb(iovb); - } - if (error >= 14) - { - struct sk_buff *lb; - while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - kfree_skb(lb); - } - if (error >= 13) - { - struct sk_buff *sb; - while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - kfree_skb(sb); - free_scq(card->scq0, NULL); - } - if (error >= 12) - { - kfree(card->rsq.org); - } - if (error >= 11) - { - kfree(card->tsq.org); - } - if (error >= 10) - { - free_irq(card->pcidev->irq, card); - } - if (error >= 4) - { - iounmap((void *) card->membase); - } - if (error >= 3) - { - kfree(card); - } -} - - - -static scq_info *get_scq(int size, u32 scd) -{ - scq_info *scq; - int i; - - if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) - return (scq_info *) NULL; - - scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); - if (scq == (scq_info *) NULL) - return (scq_info *) NULL; - scq->org = kmalloc(2 * size, GFP_KERNEL); - if (scq->org == NULL) - { - kfree(scq); - return (scq_info *) NULL; - } - scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * - (size / NS_SCQE_SIZE), GFP_KERNEL); - if (scq->skb == (struct sk_buff **) NULL) - { - kfree(scq->org); - kfree(scq); - return (scq_info *) NULL; - } - scq->num_entries = size / NS_SCQE_SIZE; - scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size); - scq->next = scq->base; - scq->last = scq->base + (scq->num_entries - 1); - scq->tail = scq->last; - scq->scd = scd; - scq->num_entries = size / NS_SCQE_SIZE; - scq->tbd_count = 0; - scq->scqfull_waitq = NULL; - scq->full = 0; - - for (i = 0; i < scq->num_entries; i++) - scq->skb[i] = NULL; - - return scq; -} - - - -/* For variable rate SCQ vcc must be NULL */ -static void free_scq(scq_info *scq, struct atm_vcc *vcc) -{ - int i; - - if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) - for (i = 0; i < scq->num_entries; i++) - { - if (scq->skb[i] != NULL) - { - vcc = scq->skb[i]->atm.vcc; - if (vcc->pop != NULL) - vcc->pop(vcc, scq->skb[i]); - else - dev_kfree_skb(scq->skb[i]); - } - } - else /* vcc must be != NULL */ - { - if (vcc == NULL) - { - printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); - for (i = 0; i < scq->num_entries; i++) - dev_kfree_skb(scq->skb[i]); - } - else - for (i = 0; i < scq->num_entries; i++) - { - if (scq->skb[i] != NULL) - { - if (vcc->pop != NULL) - vcc->pop(vcc, scq->skb[i]); - else - dev_kfree_skb(scq->skb[i]); - } - } - } - kfree(scq->skb); - kfree(scq->org); - kfree(scq); -} - - - -/* The handles passed must be pointers to the sk_buff containing the small - or large buffer(s) cast to u32. */ -static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1, - u32 handle2, u32 addr2) -{ - u32 stat; - unsigned long flags; - - -#ifdef GENERAL_DEBUG - if (!addr1) - printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index); -#endif /* GENERAL_DEBUG */ - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - if (type == BUF_SM) - { - if (!addr2) - { - if (card->sm_addr) - { - addr2 = card->sm_addr; - handle2 = card->sm_handle; - card->sm_addr = 0x00000000; - card->sm_handle = 0x00000000; - } - else /* (!sm_addr) */ - { - card->sm_addr = addr1; - card->sm_handle = handle1; - } - } - } - else /* type == BUF_LG */ - { - if (!addr2) - { - if (card->lg_addr) - { - addr2 = card->lg_addr; - handle2 = card->lg_handle; - card->lg_addr = 0x00000000; - card->lg_handle = 0x00000000; - } - else /* (!lg_addr) */ - { - card->lg_addr = addr1; - card->lg_handle = handle1; - } - } - } - - if (addr2) - { - if (type == BUF_SM) - { - if (card->sbfqc >= card->sbnr.max) - { - skb_unlink((struct sk_buff *) handle1); - kfree_skb((struct sk_buff *) handle1); - skb_unlink((struct sk_buff *) handle2); - kfree_skb((struct sk_buff *) handle2); - return; - } - else - card->sbfqc += 2; - } - else /* (type == BUF_LG) */ - { - if (card->lbfqc >= card->lbnr.max) - { - skb_unlink((struct sk_buff *) handle1); - kfree_skb((struct sk_buff *) handle1); - skb_unlink((struct sk_buff *) handle2); - kfree_skb((struct sk_buff *) handle2); - return; - } - else - card->lbfqc += 2; - } - - save_flags(flags); cli(); - - while (CMD_BUSY(card)); - writel(handle1, card->membase + DR0); - writel(addr1, card->membase + DR1); - writel(handle2, card->membase + DR2); - writel(addr2, card->membase + DR3); - writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD); - - restore_flags(flags); - - XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index, - (type == BUF_SM ? "small" : "large"), addr1, addr2); - } - - if (!card->efbie && card->sbfqc >= card->sbnr.min && - card->lbfqc >= card->lbnr.min) - { - card->efbie = 1; - writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG); - } - - return; -} - - - -static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - u32 stat_r; - ns_dev *card; - - card = (ns_dev *) dev_id; - card->intcnt++; - - PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); - - if (card->in_handler) - { - printk("nicstar%d: Re-entering ns_irq_handler()???\n", card->index); - return; - } - card->in_handler = 1; - if (card->in_poll) - { - card->in_handler = 0; - printk("nicstar%d: Called irq handler while in ns_poll()!?\n", - card->index); - return; - } - - stat_r = readl(card->membase + STAT); - - /* Transmit Status Indicator has been written to T. S. Queue */ - if (stat_r & NS_STAT_TSIF) - { - TXPRINTK("nicstar%d: TSI interrupt\n", card->index); - process_tsq(card); - writel(NS_STAT_TSIF, card->membase + STAT); - } - - /* Incomplete CS-PDU has been transmitted */ - if (stat_r & NS_STAT_TXICP) - { - writel(NS_STAT_TXICP, card->membase + STAT); - TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", - card->index); - } - - /* Transmit Status Queue 7/8 full */ - if (stat_r & NS_STAT_TSQF) - { - writel(NS_STAT_TSQF, card->membase + STAT); - PRINTK("nicstar%d: TSQ full.\n", card->index); - process_tsq(card); - } - - /* Timer overflow */ - if (stat_r & NS_STAT_TMROF) - { - writel(NS_STAT_TMROF, card->membase + STAT); - PRINTK("nicstar%d: Timer overflow.\n", card->index); - } - - /* PHY device interrupt signal active */ - if (stat_r & NS_STAT_PHYI) - { - writel(NS_STAT_PHYI, card->membase + STAT); - printk("nicstar%d: PHY interrupt.\n", card->index); - } - - /* Small Buffer Queue is full */ - if (stat_r & NS_STAT_SFBQF) - { - writel(NS_STAT_SFBQF, card->membase + STAT); - printk("nicstar%d: Small free buffer queue is full.\n", card->index); - } - - /* Large Buffer Queue is full */ - if (stat_r & NS_STAT_LFBQF) - { - writel(NS_STAT_LFBQF, card->membase + STAT); - printk("nicstar%d: Large free buffer queue is full.\n", card->index); - } - - /* Receive Status Queue is full */ - if (stat_r & NS_STAT_RSQF) - { - writel(NS_STAT_RSQF, card->membase + STAT); - printk("nicstar%d: RSQ full.\n", card->index); - process_rsq(card); - } - - /* Complete CS-PDU received */ - if (stat_r & NS_STAT_EOPDU) - { - RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); - process_rsq(card); - writel(NS_STAT_EOPDU, card->membase + STAT); - } - - /* Raw cell received */ - if (stat_r & NS_STAT_RAWCF) - { - writel(NS_STAT_RAWCF, card->membase + STAT); -#ifndef RCQ_SUPPORT - printk("nicstar%d: Raw cell received and no support yet...\n", - card->index); -#endif /* RCQ_SUPPORT */ - /* NOTE: the following procedure may keep a raw cell pending untill the - next interrupt. As this preliminary support is only meant to - avoid buffer leakage, this is not an issue. */ - while (readl(card->membase + RAWCT) != card->rawch) - { - ns_rcqe *rawcell; - - rawcell = (ns_rcqe *) bus_to_virt(card->rawch); - if (ns_rcqe_islast(rawcell)) - { - struct sk_buff *oldbuf; - - oldbuf = card->rcbuf; - card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell); - card->rawch = (u32) virt_to_bus(card->rcbuf->data); - recycle_rx_buf(card, oldbuf); - } - else - card->rawch += NS_RCQE_SIZE; - } - } - - /* Small buffer queue is empty */ - if (stat_r & NS_STAT_SFBQE) - { - int i; - struct sk_buff *sb; - - writel(NS_STAT_SFBQE, card->membase + STAT); - printk("nicstar%d: Small free buffer queue empty.\n", - card->index); - for (i = 0; i < card->sbnr.min; i++) - { - sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC); - if (sb == NULL) - { - writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); - card->efbie = 0; - break; - } - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); - } - card->sbfqc = i; - process_rsq(card); - } - - /* Large buffer queue empty */ - if (stat_r & NS_STAT_LFBQE) - { - int i; - struct sk_buff *lb; - - writel(NS_STAT_LFBQE, card->membase + STAT); - printk("nicstar%d: Large free buffer queue empty.\n", - card->index); - for (i = 0; i < card->lbnr.min; i++) - { - lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC); - if (lb == NULL) - { - writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); - card->efbie = 0; - break; - } - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); - } - card->lbfqc = i; - process_rsq(card); - } - - /* Receive Status Queue is 7/8 full */ - if (stat_r & NS_STAT_RSQAF) - { - writel(NS_STAT_RSQAF, card->membase + STAT); - RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); - process_rsq(card); - } - - card->in_handler = 0; - PRINTK("nicstar%d: end of interrupt service\n", card->index); -} - - - -static int ns_open(struct atm_vcc *vcc, short vpi, int vci) -{ - ns_dev *card; - vc_map *vc; - int error; - double tmpd; - int tcr, tcra; /* target cell rate, and absolute value */ - int n = 0; /* Number of entries in the TST. Initialized to remove - the compiler warning. */ - u32 u32d[4]; - int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler - warning. How I wish compilers were clever enough to - tell which variables can truly be used - uninitialized... */ - int inuse; /* tx or rx vc already in use by another vcc */ - - card = (ns_dev *) vcc->dev->dev_data; - PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci); - if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) - { - PRINTK("nicstar%d: unsupported AAL.\n", card->index); - return -EINVAL; - } - - if ((error = atm_find_ci(vcc, &vpi, &vci))) - { - PRINTK("nicstar%d: error in atm_find_ci().\n", card->index); - return error; - } - vc = &(card->vcmap[vpi << card->vcibits | vci]); - vcc->vpi = vpi; - vcc->vci = vci; - vcc->dev_data = vc; - - inuse = 0; - if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) - inuse = 1; - if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) - inuse += 2; - if (inuse) - { - printk("nicstar%d: %s vci already in use.\n", card->index, - inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); - return -EINVAL; - } - - vcc->flags |= ATM_VF_ADDR; - - /* NOTE: You are not allowed to modify an open connection's QOS. To change - that, remove the ATM_VF_PARTIAL flag checking. There may be other changes - needed to do that. */ - if (!(vcc->flags & ATM_VF_PARTIAL)) - { - scq_info *scq; - - vcc->flags |= ATM_VF_PARTIAL; - if (vcc->qos.txtp.traffic_class == ATM_CBR) - { - /* Check requested cell rate and availability of SCD */ - if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 && - vcc->qos.txtp.min_pcr == 0) - { - PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", - card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -EINVAL; - } - - tcr = atm_pcr_goal(&(vcc->qos.txtp)); - tcra = tcr >= 0 ? tcr : -tcr; - - PRINTK("nicstar%d: target cell rate = %d.\n", card->index, - vcc->qos.txtp.max_pcr); - - tmpd = ((double) tcra) * ((double) NS_TST_NUM_ENTRIES) / - ((double) card->max_pcr); - - n = (int) tmpd; - if (tcr > 0) - { - if (tmpd > (double) n) n++; - } - else if (tcr < 0) - { - if (tmpd < (double) n) n--; - } - else /* tcr == 0 */ - { - if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) - { - PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -EINVAL; - } - } - - if (n == 0) - { - printk("nicstar%d: selected bandwidth < granularity.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -EINVAL; - } - - if (vcc->qos.txtp.max_pcr > 0) - { - tmpd = (double) n * (double) card->max_pcr / - (double) NS_TST_NUM_ENTRIES; - if (tmpd > PCR_TOLERANCE * (double) vcc->qos.txtp.max_pcr) - { - PRINTK("nicstar%d: target cell rate exceeded requested max_pcr.\n", - card->index); - } - } - - if (n > (card->tst_free_entries - NS_TST_RESERVED)) - { - PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -EINVAL; - } - else - card->tst_free_entries -= n; - - XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n); - for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) - { - if (card->scd2vc[frscdi] == NULL) - { - card->scd2vc[frscdi] = vc; - break; - } - } - if (frscdi == NS_FRSCD_NUM) - { - PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); - card->tst_free_entries += n; - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -EBUSY; - } - - vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; - - scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); - if (scq == (scq_info *) NULL) - { - PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); - card->scd2vc[frscdi] = NULL; - card->tst_free_entries += n; - vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL); - return -ENOMEM; - } - vc->scq = scq; - u32d[0] = (u32) virt_to_bus(scq->base); - u32d[1] = (u32) 0x00000000; - u32d[2] = (u32) 0xffffffff; - u32d[3] = (u32) 0x00000000; - ns_write_sram(card, vc->cbr_scd, u32d, 4); - - fill_tst(card, n, vc); - } - else /* not CBR */ - { - vc->cbr_scd = 0x00000000; - vc->scq = card->scq0; - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) - { - vc->tx = 1; - vc->tx_vcc = vcc; - vc->tbd_count = 0; - } - if (vcc->qos.rxtp.traffic_class != ATM_NONE) - { - u32 status; - - vc->rx = 1; - vc->rx_vcc = vcc; - vc->rx_iov = NULL; - - /* Open the connection in hardware */ - if (vcc->qos.aal == ATM_AAL5) - status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; - else /* vcc->qos.aal == ATM_AAL0 */ - status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; -#ifdef RCQ_SUPPORT - status |= NS_RCTE_RAWCELLINTEN; -#endif /* RCQ_SUPPORT */ - ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) * - NS_RCT_ENTRY_SIZE, &status, 1); - } - - } - - vcc->flags |= ATM_VF_READY; - return 0; -} - - - -static void ns_close(struct atm_vcc *vcc) -{ - vc_map *vc; - ns_dev *card; - u32 data; - int i; - - vc = vcc->dev_data; - card = vcc->dev->dev_data; - PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, - (int) vcc->vpi, vcc->vci); - - vcc->flags &= ~(ATM_VF_READY); - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) - { - u32 addr; - unsigned long flags; - - addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; - save_flags(flags); cli(); - while(CMD_BUSY(card)); - writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD); - restore_flags(flags); - - vc->rx = 0; - if (vc->rx_iov != NULL) - { - struct sk_buff *iovb; - u32 stat; - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - PRINTK("nicstar%d: closing a VC with pending rx buffers.\n", - card->index); - iovb = vc->rx_iov; - recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - iovb->atm.iovcnt); - iovb->atm.iovcnt = 0; - iovb->atm.vcc = NULL; - save_flags(flags); cli(); - recycle_iov_buf(card, iovb); - restore_flags(flags); - vc->rx_iov = NULL; - } - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) - { - vc->tx = 0; - } - - if (vcc->qos.txtp.traffic_class == ATM_CBR) - { - unsigned long flags; - ns_scqe *scqep; - scq_info *scq; - - scq = vc->scq; - - for (;;) - { - save_flags(flags); cli(); - scqep = scq->next; - if (scqep == scq->base) - scqep = scq->last; - else - scqep--; - if (scqep == scq->tail) - { - restore_flags(flags); - break; - } - /* If the last entry is not a TSR, place one in the SCQ in order to - be able to completely drain it and then close. */ - if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) - { - ns_scqe tsr; - u32 scdi, scqi; - u32 data; - int index; - - tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); - scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; - scqi = scq->next - scq->base; - tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); - tsr.word_3 = 0x00000000; - tsr.word_4 = 0x00000000; - *scq->next = tsr; - index = (int) scqi; - scq->skb[index] = NULL; - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - data = (u32) virt_to_bus(scq->next); - ns_write_sram(card, scq->scd, &data, 1); - } - schedule(); - restore_flags(flags); - } - - /* Free all TST entries */ - data = NS_TST_OPCODE_VARIABLE; - for (i = 0; i < NS_TST_NUM_ENTRIES; i++) - { - if (card->tste2vc[i] == vc) - { - ns_write_sram(card, card->tst_addr + i, &data, 1); - card->tste2vc[i] = NULL; - card->tst_free_entries++; - } - } - - card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; - free_scq(vc->scq, vcc); - } - - vcc->dev_data = NULL; - vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR); - -#ifdef RX_DEBUG - { - u32 stat, cfg; - stat = readl(card->membase + STAT); - cfg = readl(card->membase + CFG); - printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); - printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n", - (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last, - readl(card->membase + TSQT)); - printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n", - (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last, - readl(card->membase + RSQT)); - printk("Empty free buffer queue interrupt %s \n", - card->efbie ? "enabled" : "disabled"); - printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", - ns_stat_sfbqc_get(stat), card->sbpool.count, - ns_stat_lfbqc_get(stat), card->lbpool.count); - printk("hbpool.count = %d iovpool.count = %d \n", - card->hbpool.count, card->iovpool.count); - } -#endif /* RX_DEBUG */ -} - - - -static void fill_tst(ns_dev *card, int n, vc_map *vc) -{ - u32 new_tst; - double c, q; - int e, r; - u32 data; - - /* It would be very complicated to keep the two TSTs synchronized while - assuring that writes are only made to the inactive TST. So, for now I - will use only one TST. If problems occur, I will change this again */ - - new_tst = card->tst_addr; - - /* Fill procedure */ - - for (e = 0; e < NS_TST_NUM_ENTRIES; e++) - { - if (card->tste2vc[e] == NULL) - break; - } - if (e == NS_TST_NUM_ENTRIES) - printk("nicstar%d: No free TST entries found. \n", card->index); - - r = n; - c = 1.0; - q = (double) n / (double) NS_TST_NUM_ENTRIES; - - data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); - - while (e < NS_TST_NUM_ENTRIES) - { - if (c >= 1.0 && card->tste2vc[e] == NULL) - { - card->tste2vc[e] = vc; - ns_write_sram(card, new_tst + e, &data, 1); - c -= 1.0; - if (--r == 0) - break; - } - - e++; - c += q; - } - if (r != 0) - printk("nicstar%d: Not enough free TST entries. CBR lower than requested.\n", - card->index); - - /* End of fill procedure */ - - data = ns_tste_make(NS_TST_OPCODE_END, new_tst); - ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); - ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); - card->tst_addr = new_tst; -} - - - -static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - ns_dev *card; - vc_map *vc; - scq_info *scq; - unsigned long buflen; - ns_scqe scqe; - u32 flags; /* TBD flags, not CPU flags */ - - card = vcc->dev->dev_data; - TXPRINTK("nicstar%d: ns_send() called.\n", card->index); - if ((vc = (vc_map *) vcc->dev_data) == NULL) - { - printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); - return -EINVAL; - } - - if (!vc->tx) - { - printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); - return -EINVAL; - } - - if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) - { - printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); - return -EINVAL; - } - - if (skb->atm.iovcnt != 0) - { - printk("nicstar%d: No scatter-gather yet.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); - return -EINVAL; - } - - skb->atm.vcc = vcc; - - if (vcc->qos.aal == ATM_AAL5) - { - buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ - flags = NS_TBD_AAL5; - scqe.word_2 = (u32) virt_to_bus(skb->data); - scqe.word_3 = (u32) skb->len; - scqe.word_4 = ((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | - ((u32) vcc->vci) << NS_TBD_VCI_SHIFT; - flags |= NS_TBD_EOPDU; - } - else /* (vcc->qos.aal == ATM_AAL0) */ - { - buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ - flags = NS_TBD_AAL0; - scqe.word_2 = (u32) virt_to_bus(skb->data) + NS_AAL0_HEADER; - scqe.word_3 = 0x00000000; - if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ - flags |= NS_TBD_EOPDU; - scqe.word_4 = *((u32 *) skb->data) & ~NS_TBD_VC_MASK; - /* Force the VPI/VCI to be the same as in VCC struct */ - scqe.word_4 |= (((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | - ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK; - } - - if (vcc->qos.txtp.traffic_class == ATM_CBR) - { - scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); - scq = ((vc_map *) vcc->dev_data)->scq; - } - else - { - scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); - scq = card->scq0; - } - - if (push_scqe(card, vc, scq, &scqe, skb) != 0) /* Timeout pushing the TBD */ - { - printk("nicstar%d: Timeout pushing TBD.\n", card->index); - vcc->stats->tx_err++; - dev_kfree_skb(skb); - return -EIO; - } - vcc->stats->tx++; - - return 0; -} - - - -static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, - struct sk_buff *skb) -{ - unsigned long flags; - ns_scqe tsr; - u32 scdi, scqi; - int scq_is_vbr; - u32 data; - int index; - - if (scq->tail == scq->next) - { - save_flags(flags); cli(); - scq->full = 1; - current->timeout = jiffies + SCQFULL_TIMEOUT; - interruptible_sleep_on(&scq->scqfull_waitq); - restore_flags(flags); - - if (scq->full) - return 1; - } - *scq->next = *tbd; - index = (int) (scq->next - scq->base); - scq->skb[index] = skb; - XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n", - card->index, (u32) skb, index); - XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", - card->index, tbd->word_1, tbd->word_2, tbd->word_3, tbd->word_4, - (u32) scq->next); - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - - vc->tbd_count++; - if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) - { - scq->tbd_count++; - scq_is_vbr = 1; - } - else - scq_is_vbr = 0; - - if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ) - { - if (scq->tail == scq->next) - { - save_flags(flags); cli(); - scq->full = 1; - current->timeout = jiffies + SCQFULL_TIMEOUT; - interruptible_sleep_on(&scq->scqfull_waitq); - restore_flags(flags); - } - - if (!scq->full) - { - tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); - if (scq_is_vbr) - scdi = NS_TSR_SCDISVBR; - else - scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; - scqi = scq->next - scq->base; - tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); - tsr.word_3 = 0x00000000; - tsr.word_4 = 0x00000000; - - *scq->next = tsr; - index = (int) scqi; - scq->skb[index] = NULL; - XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", - card->index, tsr.word_1, tsr.word_2, tsr.word_3, tsr.word_4, - (u32) scq->next); - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - vc->tbd_count = 0; - scq->tbd_count = 0; - } - else - PRINTK("nicstar%d: Could not write TSI.\n", card->index); - } - - data = (u32) virt_to_bus(scq->next); - ns_write_sram(card, scq->scd, &data, 1); - - return 0; -} - - - -static void process_tsq(ns_dev *card) -{ - u32 scdi; - scq_info *scq; - ns_tsi *previous; - - if (ns_tsi_isempty(card->tsq.next)) - return; - while (!ns_tsi_isempty(card->tsq.next)) - { - if (!ns_tsi_tmrof(card->tsq.next)) - { - scdi = ns_tsi_getscdindex(card->tsq.next); - if (scdi == NS_TSI_SCDISVBR) - scq = card->scq0; - else - { - if (card->scd2vc[scdi] == NULL) - { - printk("nicstar%d: could not find VC from SCD index.\n", - card->index); - ns_tsi_init(card->tsq.next); - return; - } - scq = card->scd2vc[scdi]->scq; - } - drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); - scq->full = 0; - wake_up_interruptible(&(scq->scqfull_waitq)); - } - - ns_tsi_init(card->tsq.next); - previous = card->tsq.next; - if (card->tsq.next == card->tsq.last) - card->tsq.next = card->tsq.base; - else - card->tsq.next++; - } - writel((((u32) previous) - ((u32) card->tsq.base)), - card->membase + TSQH); -} - - - -static void drain_scq(ns_dev *card, scq_info *scq, int pos) -{ - struct atm_vcc *vcc; - struct sk_buff *skb; - int i; - - XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n", - card->index, (u32) scq, pos); - if (pos >= scq->num_entries) - { - printk("nicstar%d: Bad index on drain_scq().\n", card->index); - return; - } - - i = (int) (scq->tail - scq->base); - if (++i == scq->num_entries) - i = 0; - while (i != pos) - { - skb = scq->skb[i]; - XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n", - card->index, (u32) skb, i); - if (skb != NULL) - { - vcc = skb->atm.vcc; - if (vcc->pop != NULL) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - scq->skb[i] = NULL; - } - if (++i == scq->num_entries) - i = 0; - } - scq->tail = scq->base + pos; -} - - - -static void process_rsq(ns_dev *card) -{ - ns_rsqe *previous; - - if (!ns_rsqe_valid(card->rsq.next)) - return; - while (ns_rsqe_valid(card->rsq.next)) - { - dequeue_rx(card, card->rsq.next); - ns_rsqe_init(card->rsq.next); - previous = card->rsq.next; - if (card->rsq.next == card->rsq.last) - card->rsq.next = card->rsq.base; - else - card->rsq.next++; - } - writel((((u32) previous) - ((u32) card->rsq.base)), - card->membase + RSQH); -} - - - -static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe) -{ - u32 vpi, vci; - vc_map *vc; - struct sk_buff *iovb; - struct iovec *iov; - struct atm_vcc *vcc; - struct sk_buff *skb; - unsigned short aal5_len; - int len; - u32 stat; - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - skb = (struct sk_buff *) rsqe->buffer_handle; - vpi = ns_rsqe_vpi(rsqe); - vci = ns_rsqe_vci(rsqe); - if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) - { - printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", - card->index, vpi, vci); - recycle_rx_buf(card, skb); - return; - } - - vc = &(card->vcmap[vpi << card->vcibits | vci]); - if (!vc->rx) - { - RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", - card->index, vpi, vci); - recycle_rx_buf(card, skb); - return; - } - - vcc = vc->rx_vcc; - - if (vcc->qos.aal == ATM_AAL0) - { - struct sk_buff *sb; - unsigned char *cell; - int i; - - cell = skb->data; - for (i = ns_rsqe_cellcount(rsqe); i; i--) - { - if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL) - { - printk("nicstar%d: Can't allocate buffers for aal0.\n", - card->index); - vcc->stats->rx_drop += i; - break; - } - if (!atm_charge(vcc, sb->truesize)) - { - RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n", - card->index); - vcc->stats->rx_drop += i - 1; /* already increased by 1 */ - kfree_skb(sb); - break; - } - /* Rebuild the header */ - *((u32 *) sb->data) = rsqe->word_1 << 4 | - (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); - if (i == 1 && ns_rsqe_eopdu(rsqe)) - *((u32 *) sb->data) |= 0x00000002; - skb_put(sb, NS_AAL0_HEADER); - memcpy(sb->tail, cell, ATM_CELL_PAYLOAD); - skb_put(sb, ATM_CELL_PAYLOAD); - sb->atm.vcc = vcc; - sb->stamp = xtime; - vcc->push(vcc, sb); - vcc->stats->rx++; - cell += ATM_CELL_PAYLOAD; - } - - recycle_rx_buf(card, skb); - return; - } - - /* To reach this point, the AAL layer can only be AAL5 */ - - if ((iovb = vc->rx_iov) == NULL) - { - iovb = skb_dequeue(&(card->iovpool.queue)); - if (iovb == NULL) /* No buffers in the queue */ - { - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); - if (iovb == NULL) - { - printk("nicstar%d: Out of iovec buffers.\n", card->index); - vcc->stats->rx_drop++; - recycle_rx_buf(card, skb); - return; - } - } - else - if (--card->iovpool.count < card->iovnr.min) - { - struct sk_buff *new_iovb; - if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->iovpool.queue, new_iovb); - card->iovpool.count++; - } - } - vc->rx_iov = iovb; - iovb->atm.iovcnt = 0; - iovb->len = 0; - iovb->tail = iovb->data = iovb->head; - iovb->atm.vcc = vcc; - /* IMPORTANT: a pointer to the sk_buff containing the small or large - buffer is stored as iovec base, NOT a pointer to the - small or large buffer itself. */ - } - else if (iovb->atm.iovcnt >= NS_MAX_IOVECS) - { - printk("nicstar%d: received too big AAL5 SDU.\n", card->index); - vcc->stats->rx_err++; - recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS); - iovb->atm.iovcnt = 0; - iovb->len = 0; - iovb->tail = iovb->data = iovb->head; - iovb->atm.vcc = vcc; - } - iov = &((struct iovec *) iovb->data)[iovb->atm.iovcnt++]; - iov->iov_base = (void *) skb; - iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; - iovb->len += iov->iov_len; - - if (iovb->atm.iovcnt == 1) - { - if (skb->list != &card->sbpool.queue) - { - printk("nicstar%d: Expected a small buffer, and this is not one.\n", - card->index); - which_list(card, skb); - vcc->stats->rx_err++; - recycle_rx_buf(card, skb); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - } - else /* iovb->atm.iovcnt >= 2 */ - { - if (skb->list != &card->lbpool.queue) - { - printk("nicstar%d: Expected a large buffer, and this is not one.\n", - card->index); - which_list(card, skb); - vcc->stats->rx_err++; - recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - iovb->atm.iovcnt); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - } - - if (ns_rsqe_eopdu(rsqe)) - { - aal5_len = *((unsigned short *) ((u32) skb->data + iov->iov_len - 6)); - /* Swap byte order. Is it just me or the nicstar manual sais this should - already be in little endian format? */ - aal5_len = ((aal5_len & 0x00ff) << 8 | (aal5_len & 0xff00) >> 8); - len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; - if (ns_rsqe_crcerr(rsqe) || - len + 8 > iovb->len || len + (47 + 8) < iovb->len) - { - if (ns_rsqe_crcerr(rsqe)) - printk("nicstar%d: AAL5 CRC error.\n", card->index); - else - printk("nicstar%d: AAL5 PDU size mismatch.\n", card->index); - vcc->stats->rx_err++; - recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, iovb->atm.iovcnt); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - - /* By this point we (hopefully) have a complete SDU without errors. */ - - if (iovb->atm.iovcnt == 1) /* Just a small buffer */ - { - /* skb points to a small buffer */ - if (!atm_charge(vcc, skb->truesize)) - { - push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), - 0, 0); - } - else - { - skb_put(skb, len); - dequeue_sm_buf(card, skb); -#ifdef NS_USE_DESTRUCTORS - skb->destructor = ns_sb_destructor; -#endif /* NS_USE_DESTRUCTORS */ - skb->atm.vcc = vcc; - skb->stamp = xtime; - vcc->push(vcc, skb); - vcc->stats->rx++; - } - } - else if (iovb->atm.iovcnt == 2) /* One small plus one large buffer */ - { - struct sk_buff *sb; - - sb = (struct sk_buff *) (iov - 1)->iov_base; - /* skb points to a large buffer */ - - if (len <= NS_SMBUFSIZE) - { - if (!atm_charge(vcc, sb->truesize)) - { - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), - 0, 0); - } - else - { - skb_put(sb, len); - dequeue_sm_buf(card, sb); -#ifdef NS_USE_DESTRUCTORS - sb->destructor = ns_sb_destructor; -#endif /* NS_USE_DESTRUCTORS */ - sb->atm.vcc = vcc; - sb->stamp = xtime; - vcc->push(vcc, sb); - vcc->stats->rx++; - } - - push_rxbufs(card, BUF_LG, (u32) skb, - (u32) virt_to_bus(skb->data), 0, 0); - - } - else /* len > NS_SMBUFSIZE, the usual case */ - { - if (!atm_charge(vcc, skb->truesize)) - { - push_rxbufs(card, BUF_LG, (u32) skb, - (u32) virt_to_bus(skb->data), 0, 0); - } - else - { - dequeue_lg_buf(card, skb); -#ifdef NS_USE_DESTRUCTORS - skb->destructor = ns_lb_destructor; -#endif /* NS_USE_DESTRUCTORS */ - skb_push(skb, NS_SMBUFSIZE); - memcpy(skb->data, sb->data, NS_SMBUFSIZE); - skb_put(skb, len - NS_SMBUFSIZE); - skb->atm.vcc = vcc; - skb->stamp = xtime; - vcc->push(vcc, skb); - vcc->stats->rx++; - } - - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), - 0, 0); - - } - - } - else /* Must push a huge buffer */ - { - struct sk_buff *hb, *sb, *lb; - int remaining, tocopy; - int j; - - hb = skb_dequeue(&(card->hbpool.queue)); - if (hb == NULL) /* No buffers in the queue */ - { - - hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC); - if (hb == NULL) - { - printk("nicstar%d: Out of huge buffers.\n", card->index); - vcc->stats->rx_drop++; - recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, - iovb->atm.iovcnt); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - else if (card->hbpool.count < card->hbnr.min) - { - struct sk_buff *new_hb; - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->hbpool.queue, new_hb); - card->hbpool.count++; - } - } - } - else - if (--card->hbpool.count < card->hbnr.min) - { - struct sk_buff *new_hb; - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->hbpool.queue, new_hb); - card->hbpool.count++; - } - if (card->hbpool.count < card->hbnr.min) - { - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->hbpool.queue, new_hb); - card->hbpool.count++; - } - } - } - - iov = (struct iovec *) iovb->data; - - if (!atm_charge(vcc, hb->truesize)) - { - recycle_iovec_rx_bufs(card, iov, iovb->atm.iovcnt); - if (card->hbpool.count < card->hbnr.max) - { - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - } - else - kfree_skb(hb); - } - else - { - /* Copy the small buffer to the huge buffer */ - sb = (struct sk_buff *) iov->iov_base; - memcpy(hb->data, sb->data, iov->iov_len); - skb_put(hb, iov->iov_len); - remaining = len - iov->iov_len; - iov++; - /* Free the small buffer */ - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), - 0, 0); - - /* Copy all large buffers to the huge buffer and free them */ - for (j = 1; j < iovb->atm.iovcnt; j++) - { - lb = (struct sk_buff *) iov->iov_base; - tocopy = MIN(remaining, iov->iov_len); - memcpy(hb->tail, lb->data, tocopy); - skb_put(hb, tocopy); - iov++; - remaining -= tocopy; - push_rxbufs(card, BUF_LG, (u32) lb, - (u32) virt_to_bus(lb->data), 0, 0); - } -#ifdef EXTRA_DEBUG - if (remaining != 0 || hb->len != len) - printk("nicstar%d: Huge buffer len mismatch.\n", card->index); -#endif /* EXTRA_DEBUG */ - hb->atm.vcc = vcc; -#ifdef NS_USE_DESTRUCTORS - hb->destructor = ns_hb_destructor; -#endif /* NS_USE_DESTRUCTORS */ - hb->stamp = xtime; - vcc->push(vcc, hb); - vcc->stats->rx++; - } - } - - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - } - -} - - - -#ifdef NS_USE_DESTRUCTORS - -static void ns_sb_destructor(struct sk_buff *sb) -{ - ns_dev *card; - u32 stat; - - card = (ns_dev *) sb->atm.vcc->dev->dev_data; - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - do - { - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); - if (sb == NULL) - break; - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); - } while (card->sbfqc < card->sbnr.min); -} - - - -static void ns_lb_destructor(struct sk_buff *lb) -{ - ns_dev *card; - u32 stat; - - card = (ns_dev *) lb->atm.vcc->dev->dev_data; - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - do - { - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); - if (lb == NULL) - break; - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); - } while (card->lbfqc < card->lbnr.min); -} - - - -static void ns_hb_destructor(struct sk_buff *hb) -{ - ns_dev *card; - - card = (ns_dev *) hb->atm.vcc->dev->dev_data; - - while (card->hbpool.count < card->hbnr.init) - { - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); - if (hb == NULL) - break; - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - } -} - -#endif /* NS_USE_DESTRUCTORS */ - - - -static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb) -{ - if (skb->list == &card->sbpool.queue) - push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); - else if (skb->list == &card->lbpool.queue) - push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0); - else - { - printk("nicstar%d: What kind of rx buffer is this?\n", card->index); - kfree_skb(skb); - } -} - - - -static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count) -{ - struct sk_buff *skb; - - for (; count > 0; count--) - { - skb = (struct sk_buff *) (iov++)->iov_base; - if (skb->list == &card->sbpool.queue) - push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), - 0, 0); - else if (skb->list == &card->lbpool.queue) - push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), - 0, 0); - else - { - printk("nicstar%d: What kind of rx buffer is this?\n", card->index); - kfree_skb(skb); - } - } -} - - - -static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb) -{ - if (card->iovpool.count < card->iovnr.max) - { - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - } - else - kfree_skb(iovb); -} - - - -static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb) -{ - skb_unlink(sb); -#ifdef NS_USE_DESTRUCTORS - if (card->sbfqc < card->sbnr.min) -#else - if (card->sbfqc < card->sbnr.init) - { - struct sk_buff *new_sb; - if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->sbpool.queue, new_sb); - skb_reserve(new_sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) new_sb, - (u32) virt_to_bus(new_sb->data), 0, 0); - } - } - if (card->sbfqc < card->sbnr.init) -#endif /* NS_USE_DESTRUCTORS */ - { - struct sk_buff *new_sb; - if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->sbpool.queue, new_sb); - skb_reserve(new_sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) new_sb, - (u32) virt_to_bus(new_sb->data), 0, 0); - } - } -} - - - -static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb) -{ - skb_unlink(lb); -#ifdef NS_USE_DESTRUCTORS - if (card->lbfqc < card->lbnr.min) -#else - if (card->lbfqc < card->lbnr.init) - { - struct sk_buff *new_lb; - if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->lbpool.queue, new_lb); - skb_reserve(new_lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) new_lb, - (u32) virt_to_bus(new_lb->data), 0, 0); - } - } - if (card->lbfqc < card->lbnr.init) -#endif /* NS_USE_DESTRUCTORS */ - { - struct sk_buff *new_lb; - if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) - { - skb_queue_tail(&card->lbpool.queue, new_lb); - skb_reserve(new_lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) new_lb, - (u32) virt_to_bus(new_lb->data), 0, 0); - } - } -} - - - -static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page) -{ - u32 stat; - ns_dev *card; - int left; - - left = (int) *pos; - card = (ns_dev *) dev->dev_data; - stat = readl(card->membase + STAT); - if (!left--) - return sprintf(page, "Pool count min init max \n"); - if (!left--) - return sprintf(page, "Small %5d %5d %5d %5d \n", - ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init, - card->sbnr.max); - if (!left--) - return sprintf(page, "Large %5d %5d %5d %5d \n", - ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init, - card->lbnr.max); - if (!left--) - return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count, - card->hbnr.min, card->hbnr.init, card->hbnr.max); - if (!left--) - return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count, - card->iovnr.min, card->iovnr.init, card->iovnr.max); - if (!left--) - { - int retval; - retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt); - card->intcnt = 0; - return retval; - } - /* Dump 25.6 Mbps PHY registers */ - if (card->max_pcr == IDT_25_PCR && !left--) - { - u32 phy_regs[4]; - u32 i; - - for (i = 0; i < 4; i++) - { - while (CMD_BUSY(card)); - writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD); - while (CMD_BUSY(card)); - phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; - } - - return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", - phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]); - } -#if 0 - /* Dump TST */ - if (left-- < NS_TST_NUM_ENTRIES) - { - if (card->tste2vc[left + 1] == NULL) - return sprintf(page, "%5d - VBR/UBR \n", left + 1); - else - return sprintf(page, "%5d - %d %d \n", left + 1, - card->tste2vc[left + 1]->tx_vcc->vpi, - card->tste2vc[left + 1]->tx_vcc->vci); - } -#endif /* 0 */ - return 0; -} - - - -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) -{ - ns_dev *card; - pool_levels pl; - int btype; - unsigned long flags; - - card = dev->dev_data; - switch (cmd) - { - case NS_GETPSTAT: - if (get_user(pl.buftype, &((pool_levels *) arg)->buftype)) - return -EFAULT; - switch (pl.buftype) - { - case NS_BUFTYPE_SMALL: - pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT)); - pl.level.min = card->sbnr.min; - pl.level.init = card->sbnr.init; - pl.level.max = card->sbnr.max; - break; - - case NS_BUFTYPE_LARGE: - pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT)); - pl.level.min = card->lbnr.min; - pl.level.init = card->lbnr.init; - pl.level.max = card->lbnr.max; - break; - - case NS_BUFTYPE_HUGE: - pl.count = card->hbpool.count; - pl.level.min = card->hbnr.min; - pl.level.init = card->hbnr.init; - pl.level.max = card->hbnr.max; - break; - - case NS_BUFTYPE_IOVEC: - pl.count = card->iovpool.count; - pl.level.min = card->iovnr.min; - pl.level.init = card->iovnr.init; - pl.level.max = card->iovnr.max; - break; - - default: - return -EINVAL; - - } - if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) - return (sizeof(pl)); - else - return -EFAULT; - - case NS_SETBUFLEV: - if (!suser()) - return -EPERM; - if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl))) - return -EFAULT; - if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max) - return -EINVAL; - if (pl.level.min == 0) - return -EINVAL; - switch (pl.buftype) - { - case NS_BUFTYPE_SMALL: - if (pl.level.max > TOP_SB) - return -EINVAL; - card->sbnr.min = pl.level.min; - card->sbnr.init = pl.level.init; - card->sbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_LARGE: - if (pl.level.max > TOP_LB) - return -EINVAL; - card->lbnr.min = pl.level.min; - card->lbnr.init = pl.level.init; - card->lbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_HUGE: - if (pl.level.max > TOP_HB) - return -EINVAL; - card->hbnr.min = pl.level.min; - card->hbnr.init = pl.level.init; - card->hbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_IOVEC: - if (pl.level.max > TOP_IOVB) - return -EINVAL; - card->iovnr.min = pl.level.min; - card->iovnr.init = pl.level.init; - card->iovnr.max = pl.level.max; - break; - - default: - return -EINVAL; - - } - return 0; - - case NS_ADJBUFLEV: - if (!suser()) - return -EPERM; - btype = (int) arg; /* an int is the same size as a pointer */ - switch (btype) - { - case NS_BUFTYPE_SMALL: - while (card->sbfqc < card->sbnr.init) - { - struct sk_buff *sb; - - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); - if (sb == NULL) - return -ENOMEM; - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); - } - break; - - case NS_BUFTYPE_LARGE: - while (card->lbfqc < card->lbnr.init) - { - struct sk_buff *lb; - - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); - if (lb == NULL) - return -ENOMEM; - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); - } - break; - - case NS_BUFTYPE_HUGE: - while (card->hbpool.count > card->hbnr.init) - { - struct sk_buff *hb; - - save_flags(flags); cli(); - hb = skb_dequeue(&card->hbpool.queue); - card->hbpool.count--; - restore_flags(flags); - if (hb == NULL) - printk("nicstar%d: huge buffer count inconsistent.\n", - card->index); - else - kfree_skb(hb); - - } - while (card->hbpool.count < card->hbnr.init) - { - struct sk_buff *hb; - - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); - if (hb == NULL) - return -ENOMEM; - save_flags(flags); cli(); - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - restore_flags(flags); - } - break; - - case NS_BUFTYPE_IOVEC: - while (card->iovpool.count > card->iovnr.init) - { - struct sk_buff *iovb; - - save_flags(flags); cli(); - iovb = skb_dequeue(&card->iovpool.queue); - card->iovpool.count--; - restore_flags(flags); - if (iovb == NULL) - printk("nicstar%d: iovec buffer count inconsistent.\n", - card->index); - else - kfree_skb(iovb); - - } - while (card->iovpool.count < card->iovnr.init) - { - struct sk_buff *iovb; - - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); - if (iovb == NULL) - return -ENOMEM; - save_flags(flags); cli(); - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - restore_flags(flags); - } - break; - - default: - return -EINVAL; - - } - return 0; - - default: - if (dev->phy->ioctl == NULL) return -EINVAL; - return dev->phy->ioctl(dev, cmd, arg); - } -} - - - -static void which_list(ns_dev *card, struct sk_buff *skb) -{ - printk("It's a %s buffer.\n", skb->list == &card->sbpool.queue ? - "small" : skb->list == &card->lbpool.queue ? "large" : - skb->list == &card->hbpool.queue ? "huge" : - skb->list == &card->iovpool.queue ? "iovec" : "unknown"); -} - - - -static void ns_poll(unsigned long arg) -{ - int i; - ns_dev *card; - unsigned long flags; - u32 stat_r, stat_w; - - PRINTK("nicstar: Entering ns_poll().\n"); - for (i = 0; i < num_cards; i++) - { - card = cards[i]; - save_flags(flags); cli(); - if (card->in_poll) - { - printk("nicstar: Re-entering ns_poll()???\n"); - continue; - } - card->in_poll = 1; - if (card->in_handler) - { - card->in_poll = 0; - printk("nicstar%d: ns_poll called while in interrupt handler!?\n", - card->index); - continue; - } - - stat_w = 0; - stat_r = readl(card->membase + STAT); - if (stat_r & NS_STAT_TSIF) - stat_w |= NS_STAT_TSIF; - if (stat_r & NS_STAT_EOPDU) - stat_w |= NS_STAT_EOPDU; - - process_tsq(card); - process_rsq(card); - - writel(card->membase + STAT, stat_w); - card->in_poll = 0; - restore_flags(flags); - } - mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); - PRINTK("nicstar: Leaving ns_poll().\n"); -} diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 7ad467066..43904624f 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -1,6 +1,6 @@ /* drivers/atm/suni.c - PMC SUNI (PHY) driver */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -45,7 +45,7 @@ struct suni_priv { PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg) -static struct timer_list poll_timer = { NULL, NULL, 0L, 0L, NULL }; +static struct timer_list poll_timer; static int start_timer = 1; static struct suni_priv *sunis = NULL; @@ -91,11 +91,7 @@ static void suni_hz(unsigned long dummy) ((GET(TACP_TCCM) & 7) << 16); if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX; } - if (!start_timer) { - del_timer(&poll_timer); - poll_timer.expires = jiffies+HZ; - add_timer(&poll_timer); - } + if (!start_timer) mod_timer(&poll_timer,jiffies+HZ); } @@ -244,7 +240,7 @@ static int suni_start(struct atm_dev *dev) else { start_timer = 0; restore_flags(flags); - /*init_timer(&poll_timer);*/ + init_timer(&poll_timer); poll_timer.expires = jiffies+HZ; poll_timer.function = suni_hz; #if 0 @@ -282,11 +278,12 @@ int __init suni_init(struct atm_dev *dev) } -#ifdef MODULE - EXPORT_SYMBOL(suni_init); +#ifdef MODULE + + int init_module(void) { MOD_INC_USE_COUNT; diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index b3ea4a071..bd1bd981f 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -347,7 +347,7 @@ static void zatm_feedback(struct atm_vcc *vcc,struct sk_buff *skb, #ifdef CONFIG_ATM_ZATM_EXACT_TS -static struct timer_list sync_timer = { NULL, NULL, 0L, 0L, NULL }; +static struct timer_list sync_timer; /* @@ -454,9 +454,7 @@ static void zatm_clock_sync(unsigned long dummy) zatm_dev->last_real_time = now; zatm_dev->last_clk = ticks; } - del_timer(&sync_timer); - sync_timer.expires += POLL_INTERVAL*HZ; - add_timer(&sync_timer); + mod_timer(&sync_timer,sync_timer.expires+POLL_INTERVAL*HZ); } @@ -475,6 +473,7 @@ static void __init zatm_clock_init(struct zatm_dev *zatm_dev) zatm_dev->last_clk = zpeekl(zatm_dev,uPD98401_TSR); if (start_timer) { start_timer = 0; + init_timer(&sync_timer); sync_timer.expires = jiffies+POLL_INTERVAL*HZ; sync_timer.function = zatm_clock_sync; add_timer(&sync_timer); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 00a05e1d1..06eed2279 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include "DAC960.h" diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 544a29583..1b2be20dd 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -35,8 +35,8 @@ #include #include #include +#include #include -#include #include diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index ea05992f1..2bb161082 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -830,7 +830,7 @@ int __init blk_dev_init(void) #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else -#if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)\ +#if !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__)\ && !defined(CONFIG_APUS) && !defined(__sh__) outb_p(0xc, 0x3f2); #endif diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c index 9e238803e..e2b40eb22 100644 --- a/drivers/block/paride/paride.c +++ b/drivers/block/paride/paride.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #ifdef CONFIG_PARPORT_MODULE #define CONFIG_PARPORT diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 19754cc9a..13b5f1b6a 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -142,9 +142,9 @@ static int pcd_drive_count; #include #include #include +#include #include -#include #ifndef MODULE diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 128f9b21d..bd2839053 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -161,8 +161,8 @@ static int pd_drive_count; #include #include #include /* for the eject ioctl */ +#include -#include #include #ifndef MODULE diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index f1cdfe3c6..58a747cb7 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -160,7 +160,7 @@ static int pf_drive_count; #include #include #include -#include +#include #include diff --git a/drivers/char/Config.in b/drivers/char/Config.in index e0371a460..e993c7e6f 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -210,4 +210,11 @@ if [ "$CONFIG_FTAPE" != "n" ]; then fi endmenu +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM + if [ "$CONFIG_DRM" = "y" ]; then + dep_tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA m + fi +fi + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 0a056d23e..3e91edffd 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -566,6 +566,11 @@ else endif endif +ifeq ($(CONFIG_DRM),y) + ALL_SUB_DIRS += drm + MOD_SUB_DIRS += drm +endif + include $(TOPDIR)/Rules.make fastdep: diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c index a7ee73433..eaf1a8357 100644 --- a/drivers/char/adbmouse.c +++ b/drivers/char/adbmouse.c @@ -174,17 +174,23 @@ int __init adb_mouse_init(void) * option, which is about using ADB keyboard buttons to emulate * mouse buttons. -- paulus */ -void __init adb_mouse_setup(char *str, int *ints) +static int __init adb_mouse_setup(char *str) { + int ints[4]; + + str = get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] >= 1) { - adb_emulate_buttons = ints[1] > 0; - if (ints[1] > 1) - adb_button2_keycode = ints[1]; + adb_emulate_buttons = ints[1]; if (ints[0] >= 2) - adb_button3_keycode = ints[2]; + adb_button2_keycode = ints[2]; + if (ints[0] >= 3) + adb_button3_keycode = ints[3]; } + return 1; } +__setup("adb_buttons=", adb_mouse_setup); + #ifdef MODULE int init_module(void) { diff --git a/drivers/char/buz.c b/drivers/char/buz.c index ba3861bf2..509f18b13 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index d01f4f63b..94e7e2628 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -619,6 +619,7 @@ static char rcsid[] = #include #include #include +#include #include #include @@ -626,8 +627,6 @@ static char rcsid[] = #include #include -#include - #define CY_LOCK(info,flags) \ do { \ spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \ diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile new file mode 100644 index 000000000..d72b726c0 --- /dev/null +++ b/drivers/char/drm/Makefile @@ -0,0 +1,27 @@ +# +# Makefile for the drm device driver. This driver provides support for +# the Direct Rendering Infrastructure (DRI) in XFree86 4.x. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +L_TARGET := libdrm.a + +L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ + lists.o lock.o ioctl.o fops.o vm.o dma.o + +M_OBJS := + +ifdef CONFIG_DRM_GAMMA +M_OBJS += gamma.o +endif + +include $(TOPDIR)/Rules.make + +gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) + $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm new file mode 100644 index 000000000..fc3c680e1 --- /dev/null +++ b/drivers/char/drm/README.drm @@ -0,0 +1,39 @@ + +The Direct Rendering Manager (drm) is a device-independent kernel-level +device driver that provides support for the XFree86 Direct Rendering +Infrastructure (DRI). + +The DRM supports the Direct Rendering Infrastructure (DRI) in four major +ways: + + 1. The DRM provides synchronized access to the graphics hardware via + the use of an optimized two-tiered lock. + + 2. The DRM enforces the DRI security policy for access to the graphics + hardware by only allowing authenticated X11 clients access to + restricted regions of memory. + + 3. The DRM provides a generic DMA engine, complete with multiple + queues and the ability to detect the need for an OpenGL context + switch. + + 4. The DRM is extensible via the use of small device-specific modules + that rely extensively on the API exported by the DRM module. + + +Documentation on the DRI is available from: + http://precisioninsight.com/piinsights.html + +For specific information about kernel-level support, see: + + The Direct Rendering Manager, Kernel Support for the Direct Rendering + Infrastructure + http://precisioninsight.com/dr/drm.html + + Hardware Locking for the Direct Rendering Infrastructure + http://precisioninsight.com/dr/locking.html + + A Security Analysis of the Direct Rendering Infrastructure + http://precisioninsight.com/dr/security.html + + diff --git a/drivers/char/drm/auth.c b/drivers/char/drm/auth.c new file mode 100644 index 000000000..2561264ff --- /dev/null +++ b/drivers/char/drm/auth.c @@ -0,0 +1,161 @@ +/* auth.c -- IOCTLs for authentication -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int drm_hash_magic(drm_magic_t magic) +{ + return magic & (DRM_HASH_SIZE-1); +} + +static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic) +{ + drm_file_t *retval = NULL; + drm_magic_entry_t *pt; + int hash = drm_hash_magic(magic); + + down(&dev->struct_sem); + for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { + if (pt->priv->authenticated) continue; + if (pt->magic == magic) { + retval = pt->priv; + break; + } + } + up(&dev->struct_sem); + return retval; +} + +int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) +{ + int hash; + drm_magic_entry_t *entry; + + DRM_DEBUG("%d\n", magic); + + hash = drm_hash_magic(magic); + entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); + if (!entry) return -ENOMEM; + entry->magic = magic; + entry->priv = priv; + entry->next = NULL; + + down(&dev->struct_sem); + if (dev->magiclist[hash].tail) { + dev->magiclist[hash].tail->next = entry; + dev->magiclist[hash].tail = entry; + } else { + dev->magiclist[hash].head = entry; + dev->magiclist[hash].tail = entry; + } + up(&dev->struct_sem); + + return 0; +} + +int drm_remove_magic(drm_device_t *dev, drm_magic_t magic) +{ + drm_magic_entry_t *prev = NULL; + drm_magic_entry_t *pt; + int hash; + + DRM_DEBUG("%d\n", magic); + hash = drm_hash_magic(magic); + + down(&dev->struct_sem); + for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { + if (pt->magic == magic) { + if (dev->magiclist[hash].head == pt) { + dev->magiclist[hash].head = pt->next; + } + if (dev->magiclist[hash].tail == pt) { + dev->magiclist[hash].tail = prev; + } + if (prev) { + prev->next = pt->next; + } + up(&dev->struct_sem); + return 0; + } + } + up(&dev->struct_sem); + + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + + return -EINVAL; +} + +int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + static drm_magic_t sequence = 0; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_auth_t auth; + + /* Find unique magic */ + if (priv->magic) { + auth.magic = priv->magic; + } else { + spin_lock(&lock); + do { + if (!sequence) ++sequence; /* reserve 0 */ + auth.magic = sequence++; + } while (drm_find_file(dev, auth.magic)); + spin_unlock(&lock); + priv->magic = auth.magic; + drm_add_magic(dev, priv, auth.magic); + } + + DRM_DEBUG("%u\n", auth.magic); + copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT); + return 0; +} + +int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_auth_t auth; + drm_file_t *file; + + copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT); + DRM_DEBUG("%u\n", auth.magic); + if ((file = drm_find_file(dev, auth.magic))) { + file->authenticated = 1; + drm_remove_magic(dev, auth.magic); + return 0; + } + return -EINVAL; +} diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c new file mode 100644 index 000000000..32469a83a --- /dev/null +++ b/drivers/char/drm/bufs.c @@ -0,0 +1,527 @@ +/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 22:48:10 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "linux/un.h" + + /* Compute order. Can be made faster. */ +int drm_order(unsigned long size) +{ + int order; + unsigned long tmp; + + for (order = 0, tmp = size; tmp >>= 1; ++order); + if (size & ~(1 << order)) ++order; + return order; +} + +int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map; + + if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */ + + map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + if (!map) return -ENOMEM; + if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EFAULT; + } + + DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", + map->offset, map->size, map->type); + if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + map->mtrr = -1; + map->handle = 0; + + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: + if (map->offset + map->size < map->offset + || map->offset < virt_to_phys(high_memory)) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } +#ifdef CONFIG_MTRR + if (map->type == _DRM_FRAME_BUFFER + || (map->flags & _DRM_WRITE_COMBINING)) { + map->mtrr = mtrr_add(map->offset, map->size, + MTRR_TYPE_WRCOMB, 1); + } +#endif + map->handle = drm_ioremap(map->offset, map->size); + break; + + + case _DRM_SHM: + DRM_DEBUG("%ld %d\n", map->size, drm_order(map->size)); + map->handle = (void *)drm_alloc_pages(drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + if (!map->handle) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + map->offset = (unsigned long)map->handle; + if (map->flags & _DRM_CONTAINS_LOCK) { + dev->lock.hw_lock = map->handle; /* Pointer to lock */ + } + break; + default: + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + + down(&dev->struct_sem); + if (dev->maplist) { + ++dev->map_count; + dev->maplist = drm_realloc(dev->maplist, + (dev->map_count-1) + * sizeof(*dev->maplist), + dev->map_count + * sizeof(*dev->maplist), + DRM_MEM_MAPS); + } else { + dev->map_count = 1; + dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist), + DRM_MEM_MAPS); + } + dev->maplist[dev->map_count-1] = map; + up(&dev->struct_sem); + + copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT); + if (map->type != _DRM_SHM) { + copy_to_user_ret(&((drm_map_t *)arg)->handle, + &map->offset, + sizeof(map->offset), + -EFAULT); + } + return 0; +} + +int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int count; + int order; + int size; + int total; + int page_order; + drm_buf_entry_t *entry; + unsigned long page; + drm_buf_t *buf; + int alignment; + unsigned long offset; + int i; + int byte_count; + int page_count; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + count = request.count; + order = drm_order(request.size); + size = 1 << order; + + DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n", + request.count, request.size, size, order, dev->queue_count); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + if (dev->queue_count) return -EBUSY; /* Not while in use */ + + alignment = (request.flags & DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + down(&dev->struct_sem); + entry = &dma->bufs[order]; + if (entry->buf_count) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->seglist = drm_alloc(count * sizeof(*entry->seglist), + DRM_MEM_SEGS); + if (!entry->seglist) { + drm_free(entry->buflist, + count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + up(&dev->struct_sem); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->seglist, 0, count * sizeof(*entry->seglist)); + + dma->pagelist = drm_realloc(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + DRM_DEBUG("pagelist: %d entries\n", + dma->page_count + (count << page_order)); + + + entry->buf_size = size; + entry->page_order = page_order; + byte_count = 0; + page_count = 0; + while (entry->buf_count < count) { + if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break; + entry->seglist[entry->seg_count++] = page; + for (i = 0; i < (1 << page_order); i++) { + DRM_DEBUG("page %d @ 0x%08lx\n", + dma->page_count + page_count, + page + PAGE_SIZE * i); + dma->pagelist[dma->page_count + page_count++] + = page + PAGE_SIZE * i; + } + for (offset = 0; + offset + size <= total && entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + byte_count + offset); + buf->address = (void *)(page + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->pid = 0; +#if DRM_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + DRM_DEBUG("buffer %d @ %p\n", + entry->buf_count, buf->address); + } + byte_count += PAGE_SIZE << page_order; + } + + dma->buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS); + for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++) + dma->buflist[i] = &entry->buflist[i - dma->buf_count]; + + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += entry->seg_count << page_order; + dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + + drm_freelist_create(&entry->freelist, entry->buf_count); + for (i = 0; i < entry->buf_count; i++) { + drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]); + } + + up(&dev->struct_sem); + + request.count = entry->buf_count; + request.size = size; + + copy_to_user_ret((drm_buf_desc_t *)arg, + &request, + sizeof(request), + -EFAULT); + + atomic_dec(&dev->buf_alloc); + return 0; +} + +int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_info_t request; + int i; + int count; + + if (!dma) return -EINVAL; + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_info_t *)arg, + sizeof(request), + -EFAULT); + + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) ++count; + } + + DRM_DEBUG("count = %d\n", count); + + if (request.count >= count) { + for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { + if (dma->bufs[i].buf_count) { + copy_to_user_ret(&request.list[count].count, + &dma->bufs[i].buf_count, + sizeof(dma->bufs[0] + .buf_count), + -EFAULT); + copy_to_user_ret(&request.list[count].size, + &dma->bufs[i].buf_size, + sizeof(dma->bufs[0].buf_size), + -EFAULT); + copy_to_user_ret(&request.list[count].low_mark, + &dma->bufs[i] + .freelist.low_mark, + sizeof(dma->bufs[0] + .freelist.low_mark), + -EFAULT); + copy_to_user_ret(&request.list[count] + .high_mark, + &dma->bufs[i] + .freelist.high_mark, + sizeof(dma->bufs[0] + .freelist.high_mark), + -EFAULT); + DRM_DEBUG("%d %d %d %d %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].buf_size, + dma->bufs[i].freelist.low_mark, + dma->bufs[i].freelist.high_mark); + ++count; + } + } + } + request.count = count; + + copy_to_user_ret((drm_buf_info_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return 0; +} + +int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + int order; + drm_buf_entry_t *entry; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_desc_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d, %d, %d\n", + request.size, request.low_mark, request.high_mark); + order = drm_order(request.size); + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; + entry = &dma->bufs[order]; + + if (request.low_mark < 0 || request.low_mark > entry->buf_count) + return -EINVAL; + if (request.high_mark < 0 || request.high_mark > entry->buf_count) + return -EINVAL; + + entry->freelist.low_mark = request.low_mark; + entry->freelist.high_mark = request.high_mark; + + return 0; +} + +int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_free_t request; + int i; + int idx; + drm_buf_t *buf; + + if (!dma) return -EINVAL; + + copy_from_user_ret(&request, + (drm_buf_free_t *)arg, + sizeof(request), + -EFAULT); + + DRM_DEBUG("%d\n", request.count); + for (i = 0; i < request.count; i++) { + copy_from_user_ret(&idx, + &request.list[i], + sizeof(idx), + -EFAULT); + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d freeing buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + drm_free_buffer(dev, buf); + } + + return 0; +} + +int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!dma) return -EINVAL; + + DRM_DEBUG("\n"); + + spin_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock(&dev->count_lock); + + copy_from_user_ret(&request, + (drm_buf_map_t *)arg, + sizeof(request), + -EFAULT); + + if (request.count >= dma->buf_count) { + virtual = do_mmap(filp, 0, dma->byte_count, + PROT_READ|PROT_WRITE, MAP_SHARED, 0); + if (virtual > -1024UL) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request.list[i].used, + &zero, + sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; + if (copy_to_user(&request.list[i].address, + &address, + sizeof(address))) { + retcode = -EFAULT; + goto done; + } + } + } +done: + request.count = dma->buf_count; + DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); + + copy_to_user_ret((drm_buf_map_t *)arg, + &request, + sizeof(request), + -EFAULT); + + return retcode; +} diff --git a/drivers/char/drm/context.c b/drivers/char/drm/context.c new file mode 100644 index 000000000..b85aed606 --- /dev/null +++ b/drivers/char/drm/context.c @@ -0,0 +1,308 @@ +/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 11:32:09 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx) +{ + DRM_DEBUG("\n"); + + if (atomic_read(&q->use_count) != 1 + || atomic_read(&q->finalization) + || atomic_read(&q->block_count)) { + DRM_ERROR("New queue is already in use: u%d f%d b%d\n", + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count)); + } + + atomic_set(&q->finalization, 0); + atomic_set(&q->block_count, 0); + atomic_set(&q->block_read, 0); + atomic_set(&q->block_write, 0); + atomic_set(&q->total_queued, 0); + atomic_set(&q->total_flushed, 0); + atomic_set(&q->total_locks, 0); + + init_waitqueue_head(&q->write_queue); + init_waitqueue_head(&q->read_queue); + init_waitqueue_head(&q->flush_queue); + + q->flags = ctx->flags; + + drm_waitlist_create(&q->waitlist, dev->dma->buf_count); + + return 0; +} + + +/* drm_alloc_queue: +PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not + disappear (so all deallocation must be done after IOCTLs are off) + 2) dev->queue_count < dev->queue_slots + 3) dev->queuelist[i].use_count == 0 and + dev->queuelist[i].finalization == 0 if i not in use +POST: 1) dev->queuelist[i].use_count == 1 + 2) dev->queue_count < dev->queue_slots */ + +static int drm_alloc_queue(drm_device_t *dev) +{ + int i; + drm_queue_t *queue; + int oldslots; + int newslots; + /* Check for a free queue */ + for (i = 0; i < dev->queue_count; i++) { + atomic_inc(&dev->queuelist[i]->use_count); + if (atomic_read(&dev->queuelist[i]->use_count) == 1 + && !atomic_read(&dev->queuelist[i]->finalization)) { + DRM_DEBUG("%d (free)\n", i); + return i; + } + atomic_dec(&dev->queuelist[i]->use_count); + } + /* Allocate a new queue */ + down(&dev->struct_sem); + + queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES); + memset(queue, 0, sizeof(*queue)); + atomic_set(&queue->use_count, 1); + + ++dev->queue_count; + if (dev->queue_count >= dev->queue_slots) { + oldslots = dev->queue_slots * sizeof(*dev->queuelist); + if (!dev->queue_slots) dev->queue_slots = 1; + dev->queue_slots *= 2; + newslots = dev->queue_slots * sizeof(*dev->queuelist); + + dev->queuelist = drm_realloc(dev->queuelist, + oldslots, + newslots, + DRM_MEM_QUEUES); + if (!dev->queuelist) { + up(&dev->struct_sem); + DRM_DEBUG("out of memory\n"); + return -ENOMEM; + } + } + dev->queuelist[dev->queue_count-1] = queue; + + up(&dev->struct_sem); + DRM_DEBUG("%d (new)\n", dev->queue_count - 1); + return dev->queue_count - 1; +} + +int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + + +int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) { + /* Init kernel's context and get a new one. */ + drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); + ctx.handle = drm_alloc_queue(dev); + } + drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx); + DRM_DEBUG("%d\n", ctx.handle); + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + if (DRM_BUFCOUNT(&q->waitlist)) { + atomic_dec(&q->use_count); + return -EBUSY; + } + + q->flags = ctx.flags; + + atomic_dec(&q->use_count); + return 0; +} + +int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + ctx.flags = q->flags; + atomic_dec(&q->use_count); + + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + + return 0; +} + +int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return drm_context_switch(dev, dev->last_context, ctx.handle); +} + +int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + drm_context_switch_complete(dev, ctx.handle); + + return 0; +} + +int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + drm_buf_t *buf; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + atomic_inc(&q->finalization); /* Mark queue in finalization state */ + atomic_sub(2, &q->use_count); /* Mark queue as unused (pending + finalization) */ + + while (test_and_set_bit(0, &dev->interrupt_flag)) { + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + /* Remove queued buffers */ + while ((buf = drm_waitlist_get(&q->waitlist))) { + drm_free_buffer(dev, buf); + } + clear_bit(0, &dev->interrupt_flag); + + /* Wakeup blocked processes */ + wake_up_interruptible(&q->read_queue); + wake_up_interruptible(&q->write_queue); + wake_up_interruptible(&q->flush_queue); + + /* Finalization over. Queue is made + available when both use_count and + finalization become 0, which won't + happen until all the waiting processes + stop waiting. */ + atomic_dec(&q->finalization); + return 0; +} diff --git a/drivers/char/drm/dma.c b/drivers/char/drm/dma.c new file mode 100644 index 000000000..0ccbfc146 --- /dev/null +++ b/drivers/char/drm/dma.c @@ -0,0 +1,530 @@ +/* dma.c -- DMA IOCTL and function support -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 13:06:51 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/dma.c,v 1.6 1999/08/20 20:00:53 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#include /* For task queue support */ + +void drm_dma_setup(drm_device_t *dev) +{ + int i; + + dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER); + memset(dev->dma, 0, sizeof(*dev->dma)); + for (i = 0; i <= DRM_MAX_ORDER; i++) + memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); +} + +void drm_dma_takedown(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i, j; + + if (!dma) return; + + /* Clear dma buffers */ + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].seg_count) { + DRM_DEBUG("order %d: buf_count = %d," + " seg_count = %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].seg_count); + for (j = 0; j < dma->bufs[i].seg_count; j++) { + drm_free_pages(dma->bufs[i].seglist[j], + dma->bufs[i].page_order, + DRM_MEM_DMA); + } + drm_free(dma->bufs[i].buflist, + dma->buf_count + * sizeof(*dma->bufs[0].buflist), + DRM_MEM_BUFS); + drm_free(dma->bufs[i].seglist, + dma->buf_count + * sizeof(*dma->bufs[0].seglist), + DRM_MEM_SEGS); + drm_freelist_destroy(&dma->bufs[i].freelist); + } + } + + if (dma->buflist) { + drm_free(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + DRM_MEM_BUFS); + } + + if (dma->pagelist) { + drm_free(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = NULL; +} + +#if DRM_DMA_HISTOGRAM +/* This is slow, but is useful for debugging. */ +int drm_histogram_slot(unsigned long count) +{ + int value = DRM_DMA_HISTOGRAM_INITIAL; + int slot; + + for (slot = 0; + slot < DRM_DMA_HISTOGRAM_SLOTS; + ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) { + if (count < value) return slot; + } + return DRM_DMA_HISTOGRAM_SLOTS - 1; +} + +void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf) +{ + cycles_t queued_to_dispatched; + cycles_t dispatched_to_completed; + cycles_t completed_to_freed; + int q2d, d2c, c2f, q2c, q2f; + + if (buf->time_queued) { + queued_to_dispatched = (buf->time_dispatched + - buf->time_queued); + dispatched_to_completed = (buf->time_completed + - buf->time_dispatched); + completed_to_freed = (buf->time_freed + - buf->time_completed); + + q2d = drm_histogram_slot(queued_to_dispatched); + d2c = drm_histogram_slot(dispatched_to_completed); + c2f = drm_histogram_slot(completed_to_freed); + + q2c = drm_histogram_slot(queued_to_dispatched + + dispatched_to_completed); + q2f = drm_histogram_slot(queued_to_dispatched + + dispatched_to_completed + + completed_to_freed); + + atomic_inc(&dev->histo.total); + atomic_inc(&dev->histo.queued_to_dispatched[q2d]); + atomic_inc(&dev->histo.dispatched_to_completed[d2c]); + atomic_inc(&dev->histo.completed_to_freed[c2f]); + + atomic_inc(&dev->histo.queued_to_completed[q2c]); + atomic_inc(&dev->histo.queued_to_freed[q2f]); + + } + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +} +#endif + +void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf) +{ + drm_device_dma_t *dma = dev->dma; + + if (!buf) return; + + buf->waiting = 0; + buf->pending = 0; + buf->pid = 0; + buf->used = 0; +#if DRM_DMA_HISTOGRAM + buf->time_completed = get_cycles(); +#endif + if (waitqueue_active(&buf->dma_wait)) { + wake_up_interruptible(&buf->dma_wait); + } else { + /* If processes are waiting, the last one + to wake will put the buffer on the free + list. If no processes are waiting, we + put the buffer on the freelist here. */ + drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf); + } +} + +void drm_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + for (i = 0; i < dma->buf_count; i++) { + if (dma->buflist[i]->pid == pid) { + switch (dma->buflist[i]->list) { + case DRM_LIST_NONE: + drm_free_buffer(dev, dma->buflist[i]); + break; + case DRM_LIST_WAIT: + dma->buflist[i]->list = DRM_LIST_RECLAIM; + break; + default: + /* Buffer already on hardware. */ + break; + } + } + } +} + +int drm_context_switch(drm_device_t *dev, int old, int new) +{ + char buf[64]; + drm_queue_t *q; + + atomic_inc(&dev->total_ctx); + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new >= dev->queue_count) { + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + q = dev->queuelist[new]; + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + atomic_dec(&q->use_count); + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + if (drm_flags & DRM_FLAG_NOCTX) { + drm_context_switch_complete(dev, new); + } else { + sprintf(buf, "C %d %d\n", old, new); + drm_write_string(dev, buf); + } + + atomic_dec(&q->use_count); + + return 0; +} + +int drm_context_switch_complete(drm_device_t *dev, int new) +{ + drm_device_dma_t *dma = dev->dma; + + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("Cannot free lock\n"); + } + } + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() + - dev->ctx_start)]); + +#endif + clear_bit(0, &dev->context_flag); + wake_up_interruptible(&dev->context_wait); + + return 0; +} + +void drm_clear_next_buffer(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + + dma->next_buffer = NULL; + if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) { + wake_up_interruptible(&dma->next_queue->flush_queue); + } + dma->next_queue = NULL; +} + + +int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long)) +{ + int i; + int candidate = -1; + int j = jiffies; + + if (!dev) { + DRM_ERROR("No device\n"); + return -1; + } + if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) { + /* This only happens between the time the + interrupt is initialized and the time + the queues are initialized. */ + return -1; + } + + /* Doing "while locked" DMA? */ + if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { + return DRM_KERNEL_CONTEXT; + } + + /* If there are buffers on the last_context + queue, and we have not been executing + this context very long, continue to + execute this context. */ + if (dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j + && DRM_WAITCOUNT(dev, dev->last_context)) { + return dev->last_context; + } + + /* Otherwise, find a candidate */ + for (i = dev->last_checked + 1; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + + if (candidate < 0) { + for (i = 0; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + } + + if (wrapper + && candidate >= 0 + && candidate != dev->last_context + && dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j) { + if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) { + del_timer(&dev->timer); + dev->timer.function = wrapper; + dev->timer.data = (unsigned long)dev; + dev->timer.expires = dev->last_switch+DRM_TIME_SLICE; + add_timer(&dev->timer); + } + return -1; + } + + return candidate; +} + + +int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d) +{ + int i; + drm_queue_t *q; + drm_buf_t *buf; + int idx; + int while_locked = 0; + drm_device_dma_t *dma = dev->dma; + DECLARE_WAITQUEUE(entry, current); + + DRM_DEBUG("%d\n", d->send_count); + + if (d->flags & _DRM_DMA_WHILE_LOCKED) { + int context = dev->lock.hw_lock->lock; + + if (!_DRM_LOCK_IS_HELD(context)) { + DRM_ERROR("No lock held during \"while locked\"" + " request\n"); + return -EINVAL; + } + if (d->context != _DRM_LOCKING_CONTEXT(context) + && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) { + DRM_ERROR("Lock held by %d while %d makes" + " \"while locked\" request\n", + _DRM_LOCKING_CONTEXT(context), + d->context); + return -EINVAL; + } + q = dev->queuelist[DRM_KERNEL_CONTEXT]; + while_locked = 1; + } else { + q = dev->queuelist[d->context]; + } + + + atomic_inc(&q->use_count); + if (atomic_read(&q->block_write)) { + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&q->write_queue, &entry); + atomic_inc(&q->block_count); + for (;;) { + if (!atomic_read(&q->block_write)) break; + schedule(); + if (signal_pending(current)) { + atomic_dec(&q->use_count); + return -EINTR; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->write_queue, &entry); + } + + for (i = 0; i < d->send_count; i++) { + idx = d->send_indices[i]; + if (idx < 0 || idx >= dma->buf_count) { + atomic_dec(&q->use_count); + DRM_ERROR("Index %d (of %d max)\n", + d->send_indices[i], dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[ idx ]; + if (buf->pid != current->pid) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + if (buf->list != DRM_LIST_NONE) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer %d on list %d\n", + current->pid, buf->idx, buf->list); + } + buf->used = d->send_sizes[i]; + buf->while_locked = while_locked; + buf->context = d->context; + if (!buf->used) { + DRM_ERROR("Queueing 0 length buffer\n"); + } + if (buf->pending) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing pending buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + if (buf->waiting) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing waiting buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + buf->waiting = 1; + if (atomic_read(&q->use_count) == 1 + || atomic_read(&q->finalization)) { + drm_free_buffer(dev, buf); + } else { + drm_waitlist_put(&q->waitlist, buf); + atomic_inc(&q->total_queued); + } + } + atomic_dec(&q->use_count); + + return 0; +} + +static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d, + int order) +{ + int i; + drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = drm_freelist_get(&dma->bufs[order].freelist, + d->flags & _DRM_DMA_WAIT); + if (!buf) break; + if (buf->pending || buf->waiting) { + DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n", + buf->idx, + buf->pid, + buf->waiting, + buf->pending); + } + buf->pid = current->pid; + copy_to_user_ret(&d->request_indices[i], + &buf->idx, + sizeof(buf->idx), + -EFAULT); + copy_to_user_ret(&d->request_sizes[i], + &buf->total, + sizeof(buf->total), + -EFAULT); + ++d->granted_count; + } + return 0; +} + + +int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma) +{ + int order; + int retcode = 0; + int tmp_order; + + order = drm_order(dma->request_size); + + dma->granted_count = 0; + retcode = drm_dma_get_buffers_of_order(dev, dma, order); + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_SMALLER_OK)) { + for (tmp_order = order - 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order >= DRM_MIN_ORDER; + --tmp_order) { + + retcode = drm_dma_get_buffers_of_order(dev, dma, + tmp_order); + } + } + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_LARGER_OK)) { + for (tmp_order = order + 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order <= DRM_MAX_ORDER; + ++tmp_order) { + + retcode = drm_dma_get_buffers_of_order(dev, dma, + tmp_order); + } + } + return 0; +} diff --git a/drivers/char/drm/drawable.c b/drivers/char/drm/drawable.c new file mode 100644 index 000000000..6a8fc753a --- /dev/null +++ b/drivers/char/drm/drawable.c @@ -0,0 +1,50 @@ +/* drawable.c -- IOCTLs for drawables -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:27:03 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_draw_t draw; + + draw.handle = 0; /* NOOP */ + DRM_DEBUG("%d\n", draw.handle); + copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT); + return 0; +} + +int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return 0; /* NOOP */ +} diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h new file mode 100644 index 000000000..2251462e8 --- /dev/null +++ b/drivers/char/drm/drm.h @@ -0,0 +1,277 @@ +/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 13:08:18 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.46 1999/08/20 20:00:53 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.2 1999/06/27 14:08:21 dawes Exp $ + * + */ + +#ifndef _DRM_H_ +#define _DRM_H_ + +#include /* For _IO* macros */ + +#define DRM_PROC_DEVICES "/proc/devices" +#define DRM_PROC_MISC "/proc/misc" +#define DRM_PROC_DRM "/proc/drm" +#define DRM_DEV_DRM "/dev/drm" +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 + + +#define DRM_NAME "drm" /* Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /* At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /* Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /* How much system ram can we lock? */ + +#define _DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */ +#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) +#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) +#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + +typedef unsigned long drm_handle_t; +typedef unsigned int drm_context_t; +typedef unsigned int drm_drawable_t; +typedef unsigned int drm_magic_t; + + +typedef struct drm_version { + int version_major; /* Major version */ + int version_minor; /* Minor version */ + int version_patchlevel;/* Patch level */ + size_t name_len; /* Length of name buffer */ + char *name; /* Name of driver */ + size_t date_len; /* Length of date buffer */ + char *date; /* User-space buffer to hold date */ + size_t desc_len; /* Length of desc buffer */ + char *desc; /* User-space buffer to hold desc */ +} drm_version_t; + +typedef struct drm_unique { + size_t unique_len; /* Length of unique */ + char *unique; /* Unique name for driver instantiation */ +} drm_unique_t; + +typedef struct drm_list { + int count; /* Length of user-space structures */ + drm_version_t *version; +} drm_list_t; + +typedef struct drm_block { + int unused; +} drm_block_t; + +typedef struct drm_control { + enum { + DRM_ADD_COMMAND, + DRM_RM_COMMAND, + DRM_INST_HANDLER, + DRM_UNINST_HANDLER + } func; + int irq; +} drm_control_t; + +typedef enum drm_map_type { + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2 /* shared, cached */ +} drm_map_type_t; + +typedef enum drm_map_flags { + _DRM_RESTRICTED = 0x01, /* Cannot be mapped to user-virtual */ + _DRM_READ_ONLY = 0x02, + _DRM_LOCKED = 0x04, /* shared, cached, locked */ + _DRM_KERNEL = 0x08, /* kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /* use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20 /* SHM page that contains lock */ +} drm_map_flags_t; + +typedef struct drm_map { + unsigned long offset; /* Requested physical address (0 for SAREA)*/ + unsigned long size; /* Requested physical size (bytes) */ + drm_map_type_t type; /* Type of memory to map */ + drm_map_flags_t flags; /* Flags */ + void *handle; /* User-space: "Handle" to pass to mmap */ + /* Kernel-space: kernel-virtual address */ + int mtrr; /* MTRR slot used */ + /* Private data */ +} drm_map_t; + +typedef enum drm_lock_flags { + _DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + _DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */ +} drm_lock_flags_t; + +typedef struct drm_lock { + int context; + drm_lock_flags_t flags; +} drm_lock_t; + +typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. + Note, the buffer may not yet have + been processed by the hardware -- + getting a hardware lock with the + hardware quiescent will ensure + that the buffer has been + processed. */ + _DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /* Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */ + _DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */ +} drm_dma_flags_t; + +typedef struct drm_buf_desc { + int count; /* Number of buffers of this size */ + int size; /* Size in bytes */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ + enum { + DRM_PAGE_ALIGN = 0x01 /* Align on page boundaries for DMA */ + } flags; +} drm_buf_desc_t; + +typedef struct drm_buf_info { + int count; /* Entries in list */ + drm_buf_desc_t *list; +} drm_buf_info_t; + +typedef struct drm_buf_free { + int count; + int *list; +} drm_buf_free_t; + +typedef struct drm_buf_pub { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int used; /* Amount of buffer in use (for DMA) */ + void *address; /* Address of buffer */ +} drm_buf_pub_t; + +typedef struct drm_buf_map { + int count; /* Length of buflist */ + void *virtual; /* Mmaped area in user-virtual */ + drm_buf_pub_t *list; /* Buffer information */ +} drm_buf_map_t; + +typedef struct drm_dma { + /* Indices here refer to the offset into + buflist in drm_buf_get_t. */ + int context; /* Context handle */ + int send_count; /* Number of buffers to send */ + int *send_indices; /* List of handles to buffers */ + int *send_sizes; /* Lengths of data to send */ + drm_dma_flags_t flags; /* Flags */ + int request_count; /* Number of buffers requested */ + int request_size; /* Desired size for buffers */ + int *request_indices; /* Buffer information */ + int *request_sizes; + int granted_count; /* Number of buffers granted */ +} drm_dma_t; + +typedef enum { + _DRM_CONTEXT_PRESERVED = 0x01, + _DRM_CONTEXT_2DONLY = 0x02 +} drm_ctx_flags_t; + +typedef struct drm_ctx { + drm_context_t handle; + drm_ctx_flags_t flags; +} drm_ctx_t; + +typedef struct drm_ctx_res { + int count; + drm_ctx_t *contexts; +} drm_ctx_res_t; + +typedef struct drm_draw { + drm_drawable_t handle; +} drm_draw_t; + +typedef struct drm_auth { + drm_magic_t magic; +} drm_auth_t; + +typedef struct drm_irq_busid { + int irq; + int busnum; + int devnum; + int funcnum; +} drm_irq_busid_t; + +#define DRM_IOCTL_BASE 'd' +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) +#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) +#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size) +#define DRM_IOWR(nr,size) _IOWR(DRM_IOCTL_BASE,nr,size) + + +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t) +#define DRM_IOCTL_GET_MAGIC DRM_IOW( 0x02, drm_auth_t) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t) + +#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t) +#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t) +#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t) +#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t) +#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t) +#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t) +#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t) +#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t) +#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t) +#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t) +#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t) + +#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t) +#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t) +#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t) +#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t) +#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t) +#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t) +#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t) +#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t) +#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t) +#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t) +#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t) +#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t) +#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t) + +#endif diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h new file mode 100644 index 000000000..75103b074 --- /dev/null +++ b/drivers/char/drm/drmP.h @@ -0,0 +1,584 @@ +/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.58 1999/08/30 13:05:00 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.2 1999/06/27 14:08:24 dawes Exp $ + * + */ + +#ifndef _DRM_P_H_ +#define _DRM_P_H_ + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MTRR +#include +#endif +#include "drm.h" + +#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then + also include looping detection. */ +#define DRM_DMA_HISTOGRAM 1 /* Make histogram of DMA latency. */ + +#define DRM_HASH_SIZE 16 /* Size of key hash table */ +#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */ + +#define DRM_FLAG_DEBUG 0x01 +#define DRM_FLAG_NOCTX 0x02 + +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 + + /* Backward compatibility section */ +#ifndef _PAGE_PWT + /* The name of _PAGE_WT was changed to + _PAGE_PWT in Linux 2.2.6 */ +#define _PAGE_PWT _PAGE_WT +#endif + /* Wait queue declarations changes in 2.3.1 */ +#ifndef DECLARE_WAITQUEUE +#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL } +typedef struct wait_queue *wait_queue_head_t; +#define init_waitqueue_head(q) *q = NULL; +#endif + +#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) +#define _DRM_CAS(lock,old,new,__ret) \ + do { \ + int __dummy; /* Can't mark eax as clobbered */ \ + __asm__ __volatile__( \ + "lock ; cmpxchg %4,%1\n\t" \ + "setnz %0" \ + : "=d" (__ret), \ + "=m" (__drm_dummy_lock(lock)), \ + "=a" (__dummy) \ + : "2" (old), \ + "r" (new)); \ + } while (0) + + + + /* Macros to make printk easier */ +#define DRM_ERROR(fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg) +#define DRM_MEM_ERROR(area, fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \ + drm_mem_stats[area].name , ##arg) +#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) + +#if DRM_DEBUG_CODE +#define DRM_DEBUG(fmt, arg...) \ + do { \ + if (drm_flags&DRM_FLAG_DEBUG) \ + printk(KERN_DEBUG \ + "[" DRM_NAME ":" __FUNCTION__ "] " fmt , \ + ##arg); \ + } while (0) +#else +#define DRM_DEBUG(fmt, arg...) do { } while (0) +#endif + +#define DRM_PROC_LIMIT (PAGE_SIZE-80) + +#define DRM_PROC_PRINT(fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) return len; + +#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { ret; return len; } + + /* Internal types and structures */ +#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define DRM_MIN(a,b) ((a)<(b)?(a):(b)) +#define DRM_MAX(a,b) ((a)>(b)?(a):(b)) + +#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) +#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) +#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) + +typedef int drm_ioctl_t(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +typedef struct drm_ioctl_desc { + drm_ioctl_t *func; + int auth_needed; + int root_only; +} drm_ioctl_desc_t; + +typedef struct drm_devstate { + pid_t owner; /* X server pid holding x_lock */ + +} drm_devstate_t; + +typedef struct drm_magic_entry { + drm_magic_t magic; + struct drm_file *priv; + struct drm_magic_entry *next; +} drm_magic_entry_t; + +typedef struct drm_magic_head { + struct drm_magic_entry *head; + struct drm_magic_entry *tail; +} drm_magic_head_t; + +typedef struct drm_vma_entry { + struct vm_area_struct *vma; + struct drm_vma_entry *next; + pid_t pid; +} drm_vma_entry_t; + +typedef struct drm_buf { + int idx; /* Index into master buflist */ + int total; /* Buffer size */ + int order; /* log-base-2(total) */ + int used; /* Amount of buffer in use (for DMA) */ + unsigned long offset; /* Byte offset (used internally) */ + void *address; /* Address of buffer */ + struct drm_buf *next; /* Kernel-only: used for free list */ + __volatile__ int waiting; /* On kernel DMA queue */ + __volatile__ int pending; /* On hardware DMA queue */ + wait_queue_head_t dma_wait; /* Processes waiting */ + pid_t pid; /* PID of holding process */ + int context; /* Kernel queue for this buffer */ + int while_locked;/* Dispatch this buffer while locked */ + enum { + DRM_LIST_NONE = 0, + DRM_LIST_FREE = 1, + DRM_LIST_WAIT = 2, + DRM_LIST_PEND = 3, + DRM_LIST_PRIO = 4, + DRM_LIST_RECLAIM = 5 + } list; /* Which list we're on */ +#if DRM_DMA_HISTOGRAM + cycles_t time_queued; /* Queued to kernel DMA queue */ + cycles_t time_dispatched; /* Dispatched to hardware */ + cycles_t time_completed; /* Completed by hardware */ + cycles_t time_freed; /* Back on freelist */ +#endif +} drm_buf_t; + +#if DRM_DMA_HISTOGRAM +#define DRM_DMA_HISTOGRAM_SLOTS 9 +#define DRM_DMA_HISTOGRAM_INITIAL 10 +#define DRM_DMA_HISTOGRAM_NEXT(current) ((current)*10) +typedef struct drm_histogram { + atomic_t total; + + atomic_t queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; + + atomic_t queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; + + atomic_t dma[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t schedule[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t ctx[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t lacq[DRM_DMA_HISTOGRAM_SLOTS]; + atomic_t lhld[DRM_DMA_HISTOGRAM_SLOTS]; +} drm_histogram_t; +#endif + + /* bufs is one longer than it has to be */ +typedef struct drm_waitlist { + int count; /* Number of possible buffers */ + drm_buf_t **bufs; /* List of pointers to buffers */ + drm_buf_t **rp; /* Read pointer */ + drm_buf_t **wp; /* Write pointer */ + drm_buf_t **end; /* End pointer */ + spinlock_t read_lock; + spinlock_t write_lock; +} drm_waitlist_t; + +typedef struct drm_freelist { + int initialized; /* Freelist in use */ + atomic_t count; /* Number of free buffers */ + drm_buf_t *next; /* End pointer */ + + wait_queue_head_t waiting; /* Processes waiting on free bufs */ + int low_mark; /* Low water mark */ + int high_mark; /* High water mark */ + atomic_t wfh; /* If waiting for high mark */ +} drm_freelist_t; + +typedef struct drm_buf_entry { + int buf_size; + int buf_count; + drm_buf_t *buflist; + int seg_count; + int page_order; + unsigned long *seglist; + + drm_freelist_t freelist; +} drm_buf_entry_t; + +typedef struct drm_hw_lock { + __volatile__ unsigned int lock; + char padding[60]; /* Pad to cache line */ +} drm_hw_lock_t; + +typedef struct drm_file { + int authenticated; + int minor; + pid_t pid; + uid_t uid; + drm_magic_t magic; + unsigned long ioctl_count; + struct drm_file *next; + struct drm_file *prev; + struct drm_device *dev; +} drm_file_t; + + +typedef struct drm_queue { + atomic_t use_count; /* Outstanding uses (+1) */ + atomic_t finalization; /* Finalization in progress */ + atomic_t block_count; /* Count of processes waiting */ + atomic_t block_read; /* Queue blocked for reads */ + wait_queue_head_t read_queue; /* Processes waiting on block_read */ + atomic_t block_write; /* Queue blocked for writes */ + wait_queue_head_t write_queue; /* Processes waiting on block_write */ + atomic_t total_queued; /* Total queued statistic */ + atomic_t total_flushed;/* Total flushes statistic */ + atomic_t total_locks; /* Total locks statistics */ + drm_ctx_flags_t flags; /* Context preserving and 2D-only */ + drm_waitlist_t waitlist; /* Pending buffers */ + wait_queue_head_t flush_queue; /* Processes waiting until flush */ +} drm_queue_t; + +typedef struct drm_lock_data { + drm_hw_lock_t *hw_lock; /* Hardware lock */ + pid_t pid; /* PID of lock holder (0=kernel) */ + wait_queue_head_t lock_queue; /* Queue of blocked processes */ + unsigned long lock_time; /* Time of last lock in jiffies */ +} drm_lock_data_t; + +typedef struct drm_device_dma { + /* Performance Counters */ + atomic_t total_prio; /* Total DRM_DMA_PRIORITY */ + atomic_t total_bytes; /* Total bytes DMA'd */ + atomic_t total_dmas; /* Total DMA buffers dispatched */ + + atomic_t total_missed_dma; /* Missed drm_do_dma */ + atomic_t total_missed_lock; /* Missed lock in drm_do_dma */ + atomic_t total_missed_free; /* Missed drm_free_this_buffer */ + atomic_t total_missed_sched;/* Missed drm_dma_schedule */ + + atomic_t total_tried; /* Tried next_buffer */ + atomic_t total_hit; /* Sent next_buffer */ + atomic_t total_lost; /* Lost interrupt */ + + drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; + int buf_count; + drm_buf_t **buflist; /* Vector of pointers info bufs */ + int seg_count; + int page_count; + unsigned long *pagelist; + unsigned long byte_count; + + /* DMA support */ + drm_buf_t *this_buffer; /* Buffer being sent */ + drm_buf_t *next_buffer; /* Selected buffer to send */ + drm_queue_t *next_queue; /* Queue from which buffer selected*/ + wait_queue_head_t waiting; /* Processes waiting on free bufs */ +} drm_device_dma_t; + +typedef struct drm_device { + const char *name; /* Simple driver name */ + char *unique; /* Unique identifier: e.g., busid */ + int unique_len; /* Length of unique field */ + dev_t device; /* Device number for mknod */ + char *devname; /* For /proc/interrupts */ + + int blocked; /* Blocked due to VC switch? */ + struct proc_dir_entry *root; /* Root for this device's entries */ + + /* Locks */ + spinlock_t count_lock; /* For inuse, open_count, buf_use */ + struct semaphore struct_sem; /* For others */ + + /* Usage Counters */ + int open_count; /* Outstanding files open */ + atomic_t ioctl_count; /* Outstanding IOCTLs pending */ + atomic_t vma_count; /* Outstanding vma areas open */ + int buf_use; /* Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /* Buffer allocation in progress */ + + /* Performance Counters */ + atomic_t total_open; + atomic_t total_close; + atomic_t total_ioctl; + atomic_t total_irq; /* Total interruptions */ + atomic_t total_ctx; /* Total context switches */ + + atomic_t total_locks; + atomic_t total_unlocks; + atomic_t total_contends; + atomic_t total_sleeps; + + /* Authentication */ + drm_file_t *file_first; + drm_file_t *file_last; + drm_magic_head_t magiclist[DRM_HASH_SIZE]; + + /* Memory management */ + drm_map_t **maplist; /* Vector of pointers to regions */ + int map_count; /* Number of mappable regions */ + + drm_vma_entry_t *vmalist; /* List of vmas (for debugging) */ + drm_lock_data_t lock; /* Information on hardware lock */ + + /* DMA queues (contexts) */ + int queue_count; /* Number of active DMA queues */ + int queue_reserved; /* Number of reserved DMA queues */ + int queue_slots; /* Actual length of queuelist */ + drm_queue_t **queuelist; /* Vector of pointers to DMA queues */ + drm_device_dma_t *dma; /* Optional pointer for DMA support */ + + /* Context support */ + int irq; /* Interrupt used by board */ + __volatile__ int context_flag; /* Context swapping flag */ + __volatile__ int interrupt_flag;/* Interruption handler flag */ + __volatile__ int dma_flag; /* DMA dispatch flag */ + struct timer_list timer; /* Timer for delaying ctx switch */ + wait_queue_head_t context_wait; /* Processes waiting on ctx switch */ + int last_checked; /* Last context checked for DMA */ + int last_context; /* Last current context */ + unsigned long last_switch; /* jiffies at last context switch */ + struct tq_struct tq; + cycles_t ctx_start; + cycles_t lck_start; +#if DRM_DMA_HISTOGRAM + drm_histogram_t histo; +#endif + + /* Callback to X server for context switch + and for heavy-handed reset. */ + char buf[DRM_BSZ]; /* Output buffer */ + char *buf_rp; /* Read pointer */ + char *buf_wp; /* Write pointer */ + char *buf_end; /* End pointer */ + struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ + wait_queue_head_t buf_readers; /* Processes waiting to read */ + wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ +} drm_device_t; + + + /* Internal function definitions */ + + /* Misc. support (init.c) */ +extern int drm_flags; +extern void drm_parse_options(char *s); + + + /* Device support (fops.c) */ +extern int drm_open_helper(struct inode *inode, struct file *filp, + drm_device_t *dev); +extern int drm_flush(struct file *filp); +extern int drm_release(struct inode *inode, struct file *filp); +extern int drm_fasync(int fd, struct file *filp, int on); +extern ssize_t drm_read(struct file *filp, char *buf, size_t count, + loff_t *off); +extern int drm_write_string(drm_device_t *dev, const char *s); + + /* Mapping support (vm.c) */ +extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access); +extern void drm_vm_open(struct vm_area_struct *vma); +extern void drm_vm_close(struct vm_area_struct *vma); +extern int drm_mmap_dma(struct file *filp, + struct vm_area_struct *vma); +extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); + + + /* Proc support (proc.c) */ +extern int drm_proc_init(drm_device_t *dev); +extern int drm_proc_cleanup(void); + + /* Memory management support (memory.c) */ +extern void drm_mem_init(void); +extern int drm_mem_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +extern void *drm_alloc(size_t size, int area); +extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, + int area); +extern char *drm_strdup(const char *s, int area); +extern void drm_strfree(const char *s, int area); +extern void drm_free(void *pt, size_t size, int area); +extern unsigned long drm_alloc_pages(int order, int area); +extern void drm_free_pages(unsigned long address, int order, + int area); +extern void *drm_ioremap(unsigned long offset, unsigned long size); +extern void drm_ioremapfree(void *pt, unsigned long size); + + /* Buffer management support (bufs.c) */ +extern int drm_order(unsigned long size); +extern int drm_addmap(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_addbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_infobufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_markbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_freebufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mapbufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Buffer list management support (lists.c) */ +extern int drm_waitlist_create(drm_waitlist_t *bl, int count); +extern int drm_waitlist_destroy(drm_waitlist_t *bl); +extern int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf); +extern drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl); + +extern int drm_freelist_create(drm_freelist_t *bl, int count); +extern int drm_freelist_destroy(drm_freelist_t *bl); +extern int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, + drm_buf_t *buf); +extern drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block); + + /* DMA support (gen_dma.c) */ +extern void drm_dma_setup(drm_device_t *dev); +extern void drm_dma_takedown(drm_device_t *dev); +extern void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern int drm_context_switch(drm_device_t *dev, int old, int new); +extern int drm_context_switch_complete(drm_device_t *dev, int new); +extern void drm_wakeup(drm_device_t *dev, drm_buf_t *buf); +extern void drm_clear_next_buffer(drm_device_t *dev); +extern int drm_select_queue(drm_device_t *dev, + void (*wrapper)(unsigned long)); +extern int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma); +extern int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma); +#if DRM_DMA_HISTOGRAM +extern int drm_histogram_slot(unsigned long count); +extern void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf); +#endif + + + /* Misc. IOCTL support (ioctl.c) */ +extern int drm_irq_busid(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_getunique(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_setunique(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Context IOCTL support (context.c) */ +extern int drm_resctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_addctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_modctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_getctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_switchctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_newctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_rmctx(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Drawable IOCTL support (drawable.c) */ +extern int drm_adddraw(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_rmdraw(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Authentication IOCTL support (auth.c) */ +extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv, + drm_magic_t magic); +extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic); +extern int drm_getmagic(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_authmagic(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + + /* Locking IOCTL support (lock.c) */ +extern int drm_block(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_unblock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_lock_take(__volatile__ unsigned int *lock, + unsigned int context); +extern int drm_lock_transfer(__volatile__ unsigned int *lock, + unsigned int context); +extern int drm_lock_free(drm_device_t *dev, + __volatile__ unsigned int *lock, + unsigned int context); +extern int drm_finish(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_flush_unblock(drm_device_t *dev, int context, + drm_lock_flags_t flags); +extern int drm_flush_block_and_flush(drm_device_t *dev, int context, + drm_lock_flags_t flags); +#endif +#endif diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c new file mode 100644 index 000000000..e0cf4ad20 --- /dev/null +++ b/drivers/char/drm/fops.c @@ -0,0 +1,204 @@ +/* fops.c -- File operations for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 11:31:46 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +/* drm_open is called whenever a process opens /dev/drm. */ + +int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev) +{ + kdev_t minor = MINOR(inode->i_rdev); + drm_file_t *priv; + + if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ + + DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + + priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + memset(priv, 0, sizeof(*priv)); + filp->private_data = priv; + priv->uid = current->euid; + priv->pid = current->pid; + priv->minor = minor; + priv->dev = dev; + priv->ioctl_count = 0; + priv->authenticated = capable(CAP_SYS_ADMIN); + + down(&dev->struct_sem); + if (!dev->file_last) { + priv->next = NULL; + priv->prev = NULL; + dev->file_first = priv; + dev->file_last = priv; + } else { + priv->next = NULL; + priv->prev = dev->file_last; + dev->file_last->next = priv; + dev->file_last = priv; + } + up(&dev->struct_sem); + + return 0; +} + +int drm_flush(struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d, f_count = %d\n", + current->pid, dev->device, dev->open_count, filp->f_count); + return 0; +} + +/* drm_release is called whenever a process closes /dev/drm*. Linux calls + this only if any mappings have been closed. */ + +int drm_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", + current->pid, dev->device, dev->open_count); + + drm_reclaim_buffers(dev, priv->pid); + + drm_fasync(-1, filp, 0); + + down(&dev->struct_sem); + if (priv->prev) priv->prev->next = priv->next; + else dev->file_first = priv->next; + if (priv->next) priv->next->prev = priv->prev; + else dev->file_last = priv->prev; + up(&dev->struct_sem); + + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + + return 0; +} + +int drm_fasync(int fd, struct file *filp, int on) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode; + + DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device); + retcode = fasync_helper(fd, filp, on, &dev->buf_async); + if (retcode < 0) return retcode; + return 0; +} + + +/* The drm_read and drm_write_string code (especially that which manages + the circular buffer), is based on Alessandro Rubini's LINUX DEVICE + DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ + +ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int left; + int avail; + int send; + int cur; + + DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); + + while (dev->buf_rp == dev->buf_wp) { + DRM_DEBUG(" sleeping\n"); + if (filp->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + interruptible_sleep_on(&dev->buf_readers); + if (signal_pending(current)) { + DRM_DEBUG(" interrupted\n"); + return -ERESTARTSYS; + } + DRM_DEBUG(" awake\n"); + } + + left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + avail = DRM_BSZ - left; + send = DRM_MIN(avail, count); + + while (send) { + if (dev->buf_wp > dev->buf_rp) { + cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp); + } else { + cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); + } + copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL); + dev->buf_rp += cur; + if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; + send -= cur; + } + + wake_up_interruptible(&dev->buf_writers); + return DRM_MIN(avail, count);; +} + +int drm_write_string(drm_device_t *dev, const char *s) +{ + int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + int send = strlen(s); + int count; + + DRM_DEBUG("%d left, %d to send (%p, %p)\n", + left, send, dev->buf_rp, dev->buf_wp); + + if (left == 1 || dev->buf_wp != dev->buf_rp) { + DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n", + left, + dev->buf_wp, + dev->buf_rp); + } + + while (send) { + if (dev->buf_wp >= dev->buf_rp) { + count = DRM_MIN(send, dev->buf_end - dev->buf_wp); + if (count == left) --count; /* Leave a hole */ + } else { + count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1); + } + strncpy(dev->buf_wp, s, count); + dev->buf_wp += count; + if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf; + send -= count; + } + + if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); + DRM_DEBUG("waking\n"); + wake_up_interruptible(&dev->buf_readers); + return 0; +} diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c new file mode 100644 index 000000000..66d828a71 --- /dev/null +++ b/drivers/char/drm/gamma_dma.c @@ -0,0 +1,802 @@ +/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 11:31:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_dma.c,v 1.8 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "gamma_drv.h" + +#include /* For task queue support */ + + +/* WARNING!!! MAGIC NUMBER!!! The number of regions already added to the + kernel must be specified here. Currently, the number is 2. This must + match the order the X server uses for instantiating register regions , + or must be passed in a new ioctl. */ +#define GAMMA_REG(reg) \ + (2 \ + + ((reg < 0x1000) \ + ? 0 \ + : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3)))) + +#define GAMMA_OFF(reg) \ + ((reg < 0x1000) \ + ? reg \ + : ((reg < 0x10000) \ + ? (reg - 0x1000) \ + : ((reg < 0x11000) \ + ? (reg - 0x10000) \ + : (reg - 0x11000)))) + +#define GAMMA_BASE(reg) ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle) +#define GAMMA_ADDR(reg) (GAMMA_BASE(reg) + GAMMA_OFF(reg)) +#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg) +#define GAMMA_READ(reg) GAMMA_DEREF(reg) +#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0) + +#define GAMMA_BROADCASTMASK 0x9378 +#define GAMMA_COMMANDINTENABLE 0x0c48 +#define GAMMA_DMAADDRESS 0x0028 +#define GAMMA_DMACOUNT 0x0030 +#define GAMMA_FILTERMODE 0x8c00 +#define GAMMA_GCOMMANDINTFLAGS 0x0c50 +#define GAMMA_GCOMMANDMODE 0x0c40 +#define GAMMA_GCOMMANDSTATUS 0x0c60 +#define GAMMA_GDELAYTIMER 0x0c38 +#define GAMMA_GDMACONTROL 0x0060 +#define GAMMA_GINTENABLE 0x0808 +#define GAMMA_GINTFLAGS 0x0810 +#define GAMMA_INFIFOSPACE 0x0018 +#define GAMMA_OUTFIFOWORDS 0x0020 +#define GAMMA_OUTPUTFIFO 0x2000 +#define GAMMA_SYNC 0x8c40 +#define GAMMA_SYNC_TAG 0x0188 + +static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address, + unsigned long length) +{ + GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address)); + while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4) + ; + GAMMA_WRITE(GAMMA_DMACOUNT, length / 4); +} + +static inline void gamma_dma_quiescent(drm_device_t *dev) +{ + while (GAMMA_READ(GAMMA_DMACOUNT)) + ; + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) + ; + GAMMA_WRITE(GAMMA_BROADCASTMASK, 3); + GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10); + GAMMA_WRITE(GAMMA_SYNC, 0); + + /* Read from first MX */ + do { + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)) + ; + } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG); + + + /* Read from second MX */ + do { + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000)) + ; + } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG); +} + +static inline void gamma_dma_ready(drm_device_t *dev) +{ + while (GAMMA_READ(GAMMA_DMACOUNT)) + ; +} + +static inline int gamma_dma_is_ready(drm_device_t *dev) +{ + return !GAMMA_READ(GAMMA_DMACOUNT); +} + +static void gamma_dma_service(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_device_dma_t *dma = dev->dma; + + atomic_inc(&dev->total_irq); + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */ + GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8); + GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001); + if (gamma_dma_is_ready(dev)) { + /* Free previous buffer */ + if (test_and_set_bit(0, &dev->dma_flag)) { + atomic_inc(&dma->total_missed_free); + return; + } + if (dma->this_buffer) { + drm_free_buffer(dev, dma->this_buffer); + dma->this_buffer = NULL; + } + clear_bit(0, &dev->dma_flag); + + /* Dispatch new buffer */ + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } +} + +/* Only called by gamma_dma_schedule. */ +static int gamma_do_dma(drm_device_t *dev, int locked) +{ + unsigned long address; + unsigned long length; + drm_buf_t *buf; + int retcode = 0; + drm_device_dma_t *dma = dev->dma; +#if DRM_DMA_HISTOGRAM + cycles_t dma_start, dma_stop; +#endif + + if (test_and_set_bit(0, &dev->dma_flag)) { + atomic_inc(&dma->total_missed_dma); + return -EBUSY; + } + +#if DRM_DMA_HISTOGRAM + dma_start = get_cycles(); +#endif + + if (!dma->next_buffer) { + DRM_ERROR("No next_buffer\n"); + clear_bit(0, &dev->dma_flag); + return -EINVAL; + } + + buf = dma->next_buffer; + address = (unsigned long)buf->address; + length = buf->used; + + DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", + buf->context, buf->idx, length); + + if (buf->list == DRM_LIST_RECLAIM) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + clear_bit(0, &dev->dma_flag); + return -EINVAL; + } + + if (!length) { + DRM_ERROR("0 length buffer\n"); + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + clear_bit(0, &dev->dma_flag); + return 0; + } + + if (!gamma_dma_is_ready(dev)) { + clear_bit(0, &dev->dma_flag); + return -EBUSY; + } + + if (buf->while_locked) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Dispatching buffer %d from pid %d" + " \"while locked\", but no lock held\n", + buf->idx, buf->pid); + } + } else { + if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + atomic_inc(&dma->total_missed_lock); + clear_bit(0, &dev->dma_flag); + return -EBUSY; + } + } + + if (dev->last_context != buf->context + && !(dev->queuelist[buf->context]->flags + & _DRM_CONTEXT_PRESERVED)) { + /* PRE: dev->last_context != buf->context */ + if (drm_context_switch(dev, dev->last_context, buf->context)) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + } + retcode = -EBUSY; + goto cleanup; + + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == buf->context. + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + } + + drm_clear_next_buffer(dev); + buf->pending = 1; + buf->waiting = 0; + buf->list = DRM_LIST_PEND; +#if DRM_DMA_HISTOGRAM + buf->time_dispatched = get_cycles(); +#endif + + gamma_dma_dispatch(dev, address, length); + drm_free_buffer(dev, dma->this_buffer); + dma->this_buffer = buf; + + atomic_add(length, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + + if (!buf->while_locked && !dev->context_flag && !locked) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } +cleanup: + + clear_bit(0, &dev->dma_flag); + +#if DRM_DMA_HISTOGRAM + dma_stop = get_cycles(); + atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); +#endif + + return retcode; +} + +static void gamma_dma_schedule_timer_wrapper(unsigned long dev) +{ + gamma_dma_schedule((drm_device_t *)dev, 0); +} + +static void gamma_dma_schedule_tq_wrapper(void *dev) +{ + gamma_dma_schedule(dev, 0); +} + +int gamma_dma_schedule(drm_device_t *dev, int locked) +{ + int next; + drm_queue_t *q; + drm_buf_t *buf; + int retcode = 0; + int processed = 0; + int missed; + int expire = 20; + drm_device_dma_t *dma = dev->dma; +#if DRM_DMA_HISTOGRAM + cycles_t schedule_start; +#endif + + if (test_and_set_bit(0, &dev->interrupt_flag)) { + /* Not reentrant */ + atomic_inc(&dma->total_missed_sched); + return -EBUSY; + } + missed = atomic_read(&dma->total_missed_sched); + +#if DRM_DMA_HISTOGRAM + schedule_start = get_cycles(); +#endif + +again: + if (dev->context_flag) { + clear_bit(0, &dev->interrupt_flag); + return -EBUSY; + } + if (dma->next_buffer) { + /* Unsent buffer that was previously + selected, but that couldn't be sent + because the lock could not be obtained + or the DMA engine wasn't ready. Try + again. */ + atomic_inc(&dma->total_tried); + if (!(retcode = gamma_do_dma(dev, locked))) { + atomic_inc(&dma->total_hit); + ++processed; + } + } else { + do { + next = drm_select_queue(dev, + gamma_dma_schedule_timer_wrapper); + if (next >= 0) { + q = dev->queuelist[next]; + buf = drm_waitlist_get(&q->waitlist); + dma->next_buffer = buf; + dma->next_queue = q; + if (buf && buf->list == DRM_LIST_RECLAIM) { + drm_clear_next_buffer(dev); + drm_free_buffer(dev, buf); + } + } + } while (next >= 0 && !dma->next_buffer); + if (dma->next_buffer) { + if (!(retcode = gamma_do_dma(dev, locked))) { + ++processed; + } + } + } + + if (--expire) { + if (missed != atomic_read(&dma->total_missed_sched)) { + atomic_inc(&dma->total_lost); + if (gamma_dma_is_ready(dev)) goto again; + } + if (processed && gamma_dma_is_ready(dev)) { + atomic_inc(&dma->total_lost); + processed = 0; + goto again; + } + } + + clear_bit(0, &dev->interrupt_flag); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() + - schedule_start)]); +#endif + return retcode; +} + +static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d) +{ + unsigned long address; + unsigned long length; + int must_free = 0; + int retcode = 0; + int i; + int idx; + drm_buf_t *buf; + drm_buf_t *last_buf = NULL; + drm_device_dma_t *dma = dev->dma; + DECLARE_WAITQUEUE(entry, current); + + /* Turn off interrupt handling */ + while (test_and_set_bit(0, &dev->interrupt_flag)) { + schedule(); + if (signal_pending(current)) return -EINTR; + } + if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { + while (!drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + ++must_free; + } + atomic_inc(&dma->total_prio); + + for (i = 0; i < d->send_count; i++) { + idx = d->send_indices[i]; + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + d->send_indices[i], dma->buf_count - 1); + continue; + } + buf = dma->buflist[ idx ]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + retcode = -EINVAL; + goto cleanup; + } + if (buf->list != DRM_LIST_NONE) { + DRM_ERROR("Process %d using %d's buffer on list %d\n", + current->pid, buf->pid, buf->list); + retcode = -EINVAL; + goto cleanup; + } + /* This isn't a race condition on + buf->list, since our concern is the + buffer reclaim during the time the + process closes the /dev/drm? handle, so + it can't also be doing DMA. */ + buf->list = DRM_LIST_PRIO; + buf->used = d->send_sizes[i]; + buf->context = d->context; + buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; + address = (unsigned long)buf->address; + length = buf->used; + if (!length) { + DRM_ERROR("0 length buffer\n"); + } + if (buf->pending) { + DRM_ERROR("Sending pending buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + retcode = -EINVAL; + goto cleanup; + } + if (buf->waiting) { + DRM_ERROR("Sending waiting buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + retcode = -EINVAL; + goto cleanup; + } + buf->pending = 1; + + if (dev->last_context != buf->context + && !(dev->queuelist[buf->context]->flags + & _DRM_CONTEXT_PRESERVED)) { + add_wait_queue(&dev->context_wait, &entry); + current->state = TASK_INTERRUPTIBLE; + /* PRE: dev->last_context != buf->context */ + drm_context_switch(dev, dev->last_context, + buf->context); + /* POST: we will wait for the context + switch and will dispatch on a later call + when dev->last_context == buf->context. + NOTE WE HOLD THE LOCK THROUGHOUT THIS + TIME! */ + schedule(); + current->state = TASK_RUNNING; + remove_wait_queue(&dev->context_wait, &entry); + if (signal_pending(current)) { + retcode = -EINTR; + goto cleanup; + } + if (dev->last_context != buf->context) { + DRM_ERROR("Context mismatch: %d %d\n", + dev->last_context, + buf->context); + } + } + +#if DRM_DMA_HISTOGRAM + buf->time_queued = get_cycles(); + buf->time_dispatched = buf->time_queued; +#endif + gamma_dma_dispatch(dev, address, length); + atomic_add(length, &dma->total_bytes); + atomic_inc(&dma->total_dmas); + + if (last_buf) { + drm_free_buffer(dev, last_buf); + } + last_buf = buf; + } + + +cleanup: + if (last_buf) { + gamma_dma_ready(dev); + drm_free_buffer(dev, last_buf); + } + + if (must_free && !dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } + clear_bit(0, &dev->interrupt_flag); + return retcode; +} + +static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +{ + DECLARE_WAITQUEUE(entry, current); + drm_buf_t *last_buf = NULL; + int retcode = 0; + drm_device_dma_t *dma = dev->dma; + + if (d->flags & _DRM_DMA_BLOCK) { + last_buf = dma->buflist[d->send_indices[d->send_count-1]]; + add_wait_queue(&last_buf->dma_wait, &entry); + } + + if ((retcode = drm_dma_enqueue(dev, d))) { + if (d->flags & _DRM_DMA_BLOCK) + remove_wait_queue(&last_buf->dma_wait, &entry); + return retcode; + } + + gamma_dma_schedule(dev, 0); + + if (d->flags & _DRM_DMA_BLOCK) { + DRM_DEBUG("%d waiting\n", current->pid); + current->state = TASK_INTERRUPTIBLE; + for (;;) { + if (!last_buf->waiting + && !last_buf->pending) + break; /* finished */ + schedule(); + if (signal_pending(current)) { + retcode = -EINTR; /* Can't restart */ + break; + } + } + current->state = TASK_RUNNING; + DRM_DEBUG("%d running\n", current->pid); + remove_wait_queue(&last_buf->dma_wait, &entry); + if (!retcode + || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { + if (!waitqueue_active(&last_buf->dma_wait)) { + drm_free_buffer(dev, last_buf); + } + } + if (retcode) { + DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", + d->context, + last_buf->waiting, + last_buf->pending, + DRM_WAITCOUNT(dev, d->context), + last_buf->idx, + last_buf->list, + last_buf->pid, + current->pid); + } + } + return retcode; +} + +int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + + copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); + DRM_DEBUG("%d %d: %d send, %d req\n", + current->pid, d.context, d.send_count, d.request_count); + + if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { + DRM_ERROR("Process %d using context %d\n", + current->pid, d.context); + return -EINVAL; + } + if (d.send_count < 0 || d.send_count > dma->buf_count) { + DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", + current->pid, d.send_count, dma->buf_count); + return -EINVAL; + } + if (d.request_count < 0 || d.request_count > dma->buf_count) { + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count); + return -EINVAL; + } + + if (d.send_count) { + if (d.flags & _DRM_DMA_PRIORITY) + retcode = gamma_dma_priority(dev, &d); + else + retcode = gamma_dma_send_buffers(dev, &d); + } + + d.granted_count = 0; + + if (!retcode && d.request_count) { + retcode = drm_dma_get_buffers(dev, &d); + } + + DRM_DEBUG("%d returning, granted = %d\n", + current->pid, d.granted_count); + copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); + + return retcode; +} + +int gamma_irq_install(drm_device_t *dev, int irq) +{ + int retcode; + + if (!irq) return -EINVAL; + + down(&dev->struct_sem); + if (dev->irq) { + up(&dev->struct_sem); + return -EBUSY; + } + dev->irq = irq; + up(&dev->struct_sem); + + DRM_DEBUG("%d\n", irq); + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + + dev->dma->next_buffer = NULL; + dev->dma->next_queue = NULL; + dev->dma->this_buffer = NULL; + + dev->tq.next = NULL; + dev->tq.sync = 0; + dev->tq.routine = gamma_dma_schedule_tq_wrapper; + dev->tq.data = dev; + + + /* Before installing handler */ + GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0); + GAMMA_WRITE(GAMMA_GDMACONTROL, 0); + + /* Install handler */ + if ((retcode = request_irq(dev->irq, + gamma_dma_service, + 0, + dev->devname, + dev))) { + down(&dev->struct_sem); + dev->irq = 0; + up(&dev->struct_sem); + return retcode; + } + + /* After installing handler */ + GAMMA_WRITE(GAMMA_GINTENABLE, 0x2001); + GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008); + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0x39090); + + return 0; +} + +int gamma_irq_uninstall(drm_device_t *dev) +{ + int irq; + + down(&dev->struct_sem); + irq = dev->irq; + dev->irq = 0; + up(&dev->struct_sem); + + if (!irq) return -EINVAL; + + DRM_DEBUG("%d\n", irq); + + GAMMA_WRITE(GAMMA_GDELAYTIMER, 0); + GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0); + GAMMA_WRITE(GAMMA_GINTENABLE, 0); + free_irq(irq, dev); + + return 0; +} + + +int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_control_t ctl; + int retcode; + + copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); + + switch (ctl.func) { + case DRM_INST_HANDLER: + if ((retcode = gamma_irq_install(dev, ctl.irq))) + return retcode; + break; + case DRM_UNINST_HANDLER: + if ((retcode = gamma_irq_uninstall(dev))) + return retcode; + break; + default: + return -EINVAL; + } + return 0; +} + +int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; + drm_queue_t *q; +#if DRM_DMA_HISTOGRAM + cycles_t start; + + dev->lck_start = start = get_cycles(); +#endif + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + + if (lock.context < 0 || lock.context >= dev->queue_count) + return -EINVAL; + q = dev->queuelist[lock.context]; + + ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + + if (!ret) { + if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) + != lock.context) { + long j = jiffies - dev->lock.lock_time; + + if (j > 0 && j <= DRM_LOCK_SLICE) { + /* Can't take lock if we just had it and + there is contention. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(j); + } + } + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + atomic_inc(&q->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + + drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */ + + if (!ret) { + if (lock.flags & _DRM_LOCK_READY) + gamma_dma_ready(dev); + if (lock.flags & _DRM_LOCK_QUIESCENT) + gamma_dma_quiescent(dev); + } + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); +#endif + + return ret; +} diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c new file mode 100644 index 000000000..d83c98ef9 --- /dev/null +++ b/drivers/char/drm/gamma_drv.c @@ -0,0 +1,525 @@ +/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.c,v 1.17 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define EXPORT_SYMTAB +#include "drmP.h" +#include "gamma_drv.h" +EXPORT_SYMBOL(gamma_init); +EXPORT_SYMBOL(gamma_cleanup); + +#define GAMMA_NAME "gamma" +#define GAMMA_DESC "3dlabs GMX 2000" +#define GAMMA_DATE "19990830" +#define GAMMA_MAJOR 0 +#define GAMMA_MINOR 0 +#define GAMMA_PATCHLEVEL 5 + +static drm_device_t gamma_device; + +static struct file_operations gamma_fops = { + open: gamma_open, + flush: drm_flush, + release: gamma_release, + ioctl: gamma_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, +}; + +static struct miscdevice gamma_misc = { + minor: MISC_DYNAMIC_MINOR, + name: GAMMA_NAME, + fops: &gamma_fops, +}; + +static drm_ioctl_desc_t gamma_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { gamma_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { gamma_control, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { drm_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { drm_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { drm_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { drm_resctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { gamma_dma, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { gamma_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { gamma_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls) + +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +static char *gamma = NULL; + +MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas."); +MODULE_DESCRIPTION("3dlabs GMX 2000"); +MODULE_PARM(gamma, "s"); + +/* init_module is called when insmod is used to load the module */ + +int init_module(void) +{ + return gamma_init(); +} + +/* cleanup_module is called when rmmod is used to unload the module */ + +void cleanup_module(void) +{ + gamma_cleanup(); +} +#endif + +#ifndef MODULE +/* gamma_setup is called by the kernel to parse command-line options passed + * via the boot-loader (e.g., LILO). It calls the insmod option routine, + * drm_parse_drm. + * + * This is not currently supported, since it requires changes to + * linux/init/main.c. */ + + +void __init gamma_setup(char *str, int *ints) +{ + if (ints[0] != 0) { + DRM_ERROR("Illegal command line format, ignored\n"); + return; + } + drm_parse_options(str); +} +#endif + +static int gamma_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + drm_dma_setup(dev); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); +#if DRM_DMA_HISTO + memset(&dev->histo, 0, sizeof(dev->histo)); +#endif + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + DRM_DEBUG("\n"); + + /* The kernel's context could be created here, but is now created + in drm_dma_enqueue. This is more resource-efficient for + hardware that does not do DMA, but may mean that + drm_select_queue fails between the time the interrupt is + initialized and the time the queues are initialized. */ + + return 0; +} + + +static int gamma_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + if (dev->irq) gamma_irq_uninstall(dev); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area and mtrr information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef CONFIG_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + drm_ioremapfree(map->handle, map->size); + break; + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + } + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + if (dev->queuelist) { + for (i = 0; i < dev->queue_count; i++) { + drm_waitlist_destroy(&dev->queuelist[i]->waitlist); + if (dev->queuelist[i]) { + drm_free(dev->queuelist[i], + sizeof(*dev->queuelist[0]), + DRM_MEM_QUEUES); + dev->queuelist[i] = NULL; + } + } + drm_free(dev->queuelist, + dev->queue_slots * sizeof(*dev->queuelist), + DRM_MEM_QUEUES); + dev->queuelist = NULL; + } + + drm_dma_takedown(dev); + + dev->queue_count = 0; + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +/* gamma_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). */ + +int gamma_init(void) +{ + int retcode; + drm_device_t *dev = &gamma_device; + + DRM_DEBUG("\n"); + + memset((void *)dev, 0, sizeof(*dev)); + dev->count_lock = SPIN_LOCK_UNLOCKED; + sema_init(&dev->struct_sem, 1); + +#ifdef MODULE + drm_parse_options(gamma); +#endif + + if ((retcode = misc_register(&gamma_misc))) { + DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME); + return retcode; + } + dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor); + dev->name = GAMMA_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + GAMMA_NAME, + GAMMA_MAJOR, + GAMMA_MINOR, + GAMMA_PATCHLEVEL, + GAMMA_DATE, + gamma_misc.minor); + + return 0; +} + +/* gamma_cleanup is called via cleanup_module at module unload time. */ + +void gamma_cleanup(void) +{ + drm_device_t *dev = &gamma_device; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + if (misc_deregister(&gamma_misc)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + gamma_takedown(dev); +} + +int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_version_t version; + int len; + + copy_from_user_ret(&version, + (drm_version_t *)arg, + sizeof(version), + -EFAULT); + +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + copy_to_user_ret(name, value, len, -EFAULT); \ + } + + version.version_major = GAMMA_MAJOR; + version.version_minor = GAMMA_MINOR; + version.version_patchlevel = GAMMA_PATCHLEVEL; + + DRM_COPY(version.name, GAMMA_NAME); + DRM_COPY(version.date, GAMMA_DATE); + DRM_COPY(version.desc, GAMMA_DESC); + + copy_to_user_ret((drm_version_t *)arg, + &version, + sizeof(version), + -EFAULT); + return 0; +} + +int gamma_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev = &gamma_device; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_open_helper(inode, filp, dev))) { + MOD_INC_USE_COUNT; + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return gamma_setup(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +int gamma_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (!(retcode = drm_release(inode, filp))) { + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return gamma_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + return retcode; +} + +/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ + +int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int retcode = 0; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= GAMMA_IOCTL_COUNT) { + retcode = -EINVAL; + } else { + ioctl = &gamma_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + retcode = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + retcode = -EACCES; + } else { + retcode = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + return retcode; +} + + +int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + drm_lock_transfer(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + gamma_dma_schedule(dev, 1); + if (!dev->context_flag) { + if (drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("\n"); + } + } +#if DRM_DMA_HISTOGRAM + atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() + - dev->lck_start)]); +#endif + + return 0; +} diff --git a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h new file mode 100644 index 000000000..d91526a98 --- /dev/null +++ b/drivers/char/drm/gamma_drv.h @@ -0,0 +1,58 @@ +/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:24:27 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.h,v 1.4 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#ifndef _GAMMA_DRV_H_ +#define _GAMMA_DRV_H_ + + /* gamma_drv.c */ +extern int gamma_init(void); +extern void gamma_cleanup(void); +extern int gamma_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_open(struct inode *inode, struct file *filp); +extern int gamma_release(struct inode *inode, struct file *filp); +extern int gamma_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* gamma_dma.c */ +extern int gamma_dma_schedule(drm_device_t *dev, int locked); +extern int gamma_dma(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int gamma_irq_install(drm_device_t *dev, int irq); +extern int gamma_irq_uninstall(drm_device_t *dev); +extern int gamma_control(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +#endif diff --git a/drivers/char/drm/init.c b/drivers/char/drm/init.c new file mode 100644 index 000000000..ecdf62e7c --- /dev/null +++ b/drivers/char/drm/init.c @@ -0,0 +1,99 @@ +/* init.c -- Setup/Cleanup for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_flags = 0; + +/* drm_parse_option parses a single option. See description for + drm_parse_drm for details. */ + +static void drm_parse_option(char *s) +{ + char *c, *r; + + DRM_DEBUG("\"%s\"\n", s); + if (!s || !*s) return; + for (c = s; *c && *c != ':'; c++); /* find : or \0 */ + if (*c) r = c + 1; else r = NULL; /* remember remainder */ + *c = '\0'; /* terminate */ + if (!strcmp(s, "noctx")) { + drm_flags |= DRM_FLAG_NOCTX; + DRM_INFO("Server-mediated context switching OFF\n"); + return; + } + if (!strcmp(s, "debug")) { + drm_flags |= DRM_FLAG_DEBUG; + DRM_INFO("Debug messages ON\n"); + return; + } + DRM_ERROR("\"%s\" is not a valid option\n", s); + return; +} + +/* drm_parse_options parse the insmod "drm=" options, or the command-line + * options passed to the kernel via LILO. The grammar of the format is as + * follows: + * + * drm ::= 'drm=' option_list + * option_list ::= option [ ';' option_list ] + * option ::= 'device:' major + * | 'debug' + * | 'noctx' + * major ::= INTEGER + * + * Note that 's' contains option_list without the 'drm=' part. + * + * device=major,minor specifies the device number used for /dev/drm + * if major == 0 then the misc device is used + * if major == 0 and minor == 0 then dynamic misc allocation is used + * debug=on specifies that debugging messages will be printk'd + * debug=trace specifies that each function call will be logged via printk + * debug=off turns off all debugging options + * + */ + +void drm_parse_options(char *s) +{ + char *h, *t, *n; + + DRM_DEBUG("\"%s\"\n", s ?: ""); + if (!s || !*s) return; + + for (h = t = n = s; h && *h; h = n) { + for (; *t && *t != ';'; t++); /* find ; or \0 */ + if (*t) n = t + 1; else n = NULL; /* remember next */ + *t = '\0'; /* terminate */ + drm_parse_option(h); /* parse */ + } +} + diff --git a/drivers/char/drm/ioctl.c b/drivers/char/drm/ioctl.c new file mode 100644 index 000000000..e5bfd6953 --- /dev/null +++ b/drivers/char/drm/ioctl.c @@ -0,0 +1,91 @@ +/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*- + * Created: Fri Jan 8 09:01:26 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_irq_busid_t p; + struct pci_dev *dev; + + copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT); + dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); + if (dev) p.irq = dev->irq; + else p.irq = 0; + DRM_DEBUG("%d:%d:%d => IRQ %d\n", + p.busnum, p.devnum, p.funcnum, p.irq); + copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT); + return 0; +} + +int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_unique_t u; + + copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); + if (u.unique_len >= dev->unique_len) { + copy_to_user_ret(u.unique, dev->unique, dev->unique_len, + -EFAULT); + } + u.unique_len = dev->unique_len; + copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT); + return 0; +} + +int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_unique_t u; + + if (dev->unique_len || dev->unique) return -EBUSY; + + copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT); + if (!u.unique_len) return -EINVAL; + + dev->unique_len = u.unique_len; + dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER); + copy_from_user_ret(dev->unique, u.unique, dev->unique_len, + -EFAULT); + dev->unique[dev->unique_len] = '\0'; + + dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2, + DRM_MEM_DRIVER); + sprintf(dev->devname, "%s@%s", dev->name, dev->unique); + + return 0; +} diff --git a/drivers/char/drm/lists.c b/drivers/char/drm/lists.c new file mode 100644 index 000000000..062631f98 --- /dev/null +++ b/drivers/char/drm/lists.c @@ -0,0 +1,252 @@ +/* lists.c -- Buffer list handling routines -*- linux-c -*- + * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_waitlist_create(drm_waitlist_t *bl, int count) +{ + DRM_DEBUG("%d\n", count); + if (bl->count) return -EINVAL; + + bl->count = count; + bl->bufs = drm_alloc((bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + bl->rp = bl->bufs; + bl->wp = bl->bufs; + bl->end = &bl->bufs[bl->count+1]; + bl->write_lock = SPIN_LOCK_UNLOCKED; + bl->read_lock = SPIN_LOCK_UNLOCKED; + return 0; +} + +int drm_waitlist_destroy(drm_waitlist_t *bl) +{ + DRM_DEBUG("\n"); + if (bl->rp != bl->wp) return -EINVAL; + if (bl->bufs) drm_free(bl->bufs, + (bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + bl->count = 0; + bl->bufs = NULL; + bl->rp = NULL; + bl->wp = NULL; + bl->end = NULL; + return 0; +} + +int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf) +{ + int left; + unsigned long flags; + + left = DRM_LEFTCOUNT(bl); + DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n", + buf->idx, left, bl->rp, bl->wp); + if (!left) { + DRM_ERROR("Overflow while adding buffer %d from pid %d\n", + buf->idx, buf->pid); + return -EINVAL; + } +#if DRM_DMA_HISTOGRAM + buf->time_queued = get_cycles(); +#endif + buf->list = DRM_LIST_WAIT; + + spin_lock_irqsave(&bl->write_lock, flags); + *bl->wp = buf; + if (++bl->wp >= bl->end) bl->wp = bl->bufs; + spin_unlock_irqrestore(&bl->write_lock, flags); + + return 0; +} + +drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl) +{ + drm_buf_t *buf; + unsigned long flags; + + spin_lock_irqsave(&bl->read_lock, flags); + buf = *bl->rp; + if (bl->rp == bl->wp) { + spin_unlock_irqrestore(&bl->read_lock, flags); + return NULL; + } + if (++bl->rp >= bl->end) bl->rp = bl->bufs; + spin_unlock_irqrestore(&bl->read_lock, flags); + + DRM_DEBUG("get %d\n", buf->idx); + return buf; +} + +int drm_freelist_create(drm_freelist_t *bl, int count) +{ + DRM_DEBUG("\n"); + atomic_set(&bl->count, 0); + bl->next = NULL; + init_waitqueue_head(&bl->waiting); + bl->low_mark = 0; + bl->high_mark = 0; + atomic_set(&bl->wfh, 0); + ++bl->initialized; + return 0; +} + +int drm_freelist_destroy(drm_freelist_t *bl) +{ + DRM_DEBUG("\n"); + atomic_set(&bl->count, 0); + bl->next = NULL; + return 0; +} + +int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) +{ + unsigned int old; + unsigned int new; + char failed; + int count = 0; + drm_device_dma_t *dma = dev->dma; + + if (!dma) { + DRM_ERROR("No DMA support\n"); + return 1; + } + + if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) { + DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n", + buf->idx, buf->waiting, buf->pending, buf->list); + } + DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", + buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh), + buf->waiting, buf->pending); + if (!bl) return 1; +#if DRM_DMA_HISTOGRAM + buf->time_freed = get_cycles(); + drm_histogram_compute(dev, buf); +#endif + buf->list = DRM_LIST_FREE; + do { + old = (unsigned long)bl->next; + buf->next = (void *)old; + new = (unsigned long)buf; + _DRM_CAS(&bl->next, old, new, failed); + if (++count > DRM_LOOPING_LIMIT) { + DRM_ERROR("Looping\n"); + return 1; + } + } while (failed); + atomic_inc(&bl->count); + if (atomic_read(&bl->count) > dma->buf_count) { + DRM_ERROR("%d of %d buffers free after addition of %d\n", + atomic_read(&bl->count), dma->buf_count, buf->idx); + return 1; + } + /* Check for high water mark */ + if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) { + atomic_set(&bl->wfh, 0); + wake_up_interruptible(&bl->waiting); + } + return 0; +} + +static drm_buf_t *drm_freelist_try(drm_freelist_t *bl) +{ + unsigned int old; + unsigned int new; + char failed; + drm_buf_t *buf; + int count = 0; + + if (!bl) return NULL; + + /* Get buffer */ + do { + old = (unsigned int)bl->next; + if (!old) { + return NULL; + } + new = (unsigned long)bl->next->next; + _DRM_CAS(&bl->next, old, new, failed); + if (++count > DRM_LOOPING_LIMIT) { + DRM_ERROR("Looping\n"); + return NULL; + } + } while (failed); + atomic_dec(&bl->count); + + buf = (drm_buf_t *)old; + buf->next = NULL; + buf->list = DRM_LIST_NONE; + DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", + buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh), + buf->waiting, buf->pending); + if (buf->waiting || buf->pending) { + DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n", + buf->idx, buf->waiting, buf->pending, buf->list); + } + + return buf; +} + +drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block) +{ + drm_buf_t *buf = NULL; + DECLARE_WAITQUEUE(entry, current); + + if (!bl || !bl->initialized) return NULL; + + /* Check for low water mark */ + if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */ + atomic_set(&bl->wfh, 1); + if (atomic_read(&bl->wfh)) { + DRM_DEBUG("Block = %d, count = %d, wfh = %d\n", + block, atomic_read(&bl->count), + atomic_read(&bl->wfh)); + if (block) { + add_wait_queue(&bl->waiting, &entry); + current->state = TASK_INTERRUPTIBLE; + for (;;) { + if (!atomic_read(&bl->wfh) + && (buf = drm_freelist_try(bl))) break; + schedule(); + if (signal_pending(current)) break; + } + current->state = TASK_RUNNING; + remove_wait_queue(&bl->waiting, &entry); + } + return buf; + } + + DRM_DEBUG("Count = %d, wfh = %d\n", + atomic_read(&bl->count), atomic_read(&bl->wfh)); + return drm_freelist_try(bl); +} diff --git a/drivers/char/drm/lock.c b/drivers/char/drm/lock.c new file mode 100644 index 000000000..03931acc3 --- /dev/null +++ b/drivers/char/drm/lock.c @@ -0,0 +1,227 @@ +/* lock.c -- IOCTLs for locking -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int drm_block(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + DRM_DEBUG("\n"); + return 0; +} + +int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + DRM_DEBUG("\n"); + return 0; +} + +int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) +{ + unsigned int old; + unsigned int new; + char failed; + + DRM_DEBUG("%d attempts\n", context); + do { + old = *lock; + if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; + else new = context | _DRM_LOCK_HELD; + _DRM_CAS(lock, old, new, failed); + } while (failed); + if (_DRM_LOCKING_CONTEXT(old) == context) { + if (old & _DRM_LOCK_HELD) { + if (context != DRM_KERNEL_CONTEXT) { + DRM_ERROR("%d holds heavyweight lock\n", + context); + } + return 0; + } + } + if (new == (context | _DRM_LOCK_HELD)) { + /* Have lock */ + DRM_DEBUG("%d\n", context); + return 1; + } + DRM_DEBUG("%d unable to get lock held by %d\n", + context, _DRM_LOCKING_CONTEXT(old)); + return 0; +} + +/* This takes a lock forcibly and hands it to context. Should ONLY be used + inside *_unlock to give lock to kernel before calling *_dma_schedule. */ +int drm_lock_transfer(__volatile__ unsigned int *lock, unsigned int context) +{ + unsigned int old; + unsigned int new; + char failed; + + do { + old = *lock; + new = context | _DRM_LOCK_HELD; + _DRM_CAS(lock, old, new, failed); + } while (failed); + DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context); + return 1; +} + +int drm_lock_free(drm_device_t *dev, + __volatile__ unsigned int *lock, unsigned int context) +{ + unsigned int old; + unsigned int new; + char failed; + + DRM_DEBUG("%d\n", context); + do { + old = *lock; + new = 0; + _DRM_CAS(lock, old, new, failed); + } while (failed); + if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { + DRM_ERROR("%d freed heavyweight lock held by %d\n", + context, + _DRM_LOCKING_CONTEXT(old)); + return 1; + } + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + return 0; +} + +static int drm_flush_queue(drm_device_t *dev, int context) +{ + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + atomic_inc(&q->block_write); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&q->flush_queue, &entry); + atomic_inc(&q->block_count); + for (;;) { + if (!DRM_BUFCOUNT(&q->waitlist)) break; + schedule(); + if (signal_pending(current)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->flush_queue, &entry); + } + atomic_dec(&q->use_count); + atomic_inc(&q->total_flushed); + + /* NOTE: block_write is still incremented! + Use drm_flush_unlock_queue to decrement. */ + return ret; +} + +static int drm_flush_unblock_queue(drm_device_t *dev, int context) +{ + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + if (atomic_read(&q->block_write)) { + atomic_dec(&q->block_write); + wake_up_interruptible(&q->write_queue); + } + } + atomic_dec(&q->use_count); + return 0; +} + +int drm_flush_block_and_flush(drm_device_t *dev, int context, + drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = drm_flush_queue(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = drm_flush_queue(dev, i); + } + } + return ret; +} + +int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = drm_flush_unblock_queue(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = drm_flush_unblock_queue(dev, i); + } + } + + return ret; +} + +int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int ret = 0; + drm_lock_t lock; + + DRM_DEBUG("\n"); + + copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); + drm_flush_unblock(dev, lock.context, lock.flags); + return ret; +} diff --git a/drivers/char/drm/memory.c b/drivers/char/drm/memory.c new file mode 100644 index 000000000..f7b5335a5 --- /dev/null +++ b/drivers/char/drm/memory.c @@ -0,0 +1,320 @@ +/* memory.c -- Memory management wrappers for DRM -*- linux-c -*- + * Created: Thu Feb 4 14:00:34 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +typedef struct drm_mem_stats { + const char *name; + int succeed_count; + int free_count; + int fail_count; + unsigned long bytes_allocated; + unsigned long bytes_freed; +} drm_mem_stats_t; + +static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED; +static unsigned long drm_ram_available = 0; +static unsigned long drm_ram_used = 0; +static drm_mem_stats_t drm_mem_stats[] = { + [DRM_MEM_DMA] = { "dmabufs" }, + [DRM_MEM_SAREA] = { "sareas" }, + [DRM_MEM_DRIVER] = { "driver" }, + [DRM_MEM_MAGIC] = { "magic" }, + [DRM_MEM_IOCTLS] = { "ioctltab" }, + [DRM_MEM_MAPS] = { "maplist" }, + [DRM_MEM_VMAS] = { "vmalist" }, + [DRM_MEM_BUFS] = { "buflist" }, + [DRM_MEM_SEGS] = { "seglist" }, + [DRM_MEM_PAGES] = { "pagelist" }, + [DRM_MEM_FILES] = { "files" }, + [DRM_MEM_QUEUES] = { "queues" }, + [DRM_MEM_CMDS] = { "commands" }, + [DRM_MEM_MAPPINGS] = { "mappings" }, + [DRM_MEM_BUFLISTS] = { "buflists" }, + { NULL, 0, } /* Last entry must be null */ +}; + +void drm_mem_init(void) +{ + drm_mem_stats_t *mem; + struct sysinfo si; + + for (mem = drm_mem_stats; mem->name; ++mem) { + mem->succeed_count = 0; + mem->free_count = 0; + mem->fail_count = 0; + mem->bytes_allocated = 0; + mem->bytes_freed = 0; + } + + si_meminfo(&si); + drm_ram_available = si.totalram; + drm_ram_used = 0; +} + +/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ + +static int _drm_mem_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_mem_stats_t *pt; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" total counts " + " | outstanding \n"); + DRM_PROC_PRINT("type alloc freed fail bytes freed" + " | allocs bytes\n\n"); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n", + "system", 0, 0, 0, drm_ram_available); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu |\n", + "locked", 0, 0, 0, drm_ram_used); + DRM_PROC_PRINT("\n"); + for (pt = drm_mem_stats; pt->name; pt++) { + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", + pt->name, + pt->succeed_count, + pt->free_count, + pt->fail_count, + pt->bytes_allocated, + pt->bytes_freed, + pt->succeed_count - pt->free_count, + (long)pt->bytes_allocated + - (long)pt->bytes_freed); + } + + return len; +} + +int drm_mem_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + int ret; + + spin_lock(&drm_mem_lock); + ret = _drm_mem_info(buf, start, offset, len, eof, data); + spin_unlock(&drm_mem_lock); + return ret; +} + +void *drm_alloc(size_t size, int area) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); + return NULL; + } + + if (!(pt = kmalloc(size, GFP_KERNEL))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += size; + spin_unlock(&drm_mem_lock); + return pt; +} + +void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + void *pt; + + if (!(pt = drm_alloc(size, area))) return NULL; + if (oldpt && oldsize) { + memcpy(pt, oldpt, oldsize); + drm_free(oldpt, oldsize, area); + } + return pt; +} + +char *drm_strdup(const char *s, int area) +{ + char *pt; + int length = s ? strlen(s) : 0; + + if (!(pt = drm_alloc(length+1, area))) return NULL; + strcpy(pt, s); + return pt; +} + +void drm_strfree(const char *s, int area) +{ + unsigned int size; + + if (!s) return; + + size = 1 + (s ? strlen(s) : 0); + drm_free((void *)s, size, area); +} + +void drm_free(void *pt, size_t size, int area) +{ + int alloc_count; + int free_count; + + if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); + else kfree_s(pt, size); + spin_lock(&drm_mem_lock); + drm_mem_stats[area].bytes_freed += size; + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +unsigned long drm_alloc_pages(int order, int area) +{ + unsigned long address; + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + spin_lock(&drm_mem_lock); + if (drm_ram_used > +(DRM_RAM_PERCENT * drm_ram_available) / 100) { + spin_unlock(&drm_mem_lock); + return 0; + } + spin_unlock(&drm_mem_lock); + + address = __get_free_pages(GFP_KERNEL, order); + if (!address) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].fail_count; + spin_unlock(&drm_mem_lock); + return 0; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_allocated += bytes; + drm_ram_used += bytes; + spin_unlock(&drm_mem_lock); + + + /* Zero outside the lock */ + memset((void *)address, 0, bytes); + + /* Reserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + mem_map_reserve(MAP_NR(addr)); + } + + return address; +} + +void drm_free_pages(unsigned long address, int order, int area) +{ + unsigned long bytes = PAGE_SIZE << order; + int alloc_count; + int free_count; + unsigned long addr; + unsigned int sz; + + if (!address) { + DRM_MEM_ERROR(area, "Attempt to free address 0\n"); + } else { + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + mem_map_unreserve(MAP_NR(addr)); + } + free_pages(address, order); + } + + spin_lock(&drm_mem_lock); + free_count = ++drm_mem_stats[area].free_count; + alloc_count = drm_mem_stats[area].succeed_count; + drm_mem_stats[area].bytes_freed += bytes; + drm_ram_used -= bytes; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +void *drm_ioremap(unsigned long offset, unsigned long size) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = ioremap(offset, size))) { + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_mem_lock); + return NULL; + } + spin_lock(&drm_mem_lock); + ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_mem_lock); + return pt; +} + +void drm_ioremapfree(void *pt, unsigned long size) +{ + int alloc_count; + int free_count; + + if (!pt) + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Attempt to free NULL pointer\n"); + else + iounmap(pt); + + spin_lock(&drm_mem_lock); + drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count; + alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&drm_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} diff --git a/drivers/char/drm/proc.c b/drivers/char/drm/proc.c new file mode 100644 index 000000000..7db90aea8 --- /dev/null +++ b/drivers/char/drm/proc.c @@ -0,0 +1,568 @@ +/* proc.c -- /proc support for DRM -*- linux-c -*- + * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static struct proc_dir_entry *drm_root = NULL; +static struct proc_dir_entry *drm_dev_root = NULL; +static char drm_slot_name[64]; + +static int drm_name_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_vm_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_clients_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_queues_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +static int drm_bufs_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#if DRM_DEBUG_CODE +static int drm_vma_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#endif +#if DRM_DMA_HISTOGRAM +static int drm_histo_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); +#endif + +struct drm_proc_list { + const char *name; + int (*f)(char *, char **, off_t, int, int *, void *); +} drm_proc_list[] = { + { "name", drm_name_info }, + { "mem", drm_mem_info }, + { "vm", drm_vm_info }, + { "clients", drm_clients_info }, + { "queues", drm_queues_info }, + { "bufs", drm_bufs_info }, +#if DRM_DEBUG_CODE + { "vma", drm_vma_info }, +#endif +#if DRM_DMA_HISTOGRAM + { "histo", drm_histo_info }, +#endif +}; +#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) + +int drm_proc_init(drm_device_t *dev) +{ + struct proc_dir_entry *ent; + int i, j; + + drm_root = create_proc_entry("video", S_IFDIR, NULL); + if (!drm_root) { + DRM_ERROR("Cannot create /proc/video\n"); + return -1; + } + + /* Instead of doing this search, we should + add some global support for /proc/video. */ + for (i = 0; i < 8; i++) { + sprintf(drm_slot_name, "video/%d", i); + drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL); + if (!drm_dev_root) { + DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name); + remove_proc_entry("video", NULL); + } + if (drm_dev_root->nlink == 2) break; + drm_dev_root = NULL; + } + if (!drm_dev_root) { + DRM_ERROR("Cannot find slot in /proc/video\n"); + return -1; + } + + for (i = 0; i < DRM_PROC_ENTRIES; i++) { + ent = create_proc_entry(drm_proc_list[i].name, + S_IFREG|S_IRUGO, drm_dev_root); + if (!ent) { + DRM_ERROR("Cannot create /proc/%s/%s\n", + drm_slot_name, drm_proc_list[i].name); + for (j = 0; j < i; j++) + remove_proc_entry(drm_proc_list[i].name, + drm_dev_root); + remove_proc_entry(drm_slot_name, NULL); + remove_proc_entry("video", NULL); + return -1; + } + ent->read_proc = drm_proc_list[i].f; + ent->data = dev; + } + + return 0; +} + + +int drm_proc_cleanup(void) +{ + int i; + + if (drm_root) { + if (drm_dev_root) { + for (i = 0; i < DRM_PROC_ENTRIES; i++) { + remove_proc_entry(drm_proc_list[i].name, + drm_dev_root); + } + remove_proc_entry(drm_slot_name, NULL); + } + remove_proc_entry("video", NULL); + remove_proc_entry(DRM_NAME, NULL); + } + drm_root = drm_dev_root = NULL; + return 0; +} + +static int drm_name_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + if (dev->unique) { + DRM_PROC_PRINT("%s 0x%x %s\n", + dev->name, dev->device, dev->unique); + } else { + DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device); + } + return len; +} + +static int _drm_vm_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_map_t *map; + const char *types[] = { "FB", "REG", "SHM" }; + const char *type; + int i; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("slot offset size type flags " + "address mtrr\n\n"); + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (map->type < 0 || map->type > 2) type = "??"; + else type = types[map->type]; + DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", + i, + map->offset, + map->size, + type, + map->flags, + (unsigned long)map->handle); + if (map->mtrr < 0) { + DRM_PROC_PRINT("none\n"); + } else { + DRM_PROC_PRINT("%4d\n", map->mtrr); + } + } + + return len; +} + +static int drm_vm_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_vm_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + + +static int _drm_queues_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int i; + drm_queue_t *q; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" ctx/flags use fin" + " blk/rw/rwf wait flushed queued" + " locks\n\n"); + for (i = 0; i < dev->queue_count; i++) { + q = dev->queuelist[i]; + atomic_inc(&q->use_count); + DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), + "%5d/0x%03x %5d %5d" + " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n", + i, + q->flags, + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count), + atomic_read(&q->block_read) ? 'r' : '-', + atomic_read(&q->block_write) ? 'w' : '-', + waitqueue_active(&q->read_queue) ? 'r':'-', + waitqueue_active(&q->write_queue) ? 'w':'-', + waitqueue_active(&q->flush_queue) ? 'f':'-', + DRM_BUFCOUNT(&q->waitlist), + atomic_read(&q->total_flushed), + atomic_read(&q->total_queued), + atomic_read(&q->total_locks)); + atomic_dec(&q->use_count); + } + + return len; +} + +static int drm_queues_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_queues_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + +/* drm_bufs_info is called whenever a process reads + /dev/drm//bufs. */ + +static int _drm_bufs_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return 0; + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].buf_count) + DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", + i, + dma->bufs[i].buf_size, + dma->bufs[i].buf_count, + atomic_read(&dma->bufs[i] + .freelist.count), + dma->bufs[i].seg_count, + dma->bufs[i].seg_count + *(1 << dma->bufs[i].page_order), + (dma->bufs[i].seg_count + * (1 << dma->bufs[i].page_order)) + * PAGE_SIZE / 1024); + } + DRM_PROC_PRINT("\n"); + for (i = 0; i < dma->buf_count; i++) { + if (i && !(i%32)) DRM_PROC_PRINT("\n"); + DRM_PROC_PRINT(" %d", dma->buflist[i]->list); + } + DRM_PROC_PRINT("\n"); + + return len; +} + +static int drm_bufs_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_bufs_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + + +static int _drm_clients_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_file_t *priv; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); + for (priv = dev->file_first; priv; priv = priv->next) { + DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", + priv->authenticated ? 'y' : 'n', + priv->minor, + priv->pid, + priv->uid, + priv->magic, + priv->ioctl_count); + } + + return len; +} + +static int drm_clients_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_clients_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} + +#if DRM_DEBUG_CODE + +static int _drm_vma_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_vma_entry_t *pt; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long i; + struct vm_area_struct *vma; + unsigned long address; +#if defined(__i386__) + unsigned int pgprot; +#endif + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", + atomic_read(&dev->vma_count), + high_memory, virt_to_phys(high_memory)); + for (pt = dev->vmalist; pt; pt = pt->next) { + if (!(vma = pt->vma)) continue; + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + pt->pid, + vma->vm_start, + vma->vm_end, + vma->vm_flags & VM_READ ? 'r' : '-', + vma->vm_flags & VM_WRITE ? 'w' : '-', + vma->vm_flags & VM_EXEC ? 'x' : '-', + vma->vm_flags & VM_MAYSHARE ? 's' : 'p', + vma->vm_flags & VM_LOCKED ? 'l' : '-', + vma->vm_flags & VM_IO ? 'i' : '-', + vma->vm_offset ); +#if defined(__i386__) + pgprot = pgprot_val(vma->vm_page_prot); + DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", + pgprot & _PAGE_PRESENT ? 'p' : '-', + pgprot & _PAGE_RW ? 'w' : 'r', + pgprot & _PAGE_USER ? 'u' : 's', + pgprot & _PAGE_PWT ? 't' : 'b', + pgprot & _PAGE_PCD ? 'u' : 'c', + pgprot & _PAGE_ACCESSED ? 'a' : '-', + pgprot & _PAGE_DIRTY ? 'd' : '-', + pgprot & _PAGE_4M ? 'm' : 'k', + pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); +#endif + DRM_PROC_PRINT("\n"); + for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) { + pgd = pgd_offset(vma->vm_mm, i); + pmd = pmd_offset(pgd, i); + pte = pte_offset(pmd, i); + if (pte_present(*pte)) { + address = __pa(pte_page(*pte)) + + (i & (PAGE_SIZE-1)); + DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx" + " %c%c%c%c%c\n", + i, + address, + pte_read(*pte) ? 'r' : '-', + pte_write(*pte) ? 'w' : '-', + pte_exec(*pte) ? 'x' : '-', + pte_dirty(*pte) ? 'd' : '-', + pte_young(*pte) ? 'a' : '-' ); + } else { + DRM_PROC_PRINT(" 0x%08lx\n", i); + } + } + } + + return len; +} + +static int drm_vma_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_vma_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} +#endif + + +#if DRM_DMA_HISTOGRAM +static int _drm_histo_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_device_dma_t *dma = dev->dma; + int i; + unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL; + unsigned long prev_value = 0; + drm_buf_t *buffer; + + if (offset > 0) return 0; /* no partial requests */ + len = 0; + *eof = 1; + + DRM_PROC_PRINT("general statistics:\n"); + DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total)); + DRM_PROC_PRINT("open %10u\n", atomic_read(&dev->total_open)); + DRM_PROC_PRINT("close %10u\n", atomic_read(&dev->total_close)); + DRM_PROC_PRINT("ioctl %10u\n", atomic_read(&dev->total_ioctl)); + DRM_PROC_PRINT("irq %10u\n", atomic_read(&dev->total_irq)); + DRM_PROC_PRINT("ctx %10u\n", atomic_read(&dev->total_ctx)); + + DRM_PROC_PRINT("\nlock statistics:\n"); + DRM_PROC_PRINT("locks %10u\n", atomic_read(&dev->total_locks)); + DRM_PROC_PRINT("unlocks %10u\n", atomic_read(&dev->total_unlocks)); + DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends)); + DRM_PROC_PRINT("sleeps %10u\n", atomic_read(&dev->total_sleeps)); + + + if (dma) { + DRM_PROC_PRINT("\ndma statistics:\n"); + DRM_PROC_PRINT("prio %10u\n", + atomic_read(&dma->total_prio)); + DRM_PROC_PRINT("bytes %10u\n", + atomic_read(&dma->total_bytes)); + DRM_PROC_PRINT("dmas %10u\n", + atomic_read(&dma->total_dmas)); + DRM_PROC_PRINT("missed:\n"); + DRM_PROC_PRINT(" dma %10u\n", + atomic_read(&dma->total_missed_dma)); + DRM_PROC_PRINT(" lock %10u\n", + atomic_read(&dma->total_missed_lock)); + DRM_PROC_PRINT(" free %10u\n", + atomic_read(&dma->total_missed_free)); + DRM_PROC_PRINT(" sched %10u\n", + atomic_read(&dma->total_missed_sched)); + DRM_PROC_PRINT("tried %10u\n", + atomic_read(&dma->total_tried)); + DRM_PROC_PRINT("hit %10u\n", + atomic_read(&dma->total_hit)); + DRM_PROC_PRINT("lost %10u\n", + atomic_read(&dma->total_lost)); + + buffer = dma->next_buffer; + if (buffer) { + DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx); + } else { + DRM_PROC_PRINT("next_buffer none\n"); + } + buffer = dma->this_buffer; + if (buffer) { + DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx); + } else { + DRM_PROC_PRINT("this_buffer none\n"); + } + } + + + DRM_PROC_PRINT("\nvalues:\n"); + if (dev->lock.hw_lock) { + DRM_PROC_PRINT("lock 0x%08x\n", + dev->lock.hw_lock->lock); + } else { + DRM_PROC_PRINT("lock none\n"); + } + DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag); + DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag); + DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag); + + DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); + DRM_PROC_PRINT("last_context %10d\n", dev->last_context); + DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch); + DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked); + + + DRM_PROC_PRINT("\n q2d d2c c2f" + " q2c q2f dma sch" + " ctx lacq lhld\n\n"); + for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) { + DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u" + " %10u %10u %10u %10u %10u\n", + i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ", + i == DRM_DMA_HISTOGRAM_SLOTS - 1 + ? prev_value : slot_value , + + atomic_read(&dev->histo + .queued_to_dispatched[i]), + atomic_read(&dev->histo + .dispatched_to_completed[i]), + atomic_read(&dev->histo + .completed_to_freed[i]), + + atomic_read(&dev->histo + .queued_to_completed[i]), + atomic_read(&dev->histo + .queued_to_freed[i]), + atomic_read(&dev->histo.dma[i]), + atomic_read(&dev->histo.schedule[i]), + atomic_read(&dev->histo.ctx[i]), + atomic_read(&dev->histo.lacq[i]), + atomic_read(&dev->histo.lhld[i])); + prev_value = slot_value; + slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value); + } + return len; +} + +static int drm_histo_info(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = _drm_histo_info(buf, start, offset, len, eof, data); + up(&dev->struct_sem); + return ret; +} +#endif diff --git a/drivers/char/drm/sigio.c b/drivers/char/drm/sigio.c new file mode 100644 index 000000000..bb75087df --- /dev/null +++ b/drivers/char/drm/sigio.c @@ -0,0 +1,82 @@ +/* sigio.c -- Support for SIGIO handler -*- linux-c -*- + * Created: Thu Jun 3 15:39:18 1999 by faith@precisioninsight.com + * Revised: Thu Jun 3 16:16:35 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 21:11:29 faith Exp $ + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 12:02:11 dawes Exp $ + * + */ + + +#ifdef XFree86Server +# include "X.h" +# include "xf86.h" +# include "xf86drm.h" +# include "xf86_OSlib.h" +# include "xf86drm.h" +#else +# include +# include +# include +#endif + +/* + * Linux libc5 defines FASYNC, but not O_ASYNC. Don't know if it is + * functional or not. + */ +#if defined(FASYNC) && !defined(O_ASYNC) +# define O_ASYNC FASYNC +#endif + +int +xf86InstallSIGIOHandler(int fd, void (*f)(int)) +{ + struct sigaction sa; + struct sigaction osa; + + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGIO); + sa.sa_flags = 0; + sa.sa_handler = f; + sigaction(SIGIO, &sa, &osa); + fcntl(fd, F_SETOWN, getpid()); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC); + return 0; +} + +int +xf86RemoveSIGIOHandler(int fd) +{ + struct sigaction sa; + struct sigaction osa; + + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGIO); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC); + sigaction(SIGIO, &sa, &osa); + return 0; +} diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c new file mode 100644 index 000000000..55bfc4c45 --- /dev/null +++ b/drivers/char/drm/vm.c @@ -0,0 +1,264 @@ +/* vm.c -- Memory mapping for DRM -*- linux-c -*- + * Created: Mon Jan 4 08:58:31 1999 by faith@precisioninsight.com + * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $ + * $XFree86$ + * + */ + +#define __NO_VERSION__ +#include "drmP.h" + +struct vm_operations_struct drm_vm_ops = { + nopage: drm_vm_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + +struct vm_operations_struct drm_vm_shm_ops = { + nopage: drm_vm_shm_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + +struct vm_operations_struct drm_vm_dma_ops = { + nopage: drm_vm_dma_nopage, + open: drm_vm_open, + close: drm_vm_close, +}; + +unsigned long drm_vm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +{ + DRM_DEBUG("0x%08lx, %d\n", address, write_access); + + return 0; /* Disallow mremap */ +} + +unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + unsigned long physical; + unsigned long offset; + unsigned long page; + + if (address > vma->vm_end) return 0; /* Disallow mremap */ + if (!dev->lock.hw_lock) return 0; /* Nothing allocated */ + + offset = address - vma->vm_start; + page = offset >> PAGE_SHIFT; + physical = (unsigned long)dev->lock.hw_lock + (offset & (~PAGE_MASK)); + atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */ + + DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); + return physical; +} + +unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma, + unsigned long address, + int write_access) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + unsigned long physical; + unsigned long offset; + unsigned long page; + + if (!dma) return 0; /* Error */ + if (address > vma->vm_end) return 0; /* Disallow mremap */ + if (!dma->pagelist) return 0; /* Nothing allocated */ + + offset = address - vma->vm_start; /* vm_offset should be 0 */ + page = offset >> PAGE_SHIFT; + physical = dma->pagelist[page] + (offset & (~PAGE_MASK)); + atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */ + + DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); + return physical; +} + +void drm_vm_open(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; +#if DRM_DEBUG_CODE + drm_vma_entry_t *vma_entry; +#endif + + DRM_DEBUG("0x%08lx,0x%08lx\n", + vma->vm_start, vma->vm_end - vma->vm_start); + atomic_inc(&dev->vma_count); + MOD_INC_USE_COUNT; + +#if DRM_DEBUG_CODE + vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); + if (vma_entry) { + down(&dev->struct_sem); + vma_entry->vma = vma; + vma_entry->next = dev->vmalist; + vma_entry->pid = current->pid; + dev->vmalist = vma_entry; + up(&dev->struct_sem); + } +#endif +} + +void drm_vm_close(struct vm_area_struct *vma) +{ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; +#if DRM_DEBUG_CODE + drm_vma_entry_t *pt, *prev; +#endif + + DRM_DEBUG("0x%08lx,0x%08lx\n", + vma->vm_start, vma->vm_end - vma->vm_start); + MOD_DEC_USE_COUNT; + atomic_dec(&dev->vma_count); + +#if DRM_DEBUG_CODE + down(&dev->struct_sem); + for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { + if (pt->vma == vma) { + if (prev) { + prev->next = pt->next; + } else { + dev->vmalist = pt->next; + } + drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + break; + } + } + up(&dev->struct_sem); +#endif +} + +int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + unsigned long length = vma->vm_end - vma->vm_start; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_offset); + + /* Length must match exact page count */ + if ((length >> PAGE_SHIFT) != dma->page_count) return -EINVAL; + + vma->vm_ops = &drm_vm_dma_ops; + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ + /* In Linux 2.2.3 and above, this is + handled in do_mmap() in mm/mmap.c. */ + ++filp->f_count; +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} + +int drm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + int i; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_offset); + + if (!vma->vm_offset) return drm_mmap_dma(filp, vma); + + /* A sequential search of a linked list is + fine here because: 1) there will only be + about 5-10 entries in the list and, 2) a + DRI client only has to do this mapping + once, so it doesn't have to be optimized + for performance, even if the list was a + bit longer. */ + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (map->offset == vma->vm_offset) break; + } + + if (i >= dev->map_count) return -EINVAL; + if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) + return -EPERM; + + /* Check for valid size. */ + if (map->size != vma->vm_end - vma->vm_start) return -EINVAL; + + + switch (map->type) { + case _DRM_FRAME_BUFFER: + case _DRM_REGISTERS: + if (vma->vm_offset >= __pa(high_memory)) { +#if defined(__i386__) + if (boot_cpu_data.x86 > 3) { + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; + pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; + } +#endif + vma->vm_flags |= VM_IO; /* not in core dump */ + } + if (remap_page_range(vma->vm_start, + vma->vm_offset, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + vma->vm_ops = &drm_vm_ops; + break; + case _DRM_SHM: + vma->vm_ops = &drm_vm_shm_ops; + /* Don't let this area swap. Change when + DRM_KERNEL advisory is supported. */ + vma->vm_flags |= VM_LOCKED; + break; + default: + return -EINVAL; /* This should never happen. */ + } + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + if (map->flags & _DRM_READ_ONLY) { + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; + } + + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ + /* In Linux 2.2.3 and above, this is + handled in do_mmap() in mm/mmap.c. */ + ++filp->f_count; +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c index 29b5e16c9..a8f83ce8e 100644 --- a/drivers/char/i2c-parport.c +++ b/drivers/char/i2c-parport.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #define I2C_DELAY 10 diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c index 59579ab76..c567a8c20 100644 --- a/drivers/char/joystick/joystick.c +++ b/drivers/char/joystick/joystick.c @@ -43,7 +43,7 @@ #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include +#include #include #endif diff --git a/drivers/char/mem.c b/drivers/char/mem.c index abda28741..ff3158e96 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -268,6 +268,7 @@ static ssize_t write_kmem(struct file * file, const char * buf, return do_write_mem(file, (void*)p, p, buf, count, ppos); } +#if !defined(CONFIG_PPC) && !defined(__mc68000__) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -305,6 +306,7 @@ static ssize_t write_port(struct file * file, const char * buf, *ppos = i; return tmp-buf; } +#endif static ssize_t read_null(struct file * file, char * buf, size_t count, loff_t *ppos) @@ -515,6 +517,7 @@ static struct file_operations null_fops = { NULL /* fsync */ }; +#if !defined(CONFIG_PPC) && !defined(__mc68000__) static struct file_operations port_fops = { memory_lseek, read_port, @@ -528,6 +531,7 @@ static struct file_operations port_fops = { NULL, /* no special release code */ NULL /* fsync */ }; +#endif static struct file_operations zero_fops = { zero_lseek, diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index b3d02c231..b4b606974 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -17,7 +17,7 @@ #include -#include +#include #include #include #include diff --git a/drivers/char/q40_keyb.c b/drivers/char/q40_keyb.c index a4b966aac..7ee9818ef 100644 --- a/drivers/char/q40_keyb.c +++ b/drivers/char/q40_keyb.c @@ -5,7 +5,7 @@ #include -#include +#include #include #include #include diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c index e872450f0..17355d9f2 100644 --- a/drivers/i2o/i2o_config.c +++ b/drivers/i2o/i2o_config.c @@ -25,10 +25,10 @@ #include #include #include +#include #include #include -#include #include "i2o_proc.h" diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index 0bde47eea..a8395b15c 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -31,9 +31,9 @@ #include #include #include +#include #include -#include #include "i2o_lan.h" diff --git a/drivers/i2o/i2o_lan.c b/drivers/i2o/i2o_lan.c index dd5c7bf19..863780f38 100644 --- a/drivers/i2o/i2o_lan.c +++ b/drivers/i2o/i2o_lan.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c index 2c26d5e0c..23232e8ef 100644 --- a/drivers/i2o/i2o_proc.c +++ b/drivers/i2o/i2o_proc.c @@ -45,11 +45,11 @@ #include #include #include +#include #include #include #include -#include #include "i2o_proc.h" diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index f4dffcf08..93fe07774 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -117,7 +117,7 @@ static int serial_refcount; static void probe_sccs(void); static void change_speed(struct mac_serial *info, struct termios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -static void set_scc_power(struct mac_serial * info, int state); +static int set_scc_power(struct mac_serial * info, int state); static int setup_scc(struct mac_serial * info); static struct tty_struct *serial_table[NUM_CHANNELS]; @@ -329,8 +329,8 @@ static _INLINE_ void receive_chars(struct mac_serial *info, if (tty->flip.count >= TTY_FLIPBUF_SIZE) { static int flip_buf_ovf; - ++flip_buf_ovf; - printk("FB. overflow: %d\n", flip_buf_ovf); + if (++flip_buf_ovf <= 1) + printk("FB. overflow: %d\n", flip_buf_ovf); break; } tty->flip.count++; @@ -586,8 +586,10 @@ static void rs_timer(void) { } -static int startup(struct mac_serial * info) +static int startup(struct mac_serial * info, int can_sleep) { + int delay; + #ifdef SERIAL_DEBUG_OPEN printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq); #endif @@ -609,7 +611,7 @@ static int startup(struct mac_serial * info) printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); #endif - set_scc_power(info, 1); + delay = set_scc_power(info, 1); setup_scc(info); @@ -620,6 +622,15 @@ static int startup(struct mac_serial * info) info->flags |= ZILOG_INITIALIZED; enable_irq(info->irq); + if (delay) { + if (can_sleep) { + /* we need to wait a bit before using the port */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(delay * HZ / 1000); + } else + mdelay(delay); + } + return 0; } @@ -740,10 +751,18 @@ static void shutdown(struct mac_serial * info) info->flags &= ~ZILOG_INITIALIZED; } -static void set_scc_power(struct mac_serial * info, int state) +/* + * Turn power on or off to the SCC and associated stuff + * (port drivers, modem, IR port, etc.) + * Returns the number of milliseconds we should wait before + * trying to use the port. + */ +static int set_scc_power(struct mac_serial * info, int state) { + int delay = 0; + if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0) - return; /* don't have serial power control */ + return 0; /* don't have serial power control */ /* The timings looks strange but that's the ones MacOS seems to use for the internal modem. I think we can use a lot faster @@ -762,16 +781,13 @@ static void set_scc_power(struct mac_serial * info, int state) feature_set(info->dev_node, FEATURE_Serial_IO_A); else feature_set(info->dev_node, FEATURE_Serial_IO_B); - mdelay(1); + delay = 1; if (info->is_cobalt_modem){ feature_set(info->dev_node, FEATURE_Modem_Reset); - mdelay(15); + mdelay(5); feature_clear(info->dev_node, FEATURE_Modem_Reset); - /* XXX Note the big 250ms, we should probably replace this - by something better since we have irqs disabled here - */ - mdelay(250); + delay = 1000; /* wait for 1s before using */ } #ifdef CONFIG_PMAC_PBOOK if (info->is_pwbk_ir) @@ -786,7 +802,7 @@ static void set_scc_power(struct mac_serial * info, int state) #ifdef SERIAL_DEBUG_POWER printk(KERN_INFO " (canceled by KGDB)\n"); #endif - return; + return 0; } #endif #ifdef CONFIG_XMON @@ -794,7 +810,7 @@ static void set_scc_power(struct mac_serial * info, int state) #ifdef SERIAL_DEBUG_POWER printk(KERN_INFO " (canceled by XMON)\n"); #endif - return; + return 0; } #endif if (info->is_cobalt_modem) { @@ -835,6 +851,7 @@ static void set_scc_power(struct mac_serial * info, int state) mdelay(5); } } + return delay; } @@ -1796,7 +1813,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp) * Start up serial port */ - retval = startup(info); + retval = startup(info, 1); if (retval) return retval; diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 1ad27358c..0936b8bfb 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -98,9 +98,7 @@ static int media_bay_task(void *); * Therefore we do it all by polling the media bay once each tick. */ -__pmac /* I don't know of any chrp with a mediabay -- Cort */ - -void +void __pmac media_bay_init(void) { struct device_node *np; @@ -174,7 +172,7 @@ media_bay_intr(int irq, void *devid, struct pt_regs *regs) } #endif -int +int __pmac check_media_bay(struct device_node *which_bay, int what) { #ifdef CONFIG_BLK_DEV_IDE @@ -192,7 +190,7 @@ check_media_bay(struct device_node *which_bay, int what) return -ENODEV; } -int +int __pmac check_media_bay_by_base(unsigned long base, int what) { #ifdef CONFIG_BLK_DEV_IDE @@ -211,7 +209,7 @@ check_media_bay_by_base(unsigned long base, int what) return -ENODEV; } -int +int __pmac media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, int irq, int index) { @@ -238,7 +236,7 @@ media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, * with the IDE driver. It needs to be a thread because * ide_register can't be called from interrupt context. */ -int +int __pmac media_bay_task(void *x) { volatile struct media_bay_info* bay; @@ -294,7 +292,7 @@ media_bay_task(void *x) } } -void +void __pmac poll_media_bay(int which) { int id = MB_CONTENTS(which); @@ -309,7 +307,7 @@ poll_media_bay(int which) } } -static void +static void __pmac set_media_bay(int which, int id) { volatile struct media_bay_info* bay; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index dc551f0b9..47ad2e076 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -95,10 +95,10 @@ static const char *version = #include #include #include /* for CONFIG_IP_MULTICAST */ +#include #include #include -#include #include #include diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 9780f59c7..3ad87d4ec 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -50,11 +50,11 @@ static const char *version = #include #include #include +#include #include #include #include #include -#include #include #include diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index dda315556..60f9f3d09 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -64,8 +64,8 @@ static int max_interrupt_work = 10; #include #include #include /* for udelay() */ +#include -#include #include #include #include diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 71e9e0fe6..4ab2add71 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -263,15 +263,26 @@ static struct pci_id_info pci_tbl[] = { PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3c905B Cyclone 100baseTx", 0x10B7, 0x9055, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, + {"3c905B Cyclone 10/100/BNC", 0x10B7, 0x9058, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1}, {"3c905B-FX Cyclone 100baseFx", 0x10B7, 0x905A, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c905C Tornado", 0x10B7, 0x9200, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c980 Cyclone", 0x10B7, 0x9800, 0xfff0, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3cSOHO100-TX Hurricane", 0x10B7, 0x7646, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, + {"3c555 Laptop Hurricane", 0x10B7, 0x5055, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1}, {"3c575 Boomerang CardBus", 0x10B7, 0x5057, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3CCFE575 Cyclone CardBus", 0x10B7, 0x5157, 0xffff, PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, 128, vortex_probe1}, + {"3CCFE656 Cyclone CardBus", 0x10B7, 0x6560, 0xffff, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS, + 128, vortex_probe1}, {"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff, PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1}, {"3Com Boomerang (unknown version)", 0x10B7, 0x9000, 0xff00, diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 4071ede14..4b4cc6466 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -192,7 +192,7 @@ int ei_close(struct net_device *dev) static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int length, send_length, output_page; unsigned long flags; @@ -405,7 +405,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; - int e8390_base; + long e8390_base; int interrupts, nr_serviced = 0; struct ei_device *ei_local; @@ -518,7 +518,7 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) static void ei_tx_err(struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned char txsr = inb_p(e8390_base+EN0_TSR); unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU); @@ -556,7 +556,7 @@ static void ei_tx_err(struct net_device *dev) static void ei_tx_intr(struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int status = inb(e8390_base + EN0_TSR); @@ -646,7 +646,7 @@ static void ei_tx_intr(struct net_device *dev) static void ei_receive(struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned char rxing_page, this_frame, next_frame; unsigned short current_offset; @@ -775,7 +775,7 @@ static void ei_receive(struct net_device *dev) static void ei_rx_overrun(struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; struct ei_device *ei_local = (struct ei_device *) dev->priv; @@ -844,7 +844,7 @@ static void ei_rx_overrun(struct net_device *dev) static struct net_device_stats *get_stats(struct net_device *dev) { - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; unsigned long flags; @@ -919,7 +919,7 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev) static void do_set_multicast_list(struct net_device *dev) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; int i; struct ei_device *ei_local = (struct ei_device*)dev->priv; @@ -1024,7 +1024,7 @@ int ethdev_init(struct net_device *dev) void NS8390_init(struct net_device *dev, int startp) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int i; int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48; @@ -1088,7 +1088,7 @@ void NS8390_init(struct net_device *dev, int startp) static void NS8390_trigger_send(struct net_device *dev, unsigned int length, int start_page) { - int e8390_base = dev->base_addr; + long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); diff --git a/drivers/net/Config.in b/drivers/net/Config.in index bc70a3283..1902e5070 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -150,6 +150,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi + tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi bool 'Pocket and portable adaptors' CONFIG_NET_POCKET if [ "$CONFIG_NET_POCKET" = "y" ]; then @@ -308,3 +309,7 @@ if [ "$CONFIG_LAPB" != "n" ]; then dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB fi fi + +if [ "$CONFIG_PCMCIA" != "n" ]; then + source drivers/net/pcmcia/Config.in +fi diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 88aca4602..3640e78d7 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,7 +5,7 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc +ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc pcmcia L_TARGET := net.a L_OBJS := auto_irq.o @@ -29,6 +29,11 @@ CONFIG_85230_MODULE := CONFIG_SYNCPPP_BUILTIN := CONFIG_SYNCPPP_MODULE := +ifneq ($(CONFIG_PCMCIA),n) + SUB_DIRS += pcmcia + MOD_SUB_DIRS += pcmcia +endif + ifeq ($(CONFIG_ISDN),y) ifeq ($(CONFIG_ISDN_PPP),y) CONFIG_SLHC_BUILTIN = y @@ -1119,6 +1124,14 @@ else endif endif +ifeq ($(CONFIG_ADAPTEC_STARFIRE),y) +L_OBJS += starfire.o +else + ifeq ($(CONFIG_ADAPTEC_STARFIRE),m) + M_OBJS += starfire.o + endif +endif + ifeq ($(CONFIG_VENDOR_SANGOMA),y) LX_OBJS += sdladrv.o L_OBJS += sdlamain.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 268e27185..27c431e14 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -118,6 +118,7 @@ extern int bagetlance_probe(struct net_device *); extern int dec_lance_probe(struct net_device *); extern int mvme147lance_probe(struct net_device *dev); extern int via_rhine_probe(struct net_device *dev); +extern int starfire_probe(struct net_device *dev); extern int tc515_probe(struct net_device *dev); extern int lance_probe(struct net_device *dev); extern int rcpci_probe(struct net_device *); @@ -224,6 +225,9 @@ struct devprobe pci_probes[] __initdata = { #ifdef CONFIG_VIA_RHINE {via_rhine_probe, 0}, #endif +#ifdef CONFIG_ADAPTEC_STARFIRE + {starfire_probe, 0}, +#endif {NULL, 0}, }; diff --git a/drivers/net/cosa.c b/drivers/net/cosa.c index c3aa80734..863cd4b59 100644 --- a/drivers/net/cosa.c +++ b/drivers/net/cosa.c @@ -90,6 +90,7 @@ #include #include #include +#include #undef COSA_SLOW_IO /* for testing purposes only */ #undef REALLY_SLOW_IO @@ -97,7 +98,6 @@ #include #include #include -#include #include "syncppp.h" #include "cosa.h" diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index c2e33d8ad..cd7d1c43c 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -446,6 +446,7 @@ static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com #include #include #include +#include #include #include @@ -453,7 +454,6 @@ static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com #include #include #include -#include #include #include diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index bb3f21218..f436802eb 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -150,7 +150,7 @@ static const char *version = /* For linux 2.1.xx */ #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 -#include +#include #include #include diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index b1e61c415..e1a4a3c91 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -94,7 +94,7 @@ static int debug = -1; /* The debug level */ #include /* Ignore the bogus warning in 2.1.100+ */ #endif #endif -#include +#include #include #include @@ -583,10 +583,10 @@ int eepro100_init(struct net_device *dev) #endif /* Remove I/O space marker in bit 0. */ if (pciaddr & 1) { - ioaddr = pciaddr & ~3; + ioaddr = pciaddr & ~3UL; if (check_region(ioaddr, 32)) continue; - } else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, 0x1000)) == 0) { + } else if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) { printk(KERN_INFO "Failed to map PCI address %#x.\n", pciaddr); continue; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index d0fc55d7b..e319463be 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -121,7 +121,7 @@ #include #include -#include +#include #ifndef NET_DEBUG #define NET_DEBUG 4 diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c index 6486a249d..9cad49031 100644 --- a/drivers/net/fc/iph5526.c +++ b/drivers/net/fc/iph5526.c @@ -47,9 +47,9 @@ static const char *version = #include #include #include +#include #include #include -#include #include #include /* had the declarations for init_fcdev among others + includes if_fcdevice.h */ diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index d636c027d..cf2514fa6 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -149,10 +149,10 @@ static char mcchannelid[] = { #include #include #include +#include #include #include -#include #include #include diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index b2ada06f9..615592776 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -47,11 +47,11 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 1295c5abc..72f9d8f7e 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -105,7 +105,7 @@ pci_clone_list[] __initdata = { #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ int ne2k_pci_probe(struct net_device *dev); -static struct net_device *ne2k_pci_probe1(struct net_device *dev, int ioaddr, int irq, +static struct net_device *ne2k_pci_probe1(struct net_device *dev, long ioaddr, int irq, int chip_idx); static int ne2k_pci_open(struct net_device *dev); @@ -196,9 +196,9 @@ int __init ne2k_pci_probe(struct net_device *dev) return -ENODEV; while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) { - u8 pci_irq_line; + int pci_irq_line; u16 pci_command, new_command; - u32 pci_ioaddr; + unsigned long pci_ioaddr; /* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */ for (i = 0; pci_clone_list[i].vendor != 0; i++) @@ -232,19 +232,19 @@ int __init ne2k_pci_probe(struct net_device *dev) pci_command, new_command); pci_write_config_word(pdev, PCI_COMMAND, new_command); } - +#ifndef __sparc__ if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS) printk(KERN_WARNING " WARNING: The PCI BIOS assigned this PCI NE2k" " card to IRQ %d, which is unlikely to work!.\n" KERN_WARNING " You should use the PCI BIOS setup to assign" " a valid IRQ line.\n", pci_irq_line); - - printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n", +#endif + printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n", pci_clone_list[i].name, pci_ioaddr, pci_irq_line); dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i); if (dev == 0) { /* Should not happen. */ - printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n", + printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n", pci_ioaddr); continue; } else { @@ -263,7 +263,7 @@ int __init ne2k_pci_probe(struct net_device *dev) return cards_found ? 0 : -ENODEV; } -static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, int ioaddr, int irq, int chip_idx) +static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, long ioaddr, int irq, int chip_idx) { int i; unsigned char SA_prom[32]; @@ -340,7 +340,6 @@ static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, int ioa /* Note: all PCI cards have at least 16 bit access, so we don't have to check for 8 bit cards. Most cards permit 32 bit access. */ - if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) { for (i = 0; i < 4 ; i++) ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT)); @@ -367,7 +366,7 @@ static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, int ioa request_region(ioaddr, NE_IO_EXTENT, dev->name); - printk("%s: %s found at %#x, IRQ %d, ", + printk("%s: %s found at %#lx, IRQ %d, ", dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); for(i = 0; i < 6; i++) { printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); @@ -447,7 +446,7 @@ static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { - int nic_base = dev->base_addr; + long nic_base = dev->base_addr; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { @@ -485,7 +484,7 @@ ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int rin static void ne2k_pci_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { - int nic_base = dev->base_addr; + long nic_base = dev->base_addr; char *buf = skb->data; /* This *shouldn't* happen. If it does, it's the last thing you'll see */ @@ -530,7 +529,7 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, const unsigned char *buf, const int start_page) { - int nic_base = NE_BASE; + long nic_base = NE_BASE; unsigned long dma_start; /* On little-endian it's always safe to round the count up for diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in new file mode 100644 index 000000000..4585791e0 --- /dev/null +++ b/drivers/net/pcmcia/Config.in @@ -0,0 +1,13 @@ +# +# PCMCIA Network device configuration +# + +mainmenu_option next_comment +comment 'PCMCIA network devices' + +tristate 'PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)' CONFIG_PCMCIA_PCNET + +# only available as a module right now +dep_tristate 'Aviator/Raytheon 2.4MHz wireless' CONFIG_PCMCIA_RAYCS m + +endmenu diff --git a/drivers/net/pcmcia/Makefile b/drivers/net/pcmcia/Makefile new file mode 100644 index 000000000..44ccafb15 --- /dev/null +++ b/drivers/net/pcmcia/Makefile @@ -0,0 +1,32 @@ +# +# drivers/net/pcmcia/Makefile +# +# Makefile for the Linux PCMCIA network device drivers. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := pcmcia_net.a +L_OBJS := +M_OBJS := +MOD_LIST_NAME := NET_MODULES + +ifeq ($(CONFIG_PCMCIA_PCNET),y) + O_OBJS += pcnet_cs.o +else + ifeq ($(CONFIG_PCMCIA_PCNET),m) + MX_OBJS += pcnet_cs.o + endif +endif + +ifeq ($(CONFIG_PCMCIA_RAYCS),y) +LX_OBJS += ray_cs.o +else + ifeq ($(CONFIG_PCMCIA_RAYCS),m) + MX_OBJS += ray_cs.o + endif +endif + +include $(TOPDIR)/Rules.make diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c new file mode 100644 index 000000000..055610824 --- /dev/null +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -0,0 +1,1359 @@ +/*====================================================================== + + A PCMCIA ethernet driver for NS8390-based cards + + This driver supports the D-Link DE-650 and Linksys EthernetCard + cards, the newer D-Link and Linksys combo cards, Accton EN2212 + cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory + mode, and the IBM Credit Card Adapter, the NE4100, the Thomas + Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory + mode. It will also handle the Socket EA card in either mode. + + Copyright (C) 1998 David A. Hinds -- dhinds@hyper.stanford.edu + + pcnet_cs.c 1.94 1999/07/29 06:04:49 + + The network driver code is based on Donald Becker's NE2000 code: + + Written 1992,1993 by Donald Becker. + Copyright 1993 United States Government as represented by the + Director, National Security Agency. This software may be used and + distributed according to the terms of the GNU Public License, + incorporated herein by reference. + Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov + + Based also on Keith Moore's changes to Don Becker's code, for IBM + CCAE support. Drivers merged back together, and shared-memory + Socket EA support added, by Ken Raeburn, September 1995. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../../drivers/net/8390.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PCNET_CMD 0x00 +#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ +#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */ +#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */ + +#define PCNET_START_PG 0x40 /* First page of TX buffer */ +#define PCNET_STOP_PG 0x80 /* Last page +1 of RX ring */ + +/* Socket EA cards have a larger packet buffer */ +#define SOCKET_START_PG 0x01 +#define SOCKET_STOP_PG 0xff + +#define PCNET_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ + +static char *if_names[] = { "auto", "10baseT", "10base2"}; + +#define PCMCIA_DEBUG 6 +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"pcnet_cs.c 1.94 1999/07/29 06:04:49 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* Transceiver type, for Socket EA and IBM CC cards. */ +static int if_port = 1; + +/* Use 64K packet buffer, for Socket EA cards. */ +static int use_big_buf = 1; + +/* Shared memory speed, in ns */ +static int mem_speed = 0; + +/* Insert a pause in block_output after sending a packet */ +static int delay_output = 0; + +/* Length of delay, in microseconds */ +static int delay_time = 4; + +/* Use shared memory, if available? */ +static int use_shmem = -1; + +/* Ugh! Let the user hardwire the hardware address for queer cards */ +static int hw_addr[6] = { 0, /* ... */ }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(if_port, "i"); +MODULE_PARM(use_big_buf, "i"); +MODULE_PARM(mem_speed, "i"); +MODULE_PARM(delay_output, "i"); +MODULE_PARM(delay_time, "i"); +MODULE_PARM(use_shmem, "i"); +MODULE_PARM(hw_addr, "6i"); + +/*====================================================================*/ + +static void pcnet_config(dev_link_t *link); +static void pcnet_release(u_long arg); +static int pcnet_event(event_t event, int priority, + event_callback_args_t *args); + +static int pcnet_open(struct net_device *dev); +static int pcnet_close(struct net_device *dev); + +static void pcnet_reset_8390(struct net_device *dev); + +static int set_config(struct net_device *dev, struct ifmap *map); + +static int setup_shmem_window(dev_link_t *link, int start_pg, + int stop_pg, int cm_offset); +static int setup_dma_config(dev_link_t *link, int start_pg, + int stop_pg); + +static dev_info_t dev_info = "pcnet_cs"; + +static dev_link_t *pcnet_attach(void); +static void pcnet_detach(dev_link_t *); + +static dev_link_t *dev_list; + +/*====================================================================*/ + +typedef struct hw_info_t { + u_long offset; + u_char a0, a1, a2; + u_long flags; +} hw_info_t; + +#define DELAY_OUTPUT 0x01 +#define HAS_MISC_REG 0x02 +#define USE_BIG_BUF 0x04 +#define HAS_IBM_MISC 0x08 +#define IS_DL10019A 0x10 +#define USE_SHMEM 0x80 /* autodetected */ + +static hw_info_t hw_info[] = { + { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT }, + { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 }, + { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 }, + { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94, + DELAY_OUTPUT | HAS_IBM_MISC }, + { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 }, + { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 }, + { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 }, + { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 }, + { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 }, + { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 }, + { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 }, + { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 }, + { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 }, + { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 }, + { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 }, + { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 }, + { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 }, + { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 }, + { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, + HAS_MISC_REG | HAS_IBM_MISC }, + { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 }, + { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 }, + { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 }, + { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b, + DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, + { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, + { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 } +}; + +#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) + +static hw_info_t default_info = +{ /* Unknown NE2000 Clone */ 0x00, 0x00, 0x00, 0x00, 0 }; +static hw_info_t dl_fast_info = +{ /* D-Link EtherFast */ 0x00, 0x00, 0x00, 0x00, IS_DL10019A }; + +typedef struct pcnet_dev_t { + struct net_device dev; + dev_node_t node; + u_long flags; + caddr_t base; +} pcnet_dev_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + +======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + pcnet_detach(link); + } +} + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + We never need to do anything when a pcnet device is "initialized" + by the net software, because we only register already-found cards. + +======================================================================*/ + +static int pcnet_init(struct net_device *dev) +{ + return 0; +} + +/*====================================================================== + + pcnet_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static dev_link_t *pcnet_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + pcnet_dev_t *info; + struct net_device *dev; + int i, ret; + + DEBUG(0, "pcnet_attach()\n"); + flush_stale_links(); + + /* Create new ethernet device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &pcnet_release; + link->release.data = (u_long)link; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + info = kmalloc(sizeof(struct pcnet_dev_t), GFP_KERNEL); + memset(info, 0, sizeof(struct pcnet_dev_t)); + dev = &info->dev; + ethdev_init(dev); + dev->name = info->node.dev_name; + dev->init = &pcnet_init; + dev->open = &pcnet_open; + dev->stop = &pcnet_close; + dev->set_config = &set_config; + dev->tbusy = 1; + link->priv = info; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &pcnet_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + pcnet_detach(link); + return NULL; + } + + return link; +} /* pcnet_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void pcnet_detach(dev_link_t *link) +{ + dev_link_t **linkp; + long flags; + + DEBUG(0, "pcnet_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + if (link->state & DEV_CONFIG) { + pcnet_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } + } + + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + if (link->priv) { + struct net_device *dev = link->priv; + if (link->dev != NULL) + unregister_netdev(dev); + if (dev->priv) + kfree_s(dev->priv, sizeof(struct ei_device)); + kfree_s(dev, sizeof(struct pcnet_dev_t)); + } + kfree_s(link, sizeof(struct dev_link_t)); + +} /* pcnet_detach */ + +/*====================================================================== + + For the Linksys EtherFast 10/100 card + +======================================================================*/ + +static hw_info_t *get_dl_fast(dev_link_t *link) +{ + struct net_device *dev = link->priv; + int i; + u_char sum; + + for (sum = 0, i = 0x14; i < 0x1c; i++) + sum += inb_p(dev->base_addr + i); + if (sum != 0xff) + return NULL; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i); + return &dl_fast_info; +} + +/*====================================================================== + + This probes for a card's hardware address, for card types that + encode this information in their CIS. + +======================================================================*/ + +static hw_info_t *get_hwinfo(dev_link_t *link) +{ + struct net_device *dev = link->priv; + win_req_t req; + memreq_t mem; + u_char *base, *virt; + int i, j; + + /* Allocate a small memory window */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; req.Size = 0; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestWindow, i); + return NULL; + } + + virt = ioremap(req.Base, req.Size); + mem.Page = 0; + for (i = 0; i < NR_INFO; i++) { + mem.CardOffset = hw_info[i].offset & ~(req.Size-1); + CardServices(MapMemPage, link->win, &mem); + base = &virt[hw_info[i].offset & (req.Size-1)]; + if ((readb(base+0) == hw_info[i].a0) && + (readb(base+2) == hw_info[i].a1) && + (readb(base+4) == hw_info[i].a2)) + break; + } + if (i < NR_INFO) { + for (j = 0; j < 6; j++) + dev->dev_addr[j] = readb(base + (j<<1)); + } + + iounmap(virt); + j = CardServices(ReleaseWindow, link->win); + if (j != CS_SUCCESS) + cs_error(link->handle, ReleaseWindow, j); + return (i < NR_INFO) ? hw_info+i : NULL; +} /* get_hwinfo */ + +/*====================================================================== + + This probes for a card's hardware address by reading the PROM. + It checks the address against a list of known types, then falls + back to a simple NE2000 clone signature check. + +======================================================================*/ + +static hw_info_t *get_prom(dev_link_t *link) +{ + struct net_device *dev = link->priv; + unsigned char prom[32]; + int i, j, ioaddr; + + /* This is lifted straight from drivers/net/ne.c */ + struct { + unsigned char value, offset; + } program_seq[] = { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + + ioaddr = dev->base_addr; + + pcnet_reset_8390(dev); + udelay(10000); + + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + + for (i = 0; i < 32; i++) + prom[i] = inb(ioaddr + PCNET_DATAPORT); + for (i = 0; i < NR_INFO; i++) { + if ((prom[0] == hw_info[i].a0) && + (prom[2] == hw_info[i].a1) && + (prom[4] == hw_info[i].a2)) + break; + } + if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { + for (j = 0; j < 6; j++) + dev->dev_addr[j] = prom[j<<1]; + return (i < NR_INFO) ? hw_info+i : &default_info; + } + return NULL; +} /* get_prom */ + +/*====================================================================== + + This should be totally unnecessary... but when we can't figure + out the hardware address any other way, we'll let the user hard + wire it when the module is initialized. + +======================================================================*/ + +static hw_info_t *get_hwired(dev_link_t *link) +{ + struct net_device *dev = link->priv; + int i; + + for (i = 0; i < 6; i++) + if (hw_addr[i] != 0) break; + if (i == 6) + return NULL; + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = hw_addr[i]; + + return &default_info; +} /* get_hwired */ + +/*====================================================================== + + pcnet_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static int try_io_port(dev_link_t *link) +{ + int j, ret; + if (link->io.NumPorts1 == 32) { + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (link->io.NumPorts2 > 0) { + /* for master/slave multifunction cards */ + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->irq.Attributes = + IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + } + } else { + /* This should be two 16-port windows */ + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + } + if (link->io.BasePort1 == 0) { + for (j = 0; j < 0x400; j += 0x20) { + link->io.BasePort1 = j ^ 0x300; + link->io.BasePort2 = (j ^ 0x300) + 0x10; + ret = CardServices(RequestIO, link->handle, &link->io); + if (ret == CS_SUCCESS) return ret; + } + return ret; + } else { + return CardServices(RequestIO, link->handle, &link->io); + } +} + +static void pcnet_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + pcnet_dev_t *info; + struct net_device *dev; + int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; + int manfid = 0, prodid = 0, has_shmem = 0; + u_short buf[64]; + hw_info_t *hw_info; + + handle = link->handle; + info = link->priv; + dev = &info->dev; + + DEBUG(0, "pcnet_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_MANFID; + tuple.Attributes = TUPLE_RETURN_COMMON; + if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && + (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) { + manfid = le16_to_cpu(buf[0]); + prodid = le16_to_cpu(buf[1]); + } + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (last_ret == CS_SUCCESS) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + cistpl_io_t *io = &(parse.cftable_entry.io); + + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if ((cfg->index == 0) || (cfg->io.nwin == 0)) + goto next_entry; + + link->conf.ConfigIndex = cfg->index; + /* For multifunction cards, by convention, we configure the + network function with window 0, and serial with window 1 */ + if (io->nwin > 1) { + i = (io->win[1].len > io->win[0].len); + link->io.BasePort2 = io->win[1-i].base; + link->io.NumPorts2 = io->win[1-i].len; + } else { + i = link->io.NumPorts2 = 0; + } + has_shmem = ((cfg->mem.nwin == 1) && + (cfg->mem.win[0].len >= 0x4000)); + link->io.BasePort1 = io->win[i].base; + link->io.NumPorts1 = io->win[i].len; + if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) { + last_ret = try_io_port(link); + if (last_ret == CS_SUCCESS) break; + } + next_entry: + last_ret = CardServices(GetNextTuple, handle, &tuple); + } + if (last_ret != CS_SUCCESS) { + cs_error(handle, RequestIO, last_ret); + goto failed; + } + + CS_CHECK(RequestIRQ, handle, &link->irq); + + if (link->io.NumPorts2 == 8) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + if ((manfid == MANFID_IBM) && + (prodid == PRODID_IBM_HOME_AND_AWAY)) + link->conf.ConfigIndex |= 0x10; + + CS_CHECK(RequestConfiguration, handle, &link->conf); + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + if ((if_port == 1) || (if_port == 2)) + dev->if_port = if_port; + else + printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n"); + dev->tbusy = 0; + if (register_netdev(dev) != 0) { + printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n"); + goto failed; + } + + hw_info = get_hwinfo(link); + if (hw_info == NULL) + hw_info = get_prom(link); + if (hw_info == NULL) + hw_info = get_dl_fast(link); + if (hw_info == NULL) + hw_info = get_hwired(link); + + if (hw_info == NULL) { + printk(KERN_NOTICE "pcnet_cs: unable to read hardware net address\n"); + goto config_undo; + } + + info->flags = hw_info->flags; + /* Check for user overrides */ + info->flags |= (delay_output) ? DELAY_OUTPUT : 0; + if ((manfid == MANFID_SOCKET) && (prodid == PRODID_SOCKET_LPE)) + info->flags &= ~USE_BIG_BUF; + if (!use_big_buf) + info->flags &= ~USE_BIG_BUF; + + if (info->flags & USE_BIG_BUF) { + start_pg = SOCKET_START_PG; + stop_pg = SOCKET_STOP_PG; + cm_offset = 0x10000; + } else { + start_pg = PCNET_START_PG; + stop_pg = PCNET_STOP_PG; + cm_offset = 0; + } + + /* has_shmem is ignored if use_shmem != -1 */ + if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) || + (setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0)) + setup_dma_config(link, start_pg, stop_pg); + + ei_status.name = "NE2000"; + ei_status.word16 = 1; + ei_status.reset_8390 = &pcnet_reset_8390; + + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + printk(KERN_INFO "%s: NE2000 Compatible: io %#3lx, irq %d,", + dev->name, dev->base_addr, dev->irq); + if (info->flags & USE_SHMEM) + printk (" mem %#5lx,", dev->mem_start); + if (info->flags & HAS_MISC_REG) + printk(" %s xcvr,", if_names[dev->if_port]); + printk(" hw_addr "); + for (i = 0; i < 6; i++) + printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); + return; + +config_undo: + unregister_netdev(dev); + goto failed; +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + pcnet_release((u_long)link); + return; +} /* pcnet_config */ + +/*====================================================================== + + After a card is removed, pcnet_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void pcnet_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + pcnet_dev_t *info = link->priv; + + DEBUG(0, "pcnet_release(0x%p)\n", link); + + if (link->open) { + DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n", + info->node.dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + if (info->flags & USE_SHMEM) { + iounmap(info->base); + CardServices(ReleaseWindow, link->win); + } + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + +} /* pcnet_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + +======================================================================*/ + +static int pcnet_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + pcnet_dev_t *info = link->priv; + + DEBUG(2, "pcnet_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + info->dev.tbusy = 1; info->dev.start = 0; + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT; + pcnet_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + info->dev.tbusy = 1; info->dev.start = 0; + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + pcnet_reset_8390(&info->dev); + NS8390_init(&info->dev, 1); + info->dev.tbusy = 0; info->dev.start = 1; + } + } + break; + } + return 0; +} /* pcnet_event */ + +/*====================================================================*/ + +static void set_misc_reg(struct net_device *dev) +{ + int nic_base = dev->base_addr; + pcnet_dev_t *info = (pcnet_dev_t *)dev; + u_char tmp; + + if (info->flags & HAS_MISC_REG) { + tmp = inb_p(nic_base + PCNET_MISC) & ~3; + if (dev->if_port == 2) + tmp |= 1; + if (info->flags & USE_BIG_BUF) + tmp |= 2; + if (info->flags & HAS_IBM_MISC) + tmp |= 8; + outb_p(tmp, nic_base + PCNET_MISC); + } +} + +/*====================================================================*/ + +static int pcnet_open(struct net_device *dev) +{ + pcnet_dev_t *info = (pcnet_dev_t *)dev; + dev_link_t *link; + + DEBUG(2, "pcnet_open('%s')\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + link->open++; + MOD_INC_USE_COUNT; + + /* For D-Link EtherFast, wait for something(?) to happen */ + if (info->flags & IS_DL10019A) { + int i; + for (i = 0; i < 20; i++) { + if ((inb(dev->base_addr+0x1c) & 0x01) == 0) break; + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + } + } + + set_misc_reg(dev); + request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev_info, dev); + return ei_open(dev); +} /* pcnet_open */ + +/*====================================================================*/ + +static int pcnet_close(struct net_device *dev) +{ + dev_link_t *link; + + DEBUG(2, "pcnet_close('%s')\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + free_irq(dev->irq, dev); + + link->open--; dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies+HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} /* pcnet_close */ + +/*====================================================================== + + Hard reset the card. This used to pause for the same period that + a 8390 reset command required, but that shouldn't be necessary. + +======================================================================*/ + +static void pcnet_reset_8390(struct net_device *dev) +{ + int nic_base = dev->base_addr; + int i; + + ei_status.txing = ei_status.dmaing = 0; + + outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET); + + for (i = 0; i < 100; i++) { + if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0) + break; + udelay(100L); + } + outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */ + + if (i == 100) + printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n", + dev->name); + set_misc_reg(dev); + +} /* pcnet_reset_8390 */ + +/* ======================================================================= */ + +static int set_config(struct net_device *dev, struct ifmap *map) +{ + pcnet_dev_t *info = (pcnet_dev_t *)dev; + if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { + if ((map->port != 0) && !(info->flags & HAS_MISC_REG)) { + printk(KERN_NOTICE "%s: transceiver selection not " + "implemented\n", dev->name); + return -EINVAL; + } + if ((map->port == 1) || (map->port == 2)) { + dev->if_port = map->port; + printk(KERN_INFO "%s: switched to %s port\n", + dev->name, if_names[dev->if_port]); + } else + return -EINVAL; + } + return 0; +} + +/* ======================================================================= */ + +static void dma_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, + int ring_page) +{ + int nic_base = dev->base_addr; + + if (ei_status.dmaing) { + printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." + "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + (long)dev->interrupt); + return; + } + + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD); + outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); + outb_p(0, nic_base + EN0_RCNTHI); + outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ + outb_p(ring_page, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD); + + insw(nic_base + PCNET_DATAPORT, hdr, + sizeof(struct e8390_pkt_hdr)>>1); + /* Fix for big endian systems */ + hdr->count = le16_to_cpu(hdr->count); + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; +} + +/* ======================================================================= */ + +static void dma_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + int nic_base = dev->base_addr; + int xfer_count = count; + char *buf = skb->data; + +#ifdef PCMCIA_DEBUG + if ((ei_debug > 4) && (count != 4)) + printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4); +#endif + if (ei_status.dmaing) { + printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." + "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + (long)dev->interrupt); + return; + } + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD); + + insw(nic_base + PCNET_DATAPORT,buf,count>>1); + if (count & 0x01) + buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++; + + /* This was for the ALPHA version only, but enough people have + encountering problems that it is still here. */ +#ifdef PCMCIA_DEBUG + if (ei_debug > 4) { /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken for Rx on some cards! */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff)) + break; + } while (--tries > 0); + if (tries <= 0) + printk(KERN_NOTICE "%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } +#endif + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_status.dmaing &= ~0x01; +} /* dma_block_input */ + +/*====================================================================*/ + +static void dma_block_output(struct net_device *dev, int count, + const unsigned char *buf, + const int start_page) +{ + int nic_base = dev->base_addr; + pcnet_dev_t *info = (pcnet_dev_t *)dev; +#ifdef PCMCIA_DEBUG + int retries = 0; +#endif + u_long dma_start; + +#ifdef PCMCIA_DEBUG + if (ei_debug > 4) + printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count); +#endif + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (count & 0x01) + count++; + if (ei_status.dmaing) { + printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output." + "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", + dev->name, ei_status.dmaing, ei_status.irqlock, + (long)dev->interrupt); + return; + } + ei_status.dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD); + +#ifdef PCMCIA_DEBUG + retry: +#endif + + outb_p(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD); + outsw(nic_base + PCNET_DATAPORT, buf, count>>1); + + dma_start = jiffies; + +#ifdef PCMCIA_DEBUG + /* This was for the ALPHA version only, but enough people have + encountering problems that it is still here. */ + if (ei_debug > 4) { /* DMA termination address check... */ + int addr, tries = 20; + do { + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + if (tries <= 0) { + printk(KERN_NOTICE "%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } + } +#endif + + while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > PCNET_RDC_TIMEOUT) { + printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n", + dev->name); + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + break; + } + + outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + if (info->flags & DELAY_OUTPUT) + udelay((long)delay_time); + ei_status.dmaing &= ~0x01; +} + +/*====================================================================*/ + +static int setup_dma_config(dev_link_t *link, int start_pg, + int stop_pg) +{ + struct net_device *dev = link->priv; + + ei_status.tx_start_page = start_pg; + ei_status.rx_start_page = start_pg + TX_PAGES; + ei_status.stop_page = stop_pg; + + /* set up block i/o functions */ + ei_status.get_8390_hdr = &dma_get_8390_hdr; + ei_status.block_input = &dma_block_input; + ei_status.block_output = &dma_block_output; + + return 0; +} + +/*====================================================================*/ + +static void copyin(unsigned char *dest, unsigned char *src, int c) +{ + unsigned short *d = (unsigned short *) dest; + unsigned short *s = (unsigned short *) src; + int odd; + + if (c <= 0) + return; + odd = (c & 01); c >>= 1; + + if (c) { + do { *d++ = readw(s++); } while (--c); + } + /* get last byte by fetching a word and masking */ + if (odd) + *((unsigned char *)d) = readw(s) & 0xff; +} + +static void copyout(unsigned char *dest, const unsigned char *src, int c) +{ + volatile unsigned short *d = (unsigned short *) dest; + unsigned short *s = (unsigned short *) src; + int odd; + + if (c <= 0) + return; + odd = (c & 01); c >>= 1; + + if (c) { + do { writew(*s++, d++); } while (--c); + } + /* copy last byte doing a read-modify-write */ + if (odd) + writew((readw(d) & 0xff00) | *(u_char *)s, d); +} + +/*====================================================================*/ + +static void shmem_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, + int ring_page) +{ + void *xfer_start = (void *)(dev->rmem_start + (ring_page << 8) + - (ei_status.rx_start_page << 8)); + + copyin((void *)hdr, xfer_start, sizeof(struct e8390_pkt_hdr)); + /* Fix for big endian systems */ + hdr->count = le16_to_cpu(hdr->count); +} + +/*====================================================================*/ + +static void shmem_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + void *xfer_start = (void *)(dev->rmem_start + ring_offset + - (ei_status.rx_start_page << 8)); + char *buf = skb->data; + + if (xfer_start + count > (void *)dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = (void*)dev->rmem_end - xfer_start; + copyin(buf, xfer_start, semi_count); + buf += semi_count; + ring_offset = ei_status.rx_start_page << 8; + xfer_start = (void *)dev->rmem_start; + count -= semi_count; + } + copyin(buf, xfer_start, count); +} + +/*====================================================================*/ + +static void shmem_block_output(struct net_device *dev, int count, + const unsigned char *buf, + const int start_page) +{ + void *shmem = (void *)dev->mem_start + (start_page << 8); + shmem -= ei_status.tx_start_page << 8; + + if (ei_debug > 4) + printk(KERN_DEBUG "[bo=%d @ %x]\n", count, start_page); + + copyout(shmem, buf, count); +} + +/*====================================================================*/ + +static int setup_shmem_window(dev_link_t *link, int start_pg, + int stop_pg, int cm_offset) +{ + struct net_device *dev = link->priv; + pcnet_dev_t *info = link->priv; + win_req_t req; + memreq_t mem; + int i, window_size, offset, last_ret, last_fn; + + window_size = (stop_pg - start_pg) << 8; + if (window_size > 32 * 1024) + window_size = 32 * 1024; + + /* Make sure it's a power of two. */ + while ((window_size & (window_size - 1)) != 0) + window_size += window_size & ~(window_size - 1); + + /* Allocate a memory window */ + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; + req.Attributes |= WIN_USE_WAIT; + req.Base = 0; req.Size = window_size; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + CS_CHECK(RequestWindow, &link->win, &req); + + mem.CardOffset = (start_pg << 8) + cm_offset; + offset = mem.CardOffset % window_size; + mem.CardOffset -= offset; + mem.Page = 0; + CS_CHECK(MapMemPage, link->win, &mem); + + /* Try scribbling on the buffer */ + info->base = ioremap(req.Base, window_size); + for (i = 0; i < (TX_PAGES<<8); i += 2) + writew((i>>1), info->base+offset+i); + udelay(100); + for (i = 0; i < (TX_PAGES<<8); i += 2) + if (readw(info->base+offset+i) != (i>>1)) break; + pcnet_reset_8390(dev); + if (i != (TX_PAGES<<8)) { + iounmap(info->base); + CardServices(ReleaseWindow, link->win); + info->base = NULL; link->win = NULL; + goto failed; + } + + dev->mem_start = (u_long)info->base + offset; + dev->rmem_start = dev->mem_start + (TX_PAGES<<8); + dev->mem_end = dev->rmem_end = (u_long)info->base + req.Size; + + ei_status.tx_start_page = start_pg; + ei_status.rx_start_page = start_pg + TX_PAGES; + ei_status.stop_page = start_pg + ((req.Size - offset) >> 8); + + /* set up block i/o functions */ + ei_status.get_8390_hdr = &shmem_get_8390_hdr; + ei_status.block_input = &shmem_block_input; + ei_status.block_output = &shmem_block_output; + + info->flags |= USE_SHMEM; + return 0; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + return 1; +} + +/*====================================================================*/ + +#ifdef MODULE +int init_module(void) +#else +int init_pcnet_cs(void) +#endif +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "pcnet_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &pcnet_attach, &pcnet_detach); + DEBUG(0, "pcnet driver registered\n" ); + return 0; +} + +//__initcall(init_pcnet_cs); + +#ifdef MODULE +void cleanup_module(void) +{ + DEBUG(0, "pcnet_cs: unloading\n"); + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) + pcnet_detach(dev_list); +} +#endif diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c new file mode 100644 index 000000000..547c0a4bd --- /dev/null +++ b/drivers/net/pcmcia/ray_cs.c @@ -0,0 +1,2327 @@ +/*============================================================================= + * + * A PCMCIA client driver for the Raylink wireless LAN card. + * The starting point for this module was the skeleton.c in the + * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu + * + * + * Copyright (c) 1998 Corey Thomas (corey@world.std.com) + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of version 2 only of the GNU General Public License as + * published by the Free Software Foundation. + * + * It is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * +=============================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rayctl.h" +#include "ray_cs.h" + +/* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. + + I found that adding -DPCMCIA_DEBUG to the compile options during + the 'make config' resulted in cardmgr not finding any sockets. + Therefore, this module uses RAYLINK_DEBUG instead. + The module option to use is ray_debug=# + where # is 1 for modest output + 2 for more output + ... +*/ + +#ifdef RAYLINK_DEBUG +static int ray_debug = RAYLINK_DEBUG; +MODULE_PARM(ray_debug, "i"); +/* #define DEBUG(n, args...) if (ray_debug>(n)) printk(KERN_DEBUG args); */ +#define DEBUG(n, args...) if (ray_debug>(n)) printk(args); +#else +#define DEBUG(n, args...) +#endif +/** Prototypes based on PCMCIA skeleton driver *******************************/ +void ray_config(dev_link_t *link); +void ray_release(u_long arg); +int ray_event(event_t event, int priority, event_callback_args_t *args); +dev_link_t *ray_attach(void); +void ray_detach(dev_link_t *); + +/***** Prototypes indicated by device structure ******************************/ +int ray_dev_close(struct net_device *dev); +int ray_dev_config(struct net_device *dev, struct ifmap *map); +struct enet_statistics *ray_get_stats(struct net_device *dev); +int ray_dev_init(struct net_device *dev); +int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +int ray_open(struct net_device *dev); +int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void ray_update_multi_list(struct net_device *dev, int all); +int encapsulate_frame(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, + unsigned char *data, int len); +int translate_frame(ray_dev_t *local, struct tx_msg *ptx, + unsigned char *data, int len); +void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, + unsigned char *data); +void untranslate(ray_dev_t *local, struct sk_buff *skb, int len); + +/***** Prototypes for raylink functions **************************************/ +int asc_to_int(char a); +void authenticate(ray_dev_t *local); +int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type); +void authenticate_timeout(u_long); +int get_free_ccs(ray_dev_t *local); +int get_free_tx_ccs(ray_dev_t *local); +void init_startup_params(ray_dev_t *local); +int parse_addr(char *in_str, UCHAR *out); +int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type); +int ray_init(struct net_device *dev); +int interrupt_ecf(ray_dev_t *local, int ccs); +void ray_reset(struct net_device *dev); +void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len); +void verify_dl_startup(u_long); + +/* Prototypes for interrpt time functions **********************************/ +void ray_interrupt(int reg, void *dev_id, struct pt_regs *regs); +void clear_interrupt(ray_dev_t *local); +void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, + unsigned int pkt_addr, int rx_len); +int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len); +void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs); +void release_frag_chain(ray_dev_t *local, struct rcs *prcs); +void rx_authenticate(ray_dev_t *local, struct rcs *prcs, + unsigned int pkt_addr, int rx_len); +void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, + int rx_len); +void associate(ray_dev_t *local); + +/* Card command functions */ +int dl_startup_params(struct net_device *dev); +void join_net(u_long local); +void start_net(u_long local); +/* void start_net(ray_dev_t *local); */ + +int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare); + +/* Create symbol table for registering with kernel in init_module */ +EXPORT_SYMBOL(ray_dev_ioctl); +EXPORT_SYMBOL(ray_rx); + +/*===========================================================================*/ +/* Parameters that can be set with 'insmod' */ +/* Bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_long irq_mask = 0xdeb8; +MODULE_PARM(irq_mask,"i"); + +/* ADHOC=0, Infrastructure=1 */ +static int net_type = ADHOC; +MODULE_PARM(net_type,"i"); + +/* Hop dwell time in Kus (1024 us units defined by 802.11) */ +static int hop_dwell = 128; +MODULE_PARM(hop_dwell,"i"); + +/* Beacon period in Kus */ +static int beacon_period = 128; +MODULE_PARM(beacon_period,"i"); + +/* power save mode (0 = off, 1 = save power) */ +static int psm = 0; +MODULE_PARM(psm,"i"); + +/* String for network's Extended Service Set ID. 32 Characters max */ +static char *essid = NULL; +MODULE_PARM(essid,"s"); + +/* Default to encapsulation unless translation requested */ +static int translate = 0; +MODULE_PARM(translate,"i"); + +static int country = USA; +MODULE_PARM(country,"i"); + +static int sniffer = 0; +MODULE_PARM(sniffer,"i"); + +static int bc = 0; +MODULE_PARM(bc,"i"); + +/* 48 bit physical card address if overriding card's real physical + * address is required. Since IEEE 802.11 addresses are 48 bits + * like ethernet, an int can't be used, so a string is used. To + * allow use of addresses starting with a decimal digit, the first + * character must be a letter and will be ignored. This letter is + * followed by up to 12 hex digits which are the address. If less + * than 12 digits are used, the address will be left filled with 0's. + * Note that bit 0 of the first byte is the broadcast bit, and evil + * things will happen if it is not 0 in a card address. + */ +static char *phy_addr = NULL; +MODULE_PARM(phy_addr,"s"); + + +/* The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ +static dev_info_t dev_info = "ray_cs"; + +/* A linked list of "instances" of the ray device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). +*/ +static dev_link_t *dev_list = NULL; + +/* A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. +*/ +static const unsigned int ray_mem_speed = 0x2A; + +static UCHAR b5_default_startup_parms[] = { + 0, 0, /* Adhoc station */ + 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, /* Active scan, CA Mode */ + 0, 0, 0, 0, 0, 0, /* No default MAC addr */ + 0x7f, 0xff, /* Frag threshold */ + 0x00, 0x80, /* Hop time 128 Kus*/ + 0x01, 0x00, /* Beacon period 256 Kus */ + 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ + 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */ + 0x7f, 0xff, /* RTS threshold */ + 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */ + 0x05, /* assoc resp timeout thresh */ + 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max*/ + 0, /* Promiscuous mode */ + 0x0c, 0x0bd, /* Unique word */ + 0x32, /* Slot time */ + 0xff, 0xff, /* roam-low snr, low snr count */ + 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ + 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */ +/* b4 - b5 differences start here */ + 0x00, 0x3f, /* CW max */ + 0x00, 0x0f, /* CW min */ + 0x04, 0x08, /* Noise gain, limit offset */ + 0x28, 0x28, /* det rssi, med busy offsets */ + 7, /* det sync thresh */ + 0, 2, 2, /* test mode, min, max */ + 0, /* allow broadcast SSID probe resp */ + 0, 0, /* privacy must start, can join */ + 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */ +}; + +static UCHAR b4_default_startup_parms[] = { + 0, 0, /* Adhoc station */ + 'L','I','N','U','X', 0, 0, 0, /* 32 char ESSID */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, /* Active scan, CA Mode */ + 0, 0, 0, 0, 0, 0, /* No default MAC addr */ + 0x7f, 0xff, /* Frag threshold */ + 0x02, 0x00, /* Hop time */ + 0x00, 0x01, /* Beacon period */ + 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout*/ + 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */ + 0x7f, 0xff, /* RTS threshold */ + 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */ + 0x05, /* assoc resp timeout thresh */ + 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max*/ + 0, /* Promiscuous mode */ + 0x0c, 0x0bd, /* Unique word */ + 0x4e, /* Slot time (TBD seems wrong)*/ + 0xff, 0xff, /* roam-low snr, low snr count */ + 0x05, 0xff, /* Infra, adhoc missed bcn thresh */ + 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */ +/* b4 - b5 differences start here */ + 0x3f, 0x0f, /* CW max, min */ + 0x04, 0x08, /* Noise gain, limit offset */ + 0x28, 0x28, /* det rssi, med busy offsets */ + 7, /* det sync thresh */ + 0, 2, 2 /* test mode, min, max*/ +}; +/*===========================================================================*/ +static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0}; + +static char rcsid[] = " $Id: ray_cs.c,v 1.60 1999/09/01 20:58:45 corey Exp $ - Corey Thomas corey@world.std.com"; + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry ray_cs_proc_entry = { + 0, /* Dynamic inode # */ + 6,"ray_cs", /* name length and name */ + S_IFREG | S_IRUGO, /* mode */ + 1, 0, 0, /* nlinks, owner, group */ + 0, /* size (unused) */ + NULL, /* operations (default) */ + &ray_cs_proc_read, /* function to read data */ + /* The end ?? */ +}; +#endif +/*===========================================================================*/ +void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} +/*============================================================================= + ray_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. +=============================================================================*/ +dev_link_t *ray_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + ray_dev_t *local; + int ret; + struct net_device *dev; + + DEBUG(1, "ray_attach()\n"); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &ray_release; + link->release.data = (u_long)link; + + /* The io structure describes IO port mapping. None used here */ + link->io.NumPorts1 = 0; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 5; + + /* Interrupt setup. For PCMCIA, driver takes what's given */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + link->irq.IRQInfo2 = irq_mask; + link->irq.Handler = &ray_interrupt; + + /* General socket configuration */ + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Allocate space for private device-specific data */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + link->priv = dev; + link->irq.Instance = dev; + + local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL); + memset(local, 0, sizeof(ray_dev_t)); + dev->priv = local; + local->finder = link; + link->dev = &local->node; + local->card_status = CARD_INSERTED; + local->authentication_state = UNAUTHENTICATED; + local->num_multi = 0; + DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n", + link,dev,local,&ray_interrupt); + + /* Raylink entries in the device structure */ + dev->hard_start_xmit = &ray_dev_start_xmit; + dev->set_config = &ray_dev_config; + dev->get_stats = &ray_get_stats; + dev->do_ioctl = &ray_dev_ioctl; + + dev->set_multicast_list = &set_multicast_list; + + DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n"); + ether_setup(dev); + dev->name = local->node.dev_name; + dev->init = &ray_dev_init; + dev->open = &ray_open; + dev->stop = &ray_dev_close; + dev->tbusy = 1; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &ray_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + DEBUG(2,"ray_cs ray_attach calling CardServices(RegisterClient...)\n"); + + init_timer(&local->timer); + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + printk("ray_cs ray_attach RegisterClient unhappy - detaching\n"); + cs_error(link->handle, RegisterClient, ret); + ray_detach(link); + return NULL; + } + DEBUG(2,"ray_cs ray_attach ending\n"); + return link; +} /* ray_attach */ +/*============================================================================= + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. +=============================================================================*/ +void ray_detach(dev_link_t *link) +{ + dev_link_t **linkp; + struct net_device *dev; + long flags; + + DEBUG(1, "ray_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + + /* If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { + ray_release((u_long)link); + if(link->state & DEV_STALE_CONFIG) { + DEBUG(0,"ray_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); + link->state |= DEV_STALE_LINK; + return; + } + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + dev = link->priv; + if (dev->priv) + kfree_s(dev->priv, sizeof(ray_dev_t)); + + kfree_s(link->priv, sizeof(struct net_device)); + } + kfree_s(link, sizeof(struct dev_link_t)); + DEBUG(2,"ray_cs ray_detach ending\n"); +} /* ray_detach */ +/*============================================================================= + ray_config() is run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + ethernet device available to the system. +=============================================================================*/ +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define MAX_TUPLE_SIZE 80 +void ray_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + int i; + u_char buf[80]; + win_req_t req; + memreq_t mem; + struct net_device *dev = (struct net_device *)link->priv; + ray_dev_t *local = (ray_dev_t *)dev->priv; + + DEBUG(1, "ray_config(0x%p)\n", link); + + /* This reads the card's CONFIG tuple to find its configuration regs */ + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + tuple.TupleData = buf; + tuple.TupleDataMax = MAX_TUPLE_SIZE; + tuple.TupleOffset = 0; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Now allocate an interrupt line. Note that this does not + actually assign a handler to the interrupt. + */ + CS_CHECK(RequestIRQ, link->handle, &link->irq); + dev->irq = link->irq.AssignedIRQ; + + /* This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + +/*** Set up 32k window for shared memory (transmit and control) ************/ + req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + req.Base = 0; + req.Size = 0x8000; + req.AccessSpeed = ray_mem_speed; + link->win = (window_handle_t)link->handle; + CS_CHECK(RequestWindow, &link->win, &req); + mem.CardOffset = 0x0000; mem.Page = 0; + CS_CHECK(MapMemPage, link->win, &mem); + local->sram = (UCHAR *)(ioremap(req.Base,req.Size)); + +/*** Set up 16k window for shared memory (receive buffer) ***************/ + req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; + req.Base = 0; + req.Size = 0x4000; + req.AccessSpeed = ray_mem_speed; + local->rmem_handle = (window_handle_t)link->handle; + CS_CHECK(RequestWindow, &local->rmem_handle, &req); + mem.CardOffset = 0x8000; mem.Page = 0; + CS_CHECK(MapMemPage, local->rmem_handle, &mem); + local->rmem = (UCHAR *)(ioremap(req.Base,req.Size)); + +/*** Set up window for attribute memory ***********************************/ + req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT; + req.Base = 0; + req.Size = 0x1000; + req.AccessSpeed = ray_mem_speed; + local->amem_handle = (window_handle_t)link->handle; + CS_CHECK(RequestWindow, &local->amem_handle, &req); + mem.CardOffset = 0x0000; mem.Page = 0; + CS_CHECK(MapMemPage, local->amem_handle, &mem); + local->amem = (UCHAR *)(ioremap(req.Base,req.Size)); + + DEBUG(3,"ray_config sram=%p\n",local->sram); + DEBUG(3,"ray_config rmem=%p\n",local->rmem); + DEBUG(3,"ray_config amem=%p\n",local->amem); + if (ray_init(dev) < 0) { + ray_release((u_long)link); + return; + } + + i = register_netdev(dev); + if (i != 0) { + printk("ray_config register_netdev() failed\n"); + ray_release((u_long)link); + return; + } + + link->state &= ~DEV_CONFIG_PENDING; + DEBUG(0, "ray_cs device loaded\n"); + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + + ray_release((u_long)link); +} /* ray_config */ +/*===========================================================================*/ +int ray_init(struct net_device *dev) +{ + int i; + UCHAR *p; + struct ccs *pccs; + ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link = local->finder; + DEBUG(1, "ray_init(0x%p)\n", dev); + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_init - device not present\n"); + return -1; + } + + local->net_type = net_type; + local->sta_type = TYPE_STA; + + /* Copy the startup results to local memory */ + memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\ + sizeof(struct startup_res_6)); + + /* Check Power up test status and get mac address from card */ + if (local->startup_res.startup_word != 0x80) { +DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word); + local->card_status = CARD_INIT_ERROR; + return -1; + } + + local->fw_ver = local->startup_res.firmware_version[0]; + local->fw_bld = local->startup_res.firmware_version[1]; + local->fw_var = local->startup_res.firmware_version[2]; + DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld); + + local->tib_length = 0x20; + if ((local->fw_ver == 5) && (local->fw_bld >= 30)) + local->tib_length = local->startup_res.tib_length; + DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length); + /* Initialize CCS's to buffer free state */ + pccs = (struct ccs *)(local->sram + CCS_BASE); + for (i=0; ibuffer_status); + } + init_startup_params(local); + + /* copy mac address to startup parameters */ + if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) + { + p = local->sparm.b4.a_mac_addr; + DEBUG(1,"ray_cs phy address overridden = %2x %2x %2x %2x %2x %2x\n",\ + p[0],p[1],p[2],p[3],p[4],p[5]); + } + else + { + memcpy(&local->sparm.b4.a_mac_addr, + &local->startup_res.station_addr, ADDRLEN); + p = local->sparm.b4.a_mac_addr; + DEBUG(1,"ray_cs phy addr= %2x %2x %2x %2x %2x %2x\n",\ + p[0],p[1],p[2],p[3],p[4],p[5]); + } + + clear_interrupt(local); /* Clear any interrupt from the card */ + local->card_status = CARD_AWAITING_PARAM; + DEBUG(2,"ray_init ending\n"); + return 0; +} /* ray_init */ +/*===========================================================================*/ +/* Download startup parameters to the card and command it to read them */ +int dl_startup_params(struct net_device *dev) +{ + int ccsindex; + ray_dev_t *local = (ray_dev_t *)dev->priv; + struct ccs *pccs; + dev_link_t *link = local->finder; + + DEBUG(1,"dl_startup_params entered\n"); + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs dl_startup_params - device not present\n"); + return -1; + } + + /* Copy parameters to host to ECF area */ + if (local->fw_ver == 0x55) + memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4, + sizeof(struct b4_startup_params)); + else + memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5, + sizeof(struct b5_startup_params)); + + + /* Fill in the CCS fields for the ECF */ + if ((ccsindex = get_free_ccs(local)) == -1) return -1; + local->dl_param_ccs = ccsindex; + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd); + DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs); + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(0,"ray dl_startup_params failed - ECF not ready for intr\n"); + local->card_status = CARD_DL_PARAM_ERROR; + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + return -2; + } + local->card_status = CARD_DL_PARAM; + /* Start kernel timer to wait for dl startup to complete. */ + local->timer.expires = jiffies + HZ/2; + local->timer.data = (long)local; + local->timer.function = &verify_dl_startup; + add_timer(&local->timer); + DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n"); + return 0; +} /* dl_startup_params */ +/*===========================================================================*/ +void init_startup_params(ray_dev_t *local) +{ + int i; + static char hop_pattern_length[] = { 1, + USA_HOP_MOD, EUROPE_HOP_MOD, + JAPAN_HOP_MOD, KOREA_HOP_MOD, + SPAIN_HOP_MOD, FRANCE_HOP_MOD, + ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD, + JAPAN_TEST_HOP_MOD + }; + + if (country > JAPAN_TEST) country = USA; + else + if (country < USA) country = USA; + /* structure for hop time and beacon period is defined here using + * New 802.11D6.1 format. Card firmware is still using old format + * until version 6. + * Before After + * a_hop_time ms byte a_hop_time ms byte + * a_hop_time 2s byte a_hop_time ls byte + * a_hop_time ls byte a_beacon_period ms byte + * a_beacon_period a_beacon_period ls byte + * + * a_hop_time = uS a_hop_time = KuS + * a_beacon_period = hops a_beacon_period = KuS + */ /* 64ms = 010000 */ + if (local->fw_ver == 0x55) { + memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, + sizeof(struct b4_startup_params)); + /* Translate sane kus input values to old build 4/5 format */ + /* i = hop time in uS truncated to 3 bytes */ + i = (hop_dwell * 1024) & 0xffffff; + local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff; + local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff; + local->sparm.b4.a_beacon_period[0] = 0; + local->sparm.b4.a_beacon_period[1] = + ((beacon_period/hop_dwell) - 1) & 0xff; + local->sparm.b4.a_curr_country_code = country; + local->sparm.b4.a_hop_pattern_length = + hop_pattern_length[(int)country] - 1; + if (bc) + { + local->sparm.b4.a_ack_timeout = 0x50; + local->sparm.b4.a_sifs = 0x3f; + } + } + else { /* Version 5 uses real kus values */ + memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, + sizeof(struct b5_startup_params)); + + local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff; + local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff; + local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff; + local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff; + if (psm) + local->sparm.b5.a_power_mgt_state = 1; + local->sparm.b5.a_curr_country_code = country; + local->sparm.b5.a_hop_pattern_length = + hop_pattern_length[(int)country]; + } + + local->sparm.b4.a_network_type = net_type & 0x01; + local->sparm.b4.a_acting_as_ap_status = TYPE_STA; + + if (essid != NULL) + strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); +} /* init_startup_params */ +/*===========================================================================*/ +void verify_dl_startup(u_long data) +{ + ray_dev_t *local = (ray_dev_t *)data; + struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs; + UCHAR status; +/* UCHAR *p = local->sram + HOST_TO_ECF_BASE; */ + dev_link_t *link = local->finder; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs verify_dl_startup - device not present\n"); + return; + } +#ifdef RAYLINK_DEBUG + { + int i; + DEBUG(2,"verify_dl_startup parameters sent via ccs %d:\n",\ + local->dl_param_ccs); + for (i=0; isram + HOST_TO_ECF_BASE + i)); + } + DEBUG(1,"\n"); + } +#endif + + status = readb(&pccs->buffer_status); + if (status!= CCS_BUFFER_FREE) + { + DEBUG(0,"Download startup params failed. Status = %d\n",status); + local->card_status = CARD_DL_PARAM_ERROR; + return; + } + if (local->sparm.b4.a_network_type == ADHOC) + start_net((u_long)local); + else + join_net((u_long)local); + + return; +} /* end verify_dl_startup */ +/*===========================================================================*/ +/* Command card to start a network */ +void start_net(u_long data) +{ + ray_dev_t *local = (ray_dev_t *)data; + struct ccs *pccs; + int ccsindex; + dev_link_t *link = local->finder; + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs start_net - device not present\n"); + return; + } + /* Fill in the CCS fields for the ECF */ + if ((ccsindex = get_free_ccs(local)) == -1) return; + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + writeb(CCS_START_NETWORK, &pccs->cmd); + writeb(0, &pccs->var.start_network.update_param); + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(1,"ray start net failed - card not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + return; + } + local->card_status = CARD_DOING_ACQ; + return; +} /* end start_net */ +/*===========================================================================*/ +/* Command card to join a network */ +void join_net(u_long data) +{ + ray_dev_t *local = (ray_dev_t *)data; + + struct ccs *pccs; + int ccsindex; + dev_link_t *link = local->finder; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs join_net - device not present\n"); + return; + } + /* Fill in the CCS fields for the ECF */ + if ((ccsindex = get_free_ccs(local)) == -1) return; + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + writeb(CCS_JOIN_NETWORK, &pccs->cmd); + writeb(0, &pccs->var.join_network.update_param); + writeb(0, &pccs->var.join_network.net_initiated); + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(1,"ray join net failed - card not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + return; + } + local->card_status = CARD_DOING_ACQ; + return; +} +/*============================================================================ + After a card is removed, ray_release() will unregister the net + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. +=============================================================================*/ +void ray_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = link->priv; + ray_dev_t *local = dev->priv; + int i; + + DEBUG(1, "ray_release(0x%p)\n", link); + /* If the device is currently in use, we won't release until it + is actually closed. + */ + if (link->open) { + DEBUG(1, "ray_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + del_timer(&local->timer); + if (link->dev != '\0') unregister_netdev(dev); + /* Unlink the device chain */ + link->dev = NULL; + + iounmap(local->sram); + iounmap(local->rmem); + iounmap(local->amem); + /* Do bother checking to see if these succeed or not */ + i = CardServices(ReleaseWindow, link->win); + if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); + i = CardServices(ReleaseWindow, local->amem_handle); + if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); + i = CardServices(ReleaseWindow, local->rmem_handle); + if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); + i = CardServices(ReleaseConfiguration, link->handle); + if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); + i = CardServices(ReleaseIRQ, link->handle, &link->irq); + if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) ray_detach(link); + DEBUG(2,"ray_release ending\n"); +} /* ray_release */ +/*============================================================================= + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the net drivers from trying + to talk to the card any more. + + When a CARD_REMOVAL event is received, we immediately set a flag + to block future accesses to this device. All the functions that + actually access the device should check this flag to make sure + the card is still present. +=============================================================================*/ +int ray_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct net_device *dev = link->priv; + ray_dev_t *local = (ray_dev_t *)dev->priv; + DEBUG(1, "ray_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + dev->tbusy = 1; dev->start = 0; + if (link->state & DEV_CONFIG) { + link->release.expires = jiffies + HZ/20; + add_timer(&link->release); + del_timer(&local->timer); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + ray_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + if (link->open) { + dev->tbusy = 1; + dev->start = 0; + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) { + ray_reset(dev); + dev->tbusy = 0; + dev->start = 1; + } + } + break; + } + return 0; + DEBUG(2,"ray_event ending\n"); +} /* ray_event */ +/*===========================================================================*/ +int init_module(void) +{ + int rc; + servinfo_t serv; + + DEBUG(1, "%s\n", rcsid); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "ray: Card Services release does not match!\n"); + return -1; + } + rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach); + DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc); + proc_register(&proc_root, &ray_cs_proc_entry); + if (translate != 0) translate = 1; + return 0; +} /* init_module */ +/*===========================================================================*/ +void cleanup_module(void) +{ + DEBUG(0, "ray_cs: cleanup_module\n"); + + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list); + ray_detach(dev_list); + } + proc_unregister(&proc_root, ray_cs_proc_entry.low_ino); +} /* cleanup_module */ +/*===========================================================================*/ +int ray_dev_init(struct net_device *dev) +{ + int i; + ray_dev_t *local = dev->priv; + dev_link_t *link = local->finder; + + DEBUG(1,"ray_dev_init(dev=%p)\n",dev); + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_dev_init - device not present\n"); + return -1; + } + /* Download startup parameters */ + if ( (i = dl_startup_params(dev)) < 0) + { + DEBUG(0,"ray_dev_init dl_startup_params failed - returns 0x%x/n",i); + return -1; + } + + /* copy mac and broadcast addresses to linux device */ + memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN); + memset(dev->broadcast, 0xff, ETH_ALEN); + +#ifdef RAYLINK_DEBUG + { + UCHAR *p; + p = (UCHAR *)(local->startup_res.station_addr); + DEBUG(1,"ray_dev_init card hardware mac addr = %2x %2x %2x %2x %2x %2x\n",\ + p[0],p[1],p[2],p[3],p[4],p[5]); + } +#endif + + DEBUG(2,"ray_dev_init ending\n"); + return 0; +} +/*===========================================================================*/ +int ray_dev_config(struct net_device *dev, struct ifmap *map) +{ + ray_dev_t *local = dev->priv; + dev_link_t *link = local->finder; + /* Dummy routine to satisfy device structure */ + DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_dev_config - device not present\n"); + return -1; + } + + return 0; +} +/*===========================================================================*/ +int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + ray_dev_t *local = dev->priv; + dev_link_t *link = local->finder; + short length; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_dev_start_xmit - device not present\n"); + return -1; + } + DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); + if (dev->tbusy) + { + DEBUG(2,"ray_dev_start_xmit busy\n"); + return 1; + } + if (local->authentication_state == NEED_TO_AUTH) { + DEBUG(0,"ray_cs Sending authentication request.\n"); + if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) { + local->authentication_state = AUTHENTICATED; + dev->tbusy = 1; + return 1; + } + } + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { + case XMIT_NO_CCS: + case XMIT_NEED_AUTH: + dev->tbusy = 1; + return 1; + case XMIT_NO_INTR: + case XMIT_MSG_BAD: + case XMIT_OK: + default: + dev->trans_start = jiffies; + dev_kfree_skb(skb); + return 0; + } + return 0; +} /* ray_dev_start_xmit */ +/*===========================================================================*/ +int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, + UCHAR msg_type) +{ + ray_dev_t *local = (ray_dev_t *)dev->priv; + struct ccs *pccs; + int ccsindex; + int offset; + struct tx_msg *ptx; /* Address of xmit buffer in PC space */ + short int addr; /* Address of xmit buffer in card space */ + + DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev); + if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) + { + DEBUG(0,"ray_hw_xmit packet to large %d bytes\n",len); + return XMIT_MSG_BAD; + } + if ((ccsindex = get_free_tx_ccs(local)) == -1) + { + DEBUG(2,"ray_hw_xmit - No free tx ccs\n"); + dev->tbusy = 1; + return XMIT_NO_CCS; + } + addr = TX_BUF_BASE + (ccsindex << 11); + + if (msg_type == DATA_TYPE) { + local->stats.tx_bytes += len; + local->stats.tx_packets++; + } + + ptx = (struct tx_msg *)(local->sram + addr); + + ray_build_header(local, ptx, msg_type, data); + if (translate) { + offset = translate_frame(local, ptx, data, len); + } + else { /* Encapsulate frame */ + /* TBD TIB length will move address of ptx->var */ + memcpy( (UCHAR *)&ptx->var, data, len); + offset = 0; + } + + /* fill in the CCS */ + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + len += TX_HEADER_LENGTH + offset; + writeb(CCS_TX_REQUEST, &pccs->cmd); + writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]); + writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]); + writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]); + writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]); +/* TBD still need psm_cam? */ + writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode); + writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate); + writeb(0, &pccs->var.tx_request.antenna); + DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\ + local->net_default_tx_rate); + + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n"); +/* TBD very inefficient to copy packet to buffer, and then not + send it, but the alternative is to queue the messages and that + won't be done for a while. Maybe set tbusy until a CCS is free? +*/ + writeb(CCS_BUFFER_FREE, &pccs->buffer_status); + return XMIT_NO_INTR; + } + return XMIT_OK; +} /* end ray_hw_xmit */ +/*===========================================================================*/ +int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data, + int len) +{ + unsigned short int proto = ((struct ethhdr *)data)->h_proto; + if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ + DEBUG(3,"ray_cs translate_frame DIX II\n"); + /* Copy LLC header to card buffer */ + memcpy_toio((UCHAR *)&ptx->var, eth2_llc, sizeof(eth2_llc)); + memcpy_toio( ((UCHAR *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); + if ((proto == 0xf380) || (proto == 0x3781)) { + /* This is the selective translation table, only 2 entries */ + writeb(0xf8, (UCHAR *) &((struct snaphdr_t *)ptx->var)->org[3]); + } + /* Copy body of ethernet packet without ethernet header */ + memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \ + data + ETH_HLEN, len - ETH_HLEN); + return sizeof(struct snaphdr_t) - ETH_HLEN; + } + else { /* already 802 type, and proto is length */ + DEBUG(3,"ray_cs translate_frame 802\n"); + if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ + DEBUG(3,"ray_cs translate_frame evil IPX\n"); + memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + return 0 - ETH_HLEN; + } + memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN, len - ETH_HLEN); + return 0 - ETH_HLEN; + } + /* TBD do other frame types */ +} /* end translate_frame */ +/*===========================================================================*/ +void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type, + unsigned char *data) +{ + writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1); +/*** IEEE 802.11 Address field assignments ************* + addr_1 addr_2 addr_3 + AP destination AP(BSSID) source + Infra Terminal AP terminal destination + Adhoc destination terminal BSSID +*******************************************************/ + if (local->net_type == ADHOC) { + writeb(0, &ptx->mac.frame_ctl_2); + memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN); + memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); + } + else /* infrastructure */ + { + if (local->sparm.b4.a_acting_as_ap_status) + { + writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);; + memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN); + memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); + memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN); + } + else /* Terminal */ + { + writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2); + memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN); + memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN); + memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN); + } + } +} /* end encapsulate_frame */ +/*===========================================================================*/ +int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link = local->finder; + int err = 0; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_dev_ioctl - device not present\n"); + return -1; + } + DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd); + /* Validate the command */ + switch (cmd) + { + default: + DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd); + err = -EOPNOTSUPP; + } + return err; +} /* end ray_dev_ioctl */ +/*===========================================================================*/ +int ray_open(struct net_device *dev) +{ + dev_link_t *link; + ray_dev_t *local = (ray_dev_t *)dev->priv; + + DEBUG(1, "ray_open('%s')\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (!DEV_OK(link)) + return -ENODEV; + + if (link->open == 0) local->num_multi = 0; + link->open++; + MOD_INC_USE_COUNT; + + dev->interrupt = 0; + if (sniffer) dev->tbusy = 1; + else dev->tbusy = 0; + dev->start = 1; + + DEBUG(2,"ray_open ending\n"); + return 0; +} /* end ray_open */ +/*===========================================================================*/ +int ray_dev_close(struct net_device *dev) +{ + dev_link_t *link; + + DEBUG(1, "ray_dev_close('%s')\n", dev->name); + + for (link = dev_list; link; link = link->next) + if (link->priv == dev) break; + if (link == NULL) + return -ENODEV; + + link->open--; dev->start = 0; + if (link->state & DEV_STALE_CONFIG) { + link->release.expires = jiffies + HZ/20; + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + + MOD_DEC_USE_COUNT; + + return 0; +} /* end ray_dev_close */ +/*===========================================================================*/ +void ray_reset(struct net_device *dev) { + DEBUG(1,"ray_reset entered\n"); + return; +} +/*===========================================================================*/ +/* Cause a firmware interrupt if it is ready for one */ +/* Return nonzero if not ready */ +int interrupt_ecf(ray_dev_t *local, int ccs) +{ + int i = 50; +/* UCHAR *p = (local->amem + CIS_OFFSET + ECF_INTR_OFFSET); */ + dev_link_t *link = local->finder; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs interrupt_ecf - device not present\n"); + return -1; + } + DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs); + +/* while ( i && (*p & ECF_INTR_SET)) i--; */ + while ( i && + (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET)) + i--; + if (i == 0) { + DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n"); + return -1; + } + + *(local->sram + SCB_BASE) = ccs; + writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET); + return 0; +} /* interrupt_ecf */ +/*===========================================================================*/ +/* Get next free transmit CCS */ +/* Return - index of current tx ccs */ +int get_free_tx_ccs(ray_dev_t *local) +{ + int i; + struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + dev_link_t *link = local->finder; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs get_free_tx_ccs - device not present\n"); + return -1; + } + + for (i=0; i < NUMBER_OF_TX_CCS; i++) { + if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { + writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); + writeb(CCS_END_LIST, &(pccs+i)->link); + return i; + } + } + DEBUG(1,"ray_cs ERROR no free tx CCS for raylink card\n"); + return -1; +} /* get_free_tx_ccs */ +/*===========================================================================*/ +/* Get next free CCS */ +/* Return - index of current ccs */ +int get_free_ccs(ray_dev_t *local) +{ + int i; + struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE); + dev_link_t *link = local->finder; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs get_free_ccs - device not present\n"); + return -1; + } + for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) { + if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) { + writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status); + writeb(CCS_END_LIST, &(pccs+i)->link); + return i; + } + } + DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n"); + return -1; +} /* get_free_ccs */ +/*===========================================================================*/ +void authenticate_timeout(u_long data) +{ + ray_dev_t *local = (ray_dev_t *)data; + del_timer(&local->timer); + DEBUG(0,"ray_cs Authentication with access point failed - timeout\n"); + join_net((u_long)local); +} +/*===========================================================================*/ +int asc_to_int(char a) +{ + if (a < '0') return -1; + if (a <= '9') return (a - '0'); + if (a < 'A') return -1; + if (a <= 'F') return (10 + a - 'A'); + if (a < 'a') return -1; + if (a <= 'f') return (10 + a - 'a'); + return -1; +} +/*===========================================================================*/ +int parse_addr(char *in_str, UCHAR *out) +{ + int len; + int i,j,k; + int status; + + if (in_str == NULL) return 0; + if ((len = strlen(in_str)) < 2) return 0; + memset(out, 0, ADDRLEN); + + status = 1; + j = len - 1; + if (j > 12) j = 12; + i = 5; + + while (j > 0) + { + if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k; + else return 0; + + if (j == 0) break; + if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4; + else return 0; + if (!i--) break; + } + return status; +} +/*===========================================================================*/ +struct enet_statistics *ray_get_stats(struct net_device *dev) +{ + ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link = local->finder; + struct status *p = (struct status *)(local->sram + STATUS_BASE); + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_cs enet_statistics - device not present\n"); + return &local->stats; + } + if (p->mrx_overflow_for_host) + { + local->stats.rx_over_errors += ntohs(p->mrx_overflow); + p->mrx_overflow = 0; + p->mrx_overflow_for_host = 0; + } + if (p->mrx_checksum_error_for_host) + { + local->stats.rx_crc_errors += ntohs(p->mrx_checksum_error); + p->mrx_checksum_error = 0; + p->mrx_checksum_error_for_host = 0; + } + if (p->rx_hec_error_for_host) + { + local->stats.rx_frame_errors += ntohs(p->rx_hec_error); + p->rx_hec_error = 0; + p->rx_hec_error_for_host = 0; + } + return &local->stats; +} +/*===========================================================================*/ +void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) +{ + ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link = local->finder; + int ccsindex; + int i; + struct ccs *pccs; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(0,"ray_update_parm - device not present\n"); + return; + } + + if ((ccsindex = get_free_ccs(local)) == -1) + { + DEBUG(0,"ray_update_parm - No free ccs\n"); + return; + } + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + writeb(CCS_UPDATE_PARAMS, &pccs->cmd); + writeb(objid, &pccs->var.update_param.object_id); + writeb(1, &pccs->var.update_param.number_objects); + writeb(0, &pccs->var.update_param.failure_cause); + for (i=0; isram + HOST_TO_ECF_BASE); + } + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + } +} +/*===========================================================================*/ +static void ray_update_multi_list(struct net_device *dev, int all) +{ + struct dev_mc_list *dmi, **dmip; + int ccsindex; + struct ccs *pccs; + int i = 0; + ray_dev_t *local = (ray_dev_t *)dev->priv; + dev_link_t *link = local->finder; + UCHAR *p = local->sram + HOST_TO_ECF_BASE; + + if (!(link->state & DEV_PRESENT)) { + DEBUG(1,"ray_update_multi_list - device not present\n"); + return; + } + else + DEBUG(1,"ray_update_multi_list(%p)\n",dev); + if ((ccsindex = get_free_ccs(local)) == -1) + { + DEBUG(1,"ray_update_multi - No free ccs\n"); + return; + } + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd); + + if (all) { + writeb(0xff, &pccs->var); + local->num_multi = 0xff; + } + else { + /* Copy the kernel's list of MC addresses to card */ + for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) { + memcpy_toio(p, dmi->dmi_addr, ETH_ALEN); + DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]); + p += ETH_ALEN; + i++; + } + if (i > 256/ADDRLEN) i = 256/ADDRLEN; + writeb((UCHAR)i, &pccs->var); + DEBUG(1,"ray_cs update_multi %d addresses in list\n", i); + /* Interrupt the firmware to process the command */ + local->num_multi = i; + } + if (interrupt_ecf(local, ccsindex)) { + DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + } +} /* end ray_update_multi_list */ +/*===========================================================================*/ +static void set_multicast_list(struct net_device *dev) +{ + ray_dev_t *local = (ray_dev_t *)dev->priv; + UCHAR promisc; + + DEBUG(1,"ray_cs set_multicast_list(%p)\n",dev); + + if (dev->flags & IFF_PROMISC) + { + if (local->sparm.b5.a_promiscuous_mode == 0) { + DEBUG(1,"ray_cs set_multicast_list promisc on\n"); + local->sparm.b5.a_promiscuous_mode = 1; + promisc = 1; + ray_update_parm(dev, OBJID_promiscuous_mode, \ + &promisc, sizeof(promisc)); + } + } + else { + if (local->sparm.b5.a_promiscuous_mode == 1) { + DEBUG(1,"ray_cs set_multicast_list promisc off\n"); + local->sparm.b5.a_promiscuous_mode = 0; + promisc = 0; + ray_update_parm(dev, OBJID_promiscuous_mode, \ + &promisc, sizeof(promisc)); + } + } + + if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1); + else + { + if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0); + } +} /* end set_multicast_list */ +/*============================================================================= + * All routines below here are run at interrupt time. +=============================================================================*/ +void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + dev_link_t *link; + ray_dev_t *local; + struct ccs *pccs; + struct rcs *prcs; + UCHAR rcsindex; + UCHAR tmp; + UCHAR cmd; + UCHAR status; + + if (dev == NULL) { + link = dev_list; + dev = (struct net_device *)link->priv; + DEBUG(4,"ray_cs interrupt dev = %p, link = %p\n",dev,link); + if (dev->irq != irq) + { + DEBUG(0,"ray_cs interrupt irq %d for unknown device.\n", irq); + return; + } + } + DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); + + if (dev->interrupt) { + printk("ray_cs Reentering interrupt handler not allowed\n"); + return; + } + dev->interrupt = 1; + local = (ray_dev_t *)dev->priv; + link = (dev_link_t *)local->finder; + if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { + DEBUG(1,"ray_cs interrupt from device not present or suspended.\n"); + return; + } + rcsindex = ((struct scb *)(local->sram))->rcs_index; + + if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) + { + DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); + clear_interrupt(local); + dev->interrupt = 0; + return; + } + if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ + { + pccs = ((struct ccs *) (local->sram + CCS_BASE)) + rcsindex; + cmd = readb(&pccs->cmd); + status = readb(&pccs->buffer_status); + switch (cmd) + { + case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */ + del_timer(&local->timer); + if (status == CCS_COMMAND_COMPLETE) { + DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n"); + } + else { + DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n"); + } + break; + case CCS_UPDATE_PARAMS: + DEBUG(1,"ray_cs interrupt update params done\n"); + if (status != CCS_COMMAND_COMPLETE) { + tmp = readb(&pccs->var.update_param.failure_cause); + DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp); + } + break; + case CCS_REPORT_PARAMS: + DEBUG(1,"ray_cs interrupt report params done\n"); + break; + case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */ + DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n"); + break; + case CCS_UPDATE_POWER_SAVINGS_MODE: + DEBUG(1,"ray_cs interrupt update power save mode done\n"); + break; + case CCS_START_NETWORK: + case CCS_JOIN_NETWORK: + if (status == CCS_COMMAND_COMPLETE) { + if (readb(&pccs->var.start_network.net_initiated) == 1) { + DEBUG(0,"ray_cs interrupt network \"%s\"started\n",\ + local->sparm.b4.a_current_ess_id); + } + else { + DEBUG(0,"ray_cs interrupt network \"%s\" joined\n",\ + local->sparm.b4.a_current_ess_id); + } + memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN); + + if (local->fw_ver == 0x55) local->net_default_tx_rate = 3; + else local->net_default_tx_rate = + readb(&pccs->var.start_network.net_default_tx_rate); + local->encryption = readb(&pccs->var.start_network.encryption); + if (!sniffer && (local->net_type == INFRA) + && !(local->sparm.b4.a_acting_as_ap_status)) { + authenticate(local); + } + local->card_status = CARD_ACQ_COMPLETE; + } + else { + local->card_status = CARD_ACQ_FAILED; + + del_timer(&local->timer); + local->timer.expires = jiffies + HZ*5; + local->timer.data = (long)local; + if (status == CCS_START_NETWORK) { + DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\ + local->sparm.b4.a_current_ess_id); + local->timer.function = &start_net; + } + else { + DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\ + local->sparm.b4.a_current_ess_id); + local->timer.function = &join_net; + } + add_timer(&local->timer); + } + break; + case CCS_START_ASSOCIATION: + if (status == CCS_COMMAND_COMPLETE) { + local->card_status = CARD_ASSOC_COMPLETE; + DEBUG(0,"ray_cs association successful\n"); + } + else + { + DEBUG(0,"ray_cs association failed,\n"); + local->card_status = CARD_ASSOC_FAILED; + join_net((u_long)local); + } + break; + case CCS_TX_REQUEST: + if (status == CCS_COMMAND_COMPLETE) { + DEBUG(3,"ray_cs interrupt tx request complete\n"); + } + else { + DEBUG(1,"ray_cs interrupt tx request failed\n"); + } + if (!sniffer) dev->tbusy = 0; + mark_bh(NET_BH); + break; + case CCS_TEST_MEMORY: + DEBUG(1,"ray_cs interrupt mem test done\n"); + break; + case CCS_SHUTDOWN: + DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n"); + break; + case CCS_DUMP_MEMORY: + DEBUG(1,"ray_cs interrupt dump memory done\n"); + break; + case CCS_START_TIMER: + DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n"); + break; + default: + DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\ + rcsindex, cmd); + } + writeb(CCS_BUFFER_FREE, &pccs->buffer_status); + } + else /* It's an RCS */ + { + prcs = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + + switch (readb(&prcs->interrupt_id)) + { + case PROCESS_RX_PACKET: + ray_rx(dev, local, prcs); + break; + case REJOIN_NET_COMPLETE: + DEBUG(1,"ray_cs interrupt rejoin net complete\n"); + local->card_status = CARD_ACQ_COMPLETE; + /* do we need to clear tx buffers CCS's? */ + if (local->sparm.b4.a_network_type == ADHOC) { + if (!sniffer) dev->tbusy = 0; + } + else { + memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN); + DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\ + local->bss_id[0], local->bss_id[1], local->bss_id[2],\ + local->bss_id[3], local->bss_id[4], local->bss_id[5]); + if (!sniffer) authenticate(local); + } + break; + case ROAMING_INITIATED: + DEBUG(1,"ray_cs interrupt roaming initiated\n"); + dev->tbusy = 1; + local->card_status = CARD_DOING_ACQ; + break; + case JAPAN_CALL_SIGN_RXD: + DEBUG(1,"ray_cs interrupt japan call sign rx\n"); + break; + default: + DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\ + rcsindex, readb(&prcs->interrupt_id)); + break; + } + writeb(CCS_BUFFER_FREE, &prcs->buffer_status); + } + clear_interrupt(local); + dev->interrupt = 0; +} /* ray_interrupt */ +/*===========================================================================*/ +void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) +{ + int rx_len; + unsigned int pkt_addr; + UCHAR *pmsg; + DEBUG(4,"ray_rx process rx packet\n"); + + /* Calculate address of packet within Rx buffer */ + pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8) + + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END; + /* Length of first packet fragment */ + rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8) + + readb(&prcs->var.rx_packet.rx_data_length[1]); + + pmsg = local->rmem + pkt_addr; + switch(readb(pmsg)) + { + case DATA_TYPE: + DEBUG(4,"ray_rx data type\n"); + rx_data(dev, prcs, pkt_addr, rx_len); + break; + case AUTHENTIC_TYPE: + DEBUG(4,"ray_rx authentic type\n"); + if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); + else rx_authenticate(local, prcs, pkt_addr, rx_len); + break; + case DEAUTHENTIC_TYPE: + DEBUG(4,"ray_rx deauth type\n"); + if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); + else rx_deauthenticate(local, prcs, pkt_addr, rx_len); + break; + case NULL_MSG_TYPE: + DEBUG(3,"ray_cs rx NULL msg\n"); + break; + case BEACON_TYPE: + DEBUG(4,"ray_rx beacon type\n"); + if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len); + + copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, + rx_len < sizeof(struct beacon_rx) ? + rx_len : sizeof(struct beacon_rx)); + + /* Get the statistics so the card counters never overflow */ + ray_get_stats(dev); + break; + default: + DEBUG(0,"ray_cs unknown pkt type %2x\n", readb(pmsg)); + break; + } + +} /* end ray_rx */ +/*===========================================================================*/ +void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, + int rx_len) +{ + struct sk_buff *skb = NULL; + struct rcs *prcslink = prcs; + ray_dev_t *local = dev->priv; + UCHAR *rx_ptr; + int total_len; + int tmp; + + if (!sniffer) { + if (translate) { +/* TBD length needs fixing for translated header */ + if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || + rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) + { + DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); + return; + } + } + else /* encapsulated ethernet */ { + if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) || + rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) + { + DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len); + return; + } + } + } + DEBUG(4,"ray_cs rx_data packet\n"); + /* If fragmented packet, verify sizes of fragments add up */ + if (prcs->var.rx_packet.next_frag_rcs_index != 0xFF) { + DEBUG(1,"ray_cs rx'ed fragment\n"); + tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8) + + readb(&prcs->var.rx_packet.totalpacketlength[1]); + total_len = tmp; + prcslink = prcs; + do { + tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) + + readb(&prcslink->var.rx_packet.rx_data_length[1]); + if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF + || tmp < 0) break; + prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + + readb(&prcslink->link_field); + } while (1); + + if (tmp < 0) + { + DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n"); + local->stats.rx_dropped++; + release_frag_chain(local, prcs); + return; + } + } + else { /* Single unfragmented packet */ + total_len = rx_len; + } + + skb = dev_alloc_skb( total_len+5 ); + if (skb == NULL) + { + DEBUG(0,"ray_cs rx_data could not allocate skb\n"); + local->stats.rx_dropped++; + if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) + release_frag_chain(local, prcs); + return; + } + skb_reserve( skb, 2); /* Align IP on 16 byte (TBD check this)*/ + skb->dev = dev; + + DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len); + +/************************/ + /* Reserve enough room for the whole damn packet. */ + rx_ptr = skb_put( skb, total_len); + /* Copy the whole packet to sk_buff */ + rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len); + + /* Now, deal with encapsulation/translation/sniffer */ + if (!sniffer) { + if (!translate) { + /* Encapsulated ethernet, so just lop off 802.11 MAC header */ +/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */ + skb_pull( skb, RX_MAC_HEADER_LENGTH); + } + else { + /* Do translation */ + untranslate(local, skb, total_len); + } + } + else + { /* sniffer mode, so just pass whole packet */ }; + +/************************/ + /* Now pick up the rest of the fragments if any */ + tmp = 17; + if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) { + prcslink = prcs; + DEBUG(1,"ray_cs rx_data in fragment loop\n"); + do { + prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + + readb(&prcslink->var.rx_packet.next_frag_rcs_index); + rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8) + + readb(&prcslink->var.rx_packet.rx_data_length[1])) + & RX_BUFF_END; + pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8) + + readb(&prcslink->var.rx_packet.rx_data_ptr[1])) + & RX_BUFF_END; + + rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len); + + } while (tmp-- && + readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF); + release_frag_chain(local, prcs); + } + + skb->protocol = eth_type_trans(skb,dev); + netif_rx(skb); + + local->stats.rx_packets++; + local->stats.rx_bytes += skb->len; +} /* end rx_data */ +/*===========================================================================*/ +void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) +{ + snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); + struct mac_header *pmac = (struct mac_header *)skb->data; + unsigned short type = *(unsigned short *)psnap->ethertype; + unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff; + unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff; + int delta; + struct ethhdr *peth; + UCHAR srcaddr[ADDRLEN]; + UCHAR destaddr[ADDRLEN]; + int i; + + if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA) + memcpy(destaddr, pmac->addr_3, ADDRLEN); + else + memcpy(destaddr, pmac->addr_1, ADDRLEN); + memcpy(srcaddr, pmac->addr_2, ADDRLEN); + + DEBUG(3,"skb->data before untranslate"); + for (i=0;i<64;i++) + DEBUG(3,"%02x ",skb->data[i]); + DEBUG(3,"\ntype = %08x, xsap = %08x, org = %08x\n",type,xsap,org); + DEBUG(3,"untranslate skb->data = %p\n",skb->data); + + if ( xsap != SNAP_ID) { + /* not a snap type so leave it alone */ + DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff); + + delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; + peth = (struct ethhdr *)(skb->data + delta); + peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); + } + else { /* Its a SNAP */ + if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */ + DEBUG(3,"ray_cs untranslate Bridge encap\n"); + delta = RX_MAC_HEADER_LENGTH + + sizeof(struct snaphdr_t) - ETH_HLEN; + peth = (struct ethhdr *)(skb->data + delta); + peth->h_proto = type; + } + else { + if (org == RFC1042_ENCAP) { + switch (type) { + case RAY_IPX_TYPE: + case APPLEARP_TYPE: + DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); + delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; + peth = (struct ethhdr *)(skb->data + delta); + peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); + break; + default: + DEBUG(3,"ray_cs untranslate RFC default\n"); + delta = RX_MAC_HEADER_LENGTH + + sizeof(struct snaphdr_t) - ETH_HLEN; + peth = (struct ethhdr *)(skb->data + delta); + peth->h_proto = type; + break; + } + } + else { + printk("ray_cs untranslate very confused by packet\n"); + delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; + peth = (struct ethhdr *)(skb->data + delta); + peth->h_proto = type; + } + } + } +/* TBD reserve skb_reserve(skb, delta); */ + skb_pull(skb, delta); + DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data); + memcpy(peth->h_dest, destaddr, ADDRLEN); + memcpy(peth->h_source, srcaddr, ADDRLEN); + DEBUG(3,"skb->data after untranslate:"); + for (i=0;i<64;i++) + DEBUG(3,"%02x ",skb->data[i]); + DEBUG(3,"\n"); +} /* end untranslate */ +/*===========================================================================*/ +/* Copy data from circular receive buffer to PC memory. + * dest = destination address in PC memory + * pkt_addr = source address in receive buffer + * len = length of packet to copy + */ +int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length) +{ + int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1); + if (wrap_bytes <= 0) + { + memcpy_fromio(dest,local->rmem + pkt_addr,length); + } + else /* Packet wrapped in circular buffer */ + { + memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes); + memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes); + } + return length; +} +/*===========================================================================*/ +void release_frag_chain(ray_dev_t *local, struct rcs* prcs) +{ + struct rcs *prcslink = prcs; + int tmp = 17; + unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index); + + while (tmp--) { + writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); + if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) { + DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); + break; + } + prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex; + rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index); + } + writeb(CCS_BUFFER_FREE, &prcslink->buffer_status); +} +/*===========================================================================*/ +void authenticate(ray_dev_t *local) +{ + dev_link_t *link = local->finder; + DEBUG(0,"ray_cs Starting authentication.\n"); + if (!(link->state & DEV_PRESENT)) { + DEBUG(1,"ray_cs authenticate - device not present\n"); + return; + } + + del_timer(&local->timer); + if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) { + local->timer.function = &join_net; + } + else { + local->timer.function = &authenticate_timeout; + } + local->timer.expires = jiffies + HZ*2; + local->timer.data = (long)local; + add_timer(&local->timer); + local->authentication_state = AWAITING_RESPONSE; +} /* end authenticate */ +/*===========================================================================*/ +void rx_authenticate(ray_dev_t *local, struct rcs *prcs, + unsigned int pkt_addr, int rx_len) +{ + UCHAR buff[256]; + struct rx_msg *msg = (struct rx_msg *)buff; + + del_timer(&local->timer); + + copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); + /* if we are trying to get authenticated */ + if (local->sparm.b4.a_network_type == ADHOC) { + DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]); + if (msg->var[2] == 1) { + DEBUG(0,"ray_cs Sending authentication response.\n"); + if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) { + local->authentication_state = NEED_TO_AUTH; + memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN); + } + } + } + else /* Infrastructure network */ + { + if (local->authentication_state == AWAITING_RESPONSE) { + /* Verify authentication sequence #2 and success */ + if (msg->var[2] == 2) { + if ((msg->var[3] | msg->var[4]) == 0) { + DEBUG(1,"Authentication successful\n"); + local->card_status = CARD_AUTH_COMPLETE; + associate(local); + local->authentication_state = AUTHENTICATED; + } + else { + DEBUG(0,"Authentication refused\n"); + local->card_status = CARD_AUTH_REFUSED; + join_net((u_long)local); + local->authentication_state = UNAUTHENTICATED; + } + } + } + } + +} /* end rx_authenticate */ +/*===========================================================================*/ +void associate(ray_dev_t *local) +{ + struct ccs *pccs; + dev_link_t *link = local->finder; + struct net_device *dev = link->priv; + int ccsindex; + if (!(link->state & DEV_PRESENT)) { + DEBUG(1,"ray_cs associate - device not present\n"); + return; + } + /* If no tx buffers available, return*/ + if ((ccsindex = get_free_ccs(local)) == -1) + { +/* TBD should never be here but... what if we are? */ + DEBUG(1,"ray_cs associate - No free ccs\n"); + return; + } + DEBUG(1,"ray_cs Starting association with access point\n"); + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + /* fill in the CCS */ + writeb(CCS_START_ASSOCIATION, &pccs->cmd); + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + + del_timer(&local->timer); + local->timer.expires = jiffies + HZ*2; + local->timer.data = (long)local; + local->timer.function = &join_net; + add_timer(&local->timer); + local->card_status = CARD_ASSOC_FAILED; + return; + } + if (!sniffer) dev->tbusy = 0; + +} /* end associate */ +/*===========================================================================*/ +void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, + unsigned int pkt_addr, int rx_len) +{ +/* UCHAR buff[256]; + struct rx_msg *msg = (struct rx_msg *)buff; +*/ + DEBUG(0,"Deauthentication frame received\n"); + local->authentication_state = UNAUTHENTICATED; + /* Need to reauthenticate or rejoin depending on reason code */ +/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff); + */ +} +/*===========================================================================*/ +void clear_interrupt(ray_dev_t *local) +{ + writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET); +} +/*===========================================================================*/ +#ifdef CONFIG_PROC_FS +#define MAXDATA (PAGE_SIZE - 80) + +static char *card_status[] = { + "Card inserted - uninitialized", /* 0 */ + "Card not downloaded", /* 1 */ + "Waiting for download parameters", /* 2 */ + "Card doing acquisition", /* 3 */ + "Acquisition complete", /* 4 */ + "Authentication complete", /* 5 */ + "Association complete", /* 6 */ + "???", "???", "???", "???", /* 7 8 9 10 undefined */ + "Card init error", /* 11 */ + "Download parameters error", /* 12 */ + "???", /* 13 */ + "Acquisition failed", /* 14 */ + "Authentication refused", /* 15 */ + "Association failed" /* 16 */ +}; + +static char *nettype[] = {"Adhoc", "Infra "}; +static char *framing[] = {"Encapsulation", "Translation"} +; +/*===========================================================================*/ +int ray_cs_proc_read(char *buf, char **start, off_t offset, + int len, int unused) +{ +/* Print current values which are not available via other means + * eg ifconfig + */ + int i; + dev_link_t *link = dev_list; + struct net_device *dev = (struct net_device *)link->priv; + ray_dev_t *local = (ray_dev_t *)dev->priv; + UCHAR *p; + struct freq_hop_element *pfh; + UCHAR c[33]; + + len = 0; + + len += sprintf(buf + len, "Raylink Wireless LAN driver status\n"); + len += sprintf(buf + len, "%s\n", rcsid); + /* build 4 does not report version, and field is 0x55 after memtest */ + len += sprintf(buf + len, "Firmware version = "); + if (local->fw_ver == 0x55) + len += sprintf(buf + len, "4 - Use dump_cis for more details\n"); + else + len += sprintf(buf + len, "%2d.%02d.%02d\n", + local->fw_ver, local->fw_bld, local->fw_var); + + for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i]; + c[32] = 0; + len += sprintf(buf + len, "%s network ESSID = \"%s\"\n", + nettype[local->sparm.b5.a_network_type], c); + + p = local->bss_id; + len += sprintf(buf + len, + "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", + p[0],p[1],p[2],p[3],p[4],p[5]); + + len += sprintf(buf + len, "Country code = %d\n", + local->sparm.b5.a_curr_country_code); + + i = local->card_status; + if (i < 0) i = 10; + if (i > 16) i = 10; + len += sprintf(buf + len, "Card status = %s\n", card_status[i]); + + len += sprintf(buf + len, "Framing mode = %s\n",framing[translate]); + + /* Pull some fields out of last beacon received */ + len += sprintf(buf + len, "Beacon Interval = %d Kus\n", + local->last_bcn.beacon_intvl[0] + + 256 * local->last_bcn.beacon_intvl[1]); + + p = local->last_bcn.elements; + if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2; + else { + len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]); + return len; + } + + if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) { + len += sprintf(buf + len, "Supported rate codes = "); + for (i=2; idwell_time[0] + 256 * pfh->dwell_time[1]); + len += sprintf(buf + len, "Hop set = %d \n", pfh->hop_set); + len += sprintf(buf + len, "Hop pattern = %d \n", pfh->hop_pattern); + len += sprintf(buf + len, "Hop index = %d \n", pfh->hop_index); + p += p[1] + 2; + } + else { + len += sprintf(buf + len, "Parse beacon failed at FH param element\n"); + return len; + } + return len; +} + +#endif +/*===========================================================================*/ +int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type) +{ + int addr; + struct ccs *pccs; + struct tx_msg *ptx; + int ccsindex; + + /* If no tx buffers available, return */ + if ((ccsindex = get_free_tx_ccs(local)) == -1) + { +/* TBD should never be here but... what if we are? */ + DEBUG(1,"ray_cs send authenticate - No free tx ccs\n"); + return -1; + } + + pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex; + + /* Address in card space */ + addr = TX_BUF_BASE + (ccsindex << 11); + /* fill in the CCS */ + writeb(CCS_TX_REQUEST, &pccs->cmd); + writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr); + writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1); + writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length); + writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1); + writeb(0, &pccs->var.tx_request.pow_sav_mode); + + ptx = (struct tx_msg *)(local->sram + addr); + /* fill in the mac header */ + writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1); + writeb(0, &ptx->mac.frame_ctl_2); + + memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN); + memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN); + memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN); + + /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */ + memset_io(ptx->var, 0, 6); + writeb(auth_type & 0xff, ptx->var + 2); + + /* Interrupt the firmware to process the command */ + if (interrupt_ecf(local, ccsindex)) { + DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n"); + writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status); + return -1; + } + return 0; +} /* End build_auth_frame */ +/*===========================================================================*/ diff --git a/drivers/net/pcmcia/ray_cs.h b/drivers/net/pcmcia/ray_cs.h new file mode 100644 index 000000000..28502954e --- /dev/null +++ b/drivers/net/pcmcia/ray_cs.h @@ -0,0 +1,60 @@ +/* Raytheon wireless LAN PCMCIA card driver for Linux + A PCMCIA client driver for the Raylink wireless network card + Written by Corey Thomas +*/ + +#ifndef RAYLINK_H + +struct beacon_rx { + struct mac_header mac; + UCHAR timestamp[8]; + UCHAR beacon_intvl[2]; + UCHAR capability[2]; + UCHAR elements[sizeof(struct essid_element) + + sizeof(struct rates_element) + + sizeof(struct freq_hop_element) + + sizeof(struct japan_call_sign_element) + + sizeof(struct tim_element)]; +}; + +typedef struct ray_dev_t { + int card_status; + int authentication_state; + dev_node_t node; + window_handle_t amem_handle; /* handle to window for attribute memory */ + window_handle_t rmem_handle; /* handle to window for rx buffer on card */ + UCHAR *sram; /* pointer to beginning of shared RAM */ + UCHAR *amem; /* pointer to attribute mem window */ + UCHAR *rmem; /* pointer to receive buffer window */ + dev_link_t *finder; /* pointer back to dev_link_t for card */ + struct timer_list timer; + int dl_param_ccs; + union { + struct b4_startup_params b4; + struct b5_startup_params b5; + } sparm; + int timeout_flag; + UCHAR supported_rates[8]; + UCHAR japan_call_sign[12]; + struct startup_res_6 startup_res; + int num_multi; + /* Network parameters from start/join */ + UCHAR bss_id[6]; + UCHAR auth_id[6]; + UCHAR net_default_tx_rate; + UCHAR encryption; + struct enet_statistics stats; + + UCHAR net_type; + UCHAR sta_type; + UCHAR fw_ver; + UCHAR fw_bld; + UCHAR fw_var; + UCHAR ASIC_version; + UCHAR assoc_id[2]; + UCHAR tib_length; + struct beacon_rx last_bcn; +} ray_dev_t; +/*****************************************************************************/ + +#endif /* RAYLINK_H */ diff --git a/drivers/net/pcmcia/rayctl.h b/drivers/net/pcmcia/rayctl.h new file mode 100644 index 000000000..a301b0bd2 --- /dev/null +++ b/drivers/net/pcmcia/rayctl.h @@ -0,0 +1,725 @@ +#ifndef RAYLINK_H + +typedef unsigned char UCHAR; + +/****** IEEE 802.11 constants ************************************************/ +#define ADDRLEN 6 +/* Frame control 1 bit fields */ +#define PROTOCOL_VER 0x00 +#define DATA_TYPE 0x08 +#define ASSOC_REQ_TYPE 0x00 +#define ASSOC_RESP_TYPE 0x10 +#define REASSOC_REQ_TYPE 0x20 +#define REASSOC_RESP_TYPE 0x30 +#define NULL_MSG_TYPE 0x48 +#define BEACON_TYPE 0x80 +#define DISASSOC_TYPE 0xA0 +#define PSPOLL_TYPE 0xA4 +#define AUTHENTIC_TYPE 0xB0 +#define DEAUTHENTIC_TYPE 0xC0 +/* Frame control 2 bit fields */ +#define FC2_TO_DS 0x01 +#define FC2_FROM_DS 0x02 +#define FC2_MORE_FRAG 0x04 +#define FC2_RETRY 0x08 +#define FC2_PSM 0x10 +#define FC2_MORE_DATA 0x20 +#define FC2_WEP 0x40 +#define FC2_ORDER 0x80 +/*****************************************************************************/ +/* 802.11 element ID's and lengths */ +#define C_BP_CAPABILITY_ESS 0x01 +#define C_BP_CAPABILITY_IBSS 0x02 +#define C_BP_CAPABILITY_CF_POLLABLE 0x04 +#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08 +#define C_BP_CAPABILITY_PRIVACY 0x10 + +#define C_ESSID_ELEMENT_ID 0 +#define C_ESSID_ELEMENT_MAX_LENGTH 32 + +#define C_SUPPORTED_RATES_ELEMENT_ID 1 +#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2 + +#define C_FH_PARAM_SET_ELEMENT_ID 2 +#define C_FH_PARAM_SET_ELEMENT_LNGTH 5 + +#define C_CF_PARAM_SET_ELEMENT_ID 4 +#define C_CF_PARAM_SET_ELEMENT_LNGTH 6 + +#define C_TIM_ELEMENT_ID 5 +#define C_TIM_BITMAP_LENGTH 251 +#define C_TIM_BMCAST_BIT 0x01 + +#define C_IBSS_ELEMENT_ID 6 +#define C_IBSS_ELEMENT_LENGTH 2 + +#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51 +#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12 + +#define C_DISASSOC_REASON_CODE_LEN 2 +#define C_DISASSOC_REASON_CODE_DEFAULT 8 + +#define C_CRC_LEN 4 +#define C_NUM_SUPPORTED_RATES 8 +/****** IEEE 802.11 mac header for type data packets *************************/ +struct mac_header { + UCHAR frame_ctl_1; + UCHAR frame_ctl_2; + UCHAR duration_lsb; + UCHAR duration_msb; + UCHAR addr_1[ADDRLEN]; + UCHAR addr_2[ADDRLEN]; + UCHAR addr_3[ADDRLEN]; + UCHAR seq_frag_num[2]; +/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */ +}; +/****** IEEE 802.11 frame element structures *********************************/ +struct essid_element +{ + UCHAR id; + UCHAR length; + UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH]; +}; +struct rates_element +{ + UCHAR id; + UCHAR length; + UCHAR value[8]; +}; +struct freq_hop_element +{ + UCHAR id; + UCHAR length; + UCHAR dwell_time[2]; + UCHAR hop_set; + UCHAR hop_pattern; + UCHAR hop_index; +}; +struct tim_element +{ + UCHAR id; + UCHAR length; + UCHAR dtim_count; + UCHAR dtim_period; + UCHAR bitmap_control; + UCHAR tim[C_TIM_BITMAP_LENGTH]; +}; +struct ibss_element +{ + UCHAR id; + UCHAR length; + UCHAR atim_window[2]; +}; +struct japan_call_sign_element +{ + UCHAR id; + UCHAR length; + UCHAR call_sign[12]; +}; +/****** Beacon message structures ********************************************/ +/* .elements is a large lump of max size because elements are variable size */ +struct infra_beacon +{ + UCHAR timestamp[8]; + UCHAR beacon_intvl[2]; + UCHAR capability[2]; + UCHAR elements[sizeof(struct essid_element) + + sizeof(struct rates_element) + + sizeof(struct freq_hop_element) + + sizeof(struct japan_call_sign_element) + + sizeof(struct tim_element)]; +}; +struct adhoc_beacon +{ + UCHAR timestamp[8]; + UCHAR beacon_intvl[2]; + UCHAR capability[2]; + UCHAR elements[sizeof(struct essid_element) + + sizeof(struct rates_element) + + sizeof(struct freq_hop_element) + + sizeof(struct japan_call_sign_element) + + sizeof(struct ibss_element)]; +}; +/*****************************************************************************/ +/*****************************************************************************/ + + +/* #define C_MAC_HDR_2_WEP 0x40 */ +/* TX/RX CCS constants */ +#define TX_HEADER_LENGTH 0x1C +#define RX_MAC_HEADER_LENGTH 0x18 +#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6) +#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8) +#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff) +#define FCS_LEN 4 + +#define ADHOC 0 +#define INFRA 1 + +#define TYPE_STA 0 +#define TYPE_AP 1 + +#define PASSIVE_SCAN 1 +#define ACTIVE_SCAN 1 + +#define PSM_CAM 0 + +/* Country codes */ +#define USA 1 +#define EUROPE 2 +#define JAPAN 3 +#define KOREA 4 +#define SPAIN 5 +#define FRANCE 6 +#define ISRAEL 7 +#define AUSTRALIA 8 +#define JAPAN_TEST 9 + +/* Hop pattern lengths */ +#define USA_HOP_MOD 79 +#define EUROPE_HOP_MOD 79 +#define JAPAN_HOP_MOD 23 +#define KOREA_HOP_MOD 23 +#define SPAIN_HOP_MOD 27 +#define FRANCE_HOP_MOD 35 +#define ISRAEL_HOP_MOD 35 +#define AUSTRALIA_HOP_MOD 47 +#define JAPAN_TEST_HOP_MOD 23 + +#define ESSID_SIZE 32 +/**********************************************************************/ +/* CIS Register Constants */ +#define CIS_OFFSET 0x0f00 +/* Configuration Option Register (0x0F00) */ +#define COR_OFFSET 0x00 +#define COR_SOFT_RESET 0x80 +#define COR_LEVEL_IRQ 0x40 +#define COR_CONFIG_NUM 0x01 +#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM) + +/* Card Configuration and Status Register (0x0F01) */ +#define CCSR_OFFSET 0x01 +#define CCSR_HOST_INTR_PENDING 0x01 +#define CCSR_POWER_DOWN 0x04 + +/* HCS Interrupt Register (0x0F05) */ +#define HCS_INTR_OFFSET 0x05 +/* #define HCS_INTR_OFFSET 0x0A */ +#define HCS_INTR_CLEAR 0x00 + +/* ECF Interrupt Register (0x0F06) */ +#define ECF_INTR_OFFSET 0x06 +/* #define ECF_INTR_OFFSET 0x0C */ +#define ECF_INTR_SET 0x01 + +/* Authorization Register 0 (0x0F08) */ +#define AUTH_0_ON 0x57 + +/* Authorization Register 1 (0x0F09) */ +#define AUTH_1_ON 0x82 + +/* Program Mode Register (0x0F0A) */ +#define PC2PM 0x02 +#define PC2CAL 0x10 +#define PC2MLSE 0x20 + +/* PC Test Mode Register (0x0F0B) */ +#define PC_TEST_MODE 0x08 + +/* Frequency Control Word (0x0F10) */ +/* Range 0x02 - 0xA6 */ + +/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */ + +/**********************************************************************/ + +/* Shared RAM Area */ +#define SCB_BASE 0x0000 +#define STATUS_BASE 0x0100 +#define HOST_TO_ECF_BASE 0x0200 +#define ECF_TO_HOST_BASE 0x0300 +#define CCS_BASE 0x0400 +#define RCS_BASE 0x0800 +#define INFRA_TIM_BASE 0x0C00 +#define SSID_LIST_BASE 0x0D00 +#define TX_BUF_BASE 0x1000 +#define RX_BUF_BASE 0x8000 + +#define NUMBER_OF_CCS 64 +#define NUMBER_OF_RCS 64 +/*#define NUMBER_OF_TX_CCS 14 */ +#define NUMBER_OF_TX_CCS 14 + +#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg)) +#define RX_BUFF_END 0x3FFF +/* Values for buffer_status */ +#define CCS_BUFFER_FREE 0 +#define CCS_BUFFER_BUSY 1 +#define CCS_COMMAND_COMPLETE 2 +#define CCS_COMMAND_FAILED 3 + +/* Values for cmd */ +#define CCS_DOWNLOAD_STARTUP_PARAMS 1 +#define CCS_UPDATE_PARAMS 2 +#define CCS_REPORT_PARAMS 3 +#define CCS_UPDATE_MULTICAST_LIST 4 +#define CCS_UPDATE_POWER_SAVINGS_MODE 5 +#define CCS_START_NETWORK 6 +#define CCS_JOIN_NETWORK 7 +#define CCS_START_ASSOCIATION 8 +#define CCS_TX_REQUEST 9 +#define CCS_TEST_MEMORY 0xa +#define CCS_SHUTDOWN 0xb +#define CCS_DUMP_MEMORY 0xc +#define CCS_START_TIMER 0xe +#define CCS_LAST_CMD CCS_START_TIMER + +/* Values for link field */ +#define CCS_END_LIST 0xff + +/* values for buffer_status field */ +#define RCS_BUFFER_FREE 0 +#define RCS_BUFFER_BUSY 1 +#define RCS_COMPLETE 2 +#define RCS_FAILED 3 +#define RCS_BUFFER_RELEASE 0xFF + +/* values for interrupt_id field */ +#define PROCESS_RX_PACKET 0x80 /* */ +#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */ +#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */ +#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */ + +/*****************************************************************************/ +/* Memory types for dump memory command */ +#define C_MEM_PROG 0 +#define C_MEM_XDATA 1 +#define C_MEM_SFR 2 +#define C_MEM_IDATA 3 + +/*** Return values for hw_xmit **********/ +#define XMIT_OK (0) +#define XMIT_MSG_BAD (-1) +#define XMIT_NO_CCS (-2) +#define XMIT_NO_INTR (-3) +#define XMIT_NEED_AUTH (-4) + +/*** Values for card status */ +#define CARD_INSERTED (0) + +#define CARD_AWAITING_PARAM (1) +#define CARD_INIT_ERROR (11) + +#define CARD_DL_PARAM (2) +#define CARD_DL_PARAM_ERROR (12) + +#define CARD_DOING_ACQ (3) + +#define CARD_ACQ_COMPLETE (4) +#define CARD_ACQ_FAILED (14) + +#define CARD_AUTH_COMPLETE (5) +#define CARD_AUTH_REFUSED (15) + +#define CARD_ASSOC_COMPLETE (6) +#define CARD_ASSOC_FAILED (16) + +/*** Values for authentication_state */ +#define UNAUTHENTICATED (0) +#define AWAITING_RESPONSE (1) +#define AUTHENTICATED (2) +#define NEED_TO_AUTH (3) + +/*** Values for authentication type */ +#define OPEN_AUTH_REQUEST (1) +#define OPEN_AUTH_RESPONSE (2) + + +/***********************************************************************/ +/* Parameter passing structure for update/report parameter CCS's */ +struct object_id { + void *object_addr; + unsigned char object_length; +}; + +#define OBJID_network_type 0 +#define OBJID_acting_as_ap_status 1 +#define OBJID_current_ess_id 2 +#define OBJID_scanning_mode 3 +#define OBJID_power_mgt_state 4 +#define OBJID_mac_address 5 +#define OBJID_frag_threshold 6 +#define OBJID_hop_time 7 +#define OBJID_beacon_period 8 +#define OBJID_dtim_period 9 +#define OBJID_retry_max 10 +#define OBJID_ack_timeout 11 +#define OBJID_sifs 12 +#define OBJID_difs 13 +#define OBJID_pifs 14 +#define OBJID_rts_threshold 15 +#define OBJID_scan_dwell_time 16 +#define OBJID_max_scan_dwell_time 17 +#define OBJID_assoc_resp_timeout 18 +#define OBJID_adhoc_scan_cycle_max 19 +#define OBJID_infra_scan_cycle_max 20 +#define OBJID_infra_super_cycle_max 21 +#define OBJID_promiscuous_mode 22 +#define OBJID_unique_word 23 +#define OBJID_slot_time 24 +#define OBJID_roaming_low_snr 25 +#define OBJID_low_snr_count_thresh 26 +#define OBJID_infra_missed_bcn 27 +#define OBJID_adhoc_missed_bcn 28 +#define OBJID_curr_country_code 29 +#define OBJID_hop_pattern 30 +#define OBJID_reserved 31 +#define OBJID_cw_max_msb 32 +#define OBJID_cw_min_msb 33 +#define OBJID_noise_filter_gain 34 +#define OBJID_noise_limit_offset 35 +#define OBJID_det_rssi_thresh_offset 36 +#define OBJID_med_busy_thresh_offset 37 +#define OBJID_det_sync_thresh 38 +#define OBJID_test_mode 39 +#define OBJID_test_min_chan_num 40 +#define OBJID_test_max_chan_num 41 +#define OBJID_allow_bcast_ID_prbrsp 42 +#define OBJID_privacy_must_start 43 +#define OBJID_privacy_can_join 44 +#define OBJID_basic_rate_set 45 + +/**** Configuration/Status/Control Area ***************************/ +/* System Control Block (SCB) Area + * Located at Shared RAM offset 0 + */ +struct scb { + UCHAR ccs_index; + UCHAR rcs_index; +}; + +/****** Status area at Shared RAM offset 0x0100 ******************************/ +struct status { + UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/ + UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/ + UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/ + UCHAR reserved1; + short mrx_overflow; /* ECF increments on rx overflow */ + short mrx_checksum_error; /* ECF increments on rx CRC error */ + short rx_hec_error; /* ECF incs on mac header CRC error */ + UCHAR rxnoise; /* Average RSL measurement */ +}; + +/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/ +struct host_to_ecf_area { + +}; + +/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/ +struct startup_res_518 { + UCHAR startup_word; + UCHAR station_addr[ADDRLEN]; + UCHAR calc_prog_chksum; + UCHAR calc_cis_chksum; + UCHAR ecf_spare[7]; + UCHAR japan_call_sign[12]; +}; + +struct startup_res_6 { + UCHAR startup_word; + UCHAR station_addr[ADDRLEN]; + UCHAR reserved; + UCHAR supp_rates[8]; + UCHAR japan_call_sign[12]; + UCHAR calc_prog_chksum; + UCHAR calc_cis_chksum; + UCHAR firmware_version[3]; + UCHAR asic_version; + UCHAR tib_length; +}; + +struct start_join_net_params { + UCHAR net_type; + UCHAR ssid[ESSID_SIZE]; + UCHAR reserved; + UCHAR privacy_can_join; +}; + +/****** Command Control Structure area at Shared ram offset 0x0400 ***********/ +/* Structures for command specific parameters (ccs.var) */ +struct update_param_cmd { + UCHAR object_id; + UCHAR number_objects; + UCHAR failure_cause; +}; +struct report_param_cmd { + UCHAR object_id; + UCHAR number_objects; + UCHAR failure_cause; + UCHAR length; +}; +struct start_network_cmd { + UCHAR update_param; + UCHAR bssid[ADDRLEN]; + UCHAR net_initiated; + UCHAR net_default_tx_rate; + UCHAR encryption; +}; +struct join_network_cmd { + UCHAR update_param; + UCHAR bssid[ADDRLEN]; + UCHAR net_initiated; + UCHAR net_default_tx_rate; + UCHAR encryption; +}; +struct tx_requested_cmd { + + UCHAR tx_data_ptr[2]; + UCHAR tx_data_length[2]; + UCHAR host_reserved[2]; + UCHAR reserved[3]; + UCHAR tx_rate; + UCHAR pow_sav_mode; + UCHAR retries; + UCHAR antenna; +}; +struct tx_requested_cmd_4 { + + UCHAR tx_data_ptr[2]; + UCHAR tx_data_length[2]; + UCHAR dest_addr[ADDRLEN]; + UCHAR pow_sav_mode; + UCHAR retries; + UCHAR station_id; +}; +struct memory_dump_cmd { + UCHAR memory_type; + UCHAR memory_ptr[2]; + UCHAR length; +}; +struct update_association_cmd { + UCHAR status; + UCHAR aid[2]; +}; +struct start_timer_cmd { + UCHAR duration[2]; +}; + +struct ccs { + UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */ + /* 2 = command complete, 3 = failed */ + UCHAR cmd; /* command to ECF */ + UCHAR link; /* link to next CCS, FF=end of list */ + /* command specific parameters */ + union { + char reserved[13]; + struct update_param_cmd update_param; + struct report_param_cmd report_param; + UCHAR nummulticast; + UCHAR mode; + struct start_network_cmd start_network; + struct join_network_cmd join_network; + struct tx_requested_cmd tx_request; + struct memory_dump_cmd memory_dump; + struct update_association_cmd update_assoc; + struct start_timer_cmd start_timer; + } var; +}; + +/*****************************************************************************/ +/* Transmit buffer structures */ +struct tib_structure { + UCHAR ccs_index; + UCHAR psm; + UCHAR pass_fail; + UCHAR retry_count; + UCHAR max_retries; + UCHAR frags_remaining; + UCHAR no_rb; + UCHAR rts_reqd; + UCHAR csma_tx_cntrl_2; + UCHAR sifs_tx_cntrl_2; + UCHAR tx_dma_addr_1[2]; + UCHAR tx_dma_addr_2[2]; + UCHAR var_dur_2mhz[2]; + UCHAR var_dur_1mhz[2]; + UCHAR max_dur_2mhz[2]; + UCHAR max_dur_1mhz[2]; + UCHAR hdr_len; + UCHAR max_frag_len[2]; + UCHAR var_len[2]; + UCHAR phy_hdr_4; + UCHAR mac_hdr_1; + UCHAR mac_hdr_2; + UCHAR sid[2]; +}; + +struct phy_header { + UCHAR sfd[2]; + UCHAR hdr_3; + UCHAR hdr_4; +}; +struct rx_msg { + struct mac_header mac; + UCHAR var[1]; +}; + +struct tx_msg { + struct tib_structure tib; + struct phy_header phy; + struct mac_header mac; + UCHAR var[1]; +}; + +/****** ECF Receive Control Stucture (RCS) Area at Shared RAM offset 0x0800 */ +/* Structures for command specific parameters (rcs.var) */ +struct rx_packet_cmd { + UCHAR rx_data_ptr[2]; + UCHAR rx_data_length[2]; + UCHAR rx_sig_lev; + UCHAR next_frag_rcs_index; + UCHAR totalpacketlength[2]; +}; +struct rejoin_net_cmplt_cmd { + UCHAR reserved; + UCHAR bssid[ADDRLEN]; +}; +struct japan_call_sign_rxd { + UCHAR rxd_call_sign[8]; + UCHAR reserved[5]; +}; + +struct rcs { + UCHAR buffer_status; + UCHAR interrupt_id; + UCHAR link_field; + /* command specific parameters */ + union { + UCHAR reserved[13]; + struct rx_packet_cmd rx_packet; + struct rejoin_net_cmplt_cmd rejoin_net_complete; + struct japan_call_sign_rxd japan_call_sign; + } var; +}; + +/****** Startup parameter structures for both versions of firmware ***********/ +struct b4_startup_params { + UCHAR a_network_type; /* C_ADHOC, C_INFRA */ + UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ + UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ + UCHAR a_scanning_mode; /* passive 0, active 1 */ + UCHAR a_power_mgt_state; /* CAM 0, */ + UCHAR a_mac_addr[ADDRLEN]; /* */ + UCHAR a_frag_threshold[2]; /* 512 */ + UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ + UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ + UCHAR a_dtim_period; /* in beacons */ + UCHAR a_retry_max; /* */ + UCHAR a_ack_timeout; /* */ + UCHAR a_sifs; /* */ + UCHAR a_difs; /* */ + UCHAR a_pifs; /* */ + UCHAR a_rts_threshold[2]; /* */ + UCHAR a_scan_dwell_time[2]; /* */ + UCHAR a_max_scan_dwell_time[2]; /* */ + UCHAR a_assoc_resp_timeout_thresh; /* */ + UCHAR a_adhoc_scan_cycle_max; /* */ + UCHAR a_infra_scan_cycle_max; /* */ + UCHAR a_infra_super_scan_cycle_max; /* */ + UCHAR a_promiscuous_mode; /* */ + UCHAR a_unique_word[2]; /* */ + UCHAR a_slot_time; /* */ + UCHAR a_roaming_low_snr_thresh; /* */ + UCHAR a_low_snr_count_thresh; /* */ + UCHAR a_infra_missed_bcn_thresh; /* */ + UCHAR a_adhoc_missed_bcn_thresh; /* */ + UCHAR a_curr_country_code; /* C_USA */ + UCHAR a_hop_pattern; /* */ + UCHAR a_hop_pattern_length; /* */ +/* b4 - b5 differences start here */ + UCHAR a_cw_max; /* */ + UCHAR a_cw_min; /* */ + UCHAR a_noise_filter_gain; /* */ + UCHAR a_noise_limit_offset; /* */ + UCHAR a_det_rssi_thresh_offset; /* */ + UCHAR a_med_busy_thresh_offset; /* */ + UCHAR a_det_sync_thresh; /* */ + UCHAR a_test_mode; /* */ + UCHAR a_test_min_chan_num; /* */ + UCHAR a_test_max_chan_num; /* */ + UCHAR a_rx_tx_delay; /* */ + UCHAR a_current_bss_id[ADDRLEN]; /* */ + UCHAR a_hop_set; /* */ +}; +struct b5_startup_params { + UCHAR a_network_type; /* C_ADHOC, C_INFRA */ + UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */ + UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */ + UCHAR a_scanning_mode; /* passive 0, active 1 */ + UCHAR a_power_mgt_state; /* CAM 0, */ + UCHAR a_mac_addr[ADDRLEN]; /* */ + UCHAR a_frag_threshold[2]; /* 512 */ + UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */ + UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */ + UCHAR a_dtim_period; /* in beacons */ + UCHAR a_retry_max; /* 4 */ + UCHAR a_ack_timeout; /* */ + UCHAR a_sifs; /* */ + UCHAR a_difs; /* */ + UCHAR a_pifs; /* */ + UCHAR a_rts_threshold[2]; /* */ + UCHAR a_scan_dwell_time[2]; /* */ + UCHAR a_max_scan_dwell_time[2]; /* */ + UCHAR a_assoc_resp_timeout_thresh; /* */ + UCHAR a_adhoc_scan_cycle_max; /* */ + UCHAR a_infra_scan_cycle_max; /* */ + UCHAR a_infra_super_scan_cycle_max; /* */ + UCHAR a_promiscuous_mode; /* */ + UCHAR a_unique_word[2]; /* */ + UCHAR a_slot_time; /* */ + UCHAR a_roaming_low_snr_thresh; /* */ + UCHAR a_low_snr_count_thresh; /* */ + UCHAR a_infra_missed_bcn_thresh; /* */ + UCHAR a_adhoc_missed_bcn_thresh; /* */ + UCHAR a_curr_country_code; /* C_USA */ + UCHAR a_hop_pattern; /* */ + UCHAR a_hop_pattern_length; /* */ +/* b4 - b5 differences start here */ + UCHAR a_cw_max[2]; /* */ + UCHAR a_cw_min[2]; /* */ + UCHAR a_noise_filter_gain; /* */ + UCHAR a_noise_limit_offset; /* */ + UCHAR a_det_rssi_thresh_offset; /* */ + UCHAR a_med_busy_thresh_offset; /* */ + UCHAR a_det_sync_thresh; /* */ + UCHAR a_test_mode; /* */ + UCHAR a_test_min_chan_num; /* */ + UCHAR a_test_max_chan_num; /* */ + UCHAR a_allow_bcast_SSID_probe_rsp; + UCHAR a_privacy_must_start; + UCHAR a_privacy_can_join; + UCHAR a_basic_rate_set[8]; +}; + +/*****************************************************************************/ +#define RAY_IOCG_PARMS (SIOCDEVPRIVATE) +#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1) +#define RAY_DO_CMD (SIOCDEVPRIVATE + 2) + +/****** ethernet <-> 802.11 translation **************************************/ +typedef struct snaphdr_t +{ + UCHAR dsap; + UCHAR ssap; + UCHAR ctrl; + UCHAR org[3]; + UCHAR ethertype[2]; +} snaphdr_t; + +#define BRIDGE_ENCAP 0xf80000 +#define RFC1042_ENCAP 0 +#define SNAP_ID 0x0003aaaa +#define RAY_IPX_TYPE 0x8137 +#define APPLEARP_TYPE 0x80f3 +/*****************************************************************************/ +#endif /* #ifndef RAYLINK_H */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index b8d041556..a3b04feab 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -113,10 +113,10 @@ static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"; #include #include +#include #include #include #include -#include #include #include diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0dcee1ba1..32851a5d8 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -40,8 +40,8 @@ #include #include #include +#include #include -#include #define PPP_VERSION "2.4.0" diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 0d930bc41..5d0b9c659 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -424,13 +424,15 @@ static struct net_device *rtl8129_probe1(int pci_bus, int pci_devfn, /* Bring the chip out of low-power mode. */ outb(0x00, ioaddr + Config1); - if (read_eeprom(ioaddr, 0) != 0xffff) - for (i = 0; i < 3; i++) - ((u16 *)(dev->dev_addr))[i] = read_eeprom(ioaddr, i + 7); - else + if (read_eeprom(ioaddr, 0) != 0xffff) { + for (i = 0; i < 3; i++) { + ((u16 *)(dev->dev_addr))[i] = + le16_to_cpu(read_eeprom(ioaddr, i + 7)); + } + } else { for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + MAC0 + i); - + } for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x.\n", dev->dev_addr[i]); @@ -1188,7 +1190,7 @@ static int rtl8129_rx(struct net_device *dev) while ((inb(ioaddr + ChipCmd) & 1) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status = *(u32*)(rx_ring + ring_offset); + u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset)); int rx_size = rx_status >> 16; if (rtl8129_debug > 4) { @@ -1197,7 +1199,7 @@ static int rtl8129_rx(struct net_device *dev) dev->name, rx_status, rx_size, cur_rx); printk(KERN_DEBUG"%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) - printk(" %2.2x", rx_ring[ring_offset + i]); + printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i])); printk(".\n"); } if (rx_status & RxTooLong) { @@ -1248,7 +1250,7 @@ static int rtl8129_rx(struct net_device *dev) printk(KERN_DEBUG"%s: Frame wrap @%d", dev->name, semi_count); for (i = 0; i < 16; i++) - printk(" %2.2x", rx_ring[i]); + printk(" %2.2x", le32_to_cpu(rx_ring[i])); printk(".\n"); memset(rx_ring, 0xcc, 16); } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c new file mode 100644 index 000000000..09891202c --- /dev/null +++ b/drivers/net/starfire.c @@ -0,0 +1,1431 @@ +/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */ +/* + Written 1998-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + + The author may be reached as becker@usra.edu, or + Donald Becker + 312 Severn Ave. #W302 + Annapolis MD 21403 + + Support and updates available at + http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html +*/ + +static const char *versionA = +"starfire.c:v0.12 5/28/99 Written by Donald Becker\n", +*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n"; + +/* A few user-configurable values. These may be modified when a driver + module is loaded.*/ + +/* Used for tuning interrupt latency vs. overhead. */ +static int interrupt_mitigation = 0x0; + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int max_interrupt_work = 20; +static int min_pci_latency = 64; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + The Starfire has a 512 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' exist for driver interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* The "native" ring sizes are either 256 or 2048. + However in some modes a descriptor may be marked to wrap the ring earlier. + The driver allocates a single page for each descriptor ring, constraining + the maximum size in an architecture-dependent way. +*/ +#define RX_RING_SIZE 256 +#define TX_RING_SIZE 32 +/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */ +#define DONE_Q_SIZE 1024 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +/* Kernel compatibility defines, some common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ + +#define RUN_AT(x) (jiffies + (x)) + +#ifdef MODULE +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(min_pci_latency, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif + +/* + Theory of Operation + +I. Board Compatibility + +State the chips and boards this driver is known to work with. +Note any similar chips or boards that will not work. + +This driver skeleton demonstrates the driver for an idealized +descriptor-based bus-master PCI chip. + +II. Board-specific settings + +No jumpers exist on most PCI boards, so this section is usually empty. + +III. Driver operation + +IIIa. Ring buffers + +The Starfire hardware uses multiple fixed-size descriptor queues/rings. The +ring sizes are set fixed by the hardware, but may optionally be wrapped +earlier by the END bit in the descriptor. +This driver uses that hardware queue size for the Rx ring, where a large +number of entries has no ill effect beyond increases the potential backlog. +The Tx ring is wrapped with the END bit, since a large hardware Tx queue +disables the queue layer priority ordering and we have no mechanism to +utilize the hardware two-level priority queue. When modifying the +RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning +levels. + +IIIb/c. Transmit/Receive Structure + +See the Adaptec manual for the many possible structures, and options for +each structure. There are far too many to document here. + +For transmit this driver uses type 1 transmit descriptors, and relies on +automatic minimum-length padding. It does not use the completion queue +consumer index, but instead checks for non-zero status entries. + +For receive this driver uses type 0 receive descriptors. The driver +allocates full frame size skbuffs for the Rx ring buffers, so all frames +should fit in a single descriptor. The driver does not use the completion +queue consumer index, but instead checks for non-zero status entries. + +When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff +is allocated and the frame is copied to the new skbuff. When the incoming +frame is larger, the skbuff is passed directly up the protocol stack. +Buffers consumed this way are replaced by newly allocated skbuffs in a later +phase of receive. + +A notable aspect of operation is that unaligned buffers are not permitted by +the Starfire hardware. The IP header at offset 14 in an ethernet frame thus +isn't longword aligned, which may cause problems on some machine +e.g. Alphas. Copied frames are put into the skbuff at an offset of "+2", +16-byte aligning the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +IVb. References + +The Adaptec Starfire manuals. +http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html + + +IVc. Errata + +*/ + + + +/* This table drives the PCI probe routines. It's mostly boilerplate in all + PCI drivers, and will likely be provided by some future kernel. +*/ +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +}; +struct pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev, + long ioaddr, int irq, int chip_idx, int fnd_cnt); +}; + +static struct net_device *starfire_probe1(int pci_bus, int pci_devfn, + struct net_device *dev, long ioaddr, + int irq, int chp_idx, int fnd_cnt); + +#if 0 +#define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ +#endif +#define MEM_ADDR_SZ 0x80000 /* And maps in 0.5MB(!). */ + +static struct pci_id_info pci_tbl[] = { + { "Adaptec Starfire 6915", + 0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1}, + {0,}, /* 0 terminated list. */ +}; + + +/* A chip capabilities table, matching the entries in pci_tbl[] above. */ +enum chip_capability_flags {CanHaveMII=1, }; +struct chip_info { + char *chip_name; + int io_size; + int flags; + void (*media_timer)(unsigned long data); +} static skel_netdrv_tbl[] = { + {"Adaptec Starfire 6915", 128, CanHaveMII, 0, }, +}; + + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum register_offsets { + PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074, + IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088, + MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000, + TxDescCtrl=0x50090, + TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */ + TxRingHiAddr=0x5009C, /* 64 bit address extension. */ + TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4, + TxThreshold=0x500B0, + CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8, + RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0, + CompletionQConsumerIdx=0x500C4, + RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0, + RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4, + TxMode=0x55000, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrNormalSummary=0x8000, IntrAbnormalSummary=0x02000000, + IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000, + IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000, + StatsMax=0x08000000, LinkChange=0xf0000000, + IntrTxDataLow=0x00040000, +}; + +/* Bits in the RxFilterMode register. */ +enum rx_mode_bits { + AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01, + AcceptMulticast=0x10, AcceptMyPhys=0xE040, +}; + +/* The Rx and Tx buffer descriptors. */ +struct starfire_rx_desc { + u32 rxaddr; /* Optionally 64 bits. */ +}; +enum rx_desc_bits { + RxDescValid=1, RxDescEndRing=2, +}; + +/* Completion queue entry. + You must update the page allocation, init_ring and the shift count in rx() + if using a larger format. */ +struct rx_done_desc { + u32 status; /* Low 16 bits is length. */ +#ifdef full_rx_status + u32 status2; + u16 vlanid; + u16 csum; /* partial checksum */ + u32 timestamp; +#endif +}; +enum rx_done_bits { + RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000, +}; + +/* Type 1 Tx descriptor. */ +struct starfire_tx_desc { + u32 status; /* Upper bits are status, lower 16 length. */ + u32 addr; +}; +enum tx_desc_bits { + TxDescID=0xB1010000, /* Also marks single fragment, add CRC. */ + TxDescIntr=0x08000000, TxRingWrap=0x04000000, +}; +struct tx_done_report { + u32 status; /* timestamp, index. */ +#if 0 + u32 intrstatus; /* interrupt status */ +#endif +}; + +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct starfire_rx_desc *rx_ring; + struct starfire_tx_desc *tx_ring; + struct net_device *next_module; /* Link for devices of this type. */ + const char *product_name; + /* The addresses of rx/tx-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + /* Pointers to completion queues (full pages). I should cache line pad..*/ + u8 pad0[100]; + struct rx_done_desc *rx_done_q; + unsigned int rx_done; + struct tx_done_report *tx_done_q; + unsigned int tx_done; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + int chip_id; + unsigned char pci_bus, pci_devfn; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int duplex_lock:1; + unsigned int full_duplex:1, /* Full-duplex operation requested. */ + rx_flowctrl:1, + tx_flowctrl:1; /* Use 802.3x flow control. */ + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + u32 tx_mode; + u8 tx_threshold; + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ + u32 pad[4]; /* Used for 32-byte alignment */ +}; + +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev, int startup); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + + +/* A list of our installed devices, for removing the driver module. */ +static struct net_device *root_net_dev = NULL; + +/* Ideally we would detect all network cards in slot order. That would + be best done a central PCI probe dispatch, which wouldn't work + well when dynamically adding drivers. So instead we detect just the + cards we know about in slot order. */ + +static int pci_etherdev_probe(struct net_device *dev, struct pci_id_info pci_tbl[]) +{ + int cards_found = 0; + int pci_index = 0; + unsigned char pci_bus, pci_device_fn; + + if ( ! pcibios_present()) + return -ENODEV; + + for (;pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command, new_command; + int chip_idx, irq; + long pciaddr; + long ioaddr; + + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, + &pci_bus, &pci_device_fn) + != PCIBIOS_SUCCESSFUL) + break; + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_DEVICE_ID, &device); + + for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pci_tbl[chip_idx].vendor_id + && (device & pci_tbl[chip_idx].device_id_mask) == + pci_tbl[chip_idx].device_id) + break; + if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ + continue; + + { + struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); + + pciaddr = pdev->resource[0].start; +#if defined(ADDR_64BITS) && defined(__alpha__) + pciaddr |= ((long)pdev->base_address[1]) << 32; +#endif + irq = pdev->irq; + } + + if (debug > 2) + printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", + pci_tbl[chip_idx].name, pciaddr, irq); + + if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) { + if (check_region(pciaddr, pci_tbl[chip_idx].io_size)) + continue; + ioaddr = pciaddr; + } else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx.\n", + pciaddr); + continue; + } + + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | (pci_tbl[chip_idx].flags & 7); + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled the" + " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", + pci_bus, pci_device_fn, pci_command, new_command); + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + + dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr, + irq, chip_idx, cards_found); + + if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { + u8 pci_latency; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < min_pci_latency) { + printk(KERN_INFO " PCI latency timer (CFLT) is " + "unreasonably low at %d. Setting to %d clocks.\n", + pci_latency, min_pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, min_pci_latency); + } + } + dev = 0; + cards_found++; + } + + return cards_found ? 0 : -ENODEV; +} + +int starfire_probe(struct net_device *dev) +{ + if (pci_etherdev_probe(dev, pci_tbl) < 0) + return -ENODEV; + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + return 0; +} + + +static struct net_device * +starfire_probe1(int pci_bus, int pci_devfn, struct net_device *dev, + long ioaddr, int irq, int chip_id, int card_idx) +{ + struct netdev_private *np; + int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; + + dev = init_etherdev(dev, sizeof(struct netdev_private)); + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); + + /* Serial EEPROM reads are hidden by the hardware. */ + for (i = 0; i < 6; i++) + dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) /* Dump the EEPROM contents during development. */ + if (debug > 4) + for (i = 0; i < 0x20; i++) + printk("%2.2x%s", readb(ioaddr + EEPROMCtrl + i), + i % 16 != 15 ? " " : "\n"); +#endif + + /* Reset the chip to erase previous misconfiguration. */ + writel(1, ioaddr + PCIDeviceConfig); + + dev->base_addr = ioaddr; + dev->irq = irq; + + /* Make certain the descriptor lists are aligned. */ + np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15); + memset(np, 0, sizeof(*np)); + dev->priv = np; + + np->next_module = root_net_dev; + root_net_dev = dev; + + np->pci_bus = pci_bus; + np->pci_devfn = pci_devfn; + np->chip_id = chip_id; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + + if (mtu) + dev->mtu = mtu; + + if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + } + + return dev; +} + + +/* Read the MII Management Data I/O (MDIO) interfaces. */ + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); + int result, boguscnt=1000; + /* ??? Must add a busy-wait here. */ + do + result = readl(mdio_addr); + while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0); + return result & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); + writel(value, mdio_addr); + /* The busy-wait will occur before a read. */ + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) + return -EAGAIN; + + /* Disable the Rx and Tx, and reset the chip. */ + writel(0, ioaddr + GenCtrl); + writel(1, ioaddr + PCIDeviceConfig); + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + /* Allocate the various queues, failing gracefully. */ + if (np->tx_done_q == 0) + np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL); + if (np->rx_done_q == 0) + np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL); + if (np->tx_ring == 0) + np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL); + if (np->rx_ring == 0) + np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL); + if (np->tx_done_q == 0 || np->rx_done_q == 0 + || np->rx_ring == 0 || np->tx_ring == 0) + return -ENOMEM; + + MOD_INC_USE_COUNT; + + init_ring(dev); + /* Set the size of the Rx buffers. */ + writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl); + + /* Set Tx descriptor to type 1 and padding to 0 bytes. */ + writel(0x02000401, ioaddr + TxDescCtrl); + +#if defined(ADDR_64BITS) && defined(__alpha__) + writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr); + writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr); +#else + writel(0, ioaddr + RxDescQHiAddr); + writel(0, ioaddr + TxRingHiAddr); + writel(0, ioaddr + CompletionHiAddr); +#endif + writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr); + writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + + writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr); + writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr); + + if (debug > 1) + printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name); + + /* Fill both the unused Tx SA register and the Rx perfect filter. */ + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + 6-i); + for (i = 0; i < 16; i++) { + u16 *eaddrs = (u16 *)dev->dev_addr; + long setup_frm = ioaddr + 0x56000 + i*16; + writew(eaddrs[0], setup_frm); setup_frm += 4; + writew(eaddrs[1], setup_frm); setup_frm += 4; + writew(eaddrs[2], setup_frm); setup_frm += 4; + } + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + np->tx_threshold = 4; + writel(np->tx_threshold, ioaddr + TxThreshold); + writel(interrupt_mitigation, ioaddr + IntrTimerCtrl); + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + dev->tbusy = 0; + dev->interrupt = 0; + + if (debug > 1) + printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); + set_rx_mode(dev); + + check_duplex(dev, 1); + + dev->start = 1; + + /* Set the interrupt mask and enable PCI interrupts. */ + writel(IntrRxDone | IntrRxEmpty | IntrRxPCIErr | + IntrTxDone | IntrTxEmpty | IntrTxPCIErr | + StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary + | 0x0010 , ioaddr + IntrEnable); + writel(0x00800000 | readl(ioaddr + PCIDeviceConfig), + ioaddr + PCIDeviceConfig); + + /* Enable the Rx and Tx units. */ + writel(0x000F, ioaddr + GenCtrl); + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open().\n", + dev->name); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = RUN_AT(3*HZ); + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev, int startup) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int duplex, new_tx_mode ; + + new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0); + if (np->duplex_lock) + duplex = 1; + else + duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; + if (duplex) + new_tx_mode |= 2; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" + " partner capability of %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], mii_reg5); + } + if (new_tx_mode != np->tx_mode) { + np->tx_mode = new_tx_mode; + writel(np->tx_mode | 0x8000, ioaddr + TxMode); + writel(np->tx_mode, ioaddr + TxMode); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; /* Check before driver release. */ + + if (debug > 3) { + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n", + dev->name, readl(ioaddr + IntrStatus)); + } + check_duplex(dev, 0); +#if ! defined(final_version) + /* This is often falsely triggered. */ + if (readl(ioaddr + IntrStatus) & 1) { + int new_status = readl(ioaddr + IntrStatus); + /* Bogus hardware IRQ: Fake an interrupt handler call. */ + if (new_status & 1) { + printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n", + dev->name, new_status, readl(ioaddr + IntrStatus)); + intr_handler(dev->irq, dev, 0); + } + } +#endif + + np->timer.expires = RUN_AT(next_tick); + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, readl(ioaddr + IntrStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %p: ", np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr)); + printk("\n"KERN_DEBUG" Tx ring %p: ", np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status)); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + /* Grrr, we cannot offset to correctly align the IP header. */ + np->rx_ring[i].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + } + writew(i-1, dev->base_addr + RxDescQIdx); + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* Clear the remainder of the Rx buffer ring. */ + for ( ; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rxaddr = 0; + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing); + + /* Clear the completion rings. */ + for (i = 0; i < DONE_Q_SIZE; i++) { + np->rx_done_q[i].status = 0; + np->tx_done_q[i].status = 0; + } + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].status = 0; + } + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + unsigned entry; + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + if (jiffies - dev->trans_start < TX_TIMEOUT) + return 1; + tx_timeout(dev); + return 1; + } + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_skbuff[entry] = skb; + + np->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); + /* Add |TxDescIntr to generate Tx-done interrupts. */ + np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID); + if (debug > 5) { + printk(KERN_DEBUG "%s: Tx #%d slot %d %8.8x %8.8x.\n", + dev->name, np->cur_tx, entry, + le32_to_cpu(np->tx_ring[entry].status), + le32_to_cpu(np->tx_ring[entry].addr)); + } + np->cur_tx++; +#if 1 + if (entry >= TX_RING_SIZE-1) { /* Wrap ring */ + np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr); + entry = -1; + } +#endif + + /* Non-x86: explicitly flush descriptor cache lines here. */ + + /* Update the producer index. */ + writel(++entry, dev->base_addr + TxProducerIdx); + + if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) + np->tx_full = 1; + if (! np->tx_full) + clear_bit(0, (void*)&dev->tbusy); + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr, boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown " + "device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; +#if defined(__i386__) + /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ + if (test_and_set_bit(0, (void*)&dev->interrupt)) { + printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", + dev->name); + dev->interrupt = 0; /* Avoid halting machine. */ + return; + } +#else + if (dev->interrupt) { + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); + return; + } + dev->interrupt = 1; +#endif + + do { + u32 intr_status = readl(ioaddr + IntrClear); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & IntrRxDone) + netdev_rx(dev); + + /* Scavenge the skbuff list based on the Tx-done queue. + There are redundant checks here that may be cleaned up when + after the driver has proven reliable. */ + { + int consumer = readl(ioaddr + TxConsumerIdx); + int tx_status; + if (debug > 4) + printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n", + dev->name, consumer); +#if 0 + if (np->tx_done >= 250 || np->tx_done == 0) + printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, " + "%d is %8.8x.\n", dev->name, + np->tx_done, le32_to_cpu(np->tx_done_q[np->tx_done].status), + (np->tx_done+1) & (DONE_Q_SIZE-1), + le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status)); +#endif + while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) { + if (debug > 4) + printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n", + dev->name, np->tx_done, tx_status); + if ((tx_status & 0xe0000000) == 0xa0000000) { + np->stats.tx_packets++; + } else if ((tx_status & 0xe0000000) == 0x80000000) { + u16 entry = tx_status; /* Implicit truncate */ + entry >>= 3; + /* Scavenge the descriptor. */ + dev_kfree_skb(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + np->dirty_tx++; + } + np->tx_done_q[np->tx_done].status = 0; + np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1); + } + writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2); + } + if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { + /* The ring is no longer full, clear tbusy. */ + np->tx_full = 0; + clear_bit(0, (void*)&dev->tbusy); + mark_bh(NET_BH); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & IntrAbnormalSummary) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + +#if defined(__i386__) + clear_bit(0, (void*)&dev->interrupt); +#else + dev->interrupt = 0; +#endif + return; +} + +/* This routine is logically part of the interrupt handler, but seperated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + u32 desc_status; + if (np->rx_done_q == 0) { + printk(KERN_ERR "%s: rx_done_q is NULL! rx_done is %d. %p.\n", + dev->name, np->rx_done, np->tx_done_q); + return 0; + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) { + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() status of %d was %8.8x.\n", + np->rx_done, desc_status); + if (--boguscnt < 0) + break; + if (! (desc_status & RxOK)) { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + desc_status); + np->stats.rx_errors++; + if (desc_status & RxFIFOErr) + np->stats.rx_fifo_errors++; + } else { + struct sk_buff *skb; + u16 pkt_len = desc_status; /* Implicitly Truncate */ + int entry = (desc_status >> 16) & 0x7ff; + +#ifndef final_version + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + ", bogus_cnt %d.\n", + pkt_len, boguscnt); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM /* Call copy + cksum if available. */ + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { + char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr) & ~3) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in netdev_rx: %p vs. %p / %p.\n", + dev->name, bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr)), + skb->head, temp); +#endif + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); +#ifdef full_rx_status + if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) + skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + } + np->cur_rx++; + np->rx_done_q[np->rx_done].status = 0; + np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1); + } + writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx); + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + int entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + } + if (entry == RX_RING_SIZE - 1) + np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing); + /* We could defer this until later... */ + writew(entry, dev->base_addr + RxDescQIdx); + } + + if (debug > 5 + || memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1)) + printk(KERN_DEBUG " exiting netdev_rx() status of %d was %8.8x %d.\n", + np->rx_done, desc_status, + memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1)); + + /* Restart Rx engine if stopped. */ + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + + if (intr_status & LinkChange) { + printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + mdio_read(dev, np->phys[0], 4), + mdio_read(dev, np->phys[0], 5)); + check_duplex(dev, 0); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + /* Came close to underrunning the Tx FIFO, increase threshold. */ + if (intr_status & IntrTxDataLow) + writel(++np->tx_threshold, dev->base_addr + TxThreshold); + if ((intr_status & + ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow|1)) && debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & IntrTxPCIErr) + np->stats.tx_fifo_errors++; + if (intr_status & IntrRxPCIErr) + np->stats.rx_fifo_errors++; +} + +static struct enet_statistics *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ +#if LINUX_VERSION_CODE > 0x20119 + np->stats.tx_bytes = readl(ioaddr + 0x57010); + np->stats.rx_bytes = readl(ioaddr + 0x57044); +#endif + np->stats.tx_packets = readl(ioaddr + 0x57000); + np->stats.tx_aborted_errors = + readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028); + np->stats.tx_window_errors = readl(ioaddr + 0x57018); + np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008); + + /* The chip only need report frame silently dropped. */ + np->stats.rx_dropped += readw(ioaddr + RxDMAStatus); + writew(0, ioaddr + RxDMAStatus); + np->stats.rx_crc_errors = readl(ioaddr + 0x5703C); + np->stats.rx_frame_errors = readl(ioaddr + 0x57040); + np->stats.rx_length_errors = readl(ioaddr + 0x57058); + np->stats.rx_missed_errors = readl(ioaddr + 0x5707C); + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u32 rx_mode; + struct dev_mc_list *mclist; + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys; + } else if (dev->mc_count <= 15) { + /* Use the 16 element perfect filter. */ + long filter_addr = ioaddr + 0x56000 + 1*16; + for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count; + i++, mclist = mclist->next) { + u16 *eaddrs = (u16 *)mclist->dmi_addr; + writew(*eaddrs++, filter_addr); filter_addr += 4; + writew(*eaddrs++, filter_addr); filter_addr += 4; + writew(*eaddrs++, filter_addr); filter_addr += 8; + } + while (i++ < 16) { + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 8; + } + rx_mode = AcceptBroadcast | AcceptMyPhys; + } else { + /* Must use a multicast hash table. */ + long filter_addr; + u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */ + + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter); + } + /* Clear the perfect filter list. */ + filter_addr = ioaddr + 0x56000 + 1*16; + for (i = 1; i < 16; i++) { + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 4; + writew(0xffff, filter_addr); filter_addr += 8; + } + for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++) + writew(mc_filter[i], filter_addr); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } + writel(rx_mode|AcceptAll, ioaddr + RxFilterMode); +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + dev->start = 0; + dev->tbusy = 1; + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n", + dev->name, readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0, ioaddr + IntrEnable); + + /* Stop the chip's Tx and Rx processes. */ + + del_timer(&np->timer); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < 8 /* TX_RING_SIZE */; i++) + printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", + i, le32_to_cpu(np->tx_ring[i].status), + le32_to_cpu(np->tx_ring[i].addr), + le32_to_cpu(np->tx_done_q[i].status)); + printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", + (int)virt_to_bus(np->rx_ring), np->rx_done_q); + if (np->rx_done_q) + for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { + printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", + i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status)); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->rx_skbuff[i]) { +#if LINUX_VERSION_CODE < 0x20100 + np->rx_skbuff[i]->free = 1; +#endif + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + + +#ifdef MODULE +int init_module(void) +{ + if (debug) /* Emit version even if no cards detected. */ + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); +#ifdef CARDBUS + register_driver(ðerdev_ops); + return 0; +#else + if (pci_etherdev_probe(NULL, pci_tbl)) { + printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n"); + return -ENODEV; + } + return 0; +#endif +} + +void cleanup_module(void) +{ + struct net_device *next_dev; + +#ifdef CARDBUS + unregister_driver(ðerdev_ops); +#endif + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_net_dev) { + struct netdev_private *np = + (struct netdev_private *)root_net_dev->priv; + next_dev = np->next_module; + unregister_netdev(root_net_dev); + iounmap((char *)root_net_dev->base_addr); + if (np->tx_done_q) free_page((long)np->tx_done_q); + if (np->rx_done_q) free_page((long)np->rx_done_q); + kfree(root_net_dev); + root_net_dev = next_dev; + } +} + +#endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c" + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 16f9d97ed..4fff08b7f 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -240,7 +240,7 @@ static void set_multicast_list( struct net_device *dev ); /************************* End of Prototypes **************************/ -__initfunc(int sun3lance_probe( struct net_device *dev )) +int __init sun3lance_probe( struct net_device *dev ) { static int found = 0; @@ -255,7 +255,7 @@ __initfunc(int sun3lance_probe( struct net_device *dev )) return( ENODEV ); } -__initfunc(static int lance_probe( struct net_device *dev)) +static int __init lance_probe( struct net_device *dev) { unsigned long ioaddr, iopte; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index c46e722d5..77e04b9df 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2426,17 +2426,46 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs int i; for(i = 0; i < 4; i++) { - struct net_device *hdev = qp->happy_meals[i]; - struct happy_meal *hp = (struct happy_meal *) hdev->priv; - volatile u32 *sreg = qp->irq_status[i]; + struct net_device *dev = qp->happy_meals[i]; + struct happy_meal *hp = (struct happy_meal *) dev->priv; + struct hmeal_gregs *gregs = hp->gregs; + struct hmeal_tcvregs *tregs = hp->tcvregs; + unsigned int happy_status = hme_read32(hp, &gregs->stat); - if(sreg && - (hme_read32(hp, sreg) & (GREG_STAT_ERRORS | - GREG_STAT_MIFIRQ | - GREG_STAT_TXALL | - GREG_STAT_RXTOHOST)) != 0) - qp->handler(irq, hdev, ptregs); + HMD(("quattro_interrupt: status=%08x ",happy_status)); + + dev->interrupt=1; + + if(happy_status & GREG_STAT_ERRORS) { + HMD(("ERRORS ")); + if(happy_meal_is_not_so_happy(hp, gregs, happy_status)) { + dev->interrupt=0; + break; + } + } + + if(happy_status & GREG_STAT_MIFIRQ) { + HMD(("MIFIRQ ")); + happy_meal_mif_interrupt(hp, gregs, tregs); + } + + if(happy_status & GREG_STAT_TXALL) { + HMD(("TXALL ")); + happy_meal_tx(hp); + } + + if(happy_status & GREG_STAT_RXTOHOST) { + HMD(("RXTOHOST ")); + happy_meal_rx(hp, dev, gregs); + } + + if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) { + hp->dev->tbusy = 0; + mark_bh(NET_BH); + } + dev->interrupt=0; } + HMD(("done\n")); } static int happy_meal_open(struct net_device *dev) @@ -2947,8 +2976,11 @@ static struct quattro * __init quattro_sbus_find(struct linux_sbus_device *goal_ struct linux_sbus_device *sdev; struct quattro *qp; + if(qfe_sbus_list == NULL) + goto found; + for(qp = qfe_sbus_list; qp != NULL; qp = qp->next) { - for(sdev = qp->quattro_sbus_dev->child; + for(sdev = qp->quattro_sbus_dev; sdev != NULL; sdev = sdev->next) { if(sdev == goal_sdev) @@ -2980,7 +3012,7 @@ found: qp->happy_meals[i] = NULL; } qp->handler = NULL; - qp->quattro_sbus_dev = sdev; + qp->quattro_sbus_dev = goal_sdev; #ifdef CONFIG_PCI qp->quattro_pci_dev = NULL; #endif @@ -3037,7 +3069,7 @@ static void __init quattro_sbus_register_irqs(void) #ifndef __sparc_v9__ if(sparc_cpu_model == sun4c) qp->handler = sun4c_happy_meal_interrupt; - else if(sparc_cpu_model == sun4c) + else if(sparc_cpu_model == sun4d) qp->handler = sun4d_happy_meal_interrupt; else #endif @@ -3088,7 +3120,7 @@ static int __init happy_meal_ether_init(struct net_device *dev, struct linux_sbu printk(version); if(qfe_slot != -1) - printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet", + printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", dev->name, qfe_slot); else printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", @@ -3097,10 +3129,14 @@ static int __init happy_meal_ether_init(struct net_device *dev, struct linux_sbu dev->base_addr = (long) sdev; /* XXX Check for local-mac-address property on Quattro... -DaveM */ + /* Quattro local-mac-address... */ + if(qfe_slot != -1 && prom_getproplen(sdev->prom_node,"local-mac-address")==6) + prom_getproperty(sdev->prom_node,"local-mac-address",dev->dev_addr,6); + else + memcpy(dev->dev_addr,idprom->id_ethaddr,6); for(i = 0; i < 6; i++) printk("%2.2x%c", - dev->dev_addr[i] = idprom->id_ethaddr[i], - i == 5 ? ' ' : ':'); + dev->dev_addr[i], i == 5 ? ' ' : ':'); printk("\n"); hp = (struct happy_meal *) dev->priv; diff --git a/drivers/net/z85230.c b/drivers/net/z85230.c index 27fd64a7d..a802170ce 100644 --- a/drivers/net/z85230.c +++ b/drivers/net/z85230.c @@ -46,7 +46,7 @@ #include #define RT_LOCK #define RT_UNLOCK -#include +#include #include "z85230.h" #include "syncppp.h" diff --git a/drivers/parport/init.c b/drivers/parport/init.c index 172e2b6ab..7874519c7 100644 --- a/drivers/parport/init.c +++ b/drivers/parport/init.c @@ -25,6 +25,7 @@ static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_P static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE }; extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma); +extern int parport_sunbpp_init(void); static int parport_setup_ptr __initdata = 0; @@ -152,11 +153,12 @@ int __init parport_init (void) #ifdef CONFIG_PARPORT_ARC parport_arc_init(); #endif +#ifdef CONFIG_PARPORT_SUNBPP + parport_sunbpp_init(); +#endif return 0; } -__initcall (parport_init); - #endif /* Exported symbols for modules. */ diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index ef265395b..0436d0cb7 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -1,4 +1,4 @@ -/* $Id: parport_sunbpp.c,v 1.6 1999/08/31 06:57:22 davem Exp $ +/* $Id: parport_sunbpp.c,v 1.7 1999/09/02 11:59:31 davem Exp $ * Parallel-port routines for Sun architecture * * Author: Derrick J. Brashear @@ -49,24 +49,21 @@ static void parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs parport_generic_irq(irq, (struct parport *) dev_id, regs); } -void -parport_sunbpp_disable_irq(struct parport *p) +static void parport_sunbpp_disable_irq(struct parport *p) { struct bpp_regs *regs = (struct bpp_regs *)p->base; regs->p_csr &= ~(DMA_INT_ENAB); } -void -parport_sunbpp_enable_irq(struct parport *p) +static void parport_sunbpp_enable_irq(struct parport *p) { struct bpp_regs *regs = (struct bpp_regs *)p->base; regs->p_csr |= DMA_INT_ENAB; } -void -parport_sunbpp_write_data(struct parport *p, unsigned char d) +static void parport_sunbpp_write_data(struct parport *p, unsigned char d) { struct bpp_regs *regs = (struct bpp_regs *)p->base; @@ -74,182 +71,183 @@ parport_sunbpp_write_data(struct parport *p, unsigned char d) dprintk(("wrote 0x%x\n", d)); } -unsigned char -parport_sunbpp_read_data(struct parport *p) +static unsigned char parport_sunbpp_read_data(struct parport *p) { struct bpp_regs *regs = (struct bpp_regs *)p->base; return regs->p_dr; } -static void -control_pc_to_sunbpp(struct parport *p, unsigned char status) +static void control_pc_to_sunbpp(struct parport *p, unsigned char status) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; - unsigned char value_tcr = regs->p_tcr; - unsigned char value_or = regs->p_or; - - if (status & PARPORT_CONTROL_STROBE) - value_tcr |= P_TCR_DS; - if (status & PARPORT_CONTROL_AUTOFD) - value_or |= P_OR_AFXN; - if (status & PARPORT_CONTROL_INIT) - value_or |= P_OR_INIT; - if (status & PARPORT_CONTROL_SELECT) - value_or |= P_OR_SLCT_IN; - - regs->p_or = value_or; - regs->p_tcr = value_tcr; + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + if (status & PARPORT_CONTROL_STROBE) + value_tcr |= P_TCR_DS; + if (status & PARPORT_CONTROL_AUTOFD) + value_or |= P_OR_AFXN; + if (status & PARPORT_CONTROL_INIT) + value_or |= P_OR_INIT; + if (status & PARPORT_CONTROL_SELECT) + value_or |= P_OR_SLCT_IN; + + regs->p_or = value_or; + regs->p_tcr = value_tcr; } -static unsigned char -status_sunbpp_to_pc(struct parport *p) +static unsigned char status_sunbpp_to_pc(struct parport *p) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; - unsigned char bits = 0; - unsigned char value_tcr = regs->p_tcr; - unsigned char value_ir = regs->p_ir; - - if (!(value_ir & P_IR_ERR)) bits |= PARPORT_STATUS_ERROR; - if (!(value_ir & P_IR_SLCT)) bits |= PARPORT_STATUS_SELECT; - if (!(value_ir & P_IR_PE)) bits |= PARPORT_STATUS_PAPEROUT; - if (value_tcr & P_TCR_ACK) bits |= PARPORT_STATUS_ACK; - if (!(value_tcr & P_TCR_BUSY)) bits |= PARPORT_STATUS_BUSY; - - dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); - dprintk(("read status 0x%x\n", bits)); - return bits; + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char bits = 0; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_ir = regs->p_ir; + + if (!(value_ir & P_IR_ERR)) + bits |= PARPORT_STATUS_ERROR; + if (!(value_ir & P_IR_SLCT)) + bits |= PARPORT_STATUS_SELECT; + if (!(value_ir & P_IR_PE)) + bits |= PARPORT_STATUS_PAPEROUT; + if (value_tcr & P_TCR_ACK) + bits |= PARPORT_STATUS_ACK; + if (!(value_tcr & P_TCR_BUSY)) + bits |= PARPORT_STATUS_BUSY; + + dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir)); + dprintk(("read status 0x%x\n", bits)); + return bits; } -static unsigned char -control_sunbpp_to_pc(struct parport *p) +static unsigned char control_sunbpp_to_pc(struct parport *p) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; - unsigned char bits = 0; - unsigned char value_tcr = regs->p_tcr; - unsigned char value_or = regs->p_or; - - if (!(value_tcr & P_TCR_DS)) bits |= PARPORT_CONTROL_STROBE; - if (!(value_or & P_OR_AFXN)) bits |= PARPORT_CONTROL_AUTOFD; - if (!(value_or & P_OR_INIT)) bits |= PARPORT_CONTROL_INIT; - if (value_or & P_OR_SLCT_IN) bits |= PARPORT_CONTROL_SELECT; - - dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); - dprintk(("read control 0x%x\n", bits)); - return bits; + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char bits = 0; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + if (!(value_tcr & P_TCR_DS)) + bits |= PARPORT_CONTROL_STROBE; + if (!(value_or & P_OR_AFXN)) + bits |= PARPORT_CONTROL_AUTOFD; + if (!(value_or & P_OR_INIT)) + bits |= PARPORT_CONTROL_INIT; + if (value_or & P_OR_SLCT_IN) + bits |= PARPORT_CONTROL_SELECT; + + dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + dprintk(("read control 0x%x\n", bits)); + return bits; } -unsigned char -parport_sunbpp_read_control(struct parport *p) +static unsigned char parport_sunbpp_read_control(struct parport *p) { - return control_sunbpp_to_pc(p); + return control_sunbpp_to_pc(p); } -unsigned char -parport_sunbpp_frob_control(struct parport *p, unsigned char mask, - unsigned char val) +static unsigned char parport_sunbpp_frob_control(struct parport *p, + unsigned char mask, + unsigned char val) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; - unsigned char value_tcr = regs->p_tcr; - unsigned char value_or = regs->p_or; - - dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); - if (mask & PARPORT_CONTROL_STROBE) { - if (val & PARPORT_CONTROL_STROBE) - value_tcr &= ~P_TCR_DS; - else - value_tcr |= P_TCR_DS; - } - if (mask & PARPORT_CONTROL_AUTOFD) { - if (val & PARPORT_CONTROL_AUTOFD) - value_or &= ~P_OR_AFXN; - else - value_or |= P_OR_AFXN; - } - if (mask & PARPORT_CONTROL_INIT) { - if (val & PARPORT_CONTROL_INIT) - value_or &= ~P_OR_INIT; - else - value_or |= P_OR_INIT; - } - if (mask & PARPORT_CONTROL_SELECT) { - if (val & PARPORT_CONTROL_SELECT) - value_or |= P_OR_SLCT_IN; - else - value_or &= ~P_OR_SLCT_IN; - } - regs->p_or = value_or; - regs->p_tcr = value_tcr; - dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); - return parport_sunbpp_read_control(p); + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; + unsigned char value_or = regs->p_or; + + dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + if (mask & PARPORT_CONTROL_STROBE) { + if (val & PARPORT_CONTROL_STROBE) { + value_tcr &= ~P_TCR_DS; + } else { + value_tcr |= P_TCR_DS; + } + } + if (mask & PARPORT_CONTROL_AUTOFD) { + if (val & PARPORT_CONTROL_AUTOFD) { + value_or &= ~P_OR_AFXN; + } else { + value_or |= P_OR_AFXN; + } + } + if (mask & PARPORT_CONTROL_INIT) { + if (val & PARPORT_CONTROL_INIT) { + value_or &= ~P_OR_INIT; + } else { + value_or |= P_OR_INIT; + } + } + if (mask & PARPORT_CONTROL_SELECT) { + if (val & PARPORT_CONTROL_SELECT) { + value_or |= P_OR_SLCT_IN; + } else { + value_or &= ~P_OR_SLCT_IN; + } + } + + regs->p_or = value_or; + regs->p_tcr = value_tcr; + dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or)); + return parport_sunbpp_read_control(p); } -void -parport_sunbpp_write_control(struct parport *p, unsigned char d) +static void parport_sunbpp_write_control(struct parport *p, unsigned char d) { - const unsigned char wm = (PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | - PARPORT_CONTROL_INIT | - PARPORT_CONTROL_SELECT); + const unsigned char wm = (PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_INIT | + PARPORT_CONTROL_SELECT); - parport_sunbpp_frob_control (p, wm, d & wm); - return; + parport_sunbpp_frob_control (p, wm, d & wm); } -unsigned char -parport_sunbpp_read_status(struct parport *p) +static unsigned char parport_sunbpp_read_status(struct parport *p) { - return status_sunbpp_to_pc(p); + return status_sunbpp_to_pc(p); } -void parport_sunbpp_data_forward (struct parport *p) +static void parport_sunbpp_data_forward (struct parport *p) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; - unsigned char value_tcr = regs->p_tcr; + struct bpp_regs *regs = (struct bpp_regs *)p->base; + unsigned char value_tcr = regs->p_tcr; - dprintk(("forward\n")); - value_tcr = regs->p_tcr; - value_tcr &= ~P_TCR_DIR; - regs->p_tcr = value_tcr; + dprintk(("forward\n")); + value_tcr = regs->p_tcr; + value_tcr &= ~P_TCR_DIR; + regs->p_tcr = value_tcr; } -void parport_sunbpp_data_reverse (struct parport *p) +static void parport_sunbpp_data_reverse (struct parport *p) { - struct bpp_regs *regs = (struct bpp_regs *)p->base; + struct bpp_regs *regs = (struct bpp_regs *)p->base; - dprintk(("reverse\n")); - regs->p_tcr |= P_TCR_DIR; + dprintk(("reverse\n")); + regs->p_tcr |= P_TCR_DIR; } -void -parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s) +static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s) { s->u.pc.ctr = 0xc; s->u.pc.ecr = 0x0; } -void -parport_sunbpp_save_state(struct parport *p, struct parport_state *s) +static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s) { s->u.pc.ctr = parport_sunbpp_read_control(p); } -void -parport_sunbpp_restore_state(struct parport *p, struct parport_state *s) +static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s) { parport_sunbpp_write_control(p, s->u.pc.ctr); } -void -parport_sunbpp_inc_use_count(void) +static void parport_sunbpp_inc_use_count(void) { #ifdef MODULE MOD_INC_USE_COUNT; #endif } -void -parport_sunbpp_dec_use_count(void) +static void parport_sunbpp_dec_use_count(void) { #ifdef MODULE MOD_DEC_USE_COUNT; @@ -294,9 +292,7 @@ static struct parport_operations parport_sunbpp_ops = parport_ieee1284_read_byte, }; - -int -init_one_port(struct linux_sbus_device *sdev) +static int __init init_one_port(struct linux_sbus_device *sdev) { struct parport *p; /* at least in theory there may be a "we don't dma" case */ @@ -306,35 +302,44 @@ init_one_port(struct linux_sbus_device *sdev) struct bpp_regs *regs; unsigned char value_tcr; + dprintk(("init_one_port(%p): ranges, alloc_io, ", sdev)); irq = sdev->irqs[0]; prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, 1, sdev); base = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, - sdev->reg_addrs[0].reg_size, - "sunbpp", sdev->reg_addrs[0].which_io, 0); + sdev->reg_addrs[0].reg_size, + "sunbpp", sdev->reg_addrs[0].which_io, 0); size = sdev->reg_addrs[0].reg_size; dma = PARPORT_DMA_NONE; + dprintk(("alloc(ppops), ")); ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL); if (!ops) { - sparc_free_io(base, size); - return 0; + sparc_free_io(base, size); + return 0; } + memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations)); + dprintk(("register_port, ")); if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { - kfree(ops); - sparc_free_io(base, size); - return 0; + kfree(ops); + sparc_free_io(base, size); + return 0; } + dprintk(("init_one_port: request_irq(%08x:%p:%x:%s:%p) ", + p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p)); if ((err = request_irq(p->irq, parport_sunbpp_interrupt, - 0, p->name, p)) != 0) { - parport_unregister_port(p); - kfree(ops); - sparc_free_io(base, size); - return err; - } else - parport_sunbpp_enable_irq(p); + SA_SHIRQ, p->name, p)) != 0) { + dprintk(("ERROR %d\n", err)); + parport_unregister_port(p); + kfree(ops); + sparc_free_io(base, size); + return err; + } else { + dprintk(("OK\n")); + parport_sunbpp_enable_irq(p); + } regs = (struct bpp_regs *)p->base; dprintk(("forward\n")); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index e438bb3cc..94b9f035b 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #undef PARPORT_PARANOID diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index dbd5a8e31..51c229c25 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -205,6 +205,35 @@ pci_set_master(struct pci_dev *dev) } /* + * Assign new address to PCI resource. We hope our resource information + * is complete. On the PC, we don't re-assign resources unless we are + * forced to do so or the driver asks us to. + * + * Expects start=0, end=size-1, flags=resource type. + */ +int __init pci_assign_resource(struct pci_dev *dev, int i) +{ + struct resource *r = &dev->resource[i]; + struct resource *pr = pci_find_parent_resource(dev, r); + unsigned long size = r->end + 1; + + if (!pr) + return -EINVAL; + if (r->flags & IORESOURCE_IO) { + if (size > 0x100) + return -EFBIG; + if (allocate_resource(pr, r, size, 0x1000, ~0, 1024)) + return -EBUSY; + } else { + if (allocate_resource(pr, r, size, 0x10000000, ~0, size)) + return -EBUSY; + } + if (i < 6) + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start); + return 0; +} + +/* * Translate the low bits of the PCI base * to the resource type */ diff --git a/drivers/pci/setup.c b/drivers/pci/setup.c index 20386235c..53bf9f582 100644 --- a/drivers/pci/setup.c +++ b/drivers/pci/setup.c @@ -26,7 +26,6 @@ # define DBGC(args) #endif - int __init pci_claim_resource(struct pci_dev *dev, int resource) { diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 9707e21ee..b7fae8c95 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -2238,6 +2238,8 @@ void cleanup_module(void) extern int pcmcia_ds_init(void); extern int pcmcia_i82365_init(void); +extern int init_pcnet_cs(void); +extern int init_ray_cs(void); int pcmcia_init(void) { @@ -2248,7 +2250,15 @@ int pcmcia_init(void) pcmcia_i82365_init(); /* Get the ball rolling.. */ - return pcmcia_ds_init(); + pcmcia_ds_init(); + +#ifdef CONFIG_PCMCIA_PCNET + init_pcnet_cs(); +#endif +#ifdef CONFIG_PCMCIA_RAYCS + init_ray_cs(); +#endif + return 0; } #endif diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 4727e160c..225ffa757 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1034,34 +1034,38 @@ static u_int topic_set_opts(u_short s, char *buf) static void cb_get_state(u_short s) { socket_info_t *t = &socket[s]; - - pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache); - pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat); - pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat); - pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus); - pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus); - pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr); - { - struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn); - t->cap.pci_irq = (pdev) ? pdev->irq : 0; - } + struct pci_dev *dev = pci_find_slot(t->bus, t->devfn); + + if (!dev) + return; + pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &t->cache); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &t->pci_lat); + pci_read_config_byte(dev, CB_LATENCY_TIMER, &t->cb_lat); + pci_read_config_byte(dev, CB_CARDBUS_BUS, &t->cap.cardbus); + pci_read_config_byte(dev, CB_SUBORD_BUS, &t->sub_bus); + pci_read_config_word(dev, CB_BRIDGE_CONTROL, &t->bcr); + + t->cap.pci_irq = dev->irq; if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0; } static void cb_set_state(u_short s) { socket_info_t *t = &socket[s]; + struct pci_dev *dev = pci_find_slot(t->bus, t->devfn); + if (t->pmcs) - pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0); - pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0); - pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys); - pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT); - pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache); - pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat); - pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat); - pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus); - pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus); - pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr); + pci_write_config_word(dev, t->pmcs, PCI_PMCS_PWR_STATE_D0); + + pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, t->cb_phys); + pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, t->cache); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, t->pci_lat); + pci_write_config_byte(dev, CB_LATENCY_TIMER, t->cb_lat); + pci_write_config_byte(dev, CB_CARDBUS_BUS, t->cap.cardbus); + pci_write_config_byte(dev, CB_SUBORD_BUS, t->sub_bus); + pci_write_config_word(dev, CB_BRIDGE_CONTROL, t->bcr); } static int cb_get_irq_mode(u_short s) diff --git a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in index a1b9ed59b..7b9cda19c 100644 --- a/drivers/sbus/char/Config.in +++ b/drivers/sbus/char/Config.in @@ -12,6 +12,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Bidirectional parallel port support (obsolete)' CONFIG_SUN_BPP tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA + tristate 'Tadpole TS102 Microcontroller support' CONFIG_TADPOLE_TS102_UCTRL # XXX Why don't we do "source drivers/char/Config.in" somewhere? if [ "$CONFIG_PCI" = "y" ]; then diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index c516d98fd..9a4a59fe6 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -95,6 +95,14 @@ else endif endif +ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),y) +O_OBJS += uctrl.o +else + ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),m) + M_OBJS += uctrl.o + endif +endif + include $(TOPDIR)/Rules.make sunkbdmap.o: sunkeymap.c diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 37ad159bf..dc34fe4cd 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.32 1999/08/31 06:58:11 davem Exp $ +/* $Id: pcikbd.c,v 1.35 1999/09/01 08:09:26 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index e499ca889..2a6f8624b 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.17 1999/08/31 13:32:01 anton Exp $ +/* $Id: rtc.c,v 1.18 1999/08/31 18:51:36 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -29,7 +29,7 @@ static int rtc_busy = 0; /* Retrieve the current date and time from the real time clock. */ void get_rtc_time(struct rtc_time *t) { - struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; + unsigned long regs = mstk48t02_regs; unsigned long flags; u8 tmp; @@ -57,7 +57,7 @@ void get_rtc_time(struct rtc_time *t) /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { - struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; + unsigned long regs = mstk48t02_regs; unsigned long flags; u8 tmp; diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 9139f9826..6a8125080 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.34 1999/08/31 06:58:16 davem Exp $ +/* $Id: sab82532.c,v 1.35 1999/09/01 08:09:29 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2153,7 +2153,7 @@ static void __init sab82532_kgdb_hook(int line) static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.34 $"; + char *revision = "$Revision: 1.35 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c index de16771e6..21596e2cf 100644 --- a/drivers/sbus/char/su.c +++ b/drivers/sbus/char/su.c @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.25 1999/08/31 06:58:20 davem Exp $ +/* $Id: su.c,v 1.28 1999/09/01 08:09:32 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2214,7 +2214,7 @@ done: */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.25 $"; + char *revision = "$Revision: 1.28 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c index e76d76c3d..60ff763e6 100644 --- a/drivers/sbus/char/sunserial.c +++ b/drivers/sbus/char/sunserial.c @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.69 1999/08/31 06:58:29 davem Exp $ +/* $Id: sunserial.c,v 1.70 1999/09/04 20:28:17 davem Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -386,12 +386,10 @@ unsigned long __init sun_serial_setup(unsigned long memory_start) * So be very careful not to probe for keyboards if we are on a * serial console. */ - if (!serial_console) { - if (ps2kbd_probe(&memory_start) == 0) - return memory_start; - if (su_probe(&memory_start) == 0) - return memory_start; - } + if (!serial_console) + ps2kbd_probe(&memory_start); + if (su_probe(&memory_start) == 0) + return memory_start; #endif if (!ret) diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c new file mode 100644 index 000000000..b11de29eb --- /dev/null +++ b/drivers/sbus/char/uctrl.c @@ -0,0 +1,155 @@ +/* $Id: uctrl.c,v 1.2 1999/09/07 23:11:08 shadow Exp $ + * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 + * + * Copyright 1999 Derrick J Brashear (shadow@dementia.org) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define UCTRL_MINOR 174 + +struct uctrl_driver { + volatile u32 *regs; + int irq; +}; + +static struct uctrl_driver drv; + +static loff_t +uctrl_llseek(struct file *file, loff_t offset, int type) +{ + return -ESPIPE; +} + +static int +uctrl_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + default: + return -EINVAL; + } + return 0; +} + +static int +uctrl_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + return 0; +} + +static int +uctrl_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +void uctrl_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uctrl_driver *driver = (struct uctrl_driver *)dev_id; + printk("in uctrl_interrupt\n"); +} + +static struct file_operations uctrl_fops = { + uctrl_llseek, + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + uctrl_ioctl, + NULL, /* mmap */ + uctrl_open, + NULL, /* flush */ + uctrl_release +}; + +static struct miscdevice uctrl_dev = { + UCTRL_MINOR, + "uctrl", + &uctrl_fops +}; + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int uctrl_init(void)) +#endif +{ + struct uctrl_driver *driver = &drv; + int len; + struct linux_prom_irqs tmp_irq[2]; + unsigned int vaddr[2] = { 0, 0 }; + int tmpnode, uctrlnode = prom_getchild(prom_root_node); + + tmpnode = prom_searchsiblings(uctrlnode, "obio"); + + if (tmpnode) + uctrlnode = prom_getchild(tmpnode); + + uctrlnode = prom_searchsiblings(uctrlnode, "uctrl"); + + if (!uctrlnode) + return -ENODEV; + + /* the prom mapped it for us */ + len = prom_getproperty(uctrlnode, "address", (void *) vaddr, + sizeof(vaddr)); + driver->regs = vaddr[0]; + + len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq, + sizeof(tmp_irq)); + if(!driver->irq) + driver->irq = tmp_irq[0].pri; + + request_irq(driver->irq, uctrl_interrupt, 0, + "uctrl", driver); + + enable_irq(driver->irq); + + if (misc_register(&uctrl_dev)) { + printk("%s: unable to get misc minor %d\n", + __FUNCTION__, uctrl_dev.minor); + disable_irq(driver->irq); + free_irq(driver->irq, driver); + return -ENODEV; + } + + printk(KERN_INFO, "uctrl: 0x%x (irq %d)\n", driver->regs, __irq_itoa(driver->irq)); + return 0; +} + + +#ifdef MODULE +void cleanup_module(void) +{ + struct uctrl_driver *driver = &drv; + + misc_deregister(&uctrl_dev); + if (driver->irq) { + disable_irq(driver->irq); + free_irq(driver->irq, driver); + } + if (driver->regs) + driver->regs = 0; +} +#endif diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 18f2e80fd..8ed6e2737 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.44 1999/08/31 06:58:32 davem Exp $ +/* $Id: zs.c,v 1.45 1999/09/01 08:09:35 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1844,7 +1844,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.44 $"; + char *revision = "$Revision: 1.45 $"; char *version, *p; version = strchr(revision, ' '); diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 24312b1c6..ad7825c89 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.79 1999/08/31 06:57:40 davem Exp $ +/* $Id: sbus.c,v 1.80 1999/09/02 05:44:33 shadow Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -208,6 +208,9 @@ extern int flash_init(void); #ifdef CONFIG_SUN_AURORA extern int aurora_init(void); #endif +#ifdef CONFIG_TADPOLE_TS102_UCTRL +extern int ts102_uctrl_init(void); +#endif static void __init sbus_do_child_siblings(int start_node, struct linux_sbus_device *child, @@ -445,6 +448,9 @@ void __init sbus_init(void) #ifdef CONFIG_SUN_AURORA aurora_init(); #endif +#ifdef CONFIG_TADPOLE_TS102_UCTRL + ts102_uctrl_init(); +#endif #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { extern void clock_probe(void); diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c index 963c86f0c..18c87cec9 100644 --- a/drivers/scsi/53c7,8xx.c +++ b/drivers/scsi/53c7,8xx.c @@ -253,7 +253,7 @@ typedef unsigned int u32; #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index a0a009071..2fbbe449b 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -253,7 +253,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_AMIGA diff --git a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c index ae6bd1362..e4e289775 100644 --- a/drivers/scsi/AM53C974.c +++ b/drivers/scsi/AM53C974.c @@ -8,10 +8,10 @@ #include #include #include +#include #include #include -#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index a956e8402..aa1943891 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -43,9 +43,9 @@ #include #include #include +#include #include #include -#include #include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 4b08067ba..df412e35b 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1438,7 +1438,7 @@ static void NCR5380_main(void) { #ifndef DONT_USE_INTR #include -#include +#include /* * Function : void NCR5380_intr (int irq) diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 2f85cd32d..52a9196c6 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -52,7 +52,7 @@ #include #include -#include +#include #include "scsi.h" #include "hosts.h" #include "sd.h" diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 2be90c0fa..49ace00b2 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 79c3351a7..ef4b010a6 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index a31526d24..60b7b037e 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -1,5 +1,5 @@ -/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */ -#define ASC_VERSION "3.2F" /* AdvanSys Driver Version */ +/* $Id: advansys.c,v 1.59 1999/09/08 18:50:51 bobf Exp bobf $ */ +#define ASC_VERSION "3.2G" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters @@ -634,7 +634,11 @@ 3.2F (9/3/99): 1. Handle new initial function code added in v2.3.16 for all driver versions. - + + 3.2G (9/8/99): + 1. Fix PCI board detection in v2.3.13 and greater kernels. + 2. Fix comiple errors in v2.3.X with debugging enabled. + J. Known Problems/Fix List (XXX) 1. Need to add memory mapping workaround. Test the memory mapping. @@ -737,7 +741,7 @@ #include #endif /* version >= v1.3.0 */ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95) -#include +#include #endif /* version >= 2.1.95 */ #include "scsi.h" #include "hosts.h" @@ -4711,7 +4715,7 @@ advansys_detect(Scsi_Host_Template *tpnt) #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13) iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK; #else /* version >= v2.3.13 */ - iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK; + iop = pci_devp->resource[0].start & PCI_IOADDRESS_MASK; #endif /* version >= v2.3.13 */ ASC_DBG2(1, "advansys_detect: vendorID %X, deviceID %X\n", @@ -10439,9 +10443,8 @@ asc_prt_scsi_host(struct Scsi_Host *s) (unsigned) s->last_reset); printk( -" host_wait %x, host_queue %x, hostt %x, block %x,\n", - (unsigned) s->host_wait, (unsigned) s->host_queue, - (unsigned) s->hostt, (unsigned) s->block); +" host_queue %x, hostt %x, block %x,\n", + (unsigned) s->host_queue, (unsigned) s->hostt, (unsigned) s->block); printk( " wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n", diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index ff2ee13f6..4ecb7cc77 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -33,9 +33,9 @@ #include #include #include +#include #include #include -#include #include #include #include "scsi.h" diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index b5c73c7c3..812870cda 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -325,7 +325,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = { #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) -# include +# include # include # define cpuid smp_processor_id() # if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 29468801b..83215d115 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -17,9 +17,9 @@ #include #include #include +#include #include #include -#include #include #include #include "scsi.h" diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index fd4959d42..985453a0c 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -407,7 +407,7 @@ MODULE_AUTHOR("Dario Ballabio"); #endif #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101) -#include +#include #define IRQ_FLAGS #define IRQ_LOCK #define IRQ_LOCK_SAVE diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index 1b791497b..6c5519950 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -80,7 +80,7 @@ #include #ifdef __mips__ #include -#include +#include #endif #include #include "scsi.h" diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 4c52133f3..5ad320c68 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -56,7 +56,7 @@ #include #include /* for CONFIG_PCI */ #include -#include +#include struct proc_dir_entry proc_scsi_eata_pio = { PROC_SCSI_EATA_PIO, 9, "eata_pio", diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 1781be4fb..1a6b8606a 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -37,7 +38,6 @@ #include #include #include -#include #define DEBUG_ESP /* #define DEBUG_ESP_HME */ diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index aaa23937a..69c97f588 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -89,9 +89,9 @@ #include #include #include +#include #include #include -#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 4fea48e7e..1805e9e97 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -289,7 +289,7 @@ #include "hosts.h" #include "fdomain.h" #include -#include +#include #include #include #include diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 6d84f7bda..79cd0111c 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -191,7 +191,7 @@ #include #include #if LINUX_VERSION_CODE >= 0x02015F -#include +#include #endif #if LINUX_VERSION_CODE >= 0x010300 diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index c7a50300b..365351cb9 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index af2aa49ea..f1b3eadc9 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -37,7 +37,7 @@ #include #include #ifndef OLDKERN -#include +#include #endif #include #include "sd.h" diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h index 6388b2e8e..f9d334c29 100644 --- a/drivers/scsi/in2000.h +++ b/drivers/scsi/in2000.h @@ -387,7 +387,7 @@ struct IN2000_hostdata { # define CLISPIN_UNLOCK(flags) restore_flags(flags) #else /* 2.1.xxx */ # include -# include +# include # define in2000__INITFUNC(function) __initfunc(function) # define in2000__INIT __init # define in2000__INITDATA __initdata diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c index e6c0ec1d7..f37f2ae4d 100644 --- a/drivers/scsi/ini9100u.c +++ b/drivers/scsi/ini9100u.c @@ -130,7 +130,7 @@ #endif #include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) -#include +#include #endif #include #include diff --git a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c index 679bafc00..eab18bad1 100644 --- a/drivers/scsi/inia100.c +++ b/drivers/scsi/inia100.c @@ -91,7 +91,7 @@ #endif #include #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95) -#include +#include #endif #include "sd.h" #include "scsi.h" diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index f6b210064..e3d2ea4b9 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -104,7 +104,7 @@ #include #include -#include +#include #include /* diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index ca17a5b0e..5f883856b 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -15,12 +15,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index e5c36cd88..624005304 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -160,7 +160,7 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver"); #if LINUX_VERSION_CODE < 0x20100 #include #else -#include +#include #endif #include diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 59b0b7f3a..8cadff737 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include #include "scsi.h" diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index d66f53632..383c0c1f1 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -122,7 +122,7 @@ #include #include #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) -#include +#include #endif #include #include diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index c83f856d2..f05afc979 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -54,7 +54,7 @@ #include "psi_roy.h" #if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include +#include #endif #if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) #include diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index cf2f09f91..bdc285186 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -48,7 +48,7 @@ #include "pci2220i.h" #if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95) -#include +#include #endif #if LINUX_VERSION_CODE < LINUXVERSION(2,1,93) #include diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index cca528fee..2fa699576 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -33,9 +33,9 @@ #include #include #include +#include #include #include -#include #include #include #include "scsi.h" diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index cbf6a375c..af76c3aa9 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -123,9 +123,9 @@ #include #include #include +#include #include #include -#include #include "sd.h" #include "hosts.h" #include "qlogicfas.h" diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 03dcc18d2..7e209ac3a 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -53,9 +53,9 @@ #include #include #include +#include #include #include -#include #include "sd.h" #include "hosts.h" @@ -1885,9 +1885,8 @@ static int isp2x00_init(struct Scsi_Host *sh) pdev->device); return 1; } - if (command & PCI_COMMAND_IO && (io_base & 3) == 1) - io_base &= PCI_BASE_ADDRESS_IO_MASK; - else { + if (!(command & PCI_COMMAND_IO) || + !(pdev->resource[0].flags & IORESOURCE_IO)) { printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id); return 1; } diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index ff30d95ec..1b5d772a2 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include "sd.h" diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 481c3ecf9..d2c00c285 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d45c1a625..7c44cdf73 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -54,11 +54,11 @@ #define __KERNEL_SYSCALLS__ #include +#include #include #include #include -#include #include "scsi.h" #include "hosts.h" diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index ebfd9dda9..27c9e1aa1 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -83,7 +83,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b8b9f2c70..29042cab9 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -27,10 +27,10 @@ #include #include #include +#include #include #include #include -#include /* The driver prints some debugging information on the console if DEBUG is defined and non-zero. */ diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index e13cda2bb..84d5706a9 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -30,10 +30,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include "scsi.h" diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index d7c602a97..80696413e 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -110,7 +110,7 @@ #include #include #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) -#include +#include #endif #include #include diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 4f1bbf265..1e153e40d 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -188,13 +188,13 @@ * undef : traditional save_flags; cli; restore_flags; */ -//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */ +//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/linux/spinlock.h */ #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) # include -# include +# include #endif diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index ad4c56aef..211980958 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -359,7 +359,7 @@ MODULE_AUTHOR("Dario Ballabio"); #endif #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101) -#include +#include #define IRQ_FLAGS #define IRQ_LOCK #define IRQ_LOCK_SAVE diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 36fff563d..1c97ad4fe 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -134,10 +134,10 @@ #include #include #include +#include #include #include #include -#include #include #define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 6bdfc0a02..14515a018 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -152,8 +152,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/drivers/sgi/char/ds1286.c b/drivers/sgi/char/ds1286.c index 4f5c20b15..2e0e0621f 100644 --- a/drivers/sgi/char/ds1286.c +++ b/drivers/sgi/char/ds1286.c @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include -#include #include #define DS1286_VERSION "1.0" diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 033c5da9f..efca048dc 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -77,7 +77,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index dc3fc103f..08e819dce 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -149,7 +149,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 7bee7299a..bf5048fe2 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -105,9 +105,9 @@ #include #include #include +#include #include #include -#include #include #include #include "ac97.h" diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index eb7cd73d5..303b5793d 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -78,7 +78,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c index 8ccc21201..3f9250bcb 100644 --- a/drivers/sound/maestro.c +++ b/drivers/sound/maestro.c @@ -118,7 +118,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c index a3f73eded..4bfca0875 100644 --- a/drivers/sound/msnd.c +++ b/drivers/sound/msnd.c @@ -44,7 +44,7 @@ # include # include # include -# include +# include #endif #include #include "msnd.h" diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index abe4a300a..8b8190cb1 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -100,7 +100,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/sound/vwsnd.c b/drivers/sound/vwsnd.c index ef2cf7f36..17df87e24 100644 --- a/drivers/sound/vwsnd.c +++ b/drivers/sound/vwsnd.c @@ -140,9 +140,9 @@ #include #include +#include #include #include -#include #include "sound_config.h" diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index cbb13c987..48fea89d4 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -56,8 +56,8 @@ #include #include #include -//#include -#include +#include + #include "usb.h" #define NR_PORTS 3 diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c index 43311d0bb..6a466c5a7 100644 --- a/drivers/usb/cpia.c +++ b/drivers/usb/cpia.c @@ -19,8 +19,8 @@ #include #include #include +#include -#include #include #include "usb.h" diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c index b2092329e..4c00ef143 100644 --- a/drivers/usb/ezusb.c +++ b/drivers/usb/ezusb.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include "usb.h" diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c index 12c7bf006..c7a5af555 100644 --- a/drivers/usb/hp_scanner.c +++ b/drivers/usb/hp_scanner.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include "usb.h" diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index 19f2fcfd3..66205c05d 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -12,8 +12,8 @@ #include #include #include +#include -#include #include #include "usb.h" diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c index 7b7b346dd..85ca4f6fb 100644 --- a/drivers/usb/keyboard.c +++ b/drivers/usb/keyboard.c @@ -1,3 +1,11 @@ +/* + Fixes: + 1999/09/04 - Arnaldo Carvalho de Melo + Handle states in usb_kbd_irq + 1999/09/06 - Arnaldo Carvalho de Melo + rmmod usb-keyboard doesn't crash the system anymore: the irq + handlers are correctly released with usb_release_irq +*/ #include #include #include @@ -31,6 +39,7 @@ struct usb_keyboard unsigned char repeat_key; struct timer_list repeat_timer; struct list_head list; + void *irq_handler; /* host controller's IRQ transfer handle */ }; extern unsigned char usb_kbd_map[]; @@ -97,8 +106,22 @@ usb_kbd_irq(int state, void *buffer, int len, void *dev_id) struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; unsigned long *down = (unsigned long*) buffer; - if(kbd->down[0] != down[0] || kbd->down[1] != down[1]) - { + /* + * USB_ST_NOERROR is the normal case. + * USB_ST_REMOVED occurs if keyboard disconnected + * On other states, ignore + */ + + switch (state) { + case USB_ST_REMOVED: + case USB_ST_INTERNALERROR: + printk(KERN_DEBUG "%s(%d): Suspending\n", __FILE__, __LINE__); + return 0; /* disable */ + case USB_ST_NOERROR: break; + default: return 1; /* ignore */ + } + + if(kbd->down[0] != down[0] || kbd->down[1] != down[1]) { unsigned char *olddown, *newdown; unsigned char modsdelta, key; int i; @@ -202,11 +225,9 @@ usb_kbd_probe(struct usb_device *dev) usb_set_protocol(dev, 0); usb_set_idle(dev, 0, 0); - usb_request_irq(dev, - usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), - usb_kbd_irq, - endpoint->bInterval, - kbd); + kbd->irq_handler = usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_kbd_irq, endpoint->bInterval, kbd); list_add(&kbd->list, &usb_kbd_list); @@ -240,6 +261,30 @@ int usb_kbd_init(void) return 0; } +void usb_kbd_cleanup(void) +{ + struct list_head *cur, *head = &usb_kbd_list; + + cur = head->next; + + while (cur != head) { + struct usb_keyboard *kbd = list_entry(cur, struct usb_keyboard, list); + + cur = cur->next; + + list_del(&kbd->list); + INIT_LIST_HEAD(&kbd->list); + + if (kbd->irq_handler) { + usb_release_irq(kbd->dev, kbd->irq_handler); + /* never keep a reference to a released IRQ! */ + kbd->irq_handler = NULL; + } + } + + usb_deregister(&usb_kbd_driver); +} + #ifdef MODULE int init_module(void) { @@ -248,7 +293,7 @@ int init_module(void) void cleanup_module(void) { - usb_deregister(&usb_kbd_driver); + usb_kbd_cleanup(); } #endif diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 4c7b0c6d8..71a66cb8a 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -40,8 +40,7 @@ #include #include #include - -#include +#include #include "usb.h" diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c index 22dacd41e..2812fb75c 100644 --- a/drivers/usb/ohci-hcd.c +++ b/drivers/usb/ohci-hcd.c @@ -5,7 +5,7 @@ * * The OHCI HCD layer is a simple but nearly complete implementation of what * the USB people would call a HCD for the OHCI. - * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled) + * (ISO alpha , Bulk, INT u. CTRL transfers enabled) * The layer on top of it, is for interfacing to the alternate-usb * device-drivers. * @@ -17,12 +17,15 @@ * [ $Log: ohci.c,v $ ] * [ Revision 1.1 1999/04/05 08:32:30 greg ] * + * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes + * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl. + * v4.0 1999/08/18 * v3.0 1999/06/25 * v2.1 1999/05/09 code clean up * v2.0 1999/05/04 - * virtual root hub is now an option, + * virtual root hub is now enabled, * memory allocation based on kmalloc and kfree now, Bus error handling, - * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion + * INT, CTRL and BULK transfers enabled, ISO needs testing (alpha) * * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff) * from Greg Smith (ohci.c) (reset controller handling, hub) @@ -44,8 +47,8 @@ #include #include #include +#include -#include #include #include #include @@ -58,8 +61,11 @@ static int handle_apm_event(apm_event_t event); static int apm_resume = 0; #endif + static int ohci_link_ed(struct ohci * ohci, struct usb_ohci_ed *ed); - +static int sohci_kill_isoc (struct usb_isoc_desc *id); +static int sohci_get_current_frame_number (struct usb_device *usb_dev); +static int sohci_run_isoc(struct usb_isoc_desc *id, struct usb_isoc_desc *pr_id); static DECLARE_WAIT_QUEUE_HEAD(op_wakeup); void usb_pipe_to_hcd_ed(struct usb_device *usb_dev, unsigned int pipe, struct usb_hcd_ed *hcd_ed) @@ -70,7 +76,8 @@ void usb_pipe_to_hcd_ed(struct usb_device *usb_dev, unsigned int pipe, struct us hcd_ed->type = usb_pipetype(pipe); hcd_ed->slow = usb_pipeslow(pipe); hcd_ed->maxpack = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)); - OHCI_DEBUG(printk("******* hcd_ed: endpoint: %4x, function: %4x, out: %4x, type: %4x, slow: %4x, maxpack: %4x\n", hcd_ed->endpoint, hcd_ed->function, hcd_ed->out, hcd_ed->type, hcd_ed->slow, hcd_ed->maxpack); ) + OHCI_DEBUG(printk("******* hcd_ed: pipe: %8x, endpoint: %4x, function: %4x, out: %4x, type: %4x, slow: %4x, maxpack: %4x\n", pipe, hcd_ed->endpoint, hcd_ed->function, hcd_ed->out, hcd_ed->type, hcd_ed->slow, hcd_ed->maxpack); ) +OHCI_DEBUG(printk("******* dev: devnum: %4x, slow: %4x, maxpacketsize: %4x\n",usb_dev->devnum, usb_dev->slow, usb_dev->maxpacketsize); ) } @@ -81,7 +88,10 @@ void usb_pipe_to_hcd_ed(struct usb_device *usb_dev, unsigned int pipe, struct us static int sohci_blocking_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) { if(lw0 != NULL) { - ((struct ohci_state * )lw0)->status = status; + if(USB_ST_CRC < 0 && (status == USB_ST_DATAUNDERRUN || status == USB_ST_NOERROR)) + ((struct ohci_state * )lw0)->status = data_len; + else + ((struct ohci_state * )lw0)->status = status; ((struct ohci_state * )lw0)->len = data_len; } if(lw1 != NULL) { @@ -116,7 +126,59 @@ static int sohci_int_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data return 0; } - + +static int sohci_iso_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) { + + // struct ohci * ohci = ohci_in; + unsigned int ix = (unsigned int) lw0; + struct usb_isoc_desc * id = (struct usb_isoc_desc *) lw1; + struct usb_ohci_td **tdp = id->td; + int ret = 0; + int fx; + + OHCI_DEBUG({ int i; printk("USB HC ISO |||: %x: data(%d):", ed->hwINFO, data_len);) + OHCI_DEBUG( for(i=0; i < 16 ; i++ ) printk(" %02x", ((__u8 *) data)[i]);) + OHCI_DEBUG( printk(" ... ret_status: %x\n", status); }) + + tdp[ix] = NULL; + id->frames[ix].frame_length = data_len; + id->frames[ix].frame_status = status; + id->total_length += data_len; + if(status) id->error_count++; + + id->cur_completed_frame++; + id->total_completed_frames++; + + if(id->cur_completed_frame == id->callback_frames) { + id->prev_completed_frame = id->cur_completed_frame; + id->cur_completed_frame = 0; + OHCI_DEBUG(printk("USB HC ISO <<<: %x: \n", ed->hwINFO);) + ret = id->callback_fn(id->error_count, id->data, id->total_length, id); + switch (ret) { + case CB_CONT_RUN: + for (fx = 0; fx < id->frame_count; fx++) + id->frames[fx].frame_length = id->frame_size; + sohci_run_isoc(id, id->prev_isocdesc); + break; + + case CB_CONTINUE: + break; + + case CB_REUSE: + break; + + case CB_RESTART: + break; + + case CB_ABORT: + sohci_kill_isoc(id); + break; + } + } + + return 0; +} + static void * sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { struct ohci * ohci = usb_dev->bus->hcpriv; @@ -146,8 +208,8 @@ static int sohci_release_irq(struct usb_device *usb_dev, void * ed) // struct usb_device *usb_dev = ((struct ohci_device *) ((unsigned int)ed & 0xfffff000))->usb; struct ohci * ohci = usb_dev->bus->hcpriv; - OHCI_DEBUG( printk("USB HC RM_IRQ>>>:%4x\n", (unsigned int) ed);) - + OHCI_DEBUG( printk("USB HC ***** RM_IRQ>>>:%4x\n", (unsigned int) ed);) + if(ed == NULL) return 0; #ifdef VROOTHUB @@ -157,7 +219,7 @@ static int sohci_release_irq(struct usb_device *usb_dev, void * ed) ED_setSTATE((struct usb_ohci_ed *)ed, ED_STOP); usb_ohci_rm_ep(usb_dev, (struct usb_ohci_ed *) ed, NULL, NULL, NULL, 0); - + return 0; } @@ -179,7 +241,7 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devr ed = usb_ohci_add_ep(usb_dev, &hcd_ed, 0, 1); - OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ed->hwINFO, 8);) + OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: ed:%x-%x: ctrl(%d):", (unsigned int) ed, ed->hwINFO, 8);) OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);) OHCI_DEBUG( printk(" data(%d):", len);) OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) @@ -191,7 +253,7 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devr OHCI_DEBUG(printk("USB HC trans req ed %x: %x :", ed->hwINFO, (unsigned int ) ed); ) OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; ) if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed); - schedule_timeout(HZ/10); + schedule_timeout(HZ*5); if(state.status == TD_NOTACCESSED) { current->state = TASK_UNINTERRUPTIBLE; @@ -223,7 +285,7 @@ static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *d ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) &state, (__OHCI_BAG) &wait,(usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_blocking_handler); if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed); - schedule_timeout(HZ/10); + schedule_timeout(HZ*5); if(state.status == TD_NOTACCESSED) { current->state = TASK_UNINTERRUPTIBLE; @@ -267,13 +329,36 @@ static int sohci_terminate_bulk(struct usb_device *usb_dev, void * ed) return 1; } -static int sohci_usb_deallocate(struct usb_device *usb_dev) { +static int sohci_alloc_dev(struct usb_device *usb_dev) +{ + struct ohci_device *dev; + + /* Allocate the OHCI_HCD device private data */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -1; + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + atomic_set(&dev->refcnt, 1); + + if (usb_dev->parent) + dev->ohci = usb_to_ohci(usb_dev->parent)->ohci; + + return 0; +} + +static int sohci_free_dev(struct usb_device *usb_dev) +{ int cnt; DECLARE_WAITQUEUE(wait, current); - struct ohci_device *dev = usb_to_ohci(usb_dev); - - OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);) - + struct ohci_device *dev = usb_to_ohci(usb_dev); + + OHCI_DEBUG(printk("USB HC ***** free %x\n", usb_dev->devnum);) + if(usb_dev->devnum >= 0) { current->state = TASK_UNINTERRUPTIBLE; cnt = usb_ohci_rm_function(usb_dev, sohci_blocking_handler, NULL, &wait); @@ -281,109 +366,161 @@ static int sohci_usb_deallocate(struct usb_device *usb_dev) { schedule(); remove_wait_queue(&op_wakeup, &wait); } + current->state = TASK_INTERRUPTIBLE; } - - USB_FREE(dev); - usb_destroy_configuration(usb_dev); - USB_FREE(usb_dev); + +if (atomic_dec_and_test(&dev->refcnt)) + kfree(dev); return 0; } -static struct usb_device *sohci_usb_allocate(struct usb_device *parent) { - struct usb_device *usb_dev; - struct ohci_device *dev; - - USB_ALLOC(usb_dev, sizeof(*usb_dev)); - if (!usb_dev) - return NULL; - - memset(usb_dev, 0, sizeof(*usb_dev)); - USB_ALLOC(dev, sizeof(*dev)); - if (!dev) { - usb_destroy_configuration(usb_dev); - USB_FREE(usb_dev); - return NULL; - } +/* + * ISO Interface designed by Randy Dunlap + */ - /* Initialize "dev" */ - memset(dev, 0, sizeof(*dev)); +static int sohci_get_current_frame_number(struct usb_device *usb_dev) { + + struct ohci * ohci = usb_dev->bus->hcpriv; - usb_dev->hcpriv = dev; - dev->usb = usb_dev; + return readl(&ohci->regs->fmnumber) & 0xffff; +} - usb_dev->parent = parent; - if (parent) { - usb_dev->bus = parent->bus; - dev->ohci = usb_to_ohci(parent)->ohci; - } - return usb_dev; -} +static int sohci_init_isoc(struct usb_device *usb_dev, unsigned int pipe, int frame_count, void *context, struct usb_isoc_desc **idp) { -static void *sohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - struct ohci * ohci = usb_dev->bus->hcpriv; - struct ohci_device * dev = usb_to_ohci(usb_dev); - struct usb_hcd_ed hcd_ed; - struct usb_ohci_ed * ed; - struct usb_ohci_td * td; - - usb_pipe_to_hcd_ed(usb_dev, pipe, &hcd_ed); - hcd_ed.type = ISO; - ed = usb_ohci_add_ep(usb_dev, &hcd_ed, 1, 1); + struct usb_isoc_desc *id; - OHCI_DEBUG( printk("USB HC ISO>>>: %x: \n", ed->hwINFO);) + *idp = NULL; + + id = kmalloc (sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count), GFP_KERNEL); + if(!id) return -ENOMEM; + memset (id, 0, sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count)); +OHCI_DEBUG(printk("ISO alloc id: %p, size: %d\n", id, sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count));) + id->td = kmalloc (sizeof (void *) * frame_count, GFP_KERNEL); + if(!id->td) { + kfree (id); + return -ENOMEM; + } + memset (id->td, 0, sizeof (void *) * frame_count); +OHCI_DEBUG(printk("ISO alloc id->td: %p, size: %d\n", id->td, sizeof (void *) * frame_count);) - td = ohci_trans_req(ohci, ed, 0, NULL, dev->data, len, (__OHCI_BAG) completed, (__OHCI_BAG) dev_id, (usb_pipeout(pipe))?ISO_OUT:ISO_IN, sohci_int_handler); - return td; -} + id->frame_count = frame_count; + id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe)); + id->start_frame = -1; + id->end_frame = -1; + id->usb_dev = usb_dev; + id->pipe = pipe; + id->context = context; + + *idp = id; + return 0; +} -static void sohci_delete_isochronous (struct usb_device *usb_dev, void *td) -{ - // struct ohci * ohci = usb_dev->bus->hcpriv; - DECLARE_WAITQUEUE(wait, current); +void print_int_eds(struct ohci * ohci); + +static int sohci_run_isoc(struct usb_isoc_desc *id, struct usb_isoc_desc *pr_id) { + + struct ohci * ohci = id->usb_dev->bus->hcpriv; + struct usb_ohci_td ** tdp = (struct usb_ohci_td **) id->td; + struct usb_hcd_ed hcd_ed; + struct usb_ohci_ed * ed; + int ix, frlen; + unsigned char *bufptr; + + if(pr_id) + id->start_frame = pr_id->end_frame + 1; + else { + switch(id->start_type) { + case START_ABSOLUTE: + break; + + case START_RELATIVE: + if(id->start_frame < START_FRAME_FUDGE) id->start_frame = START_FRAME_FUDGE; + id->start_frame += sohci_get_current_frame_number(id->usb_dev); + break; + + case START_ASAP: + id->start_frame = START_FRAME_FUDGE + sohci_get_current_frame_number(id->usb_dev); + break; + } + } + + id->start_frame &= 0xffff; + id->end_frame = (id->start_frame + id->frame_count - 1) & 0xffff; + + id->prev_completed_frame = 0; + id->cur_completed_frame = 0; + if (id->frame_spacing <= 0) id->frame_spacing = 1; - OHCI_DEBUG( printk("USB HC RM_ISO>>>:%4x\n", (unsigned int) td);) + bufptr = id->data; + + usb_pipe_to_hcd_ed(id->usb_dev, id->pipe, &hcd_ed); + hcd_ed.type = ISO; + ed = usb_ohci_add_ep(id->usb_dev, &hcd_ed, 1, 1); + OHCI_DEBUG( printk("USB HC ISO>>>: ed: %x-%x: (%d tds)\n", (unsigned int) ed, ed->hwINFO, id->frame_count);) - current->state = TASK_UNINTERRUPTIBLE; - usb_ohci_rm_ep(usb_dev, ((struct usb_ohci_td *) td)->ed, sohci_blocking_handler, NULL, &wait, SEND); - schedule(); - remove_wait_queue(&op_wakeup, &wait); - return; + for (ix = 0; ix < id->frame_count; ix++) { + frlen = (id->frames[ix].frame_length > id->frame_size)? id->frame_size : id->frames[ix].frame_length; + printk("ISO run id->td: %p \n", &tdp[ix]); + tdp[ix] = ohci_trans_req(ohci, ed, id->start_frame + ix , NULL, bufptr, frlen, (__OHCI_BAG) ix, (__OHCI_BAG) id, + (usb_pipeout(id->pipe))?ISO_OUT:ISO_IN, + sohci_iso_handler); + bufptr += frlen; + } + + if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed); + print_int_eds(ohci); + return 0; } -static int sohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) -{ - return USB_ST_NOTSUPPORTED; -} +static int sohci_kill_isoc(struct usb_isoc_desc *id) { -static int sohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; + struct usb_ohci_ed *ed = NULL; + struct usb_ohci_td **td = id->td; + int i; +printk("KILL_ISOC***:\n"); + for (i = 0; i < id->frame_count; i++) { + if(td[i]) { + td[i]->type |= DEL; + ed = td[i]->ed; printk(" %d", i); + } + } + if(ed) usb_ohci_rm_ep(id->usb_dev, ed, NULL, NULL, NULL, TD_RM); +printk(": end KILL_ISOC***: %p\n", ed); + id->start_frame = -1; + return 0; } -static int sohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) -{ - return USB_ST_NOTSUPPORTED; + +static void sohci_free_isoc(struct usb_isoc_desc *id) { +printk("FREE_ISOC***\n"); +wait_ms(2000); + if(id->start_frame >= 0) sohci_kill_isoc(id); +printk("FREE_ISOC2***\n"); +wait_ms(2000); + kfree(id->td); + kfree(id); +printk("FREE_ISOC3***\n"); +wait_ms(2000); } struct usb_operations sohci_device_operations = { - sohci_usb_allocate, - sohci_usb_deallocate, + sohci_alloc_dev, + sohci_free_dev, sohci_control_msg, sohci_bulk_msg, sohci_request_irq, sohci_release_irq, sohci_request_bulk, sohci_terminate_bulk, - sohci_alloc_isochronous, - sohci_delete_isochronous, - sohci_sched_isochronous, - sohci_unsched_isochronous, - sohci_compress_isochronous + sohci_get_current_frame_number, + sohci_init_isoc, + sohci_free_isoc, + sohci_run_isoc, + sohci_kill_isoc }; @@ -394,7 +531,7 @@ struct usb_operations sohci_device_operations = { /* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/ void print_int_eds(struct ohci * ohci) {int i; __u32 * ed_p; for(i= 0; i < 32; i++) { - OHCI_DEBUG(printk("unlnk_branch int %2d(%2x): ", i,i); ) + OHCI_DEBUG(printk("branch int %2d(%2x): ", i,i); ) ed_p = &(ohci->hc_area->hcca.int_table[i]); while (*ed_p != 0) { OHCI_DEBUG(printk("ed: %4x; ", (((struct usb_ohci_ed *)bus_to_virt(*ed_p))->hwINFO));) @@ -431,7 +568,7 @@ static int usb_ohci_int_ballance(struct ohci * ohci, int * interval, int load) { } /* the int tree is a binary tree - * in order to process it sequentielly the indexes of the branches have to be mapped + * in order to process it sequentially the indexes of the branches have to be mapped * the mapping reverses the bits of a word of num_bits length * */ static int rev(int num_bits, int word) { @@ -445,7 +582,7 @@ static int rev(int num_bits, int word) { /* get the ed from the endpoint / usb_device address */ struct usb_ohci_ed * ohci_find_ep(struct usb_device *usb_dev, struct usb_hcd_ed *hcd_ed) { - return &(usb_to_ohci(usb_dev)->ed[hcd_ed->endpoint << 1 | ((hcd_ed->type == CTRL)? 0:hcd_ed->out)]); + return &(usb_to_ohci(usb_dev)->ed[(hcd_ed->endpoint << 1) | ((hcd_ed->type == CTRL)? 0:hcd_ed->out)]); } /* link an ed into one of the HC chains */ @@ -634,16 +771,19 @@ struct usb_ohci_ed *usb_ohci_add_ep(struct usb_device * usb_dev, struct usb_hcd_ // struct ohci * ohci = usb_dev->bus->hcpriv; struct usb_ohci_td * td; - struct usb_ohci_ed * ed; + struct usb_ohci_ed * ed, *ed1; - int ed_state; + int ed_state, ed_state1; spin_lock(&usb_ed_lock); - ed = ohci_find_ep(usb_dev, hcd_ed); + ed = ohci_find_ep(usb_dev, hcd_ed); + + ed1 = ((void *) ed) + 0x40; ed_state1 = ED_STATE(ed1); +OHCI_DEBUG(printk("++++ USB HC add 60 ed1 %x: %x :state: %x\n", ed1->hwINFO, (unsigned int ) ed1, ed_state1); ) ed_state = ED_STATE(ed); /* store state of ed */ - + OHCI_DEBUG(printk("USB HC add ed %x: %x :state: %x\n", ed->hwINFO, (unsigned int ) ed, ed_state); ) if (ed_state == ED_NEW) { OHCI_ALLOC(td, sizeof(*td)); /* dummy td; end of td list for ed */ ed->hwTailP = virt_to_bus(td); @@ -678,6 +818,8 @@ struct usb_ohci_ed *usb_ohci_add_ep(struct usb_device * usb_dev, struct usb_hcd_ * put the ep on the rm_list and request a stop of the bulk or ctrl list * real removal is done at the next start of frame (SOF) hardware interrupt * the dummy td carries the essential information (handler, proc queue, ...) + * if(send & TD_RM) then just the TD witch have (TD->type & DEL) set will be removed + * otherwise all TDs including the dummy TD of the ED will be removed */ int usb_ohci_rm_ep(struct usb_device * usb_dev, struct usb_ohci_ed *ed, f_handler handler, __OHCI_BAG lw0, __OHCI_BAG lw1, int send) { @@ -692,17 +834,21 @@ int usb_ohci_rm_ep(struct usb_device * usb_dev, struct usb_ohci_ed *ed, f_handle ed->hwINFO |= OHCI_ED_SKIP; writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */ - if(ED_STATE(ed) == ED_OPER) ohci_unlink_ed(ohci, ed); - td = (struct usb_ohci_td *) bus_to_virt(ed->hwTailP); - td->lw0 = lw0; - td->lw1 = lw1; - td->ed = ed; - td->hwINFO = TD_CC; - td->handler = handler; - td->type = send; - - ED_setSTATE(ed, ED_DEL); + if(send & TD_RM) { /* delete selected TDs */ + ED_setSTATE(ed, ED_TD_DEL); + } + else { /* delete all TDS */ + if(ED_STATE(ed) == ED_OPER) ohci_unlink_ed(ohci, ed); + td = (struct usb_ohci_td *) bus_to_virt(ed->hwTailP); + td->lw0 = lw0; + td->lw1 = lw1; + td->ed = ed; + td->hwINFO = TD_CC; + td->handler = handler; + td->type = send; + ED_setSTATE(ed, ED_DEL); + } ed->ed_prev = ohci->ed_rm_list; ohci->ed_rm_list = ed; @@ -770,7 +916,7 @@ int usb_ohci_rm_function(struct usb_device * usb_dev, f_handler handler,__OHCI_B #define FILL_ISO_TD(INFO, DATA, LEN, LW0, LW1, TYPE, HANDLER) \ OHCI_ALLOC(td_pt, sizeof(*td_pt)); \ - td_ret = (struct usb_ohci_td *) bus_to_virt(usb_ed->hwTailP); \ + td_ret = (struct usb_ohci_td *) bus_to_virt(usb_ed->hwTailP & 0xfffffff0); \ td_pt1 = td_ret; \ td_pt1->ed = ed; \ td_pt1->buffer_start = (DATA); \ @@ -779,12 +925,13 @@ int usb_ohci_rm_function(struct usb_device * usb_dev, f_handler handler,__OHCI_B td_pt1->lw0 = (LW0); \ td_pt1->lw1 = (LW1); \ td_pt1->hwINFO = (INFO); \ - td_pt1->hwCBP = (virt_to_bus(DATA) & 0xfffff000); \ - td_pt1->hwBE = virt_to_bus((DATA) + (LEN) - 1); \ + td_pt1->hwCBP = (((DATA)==NULL)||((LEN)==0))?0:(virt_to_bus(DATA) & 0xfffff000); \ + td_pt1->hwBE = (((DATA)==NULL)||((LEN)==0))?0:virt_to_bus((DATA) + (LEN) - 1); \ td_pt1->hwNextTD = virt_to_bus(td_pt); \ - td_pt1->hwPSW[0] = virt_to_bus(DATA) & 0xfff; \ - usb_ed->hwTailP = virt_to_bus(td_pt); \ - td_pt->hwNextTD = 0 + td_pt1->hwPSW[0] = (virt_to_bus(DATA) & 0xfff) | 0xe000; \ + td_pt->hwNextTD = 0; \ + usb_ed->hwTailP = td_pt1->hwNextTD + spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED; @@ -811,7 +958,7 @@ struct usb_ohci_td * ohci_trans_req(struct ohci * ohci, struct usb_ohci_ed * ed, case BULK_IN: while(data_len > 4096) { - FILL_TD( TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, 4096, NULL, NULL, BULK_IN | ADD_LEN|(cnt++?0:ST_ADDR), NULL); + FILL_TD( TD_CC | TD_DP_IN | TD_T_TOGGLE, data, 4096, NULL, NULL, BULK_IN | ADD_LEN|(cnt++?0:ST_ADDR), NULL); data += 4096; data_len -= 4096; } FILL_TD( TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1, BULK_IN |ADD_LEN|SEND|(cnt++?0:ST_ADDR), handler); @@ -925,7 +1072,8 @@ static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) { } /* there are some pending requests to remove some of the eds - * we process every td including the dummy td of these eds + * we either process every td including the dummy td of these eds + * or just those marked with TD->type&DEL * and link them to a list * */ static struct usb_ohci_td * usb_ohci_del_list(struct ohci * ohci) { @@ -964,11 +1112,12 @@ static struct usb_ohci_td * usb_ohci_del_list(struct ohci * ohci) { OHCI_DEBUG(printk("USB HC ed_rm_list: dummy (ED_DEL) td: %4x\n", (unsigned int) td);) ED_setSTATE(td->ed, ED_DEL| ED_NEW); td->next_dl_td = NULL; - } + } + if(ED_TYPE(ed) == CTRL) writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */ + if(ED_TYPE(ed) == BULK) writel(0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */ + } - writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */ - writel(0, &ohci->regs->ed_bulkcurrent); /* reset BULK list */ writel_set((0x03<<4), &ohci->regs->control); /* start CTRL u. BULK list */ ohci->ed_rm_list = NULL; @@ -1014,11 +1163,11 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list) } } /* error code of transfer */ - cc = (ED_STATE(td_list->ed) == ED_DEL || (td_list->type & DEL))? USB_ST_REMOVED : TD_CC_GET(td_list->hwINFO); + cc = (ED_STATE(td_list->ed) == ED_DEL || (td_list->type & DEL))? USB_ST_REMOVED : (USB_ST_CRC*TD_CC_GET(td_list->hwINFO)); if(td_list->type & DEL_ED) ED_setSTATE(td_list->ed, ED_NEW); /* remove ed */ - if((td_list->type & SEND) && (ED_STATE(td_list->ed) != ED_STOP)) { /* send the reply */ + if((td_list->type & SEND) && (ED_STATE(td_list->ed) != ED_STOP) && (td_list->handler)) { /* send the reply */ td_list->handler((void *) ohci, td_list->ed, td_list->ed->buffer_start, @@ -1029,6 +1178,7 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list) OHCI_DEBUG(if(cc != TD_CC_NOERROR) printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hwINFO), td_list->ed->hwINFO);) } + if(ED_STATE(td_list->ed) == ED_TD_DEL) td_list->ed->hwINFO &= ~OHCI_ED_SKIP; if(((td_list->ed->hwHeadP & 0xfffffff0) == td_list->ed->hwTailP) && (ED_STATE(td_list->ed) > ED_UNLINK)) ohci_unlink_ed(ohci, td_list->ed); /* unlink eds if they are not busy */ @@ -1050,12 +1200,18 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list) void reset_hc(struct ohci *ohci) { int timeout = 30; + int smm_timeout = 50; /* 0,5 sec */ if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */ writel(0x08, &ohci->regs->cmdstatus); /* request ownership */ printk("USB HC TakeOver from SMM\n"); - if(readl(&ohci->regs->control) & 0x100) - printk("USB HC TakeOver failed!\n"); + while(readl(&ohci->regs->control) & 0x100) { + wait_ms(10); + if (--smm_timeout == 0) { + printk("USB HC TakeOver failed!\n"); + break; + } + } } writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */ @@ -1092,7 +1248,7 @@ int start_hc(struct ohci *ohci) writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */ - writel((0xB7), &ohci->regs->control); /* USB Operational */ + writel((0xBF), &ohci->regs->control); /* USB Operational */ fminterval = 0x2edf; writel(((fminterval)*9)/10, &ohci->regs->periodicstart); @@ -1121,16 +1277,16 @@ int start_hc(struct ohci *ohci) struct ohci_device *dev; - usb_dev = sohci_usb_allocate(NULL); + usb_dev = usb_alloc_dev(NULL, ohci->bus); if (!usb_dev) return -1; dev = usb_to_ohci(usb_dev); - usb_dev->bus = ohci->bus; + // usb_dev->bus = ohci->bus; ohci->bus->root_hub = usb_dev; dev->ohci = ohci; usb_connect(usb_dev); if(usb_new_device(usb_dev) != 0) { - sohci_usb_deallocate(usb_dev); + usb_free_dev(usb_dev); return -1; } diff --git a/drivers/usb/ohci-hcd.h b/drivers/usb/ohci-hcd.h index 5c189e65b..998635ed3 100644 --- a/drivers/usb/ohci-hcd.h +++ b/drivers/usb/ohci-hcd.h @@ -22,7 +22,7 @@ * ohci-hcd.h */ -// #define OHCI_DBG /* printk some debug information */ +#define OHCI_DBG /* printk some debug information */ #include @@ -62,6 +62,7 @@ typedef int (*f_handler )(void * ohci, struct usb_ohci_ed *ed, void *data, int d #define ED_OPER 0x02 #define ED_STOP 0x03 #define ED_DEL 0x04 +#define ED_TD_DEL 0x05 #define ED_RH 0x07 /* marker for RH ED */ #define ED_STATE(ed) (((ed)->hwINFO >> 29) & 0x7) @@ -182,6 +183,7 @@ struct usb_ohci_td { #define ADD_LEN 0x00004000 #define DEL 0x00008000 #define DEL_ED 0x00040000 +#define TD_RM 0x00080000 #define OHCI_ED_SKIP (1 << 14) @@ -332,6 +334,7 @@ struct ohci_hc_area { }; struct ohci_device { struct usb_device *usb; + atomic_t refcnt; struct ohci *ohci; struct usb_ohci_ed ed[NUM_EDS]; unsigned long data[16]; diff --git a/drivers/usb/ohci-root-hub.c b/drivers/usb/ohci-root-hub.c index cc294e83a..4d7e139ba 100644 --- a/drivers/usb/ohci-root-hub.c +++ b/drivers/usb/ohci-root-hub.c @@ -234,10 +234,6 @@ int root_hub_control_msg(struct usb_device *usb_dev, unsigned int pipe, devreque OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));) OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));) - OHCI_DEBUG( { int i; printk("USB HC RH bh <<<: 1: ");) - OHCI_DEBUG( printk(" data(%d):", len);) - OHCI_DEBUG( { for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);) - OHCI_DEBUG( printk(" ret_status: %x\n", req_reply); }) return req_reply; } @@ -285,10 +281,7 @@ static void rh_int_timer_do(unsigned long ptr) { len = root_hub_send_irq(ohci, dev->data, 1 ); if(len > 0) { - OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: RH data(%d):", len);) - OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) dev->data)[i]);) - OHCI_DEBUG( printk(" ret_status: %x\n", 0); }) - + ret = ohci->rh.handler(0, dev->data, len, ohci->rh.dev_id); if(ret <= 0)ohci->rh.send = 0; /* 0 .. do not requeue */ } diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c index b73af5553..04f134dba 100644 --- a/drivers/usb/ohci.c +++ b/drivers/usb/ohci.c @@ -37,8 +37,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 92ec97cf7..826df63a8 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -16,8 +16,7 @@ #include #include #include - -#include +#include #include "usb.h" diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index d6e21e009..a77b1df01 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -41,9 +41,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -860,21 +860,10 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, if (ix < START_FRAME_FUDGE || /* too small */ ix > CAN_SCHEDULE_FRAMES) { /* too large */ #ifdef CONFIG_USB_DEBUG_ISOC - printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", - isocdesc->start_frame); + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d,%d)\n", + isocdesc->start_frame, cur_frame); #endif return -EINVAL; - } - } - else /* start_frame <= cur_frame */ { - if ((isocdesc->start_frame + UHCI_MAX_SOF_NUMBER + 1 - - cur_frame) > CAN_SCHEDULE_FRAMES) { -#ifdef CONFIG_USB_DEBUG_ISOC - printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", - isocdesc->start_frame); -#endif - return -EINVAL; - } } } /* end START_ABSOLUTE */ } diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 87ab56afe..4afeb1a30 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -237,9 +237,9 @@ void usb_free_dev(struct usb_device *dev) { if (atomic_dec_and_test(&dev->refcnt)) { usb_destroy_configuration(dev); - kfree(dev); dev->bus->op->deallocate(dev); + kfree(dev); } } diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index 469aa3588..7044bcf96 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -372,7 +372,8 @@ enum { current callback function ret. values */ CB_REUSE, /* leave descriptors as NULL, not active */ CB_RESTART, /* leave descriptors as they are, alive */ - CB_ABORT /* kill this USB transfer request */ + CB_ABORT, /* kill this USB transfer request */ + CB_CONT_RUN /* append the isoc_desc at the end of all active isoc_desc */ }; struct isoc_frame_desc { @@ -406,6 +407,7 @@ struct usb_isoc_desc { usb_device_irq callback_fn; void *data; int buf_size; + struct usb_isoc_desc *prev_isocdesc; /* previous isoc_desc, for CB_CONT_RUN */ /* * The following fields are set by the usb_run_isoc() call. */ diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c index 690b8ab04..067e7cd0c 100644 --- a/drivers/usb/usb_scsi.c +++ b/drivers/usb/usb_scsi.c @@ -36,8 +36,7 @@ #include #include #include - -#include +#include #include #include diff --git a/drivers/usb/usb_scsi_debug.c b/drivers/usb/usb_scsi_debug.c index 634f4c0f6..4168e0e17 100644 --- a/drivers/usb/usb_scsi_debug.c +++ b/drivers/usb/usb_scsi_debug.c @@ -15,8 +15,7 @@ #include #include #include - -#include +#include #include #include "../scsi/scsi.h" diff --git a/drivers/video/Config.in b/drivers/video/Config.in index 339dc6d9f..9fb8d3905 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -105,6 +105,7 @@ if [ "$CONFIG_FB" = "y" ]; then if [ "$ARCH" = "sparc" ]; then bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN + bool ' P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100 fi bool ' Leo (ZX) support' CONFIG_FB_LEO fi @@ -184,6 +185,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \ + "$CONFIG_FB_P9100" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else @@ -198,6 +200,7 @@ if [ "$CONFIG_FB" = "y" ]; then "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \ + "$CONFIG_FB_P9100" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then define_bool CONFIG_FBCON_CFB8 m fi diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 8a7c9853f..15050f347 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -281,6 +281,13 @@ L_OBJS += sbusfb.o M_OBJS += cgfourteenfb.o endif endif + ifeq ($(CONFIG_FB_P9100),y) + L_OBJS += p9100fb.o + else + ifeq ($(CONFIG_FB_P9100),m) + M_OBJS += p9100fb.o + endif + endif ifeq ($(CONFIG_FB_LEO),y) L_OBJS += leofb.o else @@ -333,6 +340,13 @@ else M_OBJS += cgfourteenfb.o endif endif + ifeq ($(CONFIG_FB_P9100),y) + M_OBJS += p9100fb.o + else + ifeq ($(CONFIG_FB_P9100),m) + M_OBJS += p9100fb.o + endif + endif ifeq ($(CONFIG_FB_LEO),y) M_OBJS += leofb.o else diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 20b825eb4..f12fec6e1 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.120 1999/08/30 10:12:18 davem Exp $ +/* $Id: atyfb.c,v 1.122 1999/09/06 20:44:08 geert Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -89,8 +89,34 @@ */ #undef DEBUG +/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */ -#define GUI_RESERVE 0x00001000 +#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */ +#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */ + /* ohne Prescaler */ +#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */ +#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */ + /* mit Prescaler 2, 4, 8 */ +#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */ +#define N_ADJ_2595 257 + +#define STOP_BITS_2595 0x1800 + + +#define MIN_N_408 2 + +#define MIN_N_1703 6 + +#define MIN_M 2 +#define MAX_M 30 +#define MIN_N 35 +#define MAX_N 255-8 + + +/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ +/* - must be large enough to catch all GUI-Regs */ +/* - must be aligned to a PAGE boundary */ +#define GUI_RESERVE (1 * PAGE_SIZE) #ifndef __powerpc__ @@ -126,6 +152,14 @@ struct pll_gx { u8 n; }; +struct pll_18818 +{ + u32 program_bits; + u32 locationAddr; + u32 period_in_ps; + u32 post_divider; +}; + struct pll_ct { u8 pll_ref_div; u8 pll_gen_cntl; @@ -150,6 +184,7 @@ struct atyfb_par { union { struct pll_gx gx; struct pll_ct ct; + struct pll_18818 ics2595; } pll; u32 accel_flags; }; @@ -196,6 +231,7 @@ struct fb_info_aty { unsigned long ati_regbase; unsigned long frame_buffer_phys; unsigned long frame_buffer; + unsigned long clk_wr_offset; struct pci_mmap_map *mmap_map; struct aty_cursor *cursor; struct aty_cmap_regs *aty_cmap_regs; @@ -213,6 +249,7 @@ struct fb_info_aty { u8 bus_type; u8 ram_type; u8 dac_type; + u8 dac_subtype; u8 clk_type; u8 mem_refresh_rate; struct display disp; @@ -329,6 +366,7 @@ static char *strtoke(char *s, const char *ct); static void reset_engine(const struct fb_info_aty *info); static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info); + static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info); static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); static u8 aty_ld_pll(int offset, const struct fb_info_aty *info); @@ -342,7 +380,37 @@ static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var); static void aty_set_pll_gx(const struct fb_info_aty *info, const struct pll_gx *pll); -static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll); + +static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp, + u32 AccelMode); +static int aty_set_dac_ATT21C498(const struct fb_info_aty *info, + const struct pll_18818 *pll, u32 bpp); +void aty_dac_waste4(const struct fb_info_aty *info); + +static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll); +static u32 aty_pll_18818_to_var(const struct pll_18818 *pll); +static void aty_set_pll18818(const struct fb_info_aty *info, + const struct pll_18818 *pll); + +static void aty_StrobeClock(const struct fb_info_aty *info); + +static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info); + +static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll); +static u32 aty_pll_408_to_var(const struct pll_18818 *pll); +static void aty_set_pll_408(const struct fb_info_aty *info, + const struct pll_18818 *pll); + +static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll); +static u32 aty_pll_1703_to_var(const struct pll_18818 *pll); +static void aty_set_pll_1703(const struct fb_info_aty *info, + const struct pll_18818 *pll); + +static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll); +static u32 aty_pll_8398_to_var(const struct pll_18818 *pll); +static void aty_set_pll_8398(const struct fb_info_aty *info, + const struct pll_18818 *pll); + static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll); static u32 aty_pll_gx_to_var(const struct pll_gx *pll, const struct fb_info_aty *info); @@ -1193,6 +1261,124 @@ static int aty_var_to_crtc(const struct fb_info_aty *info, return 0; } + +static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp, + u32 AccelMode) +{ + u32 gModeReg, devSetupRegA, temp, mask; + + gModeReg = 0; + devSetupRegA = 0; + + switch (bpp) { + case 8: + gModeReg = 0x83; + devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */; + break; + case 15: + gModeReg = 0xA0; + devSetupRegA = 0x60; + break; + case 16: + gModeReg = 0xA1; + devSetupRegA = 0x60; + break; + case 24: + gModeReg = 0xC0; + devSetupRegA = 0x60; + break; + case 32: + gModeReg = 0xE3; + devSetupRegA = 0x60; + break; + } + + if (!AccelMode) { + gModeReg = 0x80; + devSetupRegA = 0x61; + } + + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); + + aty_st_8(DAC_REGS + 2, 0x1D, info); + aty_st_8(DAC_REGS + 3, gModeReg, info); + aty_st_8(DAC_REGS, 0x02, info); + + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); + + if (info->total_vram < MEM_SIZE_1M) + mask = 0x04; + else if (info->total_vram == MEM_SIZE_1M) + mask = 0x08; + else + mask = 0x0C; + + /* The following assumes that the BIOS has correctly set R7 of the + * Device Setup Register A at boot time. + */ +#define A860_DELAY_L 0x80 + + temp = aty_ld_8(DAC_REGS, info); + aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info); + temp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info); + + return 0; +} + +static int aty_set_dac_ATT21C498(const struct fb_info_aty *info, + const struct pll_18818 *pll, u32 bpp) +{ + u32 dotClock; + int muxmode = 0; + int DACMask = 0; + + dotClock = 100000000 / pll->period_in_ps; + + switch (bpp) { + case 8: + if (dotClock > 8000) { + DACMask = 0x24; + muxmode = 1; + } else + DACMask = 0x04; + break; + case 15: + DACMask = 0x16; + break; + case 16: + DACMask = 0x36; + break; + case 24: + DACMask = 0xE6; + break; + case 32: + DACMask = 0xE6; + break; + } + + if (1 /* info->mach64DAC8Bit */) + DACMask |= 0x02; + + aty_dac_waste4(info); + aty_st_8(DAC_REGS + 2, DACMask, info); + + return muxmode; +} + +void aty_dac_waste4(const struct fb_info_aty *info) +{ + (void)aty_ld_8(DAC_REGS, info); + + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); + (void)aty_ld_8(DAC_REGS + 2, info); +} + + static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp) { static struct { @@ -1390,60 +1576,477 @@ static void aty_set_pll_gx(const struct fb_info_aty *info, } } -static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll) + +static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll) +{ + u32 MHz100; /* in 0.01 MHz */ + u32 program_bits; + u32 post_divider; + + /* Calculate the programming word */ + MHz100 = 100000000 / period_in_ps; + + program_bits = -1; + post_divider = 1; + + if (MHz100 > MAX_FREQ_2595) { + MHz100 = MAX_FREQ_2595; + return -EINVAL; + } else if (MHz100 < ABS_MIN_FREQ_2595) { + program_bits = 0; /* MHz100 = 257 */ + return -EINVAL; + } else { + while (MHz100 < MIN_FREQ_2595) { + MHz100 *= 2; + post_divider *= 2; + } + } + MHz100 *= 1000; + MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595; + + MHz100 += 500; /* + 0.5 round */ + MHz100 /= 1000; + + if (program_bits == -1) { + program_bits = MHz100 - N_ADJ_2595; + switch (post_divider) { + case 1: + program_bits |= 0x0600; + break; + case 2: + program_bits |= 0x0400; + break; + case 4: + program_bits |= 0x0200; + break; + case 8: + default: + break; + } + } + + program_bits |= STOP_BITS_2595; + + pll->program_bits = program_bits; + pll->locationAddr = 0; + pll->post_divider = post_divider; + pll->period_in_ps = period_in_ps; + + return 0; +} + +static u32 aty_pll_18818_to_var(const struct pll_18818 *pll) { - /* - * FIXME: use real calculations instead of using fixed values from the old - * driver - */ - static struct { - u32 ps_lim; /* pixclock period rounding limit (arbitrary) */ - u8 mode; /* (prescsaler << 4) | Select */ - u8 prog; /* ref_div_count */ - } ATI18818_clocks[] = { - { 7500, 0x0B, 1 }, /* 7407.4 ps = 135.00 MHz */ - { 9000, 0x0A, 1 }, /* 7936.5 ps = 126.00 MHz */ - { 11000, 0x09, 1 }, /* 10000.0 ps = 100.00 MHz */ - { 12800, 0x0D, 1 }, /* 12500.0 ps = 80.00 MHz */ - { 13500, 0x0E, 1 }, /* 13333.3 ps = 75.00 MHz */ -/* { 14000, 0x03, 2 },*/ /* 13888.8 ps = 72.00 MHz */ - { 15000, 0x1B, 1 }, /* 14814.8 ps = 67.50 MHz */ - { 15500, 0x0F, 1 }, /* 15384.6 ps = 65.00 MHz */ - { 16000, 0x1A, 1 }, /* 15873.0 ps = 63.00 MHz */ -/* { 16000, 0x02, 2 },*/ /* 15873.0 ps = 63.00 MHz */ -/* { 18000, 0x01, 2 },*/ /* 17655.4 ps = 56.64 MHz */ -/* { 19900, 0x00, 2 },*/ /* 19860.9 ps = 50.35 MHz */ - { 20000, 0x07, 1 }, /* 20000.0 ps = 50.00 MHz */ - { 20300, 0x06, 1 }, /* 20202.0 ps = 49.50 MHz */ - { 22500, 0x05, 1 }, /* 22271.2 ps = 44.90 MHz */ - { 25000, 0x04, 1 }, /* 25000.0 ps = 40.00 MHz */ -/* { 28000, 0x03, 1 },*/ /* 27777.8 ps = 36.00 MHz */ - { 30000, 0x2B, 1 }, /* 29629,6 ps = 33.75 MHz */ - { 31000, 0x1F, 1 }, /* 30769.2 ps = 32.50 MHz */ - { 32000, 0x2A, 1 }, /* 31746.0 ps = 31.50 MHz */ -/* { 32000, 0x02, 1 },*/ /* 31746.0 ps = 31.50 MHz */ -/* { 36000, 0x01, 1 },*/ /* 35310.7 ps = 28.32 MHz */ -/* { 39900, 0x00, 1 },*/ /* 39714.1 ps = 25.18 MHz */ - { 40000, 0x17, 1 }, /* 40000.0 ps = 25.00 MHz */ - { 40600, 0x16, 1 }, /* 40404.0 ps = 24.75 MHz */ - { 45000, 0x15, 1 }, /* 44543.4 ps = 22.45 MHz */ - { 50000, 0x14, 1 }, /* 50000.0 ps = 20.00 MHz */ -/* { 56000, 0x13, 1 },*/ /* 55555.5 ps = 18.00 MHz */ - { 62000, 0x2F, 1 }, /* 61538.8 ps = 16.25 MHz */ -/* { 64000, 0x12, 1 },*/ /* 63492.0 ps = 15.75 MHz */ - }; - int set; + return(pll->period_in_ps); /* default for now */ +} - for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks); - set++) - if (vclk_per <= ATI18818_clocks[set].ps_lim) { - pll->m = ATI18818_clocks[set].mode; - pll->n = ATI18818_clocks[set].prog; - return 0; +static void aty_set_pll18818(const struct fb_info_aty *info, + const struct pll_18818 *pll) +{ + u32 program_bits; + u32 locationAddr; + + u32 i; + + u8 old_clock_cntl; + u8 old_crtc_ext_disp; + + old_clock_cntl = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + udelay(15000); /* delay for 50 (15) ms */ + + program_bits = pll->program_bits; + locationAddr = pll->locationAddr; + + /* Program the clock chip */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); /* Strobe = 0 */ + aty_StrobeClock(info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info); /* Strobe = 0 */ + aty_StrobeClock(info); + + aty_ICS2595_put1bit(1, info); /* Send start bits */ + aty_ICS2595_put1bit(0, info); /* Start bit */ + aty_ICS2595_put1bit(0, info); /* Read / ~Write */ + + for (i = 0; i < 5; i++) { /* Location 0..4 */ + aty_ICS2595_put1bit(locationAddr & 1, info); + locationAddr >>= 1; + } + + for (i = 0; i < 8 + 1 + 2 + 2; i++) { + aty_ICS2595_put1bit(program_bits & 1, info); + program_bits >>= 1; + } + + udelay(1000); /* delay for 1 ms */ + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE, + info); + + udelay(50000); /* delay for 50 (15) ms */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, + ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info); + + return; +} + + +static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / period_in_ps; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xFF; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x40; } - return -EINVAL; + + temp = (unsigned int)mhz100; + temp = (unsigned int)(temp * (MIN_N_408 + 2)); + temp -= ((short)(mach64RefFreq << 1)); + + tempA = MIN_N_408; + preRemainder = 0xFFFF; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x3f; + divider |= tempA; + divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8); + } + temp += mhz100; + tempA++; + } while(tempA <= 32); + + program_bits = divider; + } + + pll->program_bits = program_bits; + pll->locationAddr = 0; + pll->post_divider = divider; /* fuer nix */ + pll->period_in_ps = period_in_ps; + + return 0; +} + +static u32 aty_pll_408_to_var(const struct pll_18818 *pll) +{ + return(pll->period_in_ps); /* default for now */ +} + +static void aty_set_pll_408(const struct fb_info_aty *info, + const struct pll_18818 *pll) +{ + u32 program_bits; + u32 locationAddr; + + u8 tmpA, tmpB, tmpC; + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->program_bits; + locationAddr = pll->locationAddr; + + /* Program clock */ + aty_dac_waste4(info); + tmpB = aty_ld_8(DAC_REGS + 2, info) | 1; + aty_dac_waste4(info); + aty_st_8(DAC_REGS + 2, tmpB, info); + + tmpA = tmpB; + tmpC = tmpA; + tmpA |= 8; + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + udelay(400); /* delay for 400 us */ + + locationAddr = (locationAddr << 2) + 0x40; + tmpB = locationAddr; + tmpA = program_bits >> 8; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + tmpB = locationAddr + 1; + tmpA = (u8)program_bits; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + tmpB = locationAddr + 2; + tmpA = 0x77; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + udelay(400); /* delay for 400 us */ + tmpA = tmpC & (~(1 | 8)); + tmpB = 1; + + aty_st_8(DAC_REGS, tmpB, info); + aty_st_8(DAC_REGS + 2, tmpA, info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + + +static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll) +{ + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u32 temp, tempB; + u16 remainder, preRemainder; + short divider = 0, tempA; + + /* Calculate the programming word */ + mhz100 = 100000000 / period_in_ps; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + divider = 0; + while (mhz100 < (mach64MinFreq << 3)) { + mhz100 <<= 1; + divider += 0x20; + } + + temp = (unsigned int)(mhz100); + temp = (unsigned int)(temp * (MIN_N_1703 + 2)); + temp -= (short)(mach64RefFreq << 1); + + tempA = MIN_N_1703; + preRemainder = 0xffff; + + do { + tempB = temp; + remainder = tempB % mach64RefFreq; + tempB = tempB / mach64RefFreq; + + if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) { + preRemainder = remainder; + divider &= ~0x1f; + divider |= tempA; + divider = (divider & 0x00ff) + ((tempB & 0xff) << 8); + } + + temp += mhz100; + tempA++; + } while (tempA <= (MIN_N_1703 << 1)); + + program_bits = divider; + } + + pll->program_bits = program_bits; + pll->locationAddr = 0; + pll->post_divider = divider; /* fuer nix */ + pll->period_in_ps = period_in_ps; + + return 0; +} + +static u32 aty_pll_1703_to_var(const struct pll_18818 *pll) +{ + return(pll->period_in_ps); /* default for now */ +} + +static void aty_set_pll_1703(const struct fb_info_aty *info, + const struct pll_18818 *pll) +{ + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->program_bits; + locationAddr = pll->locationAddr; + + /* Program clock */ + aty_dac_waste4(info); + + (void)aty_ld_8(DAC_REGS + 2, info); + aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info); + aty_st_8(DAC_REGS+2, 0, info); + aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info); + aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + + +static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll) +{ + + u32 tempA, tempB, fOut, longMHz100, diff, preDiff; + + u32 mhz100; /* in 0.01 MHz */ + u32 program_bits; + /* u32 post_divider; */ + u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; + u16 m, n, k=0, save_m, save_n, twoToKth; + + /* Calculate the programming word */ + mhz100 = 100000000 / period_in_ps; + mach64MinFreq = MIN_FREQ_2595; + mach64MaxFreq = MAX_FREQ_2595; + mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ + + save_m = 0; + save_n = 0; + + /* Calculate program word */ + if (mhz100 == 0) + program_bits = 0xE0; + else + { + if (mhz100 < mach64MinFreq) + mhz100 = mach64MinFreq; + if (mhz100 > mach64MaxFreq) + mhz100 = mach64MaxFreq; + + longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */ + + while (mhz100 < (mach64MinFreq << 3)) + { + mhz100 <<= 1; + k++; + } + + twoToKth = 1 << k; + diff = 0; + preDiff = 0xFFFFFFFF; + + for (m = MIN_M; m <= MAX_M; m++) + { + for (n = MIN_N; n <= MAX_N; n++) + { + tempA = (14.31818 * 65536); + tempA *= (n + 8); /* 43..256 */ + tempB = twoToKth * 256; + tempB *= (m + 2); /* 4..32 */ + fOut = tempA / tempB; /* 8 bit scale */ + + if (longMHz100 > fOut) + diff = longMHz100 - fOut; + else + diff = fOut - longMHz100; + + if (diff < preDiff) + { + save_m = m; + save_n = n; + preDiff = diff; + } + } + } + + program_bits = (k << 6) + (save_m) + (save_n << 8); + } + + pll->program_bits = program_bits; + pll->locationAddr = 0; + pll->post_divider = 0; + pll->period_in_ps = period_in_ps; + + return 0; +} + +static u32 aty_pll_8398_to_var(const struct pll_18818 *pll) +{ + return(pll->period_in_ps); /* default for now */ } +static void aty_set_pll_8398(const struct fb_info_aty *info, + const struct pll_18818 *pll) +{ + u32 program_bits; + u32 locationAddr; + + char old_crtc_ext_disp; + char tmp; + + old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), + info); + + program_bits = pll->program_bits; + locationAddr = pll->locationAddr; + + /* Program clock */ + tmp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); + + aty_st_8(DAC_REGS, locationAddr, info); + aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info); + aty_st_8(DAC_REGS+1, (program_bits & 0xff), info); + + tmp = aty_ld_8(DAC_CNTL, info); + aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); + + (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ + aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); + + return; +} + + static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll) { /* @@ -1474,7 +2077,42 @@ static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll) return -EINVAL; } - /* FIXME: ATI18818?? */ + +static void aty_StrobeClock(const struct fb_info_aty *info) +{ + u8 tmp; + + udelay(26); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info); + + return; +} + + +static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info) +{ + u8 tmp; + + data &= 0x01; + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2), + info); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info); + + aty_StrobeClock(info); + + tmp = aty_ld_8(CLOCK_CNTL, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info); + + aty_StrobeClock(info); + + return; +} + static u32 aty_pll_gx_to_var(const struct pll_gx *pll, const struct fb_info_aty *info) @@ -1720,27 +2358,76 @@ static void atyfb_set_par(const struct atyfb_par *par, struct fb_info_aty *info) { u32 i; + int accelmode; + int muxmode; + u8 tmp; + + accelmode = par->accel_flags; /* hack */ info->current_par = *par; if (info->blitter_may_be_busy) wait_for_idle(info); + tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_set_crtc(info, &par->crtc); - aty_st_8(CLOCK_CNTL, 0, info); - aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info); + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); + /* better call aty_StrobeClock ?? */ + aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info); if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) { - switch (info->dac_type) { + switch (info->dac_subtype) { case DAC_IBMRGB514: aty_set_dac_514(info, par->crtc.bpp); break; case DAC_ATI68860_B: - /* FIXME */ + case DAC_ATI68860_C: + muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp, + accelmode); + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x47052100, info); break; - } - aty_set_pll_gx(info, &par->pll.gx); + case DAC_ATT20C408: + muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, + par->crtc.bpp); + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x00072000, info); + break; + case DAC_ATT21C498: + muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595, + par->crtc.bpp); + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x00072000, info); + break; + default: + printk(" atyfb_set_par: DAC type not implemented yet!\n"); + aty_st_le32(BUS_CNTL, 0x890e20f1, info); + aty_st_le32(DAC_CNTL, 0x47052100, info); + /* new in 2.2.3p1 from Geert. ???????? */ aty_st_le32(BUS_CNTL, 0x590e10ff, info); aty_st_le32(DAC_CNTL, 0x47012100, info); + break; + } + + switch (info->clk_type) { + case CLK_ATI18818_1: + aty_set_pll18818(info, &par->pll.ics2595); + break; + case CLK_STG1703: + aty_set_pll_1703(info, &par->pll.ics2595); + break; + case CLK_CH8398: + aty_set_pll_8398(info, &par->pll.ics2595); + break; + case CLK_ATT20C408: + aty_set_pll_408(info, &par->pll.ics2595); + break; + case CLK_IBMRGB514: + aty_set_pll_gx(info, &par->pll.gx); + break; + default: + printk(" atyfb_set_par: CLK type not implemented yet!"); + break; + } /* Don't forget MEM_CNTL */ i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; @@ -1828,7 +2515,16 @@ static int atyfb_decode_var(const struct fb_var_screeninfo *var, if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) switch (info->clk_type) { case CLK_ATI18818_1: - err = aty_var_to_pll_18818(var->pixclock, &par->pll.gx); + err = aty_var_to_pll_18818(var->pixclock, &par->pll.ics2595); + break; + case CLK_STG1703: + err = aty_var_to_pll_1703(var->pixclock, &par->pll.ics2595); + break; + case CLK_CH8398: + err = aty_var_to_pll_8398(var->pixclock, &par->pll.ics2595); + break; + case CLK_ATT20C408: + err = aty_var_to_pll_408(var->pixclock, &par->pll.ics2595); break; case CLK_IBMRGB514: err = aty_var_to_pll_514(var->pixclock, &par->pll.gx); @@ -1864,7 +2560,23 @@ static int atyfb_encode_var(struct fb_var_screeninfo *var, if ((err = aty_crtc_to_var(&par->crtc, var))) return err; if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) - var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info); + switch (info->clk_type) { + case CLK_ATI18818_1: + var->pixclock = aty_pll_18818_to_var(&par->pll.ics2595); + break; + case CLK_STG1703: + var->pixclock = aty_pll_1703_to_var(&par->pll.ics2595); + break; + case CLK_CH8398: + var->pixclock = aty_pll_8398_to_var(&par->pll.ics2595); + break; + case CLK_ATT20C408: + var->pixclock = aty_pll_408_to_var(&par->pll.ics2595); + break; + case CLK_IBMRGB514: + var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info); + break; + } else var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info); @@ -2234,7 +2946,9 @@ struct atyclk { static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info2) { +#if defined(__sparc__) || defined(DEBUG) struct fb_info_aty *info = (struct fb_info_aty *)info2; +#endif /* __sparc__ || DEBUG */ #ifdef __sparc__ struct fbtype fbtyp; struct display *disp; @@ -2540,6 +3254,7 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++) if (aty_features[j].chip_type == Gx) { chipname = aty_features[j].name; + info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07; break; } if (!chipname) { @@ -2553,10 +3268,16 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) ramname = aty_gx_ram[info->ram_type]; /* FIXME: clockchip/RAMDAC probing? */ #ifdef CONFIG_ATARI - info->dac_type = DAC_ATI68860_B; info->clk_type = CLK_ATI18818_1; + info->dac_type = (aty_ld_le32(CONFIG_STAT0, info) >> 9) & 0x07; + if (info->dac_type == 0x07) + info->dac_subtype = DAC_ATT20C408; + else + info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | + info->dac_type; #else info->dac_type = DAC_IBMRGB514; + info->dac_subtype = DAC_IBMRGB514; info->clk_type = CLK_IBMRGB514; #endif /* FIXME */ @@ -2567,6 +3288,7 @@ static int __init aty_init(struct fb_info_aty *info, const char *name) info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); ramname = aty_ct_ram[info->ram_type]; info->dac_type = DAC_INTERNAL; + info->dac_subtype = DAC_INTERNAL; info->clk_type = CLK_INTERNAL; if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) { pll = 135; @@ -3175,7 +3897,9 @@ int __init atyfb_init(void) #endif /* __sparc__ */ } } + #elif defined(CONFIG_ATARI) + u32 clock_r; int m64_num; struct fb_info_aty *info; @@ -3199,9 +3923,27 @@ int __init atyfb_init(void) * kernel address space. */ info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); - info->frame_buffer_phys = info->frame_buffer; + info->frame_buffer_phys = info->frame_buffer; /* Fake! */ info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; - info->ati_regbase_phys = info->ati_regbase; + info->ati_regbase_phys = info->ati_regbase; /* Fake! */ + + aty_st_le32(CLOCK_CNTL, 0x12345678, info); + clock_r = aty_ld_le32(CLOCK_CNTL, info); + + switch (clock_r & 0x003F) { + case 0x12: + info->clk_wr_offset = 3; /* */ + break; + case 0x34: + info->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ + break; + case 0x16: + info->clk_wr_offset = 1; /* */ + break; + case 0x38: + info->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ + break; + } if (!aty_init(info, "ISA bus")) { kfree(info); @@ -3209,7 +3951,7 @@ int __init atyfb_init(void) return -ENXIO; } } -#endif +#endif /* CONFIG_ATARI */ return 0; } diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c index 56cc9d6c3..4b0ffb0ad 100644 --- a/drivers/video/matroxfb.c +++ b/drivers/video/matroxfb.c @@ -111,9 +111,9 @@ #include #include #include +#include #include -#include #include #ifdef CONFIG_MTRR #include diff --git a/drivers/video/p9100fb.c b/drivers/video/p9100fb.c index 8647d2082..e53543911 100644 --- a/drivers/video/p9100fb.c +++ b/drivers/video/p9100fb.c @@ -31,8 +31,9 @@ static struct sbus_mmap_map p9100_mmap_map[] = { { P9100_CTL_OFF, 0x38000000, 0x2000 }, { P9100_CMD_OFF, 0x38002000, 0x2000 }, { P9100_FB_OFF, 0x38800000, 0x200000 }, -#else { CG3_MMAP_OFFSET, 0x38800000, SBUS_MMAP_FBSIZE(1) }, +#else + { CG3_MMAP_OFFSET, 0x0, SBUS_MMAP_FBSIZE(1) }, #endif { 0, 0, 0 } }; @@ -79,22 +80,6 @@ static void p9100_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int in _READCTL(pwrup_cfg, tmp); WRITECTL(ramdac_palette_data, (fb->color_map CM(i,2) << 16)); } -#if 0 - printk("updating %d colors starting at %d\n", count, index); - - WRITECTL(ramdac_palette_rdaddr, index); - for (i = index; count--; i++){ - _READCTL(pwrup_cfg, tmp); - READCTL(ramdac_palette_data, tmp); - printk("%d: red %x ", i, tmp); - _READCTL(pwrup_cfg, tmp); - READCTL(ramdac_palette_data, tmp); - printk("green %x ", tmp); - _READCTL(pwrup_cfg, tmp); - READCTL(ramdac_palette_data, tmp); - printk("blue %x\n", tmp); - } -#endif } static void p9100_blank (struct fb_info_sbusfb *fb) @@ -121,7 +106,7 @@ static void p9100_margins (struct fb_info_sbusfb *fb, struct display *p, int x_m static char idstring[60] __initdata = { 0 }; -char * __init p9100fb_init(struct fb_info_sbusfb *fb) +__initfunc(char *p9100fb_init(struct fb_info_sbusfb *fb)) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; @@ -140,7 +125,8 @@ char * __init p9100fb_init(struct fb_info_sbusfb *fb) if (!fb->s.p9100.ctrl) { fb->s.p9100.ctrl = (struct p9100_ctrl *) - sparc_alloc_io(fb->sbdp->reg_addrs[0].phys_addr, 0, fb->sbdp->reg_addrs[1].reg_size, "p9100_ctrl", fb->iospace, 0); + sparc_alloc_io(fb->sbdp->reg_addrs[0].phys_addr, 0, + fb->sbdp->reg_addrs[1].reg_size, "p9100_ctrl", fb->iospace, 0); } strcpy(fb->info.modename, "p9100"); diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c index d34da063e..aafa04542 100644 --- a/drivers/video/sbusfb.c +++ b/drivers/video/sbusfb.c @@ -1088,7 +1088,8 @@ sizechange: #endif #ifdef CONFIG_FB_P9100 case FBTYPE_P9100COLOR: - p = p9100fb_init(fb); break; + /* Temporary crock. For now we are a cg3 */ + p = p9100fb_init(fb); type->fb_type = FBTYPE_SUN3COLOR; break; #endif } diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index fd55f6448..6143bd5d0 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include /* * We should make this work with a "stub-only" /proc, diff --git a/fs/pipe.c b/fs/pipe.c index 8373584bd..7cdd2b394 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -59,37 +59,32 @@ pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) if (count == 0) goto out_nolock; - /* Grab, or try to grab, the pipe's semaphore with data present. */ - if (filp->f_flags & O_NONBLOCK) { + /* Get the pipe semaphore */ + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + + if (PIPE_EMPTY(*inode)) { + ret = 0; + if (!PIPE_WRITERS(*inode)) + goto out; + ret = -EAGAIN; - if (down_trylock(PIPE_SEM(*inode))) - goto out_nolock; - ret = PIPE_WRITERS(*inode) ? -EAGAIN : 0; - if (PIPE_EMPTY(*inode)) + if (filp->f_flags & O_NONBLOCK) goto out; - } else { - ret = -ERESTARTSYS; - if (down_interruptible(PIPE_SEM(*inode))) - goto out_nolock; - if (PIPE_EMPTY(*inode)) { + for (;;) { + pipe_wait(inode); + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out_nolock; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; ret = 0; + if (!PIPE_EMPTY(*inode)) + break; if (!PIPE_WRITERS(*inode)) goto out; - - for (;;) { - pipe_wait(inode); - ret = -ERESTARTSYS; - if (signal_pending(current)) - goto out_nolock; - if (down_interruptible(PIPE_SEM(*inode))) - goto out_nolock; - ret = 0; - if (!PIPE_EMPTY(*inode)) - break; - if (!PIPE_WRITERS(*inode)) - goto out; - } } } diff --git a/fs/udf/file.c b/fs/udf/file.c index d34ed9242..282466841 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -168,15 +168,12 @@ static long long udf_file_llseek(struct file * file, long long offset, int origi break; } } +#if BITS_PER_LONG < 64 if (((unsigned long long) offset >> 32) != 0) { -#if BITS_PER_LONG < 64 return -EINVAL; -#else - if (offset > ???) - return -EINVAL; -#endif } +#endif if (offset != file->f_pos) { file->f_pos = offset; diff --git a/fs/udf/super.c b/fs/udf/super.c index e1a60833a..c6ff2c6e2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -183,7 +183,7 @@ int __init init_udf_fs(void) int size; size = sizeof(struct super_block) + - (int)&sb.u - (int)&sb; + (long)&sb.u - (long)&sb; if ( size < sizeof(struct udf_sb_info) ) { printk(KERN_ERR "udf: Danger! Kernel was compiled without enough room for udf_sb_info\n"); diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h index c6df87026..906a619bc 100644 --- a/fs/udf/udfend.h +++ b/fs/udf/udfend.h @@ -46,6 +46,10 @@ #endif +#ifdef __KERNEL__ +#include +#endif + static inline lb_addr lelb_to_cpu(lb_addr in) { lb_addr out; diff --git a/include/asm-alpha/dma.h b/include/asm-alpha/dma.h index ed0ac8cc5..28762e674 100644 --- a/include/asm-alpha/dma.h +++ b/include/asm-alpha/dma.h @@ -19,8 +19,8 @@ #define _ASM_DMA_H #include +#include #include -#include #define dma_outb outb #define dma_inb inb diff --git a/include/asm-alpha/hardirq.h b/include/asm-alpha/hardirq.h index a8e5023d0..31cdbac06 100644 --- a/include/asm-alpha/hardirq.h +++ b/include/asm-alpha/hardirq.h @@ -36,7 +36,7 @@ extern int __local_irq_count; #else #include -#include +#include #include extern int global_irq_holder; diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index 0082f4bc2..004924b93 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -9,12 +9,12 @@ * in (currently 8192). */ #include +#include /* For the task lock */ #include #include /* For TASK_SIZE */ #include #include -#include /* For the task lock */ /* Caches aren't brain-dead on the Alpha. */ diff --git a/include/asm-alpha/smplock.h b/include/asm-alpha/smplock.h index a33fd546a..2a5c62700 100644 --- a/include/asm-alpha/smplock.h +++ b/include/asm-alpha/smplock.h @@ -6,7 +6,7 @@ #include #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h index 73c4701ed..6153b2a86 100644 --- a/include/asm-alpha/spinlock.h +++ b/include/asm-alpha/spinlock.h @@ -2,103 +2,6 @@ #define _ALPHA_SPINLOCK_H #include - -/* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. - */ -#define spin_lock_irqsave(lock, flags) \ - do { local_irq_save(flags); spin_lock(lock); } while (0) -#define spin_lock_irq(lock) \ - do { local_irq_disable(); spin_lock(lock); } while (0) -#define spin_lock_bh(lock) \ - do { local_bh_disable(); spin_lock(lock); } while (0) - -#define read_lock_irqsave(lock, flags) \ - do { local_irq_save(flags); read_lock(lock); } while (0) -#define read_lock_irq(lock) \ - do { local_irq_disable(); read_lock(lock); } while (0) -#define read_lock_bh(lock) \ - do { local_bh_disable(); read_lock(lock); } while (0) - -#define write_lock_irqsave(lock, flags) \ - do { local_irq_save(flags); write_lock(lock); } while (0) -#define write_lock_irq(lock) \ - do { local_irq_disable(); write_lock(lock); } while (0) -#define write_lock_bh(lock) \ - do { local_bh_disable(); write_lock(lock); } while (0) - -#define spin_unlock_irqrestore(lock, flags) \ - do { spin_unlock(lock); local_irq_restore(flags); } while (0) -#define spin_unlock_irq(lock) \ - do { spin_unlock(lock); local_irq_enable(); } while (0) -#define spin_unlock_bh(lock) \ - do { spin_unlock(lock); local_bh_enable(); } while (0) - -#define read_unlock_irqrestore(lock, flags) \ - do { read_unlock(lock); local_irq_restore(flags); } while (0) -#define read_unlock_irq(lock) \ - do { read_unlock(lock); local_irq_enable(); } while (0) -#define read_unlock_bh(lock) \ - do { read_unlock(lock); local_bh_enable(); } while (0) - -#define write_unlock_irqrestore(lock, flags) \ - do { write_unlock(lock); local_irq_restore(flags); } while (0) -#define write_unlock_irq(lock) \ - do { write_unlock(lock); local_irq_enable(); } while (0) -#define write_unlock_bh(lock) \ - do { write_unlock(lock); local_bh_enable(); } while (0) - -#ifndef __SMP__ - -/* - * Your basic spinlocks, allowing only a single CPU anywhere - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - 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 - -#define spin_lock_init(lock) ((void)(lock)) -#define spin_lock(lock) ((void)(lock)) -#define spin_trylock(lock) ((void)(lock), 1) -#define spin_unlock_wait(lock) ((void)(lock)) -#define spin_unlock(lock) ((void)(lock)) -#define spin_is_locked(lock) ((void)(lock), 0) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { } -#else - typedef struct { int gcc_is_buggy; } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#endif - -#define read_lock(lock) ((void)(lock)) -#define read_unlock(lock) ((void)(lock)) -#define write_lock(lock) ((void)(lock)) -#define write_unlock(lock) ((void)(lock)) - -#else /* __SMP__ */ - #include #include @@ -264,5 +167,4 @@ static inline void read_unlock(rwlock_t * lock) : "m" (__dummy_lock(lock))); } -#endif /* SMP */ #endif /* _ALPHA_SPINLOCK_H */ diff --git a/include/asm-arm/dma.h b/include/asm-arm/dma.h index 3d53a4106..b67e33a9d 100644 --- a/include/asm-arm/dma.h +++ b/include/asm-arm/dma.h @@ -5,8 +5,8 @@ typedef unsigned int dmach_t; #include #include +#include #include -#include #include /* diff --git a/include/asm-arm/semaphore.h b/include/asm-arm/semaphore.h index 30d7ffba9..71509e9e8 100644 --- a/include/asm-arm/semaphore.h +++ b/include/asm-arm/semaphore.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include struct semaphore { diff --git a/include/asm-arm/smplock.h b/include/asm-arm/smplock.h index e62326a10..1590fafe9 100644 --- a/include/asm-arm/smplock.h +++ b/include/asm-arm/smplock.h @@ -4,7 +4,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-arm/spinlock.h b/include/asm-arm/spinlock.h dissimilarity index 98% index 98d277259..e92e81deb 100644 --- a/include/asm-arm/spinlock.h +++ b/include/asm-arm/spinlock.h @@ -1,116 +1,6 @@ -#ifndef __ASM_SPINLOCK_H -#define __ASM_SPINLOCK_H - -/* - * To be safe, we assume the only compiler that can cope with - * empty initialisers is EGCS. - */ -#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 90)) -#define EMPTY_STRUCT struct { } -#define EMPTY_STRUCT_INIT(t) (t) { } -#else -#define EMPTY_STRUCT unsigned char -#define EMPTY_STRUCT_INIT(t) (t) 0 -#endif - -/* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. - */ -#define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) -#define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) -#define spin_lock_bh(lock) do { local_bh_disable(); spin_lock(lock); } while (0) - -#define read_lock_irqsave(lock, flags) do { local_irq_save(flags); read_lock(lock); } while (0) -#define read_lock_irq(lock) do { local_irq_disable(); read_lock(lock); } while (0) -#define read_lock_bh(lock) do { local_bh_disable(); read_lock(lock); } while (0) - -#define write_lock_irqsave(lock, flags) do { local_irq_save(flags); write_lock(lock); } while (0) -#define write_lock_irq(lock) do { local_irq_disable(); write_lock(lock); } while (0) -#define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while (0) - -#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock); local_irq_restore(flags); } while (0) -#define spin_unlock_irq(lock) do { spin_unlock(lock); local_irq_enable(); } while (0) -#define spin_unlock_bh(lock) do { spin_unlock(lock); local_bh_enable(); } while (0) - -#define read_unlock_irqrestore(lock, flags) do { read_unlock(lock); local_irq_restore(flags); } while (0) -#define read_unlock_irq(lock) do { read_unlock(lock); local_irq_enable(); } while (0) -#define read_unlock_bh(lock) do { read_unlock(lock); local_bh_enable(); } while (0) - -#define write_unlock_irqrestore(lock, flags) do { write_unlock(lock); local_irq_restore(flags); } while (0) -#define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0) -#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0) - -#ifndef __SMP__ - -#define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debugging */ - -#if (DEBUG_SPINLOCKS < 1) -/* - * Your basic spinlocks, allowing only a single CPU anywhere - */ -typedef EMPTY_STRUCT spinlock_t; -#define SPIN_LOCK_UNLOCKED EMPTY_STRUCT_INIT(spinlock_t) - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) - -#elif (DEBUG_SPINLOCKS < 2) - -typedef struct { - volatile unsigned int lock; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (pinlock_t) { 0 } - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_lock(x) do { (x)->lock = 1; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) -#define spin_unlock_wait(x) do { } while (0) -#define spin_unlock(x) do { (x)->lock = 0; } while (0) - -#else /* (DEBUG_SPINLOCKS >= 2) */ - -typedef struct { - volatule unsigned int lock; - volatile unsigned int babble; - const char *module; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ } - -#include - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0) -#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0) -#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0) - -#endif - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef EMPTY_STRUCT rwlock_t; -#define RW_LOCK_UNLOCKED EMPTY_STRUCT_INIT(rwlock_t) - -#define read_lock(lock) (void)(lock) /* Not "unused variable". */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Not "unused variable". */ -#define write_unlock(lock) do { } while(0) - -#else -#error ARM architecture does not support spin locks -#endif /* SMP */ -#endif /* __ASM_SPINLOCK_H */ +#ifndef __ASM_SPINLOCK_H +#define __ASM_SPINLOCK_H + +#error ARM architecture does not support SMP spin locks + +#endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-generic/smplock.h b/include/asm-generic/smplock.h index e62326a10..1590fafe9 100644 --- a/include/asm-generic/smplock.h +++ b/include/asm-generic/smplock.h @@ -4,7 +4,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-i386/dma.h b/include/asm-i386/dma.h index cdd66df13..1bc9899b2 100644 --- a/include/asm-i386/dma.h +++ b/include/asm-i386/dma.h @@ -9,8 +9,8 @@ #define _ASM_DMA_H #include +#include /* And spinlocks */ #include /* need byte IO */ -#include /* And spinlocks */ #include diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index bd51aa843..3997b2aae 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include struct semaphore { diff --git a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h index 4d44a2919..152c1a9fa 100644 --- a/include/asm-i386/smplock.h +++ b/include/asm-i386/smplock.h @@ -4,7 +4,7 @@ * i386 SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h dissimilarity index 66% index d3e9fc744..f8254a492 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -1,225 +1,109 @@ -#ifndef __ASM_SPINLOCK_H -#define __ASM_SPINLOCK_H - -/* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. - */ -#define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) -#define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) -#define spin_lock_bh(lock) do { local_bh_disable(); spin_lock(lock); } while (0) - -#define read_lock_irqsave(lock, flags) do { local_irq_save(flags); read_lock(lock); } while (0) -#define read_lock_irq(lock) do { local_irq_disable(); read_lock(lock); } while (0) -#define read_lock_bh(lock) do { local_bh_disable(); read_lock(lock); } while (0) - -#define write_lock_irqsave(lock, flags) do { local_irq_save(flags); write_lock(lock); } while (0) -#define write_lock_irq(lock) do { local_irq_disable(); write_lock(lock); } while (0) -#define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while (0) - -#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock); local_irq_restore(flags); } while (0) -#define spin_unlock_irq(lock) do { spin_unlock(lock); local_irq_enable(); } while (0) -#define spin_unlock_bh(lock) do { spin_unlock(lock); local_bh_enable(); } while (0) - -#define read_unlock_irqrestore(lock, flags) do { read_unlock(lock); local_irq_restore(flags); } while (0) -#define read_unlock_irq(lock) do { read_unlock(lock); local_irq_enable(); } while (0) -#define read_unlock_bh(lock) do { read_unlock(lock); local_bh_enable(); } while (0) - -#define write_unlock_irqrestore(lock, flags) do { write_unlock(lock); local_irq_restore(flags); } while (0) -#define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0) -#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0) - -#ifndef __SMP__ - -#define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ - -#if (DEBUG_SPINLOCKS < 1) - -/* - * Your basic spinlocks, allowing only a single CPU anywhere - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - 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 - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) - -#elif (DEBUG_SPINLOCKS < 2) - -typedef struct { - volatile unsigned int lock; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do { (x)->lock = 1; } while (0) -#define spin_unlock_wait(x) do { } while (0) -#define spin_unlock(x) do { (x)->lock = 0; } while (0) - -#else /* (DEBUG_SPINLOCKS >= 2) */ - -typedef struct { - volatile unsigned int lock; - volatile unsigned int babble; - const char *module; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ } - -#include - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0) -#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0) -#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0) - -#endif /* DEBUG_SPINLOCKS */ - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { } -#else - typedef struct { int gcc_is_buggy; } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#endif - -#define read_lock(lock) (void)(lock) /* Not "unused variable". */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Not "unused variable". */ -#define write_unlock(lock) do { } while(0) - -#else /* __SMP__ */ - -/* - * Your basic spinlocks, allowing only a single CPU anywhere - */ - -typedef struct { - volatile unsigned int lock; -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(x) do { (x)->lock = 0; } while(0) -/* - * Simple spin lock operations. There are two variants, one clears IRQ's - * on the local processor, one does not. - * - * We make no fairness assumptions. They have a cost. - */ - -#define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock) - -typedef struct { unsigned long a[100]; } __dummy_lock_t; -#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) - -#define spin_lock_string \ - "\n1:\t" \ - "lock ; btsl $0,%0\n\t" \ - "jc 2f\n" \ - ".section .text.lock,\"ax\"\n" \ - "2:\t" \ - "testb $1,%0\n\t" \ - "jne 2b\n\t" \ - "jmp 1b\n" \ - ".previous" - -#define spin_unlock_string \ - "lock ; btrl $0,%0" - -#define spin_lock(lock) \ -__asm__ __volatile__( \ - spin_lock_string \ - :"=m" (__dummy_lock(lock))) - -#define spin_unlock(lock) \ -__asm__ __volatile__( \ - spin_unlock_string \ - :"=m" (__dummy_lock(lock))) - -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { - volatile unsigned int lock; - unsigned long previous; -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } - -/* - * On x86, we implement read-write locks as a 32-bit counter - * with the high bit (sign) being the "write" bit. - * - * The inline assembly is non-obvious. Think about it. - */ -#define read_lock(rw) \ - asm volatile("\n1:\t" \ - "lock ; incl %0\n\t" \ - "js 2f\n" \ - ".section .text.lock,\"ax\"\n" \ - "2:\tlock ; decl %0\n" \ - "3:\tcmpl $0,%0\n\t" \ - "js 3b\n\t" \ - "jmp 1b\n" \ - ".previous" \ - :"=m" (__dummy_lock(&(rw)->lock))) - -#define read_unlock(rw) \ - asm volatile("lock ; decl %0" \ - :"=m" (__dummy_lock(&(rw)->lock))) - -#define write_lock(rw) \ - asm volatile("\n1:\t" \ - "lock ; btsl $31,%0\n\t" \ - "jc 4f\n" \ - "2:\ttestl $0x7fffffff,%0\n\t" \ - "jne 3f\n" \ - ".section .text.lock,\"ax\"\n" \ - "3:\tlock ; btrl $31,%0\n" \ - "4:\tcmp $0,%0\n\t" \ - "jne 4b\n\t" \ - "jmp 1b\n" \ - ".previous" \ - :"=m" (__dummy_lock(&(rw)->lock))) - -#define write_unlock(rw) \ - asm volatile("lock ; btrl $31,%0":"=m" (__dummy_lock(&(rw)->lock))) - -#endif /* __SMP__ */ -#endif /* __ASM_SPINLOCK_H */ +#ifndef __ASM_SPINLOCK_H +#define __ASM_SPINLOCK_H + +/* + * Your basic SMP spinlocks, allowing only a single CPU anywhere + */ + +typedef struct { + volatile unsigned int lock; +} spinlock_t; + +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } + +#define spin_lock_init(x) do { (x)->lock = 0; } while(0) +/* + * Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ + +#define spin_unlock_wait(x) do { barrier(); } while(((volatile spinlock_t *)(x))->lock) + +typedef struct { unsigned long a[100]; } __dummy_lock_t; +#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) + +#define spin_lock_string \ + "\n1:\t" \ + "lock ; btsl $0,%0\n\t" \ + "jc 2f\n" \ + ".section .text.lock,\"ax\"\n" \ + "2:\t" \ + "testb $1,%0\n\t" \ + "jne 2b\n\t" \ + "jmp 1b\n" \ + ".previous" + +#define spin_unlock_string \ + "lock ; btrl $0,%0" + +#define spin_lock(lock) \ +__asm__ __volatile__( \ + spin_lock_string \ + :"=m" (__dummy_lock(lock))) + +#define spin_unlock(lock) \ +__asm__ __volatile__( \ + spin_unlock_string \ + :"=m" (__dummy_lock(lock))) + +#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) + +/* + * Read-write spinlocks, allowing multiple readers + * but only one writer. + * + * NOTE! it is quite common to have readers in interrupts + * but no interrupt writers. For those circumstances we + * can "mix" irq-safe locks - any writer needs to get a + * irq-safe write-lock, but readers can get non-irqsafe + * read-locks. + */ +typedef struct { + volatile unsigned int lock; + unsigned long previous; +} rwlock_t; + +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } + +/* + * On x86, we implement read-write locks as a 32-bit counter + * with the high bit (sign) being the "write" bit. + * + * The inline assembly is non-obvious. Think about it. + */ +#define read_lock(rw) \ + asm volatile("\n1:\t" \ + "lock ; incl %0\n\t" \ + "js 2f\n" \ + ".section .text.lock,\"ax\"\n" \ + "2:\tlock ; decl %0\n" \ + "3:\tcmpl $0,%0\n\t" \ + "js 3b\n\t" \ + "jmp 1b\n" \ + ".previous" \ + :"=m" (__dummy_lock(&(rw)->lock))) + +#define read_unlock(rw) \ + asm volatile("lock ; decl %0" \ + :"=m" (__dummy_lock(&(rw)->lock))) + +#define write_lock(rw) \ + asm volatile("\n1:\t" \ + "lock ; btsl $31,%0\n\t" \ + "jc 4f\n" \ + "2:\ttestl $0x7fffffff,%0\n\t" \ + "jne 3f\n" \ + ".section .text.lock,\"ax\"\n" \ + "3:\tlock ; btrl $31,%0\n" \ + "4:\tcmp $0,%0\n\t" \ + "jne 4b\n\t" \ + "jmp 1b\n" \ + ".previous" \ + :"=m" (__dummy_lock(&(rw)->lock))) + +#define write_unlock(rw) \ + asm volatile("lock ; btrl $31,%0":"=m" (__dummy_lock(&(rw)->lock))) + +#endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h index c194bdb84..cb4f38230 100644 --- a/include/asm-m68k/semaphore.h +++ b/include/asm-m68k/semaphore.h @@ -3,10 +3,10 @@ #include #include +#include #include #include -#include /* * SMP- and interrupt-safe semaphores.. diff --git a/include/asm-m68k/smplock.h b/include/asm-m68k/smplock.h index e62326a10..1590fafe9 100644 --- a/include/asm-m68k/smplock.h +++ b/include/asm-m68k/smplock.h @@ -4,7 +4,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-m68k/spinlock.h b/include/asm-m68k/spinlock.h dissimilarity index 97% index dc4f55b2a..fec148175 100644 --- a/include/asm-m68k/spinlock.h +++ b/include/asm-m68k/spinlock.h @@ -1,72 +1,6 @@ -#ifndef __M68K_SPINLOCK_H -#define __M68K_SPINLOCK_H - -/* - * We don't do SMP on the m68k .... at least not yet. - */ - -/* - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) -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 - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() -#define spin_lock_bh(lock) local_bh_disable() -#define spin_unlock_bh(lock) local_bh_enable() - -#define spin_lock_irqsave(lock, flags) \ - do { save_flags(flags); cli(); } while (0) -#define spin_unlock_irqrestore(lock, flags) \ - restore_flags(flags) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { } -#else -typedef struct { int gcc_is_buggy; } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#endif - -#define read_lock(lock) (void)(lock) /* Not "unused variable". */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Not "unused variable". */ -#define write_unlock(lock) do { } while(0) -#define read_lock_irq(lock) cli() -#define read_unlock_irq(lock) sti() -#define write_lock_irq(lock) cli() -#define write_unlock_irq(lock) sti() -#define read_lock_bh(lock) local_bh_disable() -#define read_unlock_bh(lock) local_bh_enable() -#define write_lock_bh(lock) local_bh_disable() -#define write_unlock_bh(lock) local_bh_enable() - -#define read_lock_irqsave(lock, flags) save_and_cli(flags) -#define read_unlock_irqrestore(lock, flags) restore_flags(flags) -#define write_lock_irqsave(lock, flags) save_and_cli(flags) -#define write_unlock_irqrestore(lock, flags) restore_flags(flags) - -#endif +#ifndef __M68K_SPINLOCK_H +#define __M68K_SPINLOCK_H + +#error "m68k doesn't do SMP" + +#endif diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h index 95c06cdef..7f815b733 100644 --- a/include/asm-mips/dma.h +++ b/include/asm-mips/dma.h @@ -14,7 +14,7 @@ #include #include /* need byte IO */ -#include /* And spinlocks */ +#include /* And spinlocks */ #include #include diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index 4555f7873..859638f5a 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include struct semaphore { diff --git a/include/asm-mips/smplock.h b/include/asm-mips/smplock.h index 61bf3ff9c..2be6e9461 100644 --- a/include/asm-mips/smplock.h +++ b/include/asm-mips/smplock.h @@ -7,7 +7,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h dissimilarity index 94% index f26068cff..aa092a2a9 100644 --- a/include/asm-mips/spinlock.h +++ b/include/asm-mips/spinlock.h @@ -1,77 +1,8 @@ -/* $Id: spinlock.h,v 1.5 1999/06/17 13:30:39 ralf Exp $ - */ -#ifndef __ASM_MIPS_SPINLOCK_H -#define __ASM_MIPS_SPINLOCK_H - -/* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. - */ -#define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) -#define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) -#define spin_lock_bh(lock) do { local_bh_disable(); spin_lock(lock); } while (0) - -#define read_lock_irqsave(lock, flags) do { local_irq_save(flags); read_lock(lock); } while (0) -#define read_lock_irq(lock) do { local_irq_disable(); read_lock(lock); } while (0) -#define read_lock_bh(lock) do { local_bh_disable(); read_lock(lock); } while (0) - -#define write_lock_irqsave(lock, flags) do { local_irq_save(flags); write_lock(lock); } while (0) -#define write_lock_irq(lock) do { local_irq_disable(); write_lock(lock); } while (0) -#define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while (0) - -#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock); local_irq_restore(flags); } while (0) -#define spin_unlock_irq(lock) do { spin_unlock(lock); local_irq_enable(); } while (0) -#define spin_unlock_bh(lock) do { spin_unlock(lock); local_bh_enable(); } while (0) - -#define read_unlock_irqrestore(lock, flags) do { read_unlock(lock); local_irq_restore(flags); } while (0) -#define read_unlock_irq(lock) do { read_unlock(lock); local_irq_enable(); } while (0) -#define read_unlock_bh(lock) do { read_unlock(lock); local_bh_enable(); } while (0) - -#define write_unlock_irqrestore(lock, flags) do { write_unlock(lock); local_irq_restore(flags); } while (0) -#define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0) -#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0) - -#ifndef __SMP__ - -/* - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - 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 - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) do { } while(0) -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { } - -#define read_lock(lock) do { } while(0) -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) do { } while(0) -#define write_unlock(lock) do { } while(0) - -#else - -#error "Nix SMP on MIPS" - -#endif /* SMP */ -#endif /* __ASM_MIPS_SPINLOCK_H */ +/* $Id: spinlock.h,v 1.5 1999/06/17 13:30:39 ralf Exp $ + */ +#ifndef __ASM_MIPS_SPINLOCK_H +#define __ASM_MIPS_SPINLOCK_H + +#error "Nix SMP on MIPS" + +#endif /* __ASM_MIPS_SPINLOCK_H */ diff --git a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h index a236cda3f..dfd6a240b 100644 --- a/include/asm-ppc/dma.h +++ b/include/asm-ppc/dma.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include /* diff --git a/include/asm-ppc/gemini.h b/include/asm-ppc/gemini.h index 6a6f4c67d..7e681e043 100644 --- a/include/asm-ppc/gemini.h +++ b/include/asm-ppc/gemini.h @@ -160,6 +160,7 @@ static inline int gemini_processor(void) extern void _gemini_reboot(void); +extern void gemini_prom_init(void); extern void gemini_init_l2(void); #endif /* __ASSEMBLY__ */ #endif diff --git a/include/asm-ppc/gemini_serial.h b/include/asm-ppc/gemini_serial.h index de3146b15..745c24a39 100644 --- a/include/asm-ppc/gemini_serial.h +++ b/include/asm-ppc/gemini_serial.h @@ -4,14 +4,20 @@ #include #include +#ifdef CONFIG_SERIAL_MANY_PORTS +#define RS_TABLE_SIZE 64 +#else +#define RS_TABLE_SIZE 4 +#endif + /* Rate for the 24.576 Mhz clock for the onboard serial chip */ #define BASE_BAUD (24576000 / 16) #ifdef CONFIG_SERIAL_DETECT_IRQ -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) +#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ) #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ) #else -#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST) +#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST) #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF) #endif diff --git a/include/asm-ppc/init.h b/include/asm-ppc/init.h index 33402a7d8..beeb4baf9 100644 --- a/include/asm-ppc/init.h +++ b/include/asm-ppc/init.h @@ -3,7 +3,8 @@ #include -#if 0/*__GNUC__ > 2 || __GNUC_MINOR__ >= 90*/ /* egcs */ +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 90 /* egcs */ +#define __pmac __attribute__ ((__section__ (".text.pmac"))) #define __pmacdata __attribute__ ((__section__ (".data.pmac"))) #define __pmacfunc(__argpmac) \ __argpmac __pmac; \ diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h index 6ce46e87c..b868fe20b 100644 --- a/include/asm-ppc/keyboard.h +++ b/include/asm-ppc/keyboard.h @@ -28,33 +28,47 @@ static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode) { - return ppc_md.kbd_setkeycode(scancode, keycode); + if ( ppc_md.kbd_setkeycode ) + return ppc_md.kbd_setkeycode(scancode, keycode); + else + return 0; } static inline int kbd_getkeycode(unsigned int scancode) { - return ppc_md.kbd_getkeycode(scancode); + if ( ppc_md.kbd_getkeycode ) + return ppc_md.kbd_getkeycode(scancode); + else + return 0; } static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) { - return ppc_md.kbd_translate(keycode, keycodep, raw_mode); + if ( ppc_md.kbd_translate ) + return ppc_md.kbd_translate(keycode, keycodep, raw_mode); + else + return 0; } static inline int kbd_unexpected_up(unsigned char keycode) { - return ppc_md.kbd_unexpected_up(keycode); + if ( ppc_md.kbd_unexpected_up ) + return ppc_md.kbd_unexpected_up(keycode); + else + return 0; } static inline void kbd_leds(unsigned char leds) { - ppc_md.kbd_leds(leds); + if ( ppc_md.kbd_leds ) + ppc_md.kbd_leds(leds); } static inline void kbd_init_hw(void) { - ppc_md.kbd_init_hw(); + if ( ppc_md.kbd_init_hw ) + ppc_md.kbd_init_hw(); } #define kbd_sysrq_xlate (ppc_md.ppc_kbd_sysrq_xlate) diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h index dded34ac9..cd1dbe294 100644 --- a/include/asm-ppc/machdep.h +++ b/include/asm-ppc/machdep.h @@ -72,6 +72,8 @@ struct machdep_calls { int (*pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val); void (*pcibios_fixup)(void); +struct pci_bus; + void (*pcibios_fixup_bus)(struct pci_bus *); }; extern struct machdep_calls ppc_md; @@ -90,7 +92,8 @@ struct boot_info int _machine; unsigned long initrd_start, initrd_size; unsigned long systemmap_start, systemmap_size; - char reserved[3684]; /* pad to 1 page */ + unsigned long prom_entry; + char reserved[3680]; /* pad to 1 page */ unsigned long magic_end; }; struct boot_info *binfo; diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h new file mode 100644 index 000000000..d1f8eb158 --- /dev/null +++ b/include/asm-ppc/pci.h @@ -0,0 +1,10 @@ +#ifndef __PPC_PCI_H +#define __PPC_PCI_H + +/* Can be used to override the logic in pci_scan_bus for skipping + * already-configured bus numbers - to be used for buggy BIOSes + * or architectures with incomplete PCI setup by the loader. + */ +#define pcibios_assign_all_busses() 0 + +#endif /* __PPC_PCI_H */ diff --git a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h index f7b87ff0d..b73bd5961 100644 --- a/include/asm-ppc/semaphore.h +++ b/include/asm-ppc/semaphore.h @@ -1,5 +1,5 @@ -#ifndef _SPARC_SEMAPHORE_H -#define _SPARC_SEMAPHORE_H +#ifndef _PPC_SEMAPHORE_H +#define _PPC_SEMAPHORE_H /* * Swiped from asm-sparc/semaphore.h and modified @@ -104,4 +104,4 @@ extern inline void up(struct semaphore * sem) #endif /* __KERNEL__ */ -#endif /* !(_SPARC_SEMAPHORE_H) */ +#endif /* !(_PPC_SEMAPHORE_H) */ diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h index 6ccff3e85..edef8a7da 100644 --- a/include/asm-ppc/serial.h +++ b/include/asm-ppc/serial.h @@ -7,9 +7,23 @@ #ifdef CONFIG_APUS #include #else +#ifdef CONFIG_GEMINI +#include +#else +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ #define BASE_BAUD ( 1843200 / 16 ) - + +#ifdef CONFIG_PMAC +/* + * Auto-probing will cause machine checks on powermacs. + */ #define SERIAL_PORT_DFNS #ifdef CONFIG_SERIAL_MANY_PORTS @@ -17,5 +31,116 @@ #else #define RS_TABLE_SIZE 4 #endif - + +#else +#define SERIAL_PORT_DFNS +/* + * PReP, CHRP, etc. + */ + +/* Standard COM flags (except for COM4, because of the 8514 problem) */ +#ifdef CONFIG_SERIAL_DETECT_IRQ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) +#else +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF +#endif + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define FOURPORT_FLAGS ASYNC_FOURPORT +#define ACCENT_FLAGS 0 +#define BOCA_FLAGS 0 +#define HUB6_FLAGS 0 +#endif + +/* + * The following define the access methods for the HUB6 card. All + * access is through two ports for all 24 possible chips. The card is + * selected through the high 2 bits, the port on that card with the + * "middle" 3 bits, and the register on that port with the bottom + * 3 bits. + * + * While the access port and interrupt is configurable, the default + * port locations are 0x302 for the port control register, and 0x303 + * for the data read/write register. Normally, the interrupt is at irq3 + * but can be anything from 3 to 7 inclusive. Note that using 3 will + * require disabling com2. + */ + +#define C_P(card,port) (((card)<<6|(port)<<3) + 1) + +#define STD_SERIAL_PORT_DEFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ + + +#ifdef CONFIG_SERIAL_MANY_PORTS +#define EXTRA_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \ + { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \ + { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \ + { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \ + { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \ + { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \ + { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \ + { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \ + { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \ + { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \ + { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \ + { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \ + { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \ + { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \ + { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \ + { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \ + { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \ + { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \ + { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \ + { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \ + { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \ + { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \ + { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \ + { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \ + { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \ + { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \ + { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */ +#else +#define EXTRA_SERIAL_PORT_DEFNS +#endif + +/* You can have up to four HUB6's in the system, but I've only + * included two cards here for a total of twelve ports. + */ +#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS)) +#define HUB6_SERIAL_PORT_DFNS \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \ + { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */ +#else +#define HUB6_SERIAL_PORT_DFNS +#endif + +#define MCA_SERIAL_PORT_DFNS + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DEFNS \ + EXTRA_SERIAL_PORT_DEFNS \ + HUB6_SERIAL_PORT_DFNS \ + MCA_SERIAL_PORT_DFNS + +#endif /* CONFIG_PMAC */ +#endif /* CONFIG_GEMINI */ #endif /* CONFIG_APUS */ diff --git a/include/asm-ppc/smplock.h b/include/asm-ppc/smplock.h index e62326a10..1590fafe9 100644 --- a/include/asm-ppc/smplock.h +++ b/include/asm-ppc/smplock.h @@ -4,7 +4,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h index 73946f206..1188809e9 100644 --- a/include/asm-ppc/softirq.h +++ b/include/asm-ppc/softirq.h @@ -54,19 +54,23 @@ static inline void end_bh_atomic(void) /* These are for the IRQs testing the lock */ static inline int softirq_trylock(int cpu) { - if (!test_and_set_bit(0,&global_bh_count)) { - if (atomic_read(&global_bh_lock) && - ppc_local_bh_count[cpu] == 0) { - ++ppc_local_bh_count[cpu]; - return 1; + if (ppc_local_bh_count[cpu] == 0) { + ppc_local_bh_count[cpu] = 1; + if (!test_and_set_bit(0,&global_bh_count)) { + mb(); + if (atomic_read(&global_bh_lock) == 0) + return 1; + clear_bit(0,&global_bh_count); } - clear_bit(0,&global_bh_count); + ppc_local_bh_count[cpu] = 0; + mb(); } return 0; } static inline void softirq_endlock(int cpu) { + mb(); ppc_local_bh_count[cpu]--; clear_bit(0,&global_bh_count); } diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h dissimilarity index 61% index f1a35ca1c..327b4927a 100644 --- a/include/asm-ppc/spinlock.h +++ b/include/asm-ppc/spinlock.h @@ -1,160 +1,69 @@ -#ifndef __ASM_SPINLOCK_H -#define __ASM_SPINLOCK_H - -#ifndef __SMP__ -/* - * Your basic spinlocks, allowing only a single CPU anywhere - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - 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 - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Avoid warnings about unused variable */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() -#define spin_lock_bh(lock) local_bh_disable() -#define spin_unlock_bh(lock) local_bh_enable() -#define spin_lock_irqsave(lock, flags) \ - do { save_flags(flags); cli(); } while (0) - -#define spin_unlock_irqrestore(lock, flags) \ - restore_flags(flags) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - * - * Gcc-2.7.x has a nasty bug with empty initializers. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { } -#else - typedef struct { int gcc_is_buggy; } rwlock_t; - #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#endif - -#define read_lock(lock) (void)(lock) /* Avoid warnings about unused variable */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Likewise */ -#define write_unlock(lock) do { } while(0) -#define read_lock_irq(lock) cli() -#define read_unlock_irq(lock) sti() -#define write_lock_irq(lock) cli() -#define write_unlock_irq(lock) sti() -#define read_lock_bh(lock) local_bh_disable() -#define read_unlock_bh(lock) local_bh_enable() -#define write_lock_bh(lock) local_bh_disable() -#define write_unlock_bh(lock) local_bh_enable() - -#define read_lock_irqsave(lock, flags) \ - do { save_flags(flags); cli(); } while (0) -#define read_unlock_irqrestore(lock, flags) \ - restore_flags(flags) -#define write_lock_irqsave(lock, flags) \ - do { save_flags(flags); cli(); } while (0) -#define write_unlock_irqrestore(lock, flags) \ - restore_flags(flags) - -#else /* __SMP__ */ - -/* Simple spin lock operations. There are two variants, one clears IRQ's - * on the local processor, one does not. - * - * We make no fairness assumptions. They have a cost. - */ - -typedef struct { - volatile unsigned long lock; - volatile unsigned long owner_pc; - volatile unsigned long owner_cpu; -} spinlock_t; - -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0 } -#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0) -#define spin_unlock_wait(lp) do { barrier(); } while((lp)->lock) - -extern void _spin_lock(spinlock_t *lock); -extern void _spin_unlock(spinlock_t *lock); -extern int spin_trylock(spinlock_t *lock); - -#define spin_lock(lp) _spin_lock(lp) -#define spin_unlock(lp) _spin_unlock(lp) - -#define spin_lock_irq(lock) \ - do { __cli(); spin_lock(lock); } while (0) -#define spin_lock_bh(___lk) do { local_bh_disable(); spin_lock(___lk); } while(0) - -#define spin_unlock_irq(lock) \ - do { spin_unlock(lock); __sti(); } while (0) -#define spin_unlock_bh(___lk) do { spin_unlock(___lk); local_bh_enable(); } while(0) - -#define spin_lock_irqsave(lock, flags) \ - do { __save_flags(flags); __cli(); spin_lock(lock); } while (0) -#define spin_unlock_irqrestore(lock, flags) \ - do { spin_unlock(lock); __restore_flags(flags); } while (0) - -extern unsigned long __spin_trylock(volatile unsigned long *lock); - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { - volatile unsigned long lock; - volatile unsigned long owner_pc; -} rwlock_t; - -#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } - -extern void _read_lock(rwlock_t *rw); -extern void _read_unlock(rwlock_t *rw); -extern void _write_lock(rwlock_t *rw); -extern void _write_unlock(rwlock_t *rw); - -#define read_lock(rw) _read_lock(rw) -#define write_lock(rw) _write_lock(rw) -#define write_unlock(rw) _write_unlock(rw) -#define read_unlock(rw) _read_unlock(rw) - -#define read_lock_irq(lock) do { __cli(); read_lock(lock); } while (0) -#define read_lock_bh(lock) do { local_bh_disable(); read_lock(lock); } while (0) -#define read_unlock_irq(lock) do { read_unlock(lock); __sti(); } while (0) -#define read_unlock_bh(lock) do { read_unlock(lock); local_bh_enable(); } while (0) -#define write_lock_irq(lock) do { __cli(); write_lock(lock); } while (0) -#define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while(0) -#define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0) -#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while(0) -#define read_lock_irqsave(lock, flags) \ - do { __save_flags(flags); __cli(); read_lock(lock); } while (0) -#define read_unlock_irqrestore(lock, flags) \ - do { read_unlock(lock); __restore_flags(flags); } while (0) -#define write_lock_irqsave(lock, flags) \ - do { __save_flags(flags); __cli(); write_lock(lock); } while (0) -#define write_unlock_irqrestore(lock, flags) \ - do { write_unlock(lock); __restore_flags(flags); } while (0) - -#endif /* SMP */ -#endif /* __ASM_SPINLOCK_H */ +#ifndef __ASM_SPINLOCK_H +#define __ASM_SPINLOCK_H + +/* Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ + +typedef struct { + volatile unsigned long lock; + volatile unsigned long owner_pc; + volatile unsigned long owner_cpu; +} spinlock_t; + +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0 } +#define spin_lock_init(lp) do { (lp)->lock = 0; } while(0) +#define spin_unlock_wait(lp) do { barrier(); } while((lp)->lock) + +extern void _spin_lock(spinlock_t *lock); +extern void _spin_unlock(spinlock_t *lock); +extern int spin_trylock(spinlock_t *lock); + +#define spin_lock(lp) _spin_lock(lp) +#define spin_unlock(lp) _spin_unlock(lp) + +#define spin_lock_irq(lock) \ + do { __cli(); spin_lock(lock); } while (0) +#define spin_lock_bh(___lk) do { local_bh_disable(); spin_lock(___lk); } while(0) + +#define spin_unlock_irq(lock) \ + do { spin_unlock(lock); __sti(); } while (0) +#define spin_unlock_bh(___lk) do { spin_unlock(___lk); local_bh_enable(); } while(0) + +#define spin_lock_irqsave(lock, flags) \ + do { __save_flags(flags); __cli(); spin_lock(lock); } while (0) +#define spin_unlock_irqrestore(lock, flags) \ + do { spin_unlock(lock); __restore_flags(flags); } while (0) + +extern unsigned long __spin_trylock(volatile unsigned long *lock); + +/* + * Read-write spinlocks, allowing multiple readers + * but only one writer. + * + * NOTE! it is quite common to have readers in interrupts + * but no interrupt writers. For those circumstances we + * can "mix" irq-safe locks - any writer needs to get a + * irq-safe write-lock, but readers can get non-irqsafe + * read-locks. + */ +typedef struct { + volatile unsigned long lock; + volatile unsigned long owner_pc; +} rwlock_t; + +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } + +extern void _read_lock(rwlock_t *rw); +extern void _read_unlock(rwlock_t *rw); +extern void _write_lock(rwlock_t *rw); +extern void _write_unlock(rwlock_t *rw); + +#define read_lock(rw) _read_lock(rw) +#define write_lock(rw) _write_lock(rw) +#define write_unlock(rw) _write_unlock(rw) +#define read_unlock(rw) _read_unlock(rw) + +#endif /* __ASM_SPINLOCK_H */ diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 0e05d90f9..9984267dd 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -1,5 +1,5 @@ /* - * $Id: system.h,v 1.47 1999/08/22 12:31:08 paulus Exp $ + * $Id: system.h,v 1.48 1999/09/05 11:56:40 paulus Exp $ * * Copyright (C) 1999 Cort Dougan */ @@ -32,6 +32,10 @@ #define rmb() __asm__ __volatile__ ("sync" : : : "memory") #define wmb() __asm__ __volatile__ ("eieio" : : : "memory") +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_rmb(var, value) do { var = value; rmb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + extern void xmon_irq(int, void *, struct pt_regs *); extern void xmon(struct pt_regs *excp); diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index 38b651bc0..4c20b768d 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h @@ -14,7 +14,7 @@ #include -__initfunc(static void check_bugs(void)) +static void __init check_bugs(void) { } #endif /* __ASM_SH_BUGS_H */ diff --git a/include/asm-sh/semaphore.h b/include/asm-sh/semaphore.h index 2a9c0a0b8..4164b7805 100644 --- a/include/asm-sh/semaphore.h +++ b/include/asm-sh/semaphore.h @@ -12,9 +12,10 @@ * */ +#include + #include #include -#include struct semaphore { atomic_t count; diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h dissimilarity index 97% index d772463ad..16f70ffd7 100644 --- a/include/asm-sh/spinlock.h +++ b/include/asm-sh/spinlock.h @@ -1,108 +1,6 @@ -#ifndef __ASM_SH_SPINLOCK_H -#define __ASM_SH_SPINLOCK_H - -/* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. - */ -#define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) -#define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) -#define spin_lock_bh(lock) do { local_bh_disable(); spin_lock(lock); } while (0) - -#define read_lock_irqsave(lock, flags) do { local_irq_save(flags); read_lock(lock); } while (0) -#define read_lock_irq(lock) do { local_irq_disable(); read_lock(lock); } while (0) -#define read_lock_bh(lock) do { local_bh_disable(); read_lock(lock); } while (0) - -#define write_lock_irqsave(lock, flags) do { local_irq_save(flags); write_lock(lock); } while (0) -#define write_lock_irq(lock) do { local_irq_disable(); write_lock(lock); } while (0) -#define write_lock_bh(lock) do { local_bh_disable(); write_lock(lock); } while (0) - -#define spin_unlock_irqrestore(lock, flags) do { spin_unlock(lock); local_irq_restore(flags); } while (0) -#define spin_unlock_irq(lock) do { spin_unlock(lock); local_irq_enable(); } while (0) -#define spin_unlock_bh(lock) do { spin_unlock(lock); local_bh_enable(); } while (0) - -#define read_unlock_irqrestore(lock, flags) do { read_unlock(lock); local_irq_restore(flags); } while (0) -#define read_unlock_irq(lock) do { read_unlock(lock); local_irq_enable(); } while (0) -#define read_unlock_bh(lock) do { read_unlock(lock); local_bh_enable(); } while (0) - -#define write_unlock_irqrestore(lock, flags) do { write_unlock(lock); local_irq_restore(flags); } while (0) -#define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0) -#define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0) - -#ifndef __SMP__ - -#define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ - -#if (DEBUG_SPINLOCKS < 1) - -/* - * Your basic spinlocks, allowing only a single CPU anywhere - */ -typedef struct { } spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { } - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) - -#elif (DEBUG_SPINLOCKS < 2) - -typedef struct { - volatile unsigned int lock; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do { (x)->lock = 1; } while (0) -#define spin_unlock_wait(x) do { } while (0) -#define spin_unlock(x) do { (x)->lock = 0; } while (0) - -#else /* (DEBUG_SPINLOCKS >= 2) */ - -typedef struct { - volatile unsigned int lock; - volatile unsigned int babble; - const char *module; -} spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ } - -#include - -#define spin_lock_init(x) do { (x)->lock = 0; } while (0) -#define spin_trylock(lock) (!test_and_set_bit(0,(lock))) - -#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0) -#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0) -#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0) - -#endif /* DEBUG_SPINLOCKS */ - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { } - -#define read_lock(lock) (void)(lock) /* Not "unused variable". */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Not "unused variable". */ -#define write_unlock(lock) do { } while(0) - -#else - -#error "No SMP on SH" - -#endif /* SMP */ -#endif /* __ASM_SH_SPINLOCK_H */ +#ifndef __ASM_SH_SPINLOCK_H +#define __ASM_SH_SPINLOCK_H + +#error "No SMP on SH" + +#endif /* __ASM_SH_SPINLOCK_H */ diff --git a/include/asm-sparc/dma.h b/include/asm-sparc/dma.h index 98dc732a0..5489148ff 100644 --- a/include/asm-sparc/dma.h +++ b/include/asm-sparc/dma.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include extern spinlock_t dma_spin_lock; diff --git a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h index 5dfc9d775..ed47c7760 100644 --- a/include/asm-sparc/hardirq.h +++ b/include/asm-sparc/hardirq.h @@ -29,7 +29,7 @@ extern unsigned int local_irq_count; #else #include -#include +#include #include #include diff --git a/include/asm-sparc/io-unit.h b/include/asm-sparc/io-unit.h index fa020cd3f..42ff9b6a7 100644 --- a/include/asm-sparc/io-unit.h +++ b/include/asm-sparc/io-unit.h @@ -5,8 +5,8 @@ #ifndef _SPARC_IO_UNIT_H #define _SPARC_IO_UNIT_H +#include #include -#include #include /* The io-unit handles all virtual to physical address translations diff --git a/include/asm-sparc/mostek.h b/include/asm-sparc/mostek.h index 3b01b4d0c..c9a10cd86 100644 --- a/include/asm-sparc/mostek.h +++ b/include/asm-sparc/mostek.h @@ -1,4 +1,4 @@ -/* $Id: mostek.h,v 1.11 1999/08/30 10:14:32 davem Exp $ +/* $Id: mostek.h,v 1.12 1999/08/31 18:51:41 davem Exp $ * mostek.h: Describes the various Mostek time of day clock registers. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -93,14 +93,14 @@ extern unsigned long mstk48t02_regs; #define MSTK_DECIMAL_TO_REGVAL(x) ((((x) / 0x0A) << 0x04) + ((x) % 0x0A)) /* Generic register set and get macros for internal use. */ -#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(regs->var & MSTK_ ## mask ## _MASK)) -#define MSTK_SET(regs,var,value,mask) do { regs->var &= ~(MSTK_ ## mask ## _MASK); regs->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0) +#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK)) +#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0) /* Macros to make register access easier on our fingers. These give you * the decimal value of the register requested if applicable. You pass * the a pointer to a 'struct mostek48t02'. */ -#define MSTK_REG_CREG(regs) (regs->creg) +#define MSTK_REG_CREG(regs) (((struct mostek48t02 *)regs)->creg) #define MSTK_REG_SEC(regs) MSTK_GET(regs,sec,SEC) #define MSTK_REG_MIN(regs) MSTK_GET(regs,min,MIN) #define MSTK_REG_HOUR(regs) MSTK_GET(regs,hour,HOUR) diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h new file mode 100644 index 000000000..17c8ce462 --- /dev/null +++ b/include/asm-sparc/pci.h @@ -0,0 +1,10 @@ +#ifndef __SPARC_PCI_H +#define __SPARC_PCI_H + +/* Can be used to override the logic in pci_scan_bus for skipping + * already-configured bus numbers - to be used for buggy BIOSes + * or architectures with incomplete PCI setup by the loader. + */ +#define pcibios_assign_all_busses() 0 + +#endif /* __SPARC_PCI_H */ diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h index 877f317cc..39284c1b8 100644 --- a/include/asm-sparc/pgtable.h +++ b/include/asm-sparc/pgtable.h @@ -11,6 +11,7 @@ #include #include +#include #include #ifdef CONFIG_SUN4 #include @@ -22,7 +23,6 @@ #include #include #include -#include extern void load_mmu(void); extern int io_remap_page_range(unsigned long from, unsigned long to, diff --git a/include/asm-sparc/sigcontext.h b/include/asm-sparc/sigcontext.h index 3c85783f1..ff9ccda16 100644 --- a/include/asm-sparc/sigcontext.h +++ b/include/asm-sparc/sigcontext.h @@ -1,18 +1,14 @@ -/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */ +/* $Id: sigcontext.h,v 1.14 1999/09/06 08:22:05 jj Exp $ */ #ifndef __SPARC_SIGCONTEXT_H #define __SPARC_SIGCONTEXT_H +#ifdef __KERNEL__ #include - -#define SUNOS_MAXWIN 31 +#endif #ifndef __ASSEMBLY__ -/* SunOS system call sigstack() uses this arg. */ -struct sunos_sigstack { - unsigned long sig_sp; - int onstack_flag; -}; +#define __SUNOS_MAXWIN 31 /* This is what SunOS does, so shall I. */ struct sigcontext { @@ -31,14 +27,23 @@ struct sigcontext { int sigc_oswins; /* outstanding windows */ /* stack ptrs for each regwin buf */ - char *sigc_spbuf[SUNOS_MAXWIN]; + char *sigc_spbuf[__SUNOS_MAXWIN]; /* Windows to restore after signal */ - struct reg_window sigc_wbuf[SUNOS_MAXWIN]; + struct { + unsigned long locals[8]; + unsigned long ins[8]; + } sigc_wbuf[__SUNOS_MAXWIN]; }; typedef struct { - struct pt_regs si_regs; + struct { + unsigned long psr; + unsigned long pc; + unsigned long npc; + unsigned long y; + unsigned long u_regs[16]; /* globals and ins */ + } si_regs; int si_mask; } __siginfo_t; @@ -52,6 +57,8 @@ typedef struct { } si_fpqueue [16]; } __siginfo_fpu_t; +#ifdef __KERNEL__ + /* This magic should be in g_upper[0] for all upper parts to be valid. This is generated by sparc64 only, but for 32bit processes, @@ -62,6 +69,8 @@ typedef struct { unsigned int o_upper[8]; } siginfo_extra_v8plus_t; +#endif + #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC_SIGCONTEXT_H) */ diff --git a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h index c3517216b..51d75eee1 100644 --- a/include/asm-sparc/signal.h +++ b/include/asm-sparc/signal.h @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.34 1998/07/29 16:32:38 jj Exp $ */ +/* $Id: signal.h,v 1.35 1999/09/06 08:22:04 jj Exp $ */ #ifndef _ASMSPARC_SIGNAL_H #define _ASMSPARC_SIGNAL_H @@ -196,10 +196,12 @@ struct __new_sigaction { __new_sigset_t sa_mask; }; +#ifdef __KERNEL__ struct k_sigaction { struct __new_sigaction sa; void *ka_restorer; }; +#endif struct __old_sigaction { __sighandler_t sa_handler; @@ -211,7 +213,7 @@ struct __old_sigaction { typedef struct sigaltstack { void *ss_sp; int ss_flags; - __kernel_size_t ss_size; + size_t ss_size; } stack_t; #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc/smplock.h b/include/asm-sparc/smplock.h index e62326a10..1590fafe9 100644 --- a/include/asm-sparc/smplock.h +++ b/include/asm-sparc/smplock.h @@ -4,7 +4,7 @@ * Default SMP lock implementation */ #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index da056db5e..bcc8f0b87 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -10,57 +10,6 @@ #ifndef __ASSEMBLY__ -#ifndef __SMP__ - -typedef unsigned char spinlock_t; -#define SPIN_LOCK_UNLOCKED 0 - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) do { } while(0) -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() -#define spin_lock_bh(lock) local_bh_disable() -#define spin_unlock_bh(lock) local_bh_enable() - -#define spin_lock_irqsave(lock, flags) save_and_cli(flags) -#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -typedef struct { volatile unsigned int lock; } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } - -#define read_lock(lock) do { } while(0) -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) do { } while(0) -#define write_unlock(lock) do { } while(0) -#define read_lock_irq(lock) cli() -#define read_unlock_irq(lock) sti() -#define write_lock_irq(lock) cli() -#define write_unlock_irq(lock) sti() -#define read_lock_bh(lock) local_bh_disable() -#define read_unlock_bh(lock) local_bh_enable() -#define write_lock_bh(lock) local_bh_disable() -#define write_unlock_bh(lock) local_bh_enable() - -#define read_lock_irqsave(lock, flags) save_and_cli(flags) -#define read_unlock_irqrestore(lock, flags) restore_flags(flags) -#define write_lock_irqsave(lock, flags) save_and_cli(flags) -#define write_unlock_irqrestore(lock, flags) restore_flags(flags) - -#else /* !(__SMP__) */ - #include /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */ @@ -371,8 +320,6 @@ extern __inline__ void write_lock(rwlock_t *rw) #endif /* SPIN_LOCK_DEBUG */ -#endif /* __SMP__ */ - #endif /* !(__ASSEMBLY__) */ #endif /* __SPARC_SPINLOCK_H */ diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 3a4ee58a3..b489cac95 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.74 1999/05/08 03:03:14 davem Exp $ */ +/* $Id: system.h,v 1.75 1999/09/01 08:06:08 davem Exp $ */ #include #ifndef __SPARC_SYSTEM_H @@ -309,6 +309,9 @@ do { register unsigned long bits asm("g7"); \ #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() #define wmb() mb() +#define set_mb(__var, __value) do { __var = __value; mb(); } while(0) +#define set_rmb(__var, __value) set_mb(__var, __value) +#define set_wmb(__var, __value) set_mb(__var, __value) #define nop() __asm__ __volatile__ ("nop"); diff --git a/include/asm-sparc64/dma.h b/include/asm-sparc64/dma.h index 784a14b78..36fe719c9 100644 --- a/include/asm-sparc64/dma.h +++ b/include/asm-sparc64/dma.h @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.14 1999/08/30 10:14:36 davem Exp $ +/* $Id: dma.h,v 1.15 1999/09/08 03:44:38 davem Exp $ * include/asm-sparc64/dma.h * * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu) @@ -10,11 +10,11 @@ #include #include #include +#include #include #include #include -#include extern spinlock_t dma_spin_lock; diff --git a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h index 42e395d73..7df1d1346 100644 --- a/include/asm-sparc64/hardirq.h +++ b/include/asm-sparc64/hardirq.h @@ -33,7 +33,7 @@ extern unsigned int local_irq_count; #else /* (__SMP__) */ #include -#include +#include #include #include diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index 618d33c99..254babf91 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.21 1999/08/30 10:14:44 davem Exp $ */ +/* $Id: io.h,v 1.24 1999/09/06 01:17:54 davem Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H @@ -16,9 +16,6 @@ #define PCI_DVMA_HASHSZ 256 -extern unsigned long pci_dvma_offset; -extern unsigned long pci_dvma_mask; - extern unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; extern unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; @@ -49,11 +46,13 @@ extern __inline__ void *phys_to_virt(unsigned long addr) #define virt_to_bus virt_to_phys #define bus_to_virt phys_to_virt -extern __inline__ unsigned long bus_dvma_to_mem(unsigned long vaddr) -{ - return vaddr & pci_dvma_mask; -} +/* Different PCI controllers we support have their PCI MEM space + * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area, + * so need to chop off the top 33 or 32 bits. + */ +extern unsigned long pci_memspace_mask; +#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask) extern __inline__ unsigned int inb(unsigned long addr) { @@ -120,12 +119,66 @@ extern void insw(unsigned long addr, void *dst, unsigned long count); extern void insl(unsigned long addr, void *dst, unsigned long count); /* Memory functions, same as I/O accesses on Ultra. */ -#define readb(addr) inb((unsigned long)(addr)) -#define readw(addr) inw((unsigned long)(addr)) -#define readl(addr) inl((unsigned long)(addr)) -#define writeb(b, addr) outb((b), (unsigned long)(addr)) -#define writew(w, addr) outw((w), (unsigned long)(addr)) -#define writel(l, addr) outl((l), (unsigned long)(addr)) +extern __inline__ unsigned int _readb(unsigned long addr) +{ + unsigned int ret; + + __asm__ __volatile__("lduba [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); + + return ret; +} + +extern __inline__ unsigned int _readw(unsigned long addr) +{ + unsigned int ret; + + __asm__ __volatile__("lduha [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); + + return ret; +} + +extern __inline__ unsigned int _readl(unsigned long addr) +{ + unsigned int ret; + + __asm__ __volatile__("lduwa [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); + + return ret; +} + +extern __inline__ void _writeb(unsigned char b, unsigned long addr) +{ + __asm__ __volatile__("stba %0, [%1] %2" + : /* no outputs */ + : "r" (b), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); +} + +extern __inline__ void _writew(unsigned short w, unsigned long addr) +{ + __asm__ __volatile__("stha %0, [%1] %2" + : /* no outputs */ + : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); +} + +extern __inline__ void _writel(unsigned int l, unsigned long addr) +{ + __asm__ __volatile__("stwa %0, [%1] %2" + : /* no outputs */ + : "r" (l), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)); +} + +#define readb(__addr) (_readb((unsigned long)(__addr))) +#define readw(__addr) (_readw((unsigned long)(__addr))) +#define readl(__addr) (_readl((unsigned long)(__addr))) +#define writeb(__b, __addr) (_writeb((__b), (unsigned long)(__addr))) +#define writew(__w, __addr) (_writew((__w), (unsigned long)(__addr))) +#define writel(__l, __addr) (_writel((__l), (unsigned long)(__addr))) /* * Memcpy to/from I/O space is just a regular memory operation on diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index bd67d60bc..9c21b9dc3 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -5,9 +5,9 @@ #ifndef _SPARC64_IOMMU_H #define _SPARC64_IOMMU_H +#include #include #include -#include /* The iommu handles all virtual to physical address translations * that occur between the SYSIO and physical memory. Access by diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h index 7f4bf12d7..045ae8bc9 100644 --- a/include/asm-sparc64/irq.h +++ b/include/asm-sparc64/irq.h @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.15 1999/08/30 10:14:48 davem Exp $ +/* $Id: irq.h,v 1.16 1999/09/06 01:17:52 davem Exp $ * irq.h: IRQ registers on the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -94,6 +94,7 @@ static __inline__ char *__irq_itoa(unsigned int irq) #define NR_IRQS 15 extern void disable_irq(unsigned int); +#define disable_irq_nosync disable_irq extern void enable_irq(unsigned int); extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *), unsigned long *); diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index 64f24b35b..5c0192cbb 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -4,9 +4,9 @@ /* Derived heavily from Linus's Alpha/AXP ASN code... */ +#include #include #include -#include #ifndef __ASSEMBLY__ diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index 52e55758a..f0ca1df71 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.10 1998/12/18 10:02:03 davem Exp $ +/* $Id: oplib.h,v 1.11 1999/08/31 19:25:49 davem Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -205,7 +205,8 @@ extern int prom_wakeupsystem(void); /* MMU and memory related OBP interfaces. */ /* Get unique string identifying SIMM at given physical address. */ -extern int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi, +extern int prom_getunumber(int syndrome_code, + unsigned long phys_addr, char *buf, int buflen); /* Retain physical memory to the caller across soft resets. */ @@ -336,6 +337,7 @@ extern long p1275_cmd (char *, long, ...); #define P1275_ARG_OUT_32B 3 #define P1275_ARG_IN_FUNCTION 4 #define P1275_ARG_IN_BUF 5 +#define P1275_ARG_IN_64B 6 #define P1275_IN(x) ((x) & 0xf) #define P1275_OUT(x) (((x) << 4) & 0xf0) diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index e672fe76e..6fc241940 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -10,11 +10,11 @@ #include #include #include +#include #include #include #include -#include /* The abstraction used here is that there are PCI controllers, * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h new file mode 100644 index 000000000..6d1558daf --- /dev/null +++ b/include/asm-sparc64/pci.h @@ -0,0 +1,44 @@ +#ifndef __SPARC64_PCI_H +#define __SPARC64_PCI_H + +#include + +/* Can be used to override the logic in pci_scan_bus for skipping + * already-configured bus numbers - to be used for buggy BIOSes + * or architectures with incomplete PCI setup by the loader. + */ +#define pcibios_assign_all_busses() 0 + +/* Map kernel buffer using consistant mode DMA for PCI device. + * Returns a 32-bit PCI DMA address. + */ +extern u32 pci_map_consistant(struct pci_dev *, void *, int); + +/* Unmap a consistant DMA translation. */ +extern void pci_unmap_consistant(struct pci_dev *, u32, int); + +/* Map a single buffer for PCI DMA in streaming mode. */ +extern u32 pci_map_single(struct pci_dev *, void *, int); + +/* Unmap a single streaming mode DMA translation. */ +extern void pci_unmap_single(struct pci_dev *, u32, int); + +/* Map a set of buffers described by scatterlist in streaming + * mode for PCI DMA. + */ +extern void pci_map_sg(struct pci_dev *, struct scatterlist *, int); + +/* Unmap a set of streaming mode DMA translations. */ +extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int); + +/* Make physical memory consistant for a single + * streaming mode DMA translation after a transfer. + */ +extern void pci_dma_sync_single(struct pci_dev *, u32, int); + +/* Make physical memory consistant for a set of streaming + * mode DMA translations after a transfer. + */ +extern void pci_dma_sync_sg(struct pci_dev *, struct scatterlist *, int); + +#endif /* __SPARC64_PCI_H */ diff --git a/include/asm-sparc64/reg.h b/include/asm-sparc64/reg.h index 429400862..fc68f9018 100644 --- a/include/asm-sparc64/reg.h +++ b/include/asm-sparc64/reg.h @@ -1,4 +1,4 @@ -/* $Id: reg.h,v 1.5 1999/08/17 17:52:32 jj Exp $ +/* $Id: reg.h,v 1.6 1999/09/06 08:22:10 jj Exp $ * linux/asm-sparc64/reg.h * Layout of the registers as expected by gdb on the Sparc * we should replace the user.h definitions with those in @@ -51,5 +51,6 @@ struct fpu { }; #define fpu_regs f_fpstatus.fpu_fr +#define fpu_fsr f_fpstatus.Fpu_fsr #endif /* __SPARC64_REG_H */ diff --git a/include/asm-sparc64/sigcontext.h b/include/asm-sparc64/sigcontext.h index 4ce040a78..d7128a875 100644 --- a/include/asm-sparc64/sigcontext.h +++ b/include/asm-sparc64/sigcontext.h @@ -1,20 +1,18 @@ -/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */ +/* $Id: sigcontext.h,v 1.12 1999/09/06 08:22:09 jj Exp $ */ #ifndef __SPARC64_SIGCONTEXT_H #define __SPARC64_SIGCONTEXT_H +#ifdef __KERNEL__ #include - -#define SUNOS_MAXWIN 31 +#endif #ifndef __ASSEMBLY__ -/* SunOS system call sigstack() uses this arg. */ -struct sunos_sigstack { - unsigned int sig_sp; - int onstack_flag; -}; +#ifdef __KERNEL__ + +#define __SUNOS_MAXWIN 31 -/* This is what SunOS does, so shall I. */ +/* This is what SunOS does, so shall I unless we use new 32bit signals or rt signals. */ struct sigcontext32 { int sigc_onstack; /* state to restore */ int sigc_mask; /* sigmask to restore */ @@ -31,44 +29,30 @@ struct sigcontext32 { int sigc_oswins; /* outstanding windows */ /* stack ptrs for each regwin buf */ - unsigned sigc_spbuf[SUNOS_MAXWIN]; + unsigned sigc_spbuf[__SUNOS_MAXWIN]; /* Windows to restore after signal */ - struct reg_window32 sigc_wbuf[SUNOS_MAXWIN]; + struct reg_window32 sigc_wbuf[__SUNOS_MAXWIN]; }; -/* This is what SunOS doesn't, so we have to write this alone. */ -struct sigcontext { - int sigc_onstack; /* state to restore */ - int sigc_mask; /* sigmask to restore */ - unsigned long sigc_sp; /* stack pointer */ - unsigned long sigc_pc; /* program counter */ - unsigned long sigc_npc; /* next program counter */ - unsigned long sigc_psr; /* for condition codes etc */ - unsigned long sigc_g1; /* User uses these two registers */ - unsigned long sigc_o0; /* within the trampoline code. */ - - /* Now comes information regarding the users window set - * at the time of the signal. - */ - int sigc_oswins; /* outstanding windows */ +#endif - /* stack ptrs for each regwin buf */ - char *sigc_spbuf[SUNOS_MAXWIN]; +#ifdef __KERNEL__ - /* Windows to restore after signal */ - struct reg_window sigc_wbuf[SUNOS_MAXWIN]; -}; +/* This is what we use for 32bit new non-rt signals. */ typedef struct { - struct pt_regs32 si_regs; + struct { + unsigned int psr; + unsigned int pc; + unsigned int npc; + unsigned int y; + unsigned int u_regs[16]; /* globals and ins */ + } si_regs; int si_mask; } __siginfo32_t; -typedef struct { - struct pt_regs si_regs; - long si_mask; -} __siginfo_t; +#endif typedef struct { unsigned int si_float_regs [64]; @@ -77,6 +61,30 @@ typedef struct { unsigned long si_fprs; } __siginfo_fpu_t; +/* This is what SunOS doesn't, so we have to write this alone + and do it properly. */ +struct sigcontext { + /* The size of this array has to match SI_MAX_SIZE from siginfo.h */ + char sigc_info[128]; + struct { + unsigned long u_regs[16]; /* globals and ins */ + unsigned long tstate; + unsigned long tpc; + unsigned long tnpc; + unsigned int y; + unsigned int fprs; + } sigc_regs; + __siginfo_fpu_t * sigc_fpu_save; + struct { + void * ss_sp; + int ss_flags; + unsigned long ss_size; + } sigc_stack; + unsigned long sigc_mask; +}; + +#ifdef __KERNEL__ + /* This magic should be in g_upper[0] for all upper parts to be valid. */ #define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 @@ -85,6 +93,8 @@ typedef struct { unsigned int o_upper[8]; } siginfo_extra_v8plus_t; +#endif + #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_SIGCONTEXT_H) */ diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h index ba179564b..463ef3fdd 100644 --- a/include/asm-sparc64/signal.h +++ b/include/asm-sparc64/signal.h @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.8 1998/07/29 16:32:39 jj Exp $ */ +/* $Id: signal.h,v 1.9 1999/09/06 08:22:11 jj Exp $ */ #ifndef _ASMSPARC64_SIGNAL_H #define _ASMSPARC64_SIGNAL_H @@ -196,7 +196,7 @@ struct sigstack { /* Type of a signal handler. */ #ifdef __KERNEL__ -typedef void (*__sighandler_t)(int, int, struct sigcontext *, char *); +typedef void (*__sighandler_t)(int, struct sigcontext *); #else typedef void (*__sighandler_t)(int); #endif @@ -219,10 +219,12 @@ struct __new_sigaction32 { __new_sigset_t32 sa_mask; }; +#ifdef __KERNEL__ struct k_sigaction { struct __new_sigaction sa; void *ka_restorer; }; +#endif struct __old_sigaction { __sighandler_t sa_handler; @@ -239,16 +241,18 @@ struct __old_sigaction32 { }; typedef struct sigaltstack { - void *ss_sp; - int ss_flags; - __kernel_size_t ss_size; + void *ss_sp; + int ss_flags; + size_t ss_size; } stack_t; +#ifdef __KERNEL__ typedef struct sigaltstack32 { - u32 ss_sp; - int ss_flags; - __kernel_size_t32 ss_size; + u32 ss_sp; + int ss_flags; + __kernel_size_t32 ss_size; } stack_t32; +#endif #endif /* !(__ASSEMBLY__) */ diff --git a/include/asm-sparc64/smplock.h b/include/asm-sparc64/smplock.h index 88a9e8bd1..5791e3c7a 100644 --- a/include/asm-sparc64/smplock.h +++ b/include/asm-sparc64/smplock.h @@ -5,7 +5,7 @@ */ #include #include -#include +#include extern spinlock_t kernel_flag; diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h index bd980ab18..02a8d2d9b 100644 --- a/include/asm-sparc64/spinlock.h +++ b/include/asm-sparc64/spinlock.h @@ -8,88 +8,6 @@ #ifndef __ASSEMBLY__ -#ifndef __SMP__ - -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } spinlock_t; -# define SPIN_LOCK_UNLOCKED (spinlock_t) { } -#else - typedef unsigned char spinlock_t; -# define SPIN_LOCK_UNLOCKED 0 -#endif - -#define spin_lock_init(lock) do { } while(0) -#define spin_lock(lock) (void)(lock) /* Avoid warnings about unused variable */ -#define spin_trylock(lock) (1) -#define spin_unlock_wait(lock) do { } while(0) -#define spin_unlock(lock) do { } while(0) -#define spin_lock_irq(lock) cli() -#define spin_unlock_irq(lock) sti() -#define spin_lock_bh(lock) \ -do { local_bh_count++; \ - barrier(); \ -} while(0) -#define spin_unlock_bh(lock) \ -do { barrier(); \ - local_bh_count--; \ -} while(0) - -#define spin_lock_irqsave(lock, flags) save_and_cli(flags) -#define spin_unlock_irqrestore(lock, flags) restore_flags(flags) - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * NOTE! it is quite common to have readers in interrupts - * but no interrupt writers. For those circumstances we - * can "mix" irq-safe locks - any writer needs to get a - * irq-safe write-lock, but readers can get non-irqsafe - * read-locks. - */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) - typedef struct { } rwlock_t; -# define RW_LOCK_UNLOCKED (rwlock_t) { } -#else - typedef unsigned int rwlock_t; -# define RW_LOCK_UNLOCKED (rwlock_t) { 0 } -#endif - -#define read_lock(lock) (void)(lock) /* Avoid warnings about unused variable */ -#define read_unlock(lock) do { } while(0) -#define write_lock(lock) (void)(lock) /* Likewise */ -#define write_unlock(lock) do { } while(0) -#define read_lock_irq(lock) cli() -#define read_unlock_irq(lock) sti() -#define read_lock_bh(lock) \ -do { local_bh_count++; \ - barrier(); \ -} while(0) -#define read_unlock_bh(lock) \ -do { barrier(); \ - local_bh_count--; \ -} while(0) - -#define write_lock_irq(lock) cli() -#define write_unlock_irq(lock) sti() - -#define write_lock_bh(lock) \ -do { local_bh_count++; \ - barrier(); \ -} while(0) - -#define write_unlock_bh(lock) \ -do { barrier(); \ - local_bh_count--; \ -} while(0) - -#define read_lock_irqsave(lock, flags) save_and_cli(flags) -#define read_unlock_irqrestore(lock, flags) restore_flags(flags) -#define write_lock_irqsave(lock, flags) save_and_cli(flags) -#define write_unlock_irqrestore(lock, flags) restore_flags(flags) - -#else /* !(__SMP__) */ - /* To get debugging spinlocks which detect and catch * deadlock situations, set DEBUG_SPINLOCKS in the sparc64 * specific makefile and rebuild your kernel. @@ -379,8 +297,6 @@ do { unsigned long flags; \ #endif /* SPIN_LOCK_DEBUG */ -#endif /* __SMP__ */ - #endif /* !(__ASSEMBLY__) */ #endif /* !(__SPARC64_SPINLOCK_H) */ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index a0e3e28ee..7120e8441 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.53 1999/08/03 05:16:14 davem Exp $ */ +/* $Id: system.h,v 1.54 1999/09/01 08:06:12 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -97,6 +97,12 @@ extern void __global_restore_flags(unsigned long flags); #define membar(type) __asm__ __volatile__ ("membar " type : : : "memory"); #define rmb() membar("#LoadLoad | #LoadStore") #define wmb() membar("#StoreLoad | #StoreStore") +#define set_mb(__var, __value) \ + do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0) +#define set_rmb(__var, __value) \ + do { __var = __value; membar("#StoreLoad"); } while(0) +#define set_wmb(__var, __value) \ + do { __var = __value; membar("#StoreStore"); } while(0) #define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index 7fa0ff49b..4289e581c 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -1,4 +1,4 @@ -/* $Id: ttable.h,v 1.12 1999/07/30 09:31:24 davem Exp $ */ +/* $Id: ttable.h,v 1.13 1999/08/31 19:25:50 davem Exp $ */ #ifndef _SPARC64_TTABLE_H #define _SPARC64_TTABLE_H @@ -54,6 +54,13 @@ clr %l6; \ nop; +#define TRAPTL1_CEE \ + ldxa [%g0] ASI_AFSR, %g1; \ + membar #Sync; \ + stxa %g1, [%g0] ASI_AFSR; \ + membar #Sync; \ + retry; nop; nop; nop; + #define TRAP_ARG(routine, arg) \ sethi %hi(109f), %g7; \ ba,pt %xcc, etrap; \ diff --git a/include/linux/arequipa.h b/include/linux/arequipa.h deleted file mode 100644 index 0e58f767c..000000000 --- a/include/linux/arequipa.h +++ /dev/null @@ -1,63 +0,0 @@ -/* arequipa.h - Arequipa interface definitions */ - -/* Written 1996-1998 by Jean-Michel Pittet and Werner Almesberger, EPFL ICA */ - - -#ifndef _LINUX_AREQUIPA_H -#define _LINUX_AREQUIPA_H - -#include - - -enum arequipa_msg_type { amt_invalid,amt_close,amt_sync }; - -struct arequipa_msg { - enum arequipa_msg_type type; - void *ptr; -}; - - -#define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) -#define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) -#define AREQUIPA_EXPECT _IO('a',ATMIOC_AREQUIPA+2) -#define AREQUIPA_CLOSE _IO('a',ATMIOC_AREQUIPA+3) -#define AREQUIPA_CTRL _IO('a',ATMIOC_AREQUIPA+4) -/* #define AREQUIPA_CLS3RD removed */ -#define AREQUIPA_SYNCREQ _IO('a',ATMIOC_AREQUIPA+6) -/* #define AREQUIPA_SYNCACK removed */ -#define AREQUIPA_WORK _IO('a',ATMIOC_AREQUIPA+8) -#define AREQUIPA_RENEGOTIATE _IO('a',ATMIOC_AREQUIPA+9) - - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include - - -extern struct atm_vcc *aqd; /* for net/atm/proc.c */ -/* extern struct rtable *arequipa_rt; - not needed; we use a local dcl instead*/ -extern struct net_device *arequipa_dev; - -int atm_init_arequipa(void); -int arequipa_attach(struct socket *lower,struct sock *upper, - unsigned long generation); - -int arequipa_preset(struct socket *lower,struct sock *upper); -int arequipa_expect(struct sock *upper,int on,int kmalloc_flags); -int arequipa_incoming(struct socket *lower); -int arequipa_close(struct sock *upper); -int arequipa_renegotiate(struct sock *upper,struct atm_qos *u_qos); -void arequipa_synchronize(void); -void arequipa_work(void); - -int arequipad_attach(struct atm_vcc *vcc); - - -#endif /* __KERNEL__ */ - -#endif diff --git a/include/linux/atm.h b/include/linux/atm.h index d2a2a7990..67a8f3465 100644 --- a/include/linux/atm.h +++ b/include/linux/atm.h @@ -47,10 +47,17 @@ #define ATM_AAL34 3 /* AAL3/4 (data) */ #define ATM_AAL5 5 /* AAL5 (data) */ -/* socket option name coding functions */ +/* + * socket option name coding functions + * + * Note that __SO_ENCODE and __SO_LEVEL are somewhat a hack since the + * << 22 only reserves 9 bits for the level. On some architectures + * SOL_SOCKET is 0xFFFF, so that's a bit of a problem + */ -#define __SO_ENCODE(l,n,t) (((l) << 22) | ((n) << 16) | sizeof(t)) -#define __SO_LEVEL(c) ((c) >> 22) +#define __SO_ENCODE(l,n,t) ((((l) & 0x1FF) << 22) | ((n) << 16) | \ + sizeof(t)) +#define __SO_LEVEL_MATCH(c,m) (((c) >> 22) == ((m) & 0x1FF)) #define __SO_NUMBER(c) (((c) >> 16) & 0x3f) #define __SO_SIZE(c) ((c) & 0x3fff) @@ -67,6 +74,8 @@ /* Quality of Service setting */ #define SO_ATMSAP __SO_ENCODE(SOL_ATM,3,struct atm_sap) /* Service Access Point */ +#define SO_ATMPVC __SO_ENCODE(SOL_ATM,4,struct sockaddr_atmpvc) + /* "PVC" address (also for SVCs); get only */ /* * Note @@@: since the socket layers don't really distinguish the control and diff --git a/include/linux/atm_tcp.h b/include/linux/atm_tcp.h index cf418e738..7e8eb77d6 100644 --- a/include/linux/atm_tcp.h +++ b/include/linux/atm_tcp.h @@ -1,7 +1,7 @@ /* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by driver-specific utilities) */ -/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */ #ifndef LINUX_ATM_TCP_H @@ -14,7 +14,7 @@ /* - * All values are in network byte order + * All values in struct atmtcp_hdr are in network byte order */ struct atmtcp_hdr { @@ -23,12 +23,38 @@ struct atmtcp_hdr { uint32_t length; /* ... of data part */ }; +/* + * All values in struct atmtcp_command are in host byte order + */ + +#define ATMTCP_HDR_MAGIC (~0) /* this length indicates a command */ +#define ATMTCP_CTRL_OPEN 1 /* request/reply */ +#define ATMTCP_CTRL_CLOSE 2 /* request/reply */ + +struct atmtcp_control { + struct atmtcp_hdr hdr; /* must be first */ + int type; /* message type; both directions */ + unsigned long vcc; /* both directions */ + struct sockaddr_atmpvc addr; /* suggested value from kernel */ + struct atm_qos qos; /* both directions */ + int result; /* to kernel only */ +}; + +/* + * Field usage: + * Messge type dir. hdr.v?i type addr qos vcc result + * ----------- ---- ------- ---- ---- --- --- ------ + * OPEN K->D Y Y Y Y Y 0 + * OPEN D->K - Y Y Y Y Y + * CLOSE K->D - - Y - Y 0 + * CLOSE D->K - - - - Y Y + */ #define SIOCSIFATMTCP _IO('a',ATMIOC_ITF) /* set ATMTCP mode */ #define ATMTCP_CREATE _IO('a',ATMIOC_ITF+14) /* create persistent ATMTCP interface */ #define ATMTCP_REMOVE _IO('a',ATMIOC_ITF+15) /* destroy persistent ATMTCP - interface*/ + interface */ #ifdef __KERNEL__ diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 267b80dd6..0287d1661 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -138,10 +138,6 @@ struct atm_cirange { #include #endif -#ifdef CONFIG_AREQUIPA -#include /* for struct sock */ -#endif - #define ATM_VF_ADDR 1 /* Address is in use. Set by anybody, cleared by device driver. */ @@ -220,17 +216,11 @@ struct atm_vcc { struct sk_buff_head listenq; int backlog_quota; /* number of connection requests we */ /* can still accept */ - int reply; + int reply; /* also used by ATMTCP */ /* Multipoint part ------------------------------------------------- */ struct atm_vcc *session; /* session VCC descriptor */ /* Other stuff ----------------------------------------------------- */ void *user_back; /* user backlink - not touched */ -#ifdef CONFIG_AREQUIPA - struct sock *upper; /* our "master" */ - struct socket *sock; /* back pointer to our own socket */ - struct atm_vcc *aq_next,*aq_prev; /* for consistency checks */ - unsigned long generation; /* generation number */ -#endif }; @@ -325,14 +315,12 @@ void shutdown_atm_dev(struct atm_dev *dev); void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev); -/* This is the algorithm used by alloc_skb - - SHIT! It is fully illegal. If we could derive truesize - from another skb parameter, we would not create this variable. - Do not wonder, if allocating 5K skbm truesize will be > 8K. +/* + * This is approximately the algorithm used by alloc_skb. + * */ -static __inline__ int atm_pdu2truesize(int pdu_size) +static __inline__ int atm_guess_pdu2truesize(int pdu_size) { return ((pdu_size+15) & ~15) + sizeof(struct sk_buff); } @@ -351,7 +339,8 @@ static __inline__ void atm_return(struct atm_vcc *vcc,int truesize) int atm_charge(struct atm_vcc *vcc,int truesize); -void atm_return(struct atm_vcc *vcc,int truesize); +struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, + int gfp_flags); int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); int atm_pcr_goal(struct atm_trafprm *tp); diff --git a/include/linux/blk.h b/include/linux/blk.h index 04372ec6e..d0db1bce6 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -4,8 +4,7 @@ #include #include #include - -#include +#include /* * Spinlock for protecting the request queue which diff --git a/include/linux/cyclomx.h b/include/linux/cyclomx.h index fa6ca3b0d..d94e45b41 100644 --- a/include/linux/cyclomx.h +++ b/include/linux/cyclomx.h @@ -23,7 +23,7 @@ #include #include -#include +#include #ifdef __KERNEL__ /* Kernel Interface */ diff --git a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h index ab8166074..2c7e5db58 100644 --- a/include/linux/hdlcdrv.h +++ b/include/linux/hdlcdrv.h @@ -106,7 +106,7 @@ struct hdlcdrv_ioctl { #include #include -#include +#include #define HDLCDRV_MAGIC 0x5ac6e778 #define HDLCDRV_IFNAMELEN 6 diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 7989f6b10..6c1b4a630 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -57,23 +57,29 @@ struct nf_hook_ops int priority; }; -struct nf_setsockopt_ops +struct nf_sockopt_ops { struct list_head list; int pf; - int optmin; - int optmax; - int (*fn)(int optval, void *user, unsigned int len); + + /* Non-inclusive ranges: use 0/0/NULL to never get called. */ + int set_optmin; + int set_optmax; + int (*set)(struct sock *sk, int optval, void *user, unsigned int len); + + int get_optmin; + int get_optmax; + int (*get)(struct sock *sk, int optval, void *user, int *len); }; /* Function to register/unregister hook points. */ int nf_register_hook(struct nf_hook_ops *reg); void nf_unregister_hook(struct nf_hook_ops *reg); -/* Functions to register setsockopt ranges (inclusive). */ -int nf_register_sockopt(struct nf_setsockopt_ops *reg); -void nf_unregister_sockopt(struct nf_setsockopt_ops *reg); +/* Functions to register get/setsockopt ranges (non-inclusive). */ +int nf_register_sockopt(struct nf_sockopt_ops *reg); +void nf_unregister_sockopt(struct nf_sockopt_ops *reg); extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; @@ -114,7 +120,10 @@ void nf_cacheflush(int pf, unsigned int hook, const void *packet, __u32 packetcount, __u32 bytecount); /* Call setsockopt() */ -int nf_setsockopt(int pf, int optval, char *opt, unsigned int len); +int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt, + int len); +int nf_getsockopt(struct sock *sk, int pf, int optval, char *opt, + int *len); struct nf_wakeme { diff --git a/include/linux/parport.h b/include/linux/parport.h index 36f4acde9..50256a87d 100644 --- a/include/linux/parport.h +++ b/include/linux/parport.h @@ -84,9 +84,9 @@ typedef enum { #ifdef __KERNEL__ #include +#include #include #include -#include #include #include #include @@ -491,7 +491,7 @@ extern void dec_parport_count(void); extern void inc_parport_count(void); /* If PC hardware is the only type supported, we can optimise a bit. */ -#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !defined(CONFIG_PARPORT_OTHER) +#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !defined(CONFIG_PARPORT_OTHER) #undef PARPORT_NEED_GENERIC_OPS #include diff --git a/include/linux/pci.h b/include/linux/pci.h index 146c435fa..ed60b7e58 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1532,6 +1532,7 @@ struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); +int pci_assign_resource(struct pci_dev *dev, int i); int pci_claim_resource(struct pci_dev *, int); void pci_assign_unassigned_resources(u32 min_io, u32 min_mem); void pci_set_bus_ranges(void); diff --git a/include/linux/sched.h b/include/linux/sched.h index 044ab67b5..6bc7cee4c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -126,7 +126,7 @@ struct sched_param { #ifdef __KERNEL__ -#include +#include /* * This serializes "schedule()" and also protects diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index cc8590a91..27232bd5b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -21,7 +21,7 @@ #include #include -#include +#include #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 7b0985b20..353cba270 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -252,6 +252,10 @@ struct ucred { #define TCP_NODELAY 1 #define TCP_MAXSEG 2 #define TCP_CORK 3 /* Linux specific (for use with sendfile) */ +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_KEEPCNT 6 +#define TCP_SYNCNT 7 #ifdef __KERNEL__ extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); diff --git a/include/asm-sh/spinlock.h b/include/linux/spinlock.h similarity index 83% copy from include/asm-sh/spinlock.h copy to include/linux/spinlock.h index d772463ad..29e2b67fe 100644 --- a/include/asm-sh/spinlock.h +++ b/include/linux/spinlock.h @@ -1,10 +1,9 @@ -#ifndef __ASM_SH_SPINLOCK_H -#define __ASM_SH_SPINLOCK_H +#ifndef __LINUX_SPINLOCK_H +#define __LINUX_SPINLOCK_H /* - * These are the generic versions of the spinlocks - * and read-write locks.. We should actually do a - * with all of this. Oh, well. + * These are the generic versions of the spinlocks and read-write + * locks.. */ #define spin_lock_irqsave(lock, flags) do { local_irq_save(flags); spin_lock(lock); } while (0) #define spin_lock_irq(lock) do { local_irq_disable(); spin_lock(lock); } while (0) @@ -30,7 +29,10 @@ #define write_unlock_irq(lock) do { write_unlock(lock); local_irq_enable(); } while (0) #define write_unlock_bh(lock) do { write_unlock(lock); local_bh_enable(); } while (0) -#ifndef __SMP__ +#ifdef CONFIG_SMP +#include + +#else /* !SMP */ #define DEBUG_SPINLOCKS 0 /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */ @@ -38,9 +40,16 @@ /* * Your basic spinlocks, allowing only a single CPU anywhere + * + * Gcc-2.7.x has a nasty bug with empty initializers. */ -typedef struct { } spinlock_t; -#define SPIN_LOCK_UNLOCKED (spinlock_t) { } +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) + 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 #define spin_lock_init(lock) do { } while(0) #define spin_lock(lock) (void)(lock) /* Not "unused variable". */ @@ -91,18 +100,21 @@ typedef struct { * can "mix" irq-safe locks - any writer needs to get a * irq-safe write-lock, but readers can get non-irqsafe * read-locks. + * + * Gcc-2.7.x has a nasty bug with empty initializers. */ -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED (rwlock_t) { } +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) + typedef struct { } rwlock_t; + #define RW_LOCK_UNLOCKED (rwlock_t) { } +#else + typedef struct { int gcc_is_buggy; } rwlock_t; + #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif #define read_lock(lock) (void)(lock) /* Not "unused variable". */ #define read_unlock(lock) do { } while(0) #define write_lock(lock) (void)(lock) /* Not "unused variable". */ #define write_unlock(lock) do { } while(0) -#else - -#error "No SMP on SH" - -#endif /* SMP */ -#endif /* __ASM_SH_SPINLOCK_H */ +#endif /* !SMP */ +#endif /* __LINUX_SPINLOCK_H */ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 80c8ed4ca..27ee9cb81 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -237,7 +237,8 @@ enum NET_IPV4_ICMP_ECHOREPLY_RATE=63, NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64, NET_IPV4_IGMP_MAX_MEMBERSHIPS=65, - NET_TCP_TW_RECYCLE=66 + NET_TCP_TW_RECYCLE=66, + NET_IPV4_TCP_KEEPALIVE_INTVL=67, }; enum { diff --git a/include/linux/tqueue.h b/include/linux/tqueue.h index d886f7533..b02f07665 100644 --- a/include/linux/tqueue.h +++ b/include/linux/tqueue.h @@ -13,9 +13,9 @@ #ifndef _LINUX_TQUEUE_H #define _LINUX_TQUEUE_H +#include #include #include -#include /* * New proposed "bottom half" handlers: diff --git a/include/linux/wait.h b/include/linux/wait.h index 79fae9356..86bd08715 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -11,9 +11,9 @@ #include #include #include +#include #include -#include #include /* diff --git a/include/net/atmclip.h b/include/net/atmclip.h index 6450ae2e7..f350c3103 100644 --- a/include/net/atmclip.h +++ b/include/net/atmclip.h @@ -46,7 +46,7 @@ struct atmarp_entry { struct clip_priv { char name[8]; /* interface name */ int number; /* for convenience ... */ - struct enet_statistics stats; + struct net_device_stats stats; struct net_device *next; /* next CLIP interface */ }; @@ -58,5 +58,6 @@ int clip_create(int number); int clip_mkip(struct atm_vcc *vcc,int timeout); int clip_setentry(struct atm_vcc *vcc,u32 ip); int clip_encap(struct atm_vcc *vcc,int mode); +void atm_clip_init(void); #endif diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h index 64153809a..7652b1512 100644 --- a/include/net/irda/irda_device.h +++ b/include/net/irda/irda_device.h @@ -35,8 +35,7 @@ #include #include - -#include +#include #include #include diff --git a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h index d66164416..52ce2b9d7 100644 --- a/include/net/irda/irqueue.h +++ b/include/net/irda/irqueue.h @@ -28,7 +28,7 @@ ********************************************************************/ #include -#include +#include #ifndef QUEUE_H #define QUEUE_H diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h index df9b78949..48ac3ee8e 100644 --- a/include/net/irda/irttp.h +++ b/include/net/irda/irttp.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/include/net/sock.h b/include/net/sock.h index d5876a8f0..6b05d7107 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -317,6 +317,11 @@ struct tcp_opt { int syn_backlog; /* Backlog of received SYNs */ int write_pending; + + unsigned int keepalive_time; /* time before keep alive takes place */ + unsigned int keepalive_intvl; /* time interval between keep alive probes */ + unsigned char keepalive_probes; /* num of allowed keep alive probes */ + unsigned char syn_retries; /* num of allowed syn retries */ }; diff --git a/include/net/tcp.h b/include/net/tcp.h index e70fec4e3..6c73eef3f 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -33,7 +33,7 @@ struct tcp_ehash_bucket { rwlock_t lock; struct sock *chain; -} __attribute__((__aligned__(SMP_CACHE_BYTES))); +} __attribute__((__aligned__(8))); extern int tcp_ehash_size; extern struct tcp_ehash_bucket *tcp_ehash; @@ -286,7 +286,12 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk) * there is no window */ #define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */ #define TCP_KEEPALIVE_PROBES 9 /* Max of 9 keepalive probes */ -#define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2) /* period of keepalive check */ +#define TCP_KEEPALIVE_INTVL (75*HZ) + +#define MAX_TCP_KEEPIDLE 32767 +#define MAX_TCP_KEEPINTVL 32767 +#define MAX_TCP_KEEPCNT 127 +#define MAX_TCP_SYNCNT 127 #define TCP_SYNACK_PERIOD (HZ/2) /* How often to run the synack slow timer */ #define TCP_QUICK_TRIES 8 /* How often we try to retransmit, until @@ -332,6 +337,12 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk) #define TIME_PROBE0 4 #define TIME_KEEPOPEN 5 +/* sysctl variables for tcp */ +extern int sysctl_tcp_keepalive_time; +extern int sysctl_tcp_keepalive_probes; +extern int sysctl_tcp_keepalive_intvl; +extern int sysctl_tcp_syn_retries; + struct open_request; struct or_calltable { @@ -611,7 +622,7 @@ extern void tcp_send_probe0(struct sock *); extern void tcp_send_partial(struct sock *); extern void tcp_write_wakeup(struct sock *); extern void tcp_send_fin(struct sock *sk); -extern void tcp_send_active_reset(struct sock *sk); +extern void tcp_send_active_reset(struct sock *sk, int priority); extern int tcp_send_synack(struct sock *); extern void tcp_transmit_skb(struct sock *, struct sk_buff *); extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue); @@ -1231,4 +1242,20 @@ extern __inline__ void tcp_listen_unlock(void) wake_up(&tcp_lhash_wait); } +static inline int keepalive_intvl_when(struct tcp_opt *tp) +{ + if (tp->keepalive_intvl) + return tp->keepalive_intvl; + else + return sysctl_tcp_keepalive_intvl; +} + +static inline int keepalive_time_when(struct tcp_opt *tp) +{ + if (tp->keepalive_time) + return tp->keepalive_time; + else + return sysctl_tcp_keepalive_time; +} + #endif /* _TCP_H */ diff --git a/kernel/dma.c b/kernel/dma.c index 4ae38f4e5..e9f0f7a52 100644 --- a/kernel/dma.c +++ b/kernel/dma.c @@ -12,9 +12,9 @@ #include #include +#include #include #include -#include /* A note on resource allocation: diff --git a/kernel/resource.c b/kernel/resource.c index 6a481f447..26ee5e29d 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -12,8 +12,7 @@ #include #include #include - -#include +#include struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF, IORESOURCE_IO }; struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF, IORESOURCE_MEM }; diff --git a/net/Config.in b/net/Config.in index 720746a1f..c00b0f902 100644 --- a/net/Config.in +++ b/net/Config.in @@ -41,7 +41,6 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_ATM_CLIP" = "y" ]; then bool ' Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP n fi -# bool ' Application REQUested IP over ATM' CONFIG_AREQUIPA y fi tristate ' LAN Emulation (LANE) support' CONFIG_ATM_LANE y if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then diff --git a/net/atm/Makefile b/net/atm/Makefile index f0b31c076..999fe1203 100644 --- a/net/atm/Makefile +++ b/net/atm/Makefile @@ -13,8 +13,8 @@ O_TARGET= atm.o ifeq ($(CONFIG_ATM),y) -O_OBJS = addr.o pvc.o raw.o signaling.o svc.o # party.o -OX_OBJS = common.o atm_misc.o resources.o +O_OBJS = addr.o pvc.o signaling.o svc.o +OX_OBJS = common.o atm_misc.o raw.o resources.o ifeq ($(CONFIG_MMU_HACKS),y) O_OBJS += mmuio.o @@ -25,11 +25,6 @@ O_OBJS += clip.o NEED_IPCOM = ipcommon.o endif -ifeq ($(CONFIG_AREQUIPA),y) -O_OBJS += arequipa.o -NEED_IPCOM = ipcommon.o -endif - ifeq ($(CONFIG_NET_SCH_ATM),y) NEED_IPCOM = ipcommon.o endif diff --git a/net/atm/addr.c b/net/atm/addr.c index cbf357a3a..f7d52a824 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -18,8 +18,7 @@ static int check_addr(struct sockaddr_atmsvc *addr) if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; if (!*addr->sas_addr.pub) - if (!*addr->sas_addr.prv) return -EINVAL; - else return 0; + return *addr->sas_addr.prv ? 0 : -EINVAL; for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */ if (!addr->sas_addr.pub[i]) return 0; return -EINVAL; diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index 353321a93..2a3a891b8 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -23,6 +23,26 @@ int atm_charge(struct atm_vcc *vcc,int truesize) } +struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size, + int gfp_flags) +{ + int guess = atm_guess_pdu2truesize(pdu_size); + + atm_force_charge(vcc,guess); + if (atomic_read(&vcc->rx_inuse) <= vcc->rx_quota) { + struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags); + + if (skb) { + atomic_add(skb->truesize-guess,&vcc->rx_inuse); + return skb; + } + } + atm_return(vcc,guess); + vcc->stats->rx_drop++; + return NULL; +} + + static int check_ci(struct atm_vcc *vcc,short vpi,int vci) { struct atm_vcc *walk; @@ -118,6 +138,6 @@ int atm_pcr_goal(struct atm_trafprm *tp) EXPORT_SYMBOL(atm_charge); -EXPORT_SYMBOL(atm_return); +EXPORT_SYMBOL(atm_alloc_charge); EXPORT_SYMBOL(atm_find_ci); EXPORT_SYMBOL(atm_pcr_goal); diff --git a/net/atm/clip.c b/net/atm/clip.c index 1746badf9..3e7a6ea16 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -45,7 +45,7 @@ struct net_device *clip_devs = NULL; struct atm_vcc *atmarpd = NULL; -static struct timer_list idle_timer = { NULL, NULL, 0L, 0L, NULL }; +static struct timer_list idle_timer; static int start_timer = 1; @@ -207,12 +207,14 @@ void clip_push(struct atm_vcc *vcc,struct sk_buff *skb) skb_pull(skb,RFC1483LLC_LEN); if (skb->protocol == htons(ETH_P_ARP)) { PRIV(skb->dev)->stats.rx_packets++; + PRIV(skb->dev)->stats.rx_bytes += skb->len; clip_arp_rcv(skb); return; } } clip_vcc->last_use = jiffies; PRIV(skb->dev)->stats.rx_packets++; + PRIV(skb->dev)->stats.rx_bytes += skb->len; netif_rx(skb); } @@ -395,13 +397,14 @@ return 0; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); - (void) ATM_SKB(skb)->vcc->dev->ops->send(ATM_SKB(skb)->vcc,skb); PRIV(dev)->stats.tx_packets++; + PRIV(dev)->stats.tx_bytes += skb->len; + (void) ATM_SKB(skb)->vcc->dev->ops->send(ATM_SKB(skb)->vcc,skb); return 0; } -static struct enet_statistics *clip_get_stats(struct net_device *dev) +static struct net_device_stats *clip_get_stats(struct net_device *dev) { return &PRIV(dev)->stats; } @@ -437,8 +440,11 @@ int clip_mkip(struct atm_vcc *vcc,int timeout) kfree_skb(skb); } else { + unsigned int len = skb->len; + clip_push(vcc,skb); PRIV(skb->dev)->stats.rx_packets--; + PRIV(skb->dev)->stats.rx_bytes -= len; } return 0; } @@ -672,6 +678,7 @@ int atm_init_atmarp(struct atm_vcc *vcc) if (atmarpd) return -EADDRINUSE; if (start_timer) { start_timer = 0; + init_timer(&idle_timer); idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ; idle_timer.function = idle_timer_check; add_timer(&idle_timer); @@ -692,3 +699,11 @@ int atm_init_atmarp(struct atm_vcc *vcc) (void) to_atmarpd(act_up,PRIV(dev)->number,0); return 0; } + + +void atm_clip_init(void) +{ + clip_tbl.lock = RW_LOCK_UNLOCKED; + clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id, + clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); +} diff --git a/net/atm/common.c b/net/atm/common.c index 9933090e6..cd1572010 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -29,10 +29,6 @@ #include #endif -#ifdef CONFIG_AREQUIPA -#include -#endif - #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #include #include "lec.h" @@ -107,10 +103,6 @@ int atm_create(struct socket *sock,int protocol,int family) if (sock->type == SOCK_STREAM) return -EINVAL; if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM; vcc = sk->protinfo.af_atm; -#ifdef CONFIG_AREQUIPA - vcc->upper = NULL; - vcc->sock = sock; -#endif vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX; vcc->dev = NULL; vcc->family = sock->ops->family; @@ -620,29 +612,6 @@ int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) if (!capable(CAP_NET_ADMIN)) return -EPERM; return clip_encap(vcc,arg); #endif -#ifdef CONFIG_AREQUIPA - case AREQUIPA_PRESET: - { - struct socket *upper; - - if (!(upper = sockfd_lookup(arg,&error))) - return error; - if (upper->ops->family != PF_INET) - return -EPROTOTYPE; - return arequipa_preset(sock,upper->sk); - } - case AREQUIPA_INCOMING: - return arequipa_incoming(sock); - case AREQUIPA_CTRL: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - error = arequipad_attach(vcc); - if (!error) sock->state = SS_CONNECTED; - return error; - case AREQUIPA_WORK: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - arequipa_work(); - return 0; -#endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) case ATMLEC_CTRL: if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -899,6 +868,8 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, case SO_BCTXOPT: /* fall through */ case SO_BCRXOPT: + printk(KERN_WARNING "Warning: SO_BCTXOPT/SO_BCRXOPT " + "are obsolete\n"); break; case SO_ATMQOS: if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL; @@ -907,6 +878,19 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, case SO_SETCLP: return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0,(unsigned long *) optval) ? -EFAULT : 0; + case SO_ATMPVC: + { + struct sockaddr_atmpvc pvc; + + if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) + return -ENOTCONN; + pvc.sap_family = AF_ATMPVC; + pvc.sap_addr.itf = vcc->dev->number; + pvc.sap_addr.vpi = vcc->vpi; + pvc.sap_addr.vci = vcc->vci; + return copy_to_user(optval,&pvc,sizeof(pvc)) ? + -EFAULT : 0; + } default: if (level == SOL_SOCKET) return -EINVAL; break; @@ -919,7 +903,7 @@ static int atm_do_getsockopt(struct socket *sock,int level,int optname, int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, int optlen) { - if (level == __SO_LEVEL(optname) && optlen != __SO_SIZE(optname)) + if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) return -EINVAL; return atm_do_setsockopt(sock,level,optname,optval,optlen); } @@ -931,7 +915,7 @@ int atm_getsockopt(struct socket *sock,int level,int optname, int len; if (get_user(len,optlen)) return -EFAULT; - if (level == __SO_LEVEL(optname) && len != __SO_SIZE(optname)) + if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) return -EINVAL; return atm_do_getsockopt(sock,level,optname,optval,len); } diff --git a/net/atm/lec.c b/net/atm/lec.c index ab640c4e6..67e8c33b4 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -59,7 +59,7 @@ static int lec_open(struct net_device *dev); static int lec_send_packet(struct sk_buff *skb, struct net_device *dev); static int lec_close(struct net_device *dev); -static struct enet_statistics *lec_get_stats(struct net_device *dev); +static struct net_device_stats *lec_get_stats(struct net_device *dev); static int lec_init(struct net_device *dev); static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv, unsigned char *mac_addr); @@ -165,8 +165,10 @@ unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) /* offset 4 comes from LAN destination field in LE control frames */ if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT)) memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t)); - else + else { memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t)); + rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0)); + } return NULL; } @@ -189,7 +191,7 @@ lec_open(struct net_device *dev) dev->tbusy = 0; dev->start = 1; dev->interrupt = 1; - memset(&priv->stats,0,sizeof(struct enet_statistics)); + memset(&priv->stats,0,sizeof(struct net_device_stats)); return 0; } @@ -348,16 +350,18 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) ATM_SKB(skb2)->atm_options = send_vcc->atm_options; DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name, send_vcc->vpi, send_vcc->vci); - send_vcc->dev->ops->send(send_vcc, skb2); priv->stats.tx_packets++; + priv->stats.tx_bytes += skb2->len; + send_vcc->dev->ops->send(send_vcc, skb2); } ATM_SKB(skb)->vcc = send_vcc; atomic_add(skb->truesize, &send_vcc->tx_inuse); ATM_SKB(skb)->iovcnt = 0; ATM_SKB(skb)->atm_options = send_vcc->atm_options; - send_vcc->dev->ops->send(send_vcc, skb); priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + send_vcc->dev->ops->send(send_vcc, skb); } /* Should we wait for card's device driver to notify us? */ dev->tbusy=0; @@ -378,12 +382,10 @@ lec_close(struct net_device *dev) * Get the current statistics. * This may be called with the card open or closed. */ -static struct enet_statistics * +static struct net_device_stats * lec_get_stats(struct net_device *dev) { - struct lec_priv *priv = (struct lec_priv *)dev->priv; - - return (struct enet_statistics *)&priv->stats; + return &((struct lec_priv *)dev->priv)->stats; } static int @@ -714,8 +716,9 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb) else #endif skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + netif_rx(skb); } } @@ -769,12 +772,12 @@ lecd_attach(struct atm_vcc *vcc, int arg) return -EINVAL; #endif if (!dev_lec[i]) { - dev_lec[i] = (struct net_device*)kmalloc(sizeof(struct net_device)+ - sizeof(myname)+1, - GFP_KERNEL); + dev_lec[i] = (struct net_device*) + kmalloc(sizeof(struct net_device)+sizeof(myname)+1, + GFP_KERNEL); if (!dev_lec[i]) return -ENOMEM; - memset(dev_lec[i],0, sizeof(struct net_device)+sizeof(myname)+1); + memset(dev_lec[i],0,sizeof(struct net_device)+sizeof(myname)+1); dev_lec[i]->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL); if (!dev_lec[i]->priv) @@ -888,7 +891,8 @@ void cleanup_module(void) * lec will be used. * If dst_mac == NULL, targetless LE_ARP will be sent */ -static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs) +static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, + u8 **tlvs, u32 *sizeoftlvs) { struct lec_priv *priv = (struct lec_priv *)dev->priv; struct lec_arp_table *table; @@ -968,7 +972,8 @@ static int lane2_associate_req (struct net_device *dev, u8 *lan_dst, * LANE2: 3.1.5, LE_ASSOCIATE.indication * */ -static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs) +static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, + u8 *tlvs, u32 sizeoftlvs) { #if 0 int i = 0; @@ -1004,8 +1009,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, u8 *tlvs, priv->lane2_ops->associate_indicator(dev, mac_addr, tlvs, sizeoftlvs); } - else - printk("lane:(%s) lane2_associate_ind: could not notify MPOA\n", dev->name); return; } diff --git a/net/atm/lec.h b/net/atm/lec.h index 4ed1ddfbf..4a94c2b6d 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -74,7 +74,7 @@ struct atm_lane_ops { #define LEC_ARP_TABLE_SIZE 16 struct lec_priv { - struct enet_statistics stats; + struct net_device_stats stats; unsigned short lecid; /* Lecid of this client */ struct lec_arp_table *lec_arp_empty_ones; /* Used for storing VCC's that don't have a MAC address attached yet */ diff --git a/net/atm/mpc.h b/net/atm/mpc.h index ca2e650a2..2237ba43f 100644 --- a/net/atm/mpc.h +++ b/net/atm/mpc.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "mpoa_caches.h" /* kernel -> mpc-daemon */ @@ -16,7 +16,7 @@ int atm_mpoa_vcc_attach(struct atm_vcc *vcc, long arg); struct mpoa_client { struct mpoa_client *next; - struct net_device *dev; /* lec in question */ + struct net_device *dev; /* lec in question */ int dev_num; /* e.g. 2 for lec2 */ int (*old_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ diff --git a/net/atm/proc.c b/net/atm/proc.c index 3d9cffd02..7875d9dfd 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -38,11 +38,6 @@ #include "common.h" /* atm_proc_init prototype */ #include "signaling.h" /* to get sigd - ugly too */ -#ifdef CONFIG_AREQUIPA -#include -void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb); -#endif - #ifdef CONFIG_ATM_CLIP #include #include "ipcommon.h" @@ -111,9 +106,6 @@ ENTRY(arp); #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) ENTRY(lec); #endif -#ifdef CONFIG_AREQUIPA -ENTRY(arequipa); -#endif static int atm_header(ino_t ino,char *buf) @@ -137,10 +129,6 @@ static int atm_header(ino_t ino,char *buf) " Status Flags " "VPI/VCI Recv VPI/VCI\n"); #endif -#ifdef CONFIG_AREQUIPA - if (ino == INO(arequipa)) - return sprintf(buf,"Itf VPI VCI State Sock# Inode\n"); -#endif return -EINVAL; } @@ -300,37 +288,6 @@ static void svc_info(struct atm_vcc *vcc,char *buf) } -#ifdef CONFIG_AREQUIPA - - -static const char *arequipa_state(const struct atm_vcc *vcc) -{ - if (!(vcc->flags & ATM_VF_REGIS) && vcc->family != PF_ATMPVC) - return "DOOMED"; - if (vcc->upper) return "ATTACHED"; - return "DANGLING"; -} - - -static void arequipa_info(struct atm_vcc *vcc,char *buf) -{ - char *here; - - if (!vcc->dev) sprintf(buf,"Unassigned "); - else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci); - here = strchr(buf,0); - here += sprintf(here,"%-8s ",arequipa_state(vcc)); - if (vcc->upper) - here += sprintf(here,"%5d %ld",vcc->upper->num, - vcc->upper->socket && SOCK_INODE(vcc->upper->socket) ? - SOCK_INODE(vcc->upper->socket)->i_ino : 0); - strcat(here,"\n"); -} - - -#endif - - #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) static char* @@ -458,18 +415,6 @@ static int atm_info(ino_t ino,loff_t *pos,char *buf) return 0; } #endif -#ifdef CONFIG_AREQUIPA - if (ino == INO(arequipa)) { - left = *pos-1; - for (dev = atm_devs; dev; dev = dev->next) - for (vcc = dev->vccs; vcc; vcc = vcc->next) - if (vcc->push == atm_push_arequipa && !left--) { - arequipa_info(vcc,buf); - return strlen(buf); - } - return 0; - } -#endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) if (ino == INO(lec)) { struct lec_priv *priv; @@ -610,8 +555,5 @@ int __init atm_proc_init(void) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) REG(lec); #endif -#ifdef CONFIG_AREQUIPA - REG(arequipa); -#endif return error; } diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 077dce961..4b6817eb9 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -1,6 +1,6 @@ /* net/atm/pvc.c - ATM PVC sockets */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -14,9 +14,6 @@ #include #include #include /* for sock_no_* */ -#ifdef CONFIG_AREQUIPA -#include -#endif #ifdef CONFIG_ATM_CLIP #include #endif @@ -66,14 +63,11 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, int *sockaddr_len,int peer) { struct sockaddr_atmpvc *addr; - struct atm_vcc *vcc; + struct atm_vcc *vcc = ATM_SD(sock); -#if 0 /* add some sanity checks later ... @@@ */ - if (sock->state != SS_CONNECTED) return -EINVAL; -#endif + if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) return -ENOTCONN; *sockaddr_len = sizeof(struct sockaddr_atmpvc); addr = (struct sockaddr_atmpvc *) sockaddr; - vcc = ATM_SD(sock); addr->sap_family = AF_ATMPVC; addr->sap_addr.itf = vcc->dev->number; addr->sap_addr.vpi = vcc->vpi; @@ -102,6 +96,7 @@ static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { sock_no_mmap }; + #include SOCKOPS_WRAP(pvc_proto, PF_ATMPVC); @@ -137,15 +132,7 @@ void __init atmpvc_proto_init(struct net_proto *pro) return; } #ifdef CONFIG_ATM_CLIP - clip_tbl.lock = RW_LOCK_UNLOCKED; - if (clip_tbl.kmem_cachep == NULL) - clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id, - clip_tbl.entry_size, - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); -#endif -#ifdef CONFIG_AREQUIPA - (void) atm_init_arequipa(); + atm_clip_init(); #endif #ifdef CONFIG_PROC_FS error = atm_proc_init(); diff --git a/net/atm/raw.c b/net/atm/raw.c index ff7dad7bb..d93baa0ec 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -1,9 +1,10 @@ /* net/atm/raw.c - Raw AAL0 and AAL5 transports */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC */ +/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ #include +#include #include #include #include @@ -78,3 +79,6 @@ int atm_init_aal5(struct atm_vcc *vcc) vcc->push_oam = NULL; return 0; } + + +EXPORT_SYMBOL(atm_init_aal5); diff --git a/net/atm/svc.c b/net/atm/svc.c index febba7925..778ce1856 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -311,7 +311,7 @@ static int svc_setsockopt(struct socket *sock,int level,int optname, { struct atm_vcc *vcc; - if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP || + if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP || optlen != sizeof(struct atm_sap)) return atm_setsockopt(sock,level,optname,optval,optlen); vcc = ATM_SD(sock); @@ -326,7 +326,7 @@ static int svc_getsockopt(struct socket *sock,int level,int optname, { int len; - if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP) + 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; diff --git a/net/atm/tunable.h b/net/atm/tunable.h index c8deed47d..75071f75a 100644 --- a/net/atm/tunable.h +++ b/net/atm/tunable.h @@ -6,13 +6,6 @@ #ifndef NET_ATM_TUNABLE_H #define NET_ATM_TUNABLE_H -#if 0 -/* this is just a reminder - TTS is a device-specific parameter and shall be - used inside device drivers only */ -#define ATM_TTS 1000 /* worst-case time to service of device - drivers, in microseconds */ -#endif - #define ATM_RXBQ_DEF ( 64*1024) /* default RX buffer quota, in bytes */ #define ATM_TXBQ_DEF ( 64*1024) /* default TX buffer quota, in bytes */ #define ATM_RXBQ_MIN ( 1*1024) /* RX buffer minimum, in bytes */ diff --git a/net/core/netfilter.c b/net/core/netfilter.c index a03e7477f..a6472a7de 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #define __KERNEL_SYSCALLS__ #include @@ -47,6 +47,7 @@ struct nf_info }; static rwlock_t nf_lock = RW_LOCK_UNLOCKED; +static DECLARE_MUTEX(nf_sockopt_mutex); struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; static LIST_HEAD(nf_sockopts); @@ -91,15 +92,15 @@ void nf_unregister_hook(struct nf_hook_ops *reg) write_unlock_bh(&nf_lock); } -/* Do inclusive ranges overlap? */ +/* Do exclusive ranges overlap? */ static inline int overlap(int min1, int max1, int min2, int max2) { - return (min1 >= min2 && min1 <= max2) - || (max1 >= min2 && max1 <= max2); + return (min1 >= min2 && min1 < max2) + || (max1 > min2 && max1 <= max2); } -/* Functions to register setsockopt ranges (inclusive). */ -int nf_register_sockopt(struct nf_setsockopt_ops *reg) +/* Functions to register sockopt ranges (exclusive). */ +int nf_register_sockopt(struct nf_sockopt_ops *reg) { struct list_head *i; int ret = 0; @@ -109,33 +110,44 @@ int nf_register_sockopt(struct nf_setsockopt_ops *reg) NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf); return -EINVAL; } - if (reg->optmin > reg->optmax) { - NFDEBUG("nf_register_sockopt: bad val: min=%i max=%i.\n", - reg->optmin, reg->optmax); + if (reg->set_optmin > reg->set_optmax) { + NFDEBUG("nf_register_sockopt: bad set val: min=%i max=%i.\n", + reg->set_optmin, reg->set_optmax); + return -EINVAL; + } + if (reg->get_optmin > reg->get_optmax) { + NFDEBUG("nf_register_sockopt: bad get val: min=%i max=%i.\n", + reg->get_optmin, reg->get_optmax); return -EINVAL; } #endif - write_lock_bh(&nf_lock); + if (down_interruptible(&nf_sockopt_mutex) != 0) + return -EINTR; + for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { - struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i; + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; if (ops->pf == reg->pf - && overlap(ops->optmin, ops->optmax, - reg->optmin, reg->optmax)) { - NFDEBUG("nf_register_sockopt overlap: %u-%u v %u-%u\n", - ops->optmin, ops->optmax, - reg->optmin, reg->optmax); + && (overlap(ops->set_optmin, ops->set_optmax, + reg->set_optmin, reg->set_optmax) + || overlap(ops->get_optmin, ops->get_optmax, + reg->get_optmin, reg->get_optmax))) { + NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", + ops->set_optmin, ops->set_optmax, + ops->get_optmin, ops->get_optmax, + reg->set_optmin, reg->set_optmax, + reg->get_optmin, reg->get_optmax); ret = -EBUSY; goto out; } } - + list_add(®->list, &nf_sockopts); out: - write_unlock_bh(&nf_lock); + up(&nf_sockopt_mutex); return ret; } -void nf_unregister_sockopt(struct nf_setsockopt_ops *reg) +void nf_unregister_sockopt(struct nf_sockopt_ops *reg) { #ifdef CONFIG_NETFILTER_DEBUG if (reg->pf<0 || reg->pf>=NPROTO) { @@ -143,9 +155,10 @@ void nf_unregister_sockopt(struct nf_setsockopt_ops *reg) return; } #endif - write_lock_bh(&nf_lock); + /* No point being interruptible: we're probably in cleanup_module() */ + down(&nf_sockopt_mutex); list_del(®->list); - write_unlock_bh(&nf_lock); + up(&nf_sockopt_mutex); } #ifdef CONFIG_NETFILTER_DEBUG @@ -290,8 +303,9 @@ void nf_cacheflush(int pf, unsigned int hook, const void *packet, read_unlock_bh(&nf_lock); } -/* Call setsockopt() */ -int nf_setsockopt(int pf, int val, char *opt, unsigned int len) +/* Call get/setsockopt() */ +static int nf_sockopt(struct sock *sk, int pf, int val, + char *opt, int *len, int get) { struct list_head *i; int ret; @@ -299,21 +313,44 @@ int nf_setsockopt(int pf, int val, char *opt, unsigned int len) if (!capable(CAP_NET_ADMIN)) return -EPERM; - read_lock_bh(&nf_lock); + if (down_interruptible(&nf_sockopt_mutex) != 0) + return -EINTR; + for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { - struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i; - if (ops->pf == pf - && val >= ops->optmin && val <= ops->optmax) { - ret = ops->fn(val, opt, len); - goto out; + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; + if (ops->pf == pf) { + if (get) { + if (val >= ops->get_optmin + && val < ops->get_optmax) { + ret = ops->get(sk, val, opt, len); + goto out; + } + } else { + if (val >= ops->set_optmin + && val < ops->set_optmax) { + ret = ops->set(sk, val, opt, *len); + goto out; + } + } } } ret = -ENOPROTOOPT; out: - read_unlock_bh(&nf_lock); + up(&nf_sockopt_mutex); return ret; } +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt, + int len) +{ + return nf_sockopt(sk, pf, val, opt, &len, 0); +} + +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len) +{ + return nf_sockopt(sk, pf, val, opt, len, 1); +} + static unsigned int nf_iterate(struct list_head *head, struct sk_buff **skb, int hook, diff --git a/net/core/sock.c b/net/core/sock.c index 667ae9931..2b0018ec9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.85 1999/08/23 05:16:08 davem Exp $ + * Version: $Id: sock.c,v 1.86 1999/09/01 08:11:49 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 6ab62db05..e34f4b6aa 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 35fe59751..996beaa0c 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/net/decnet/dn_timer.c b/net/decnet/dn_timer.c index 76cf8104d..1e6bd8272 100644 --- a/net/decnet/dn_timer.c +++ b/net/decnet/dn_timer.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/net/econet/econet.c b/net/econet/econet.c index 65194de88..6e7523eed 100644 --- a/net/econet/econet.c +++ b/net/econet/econet.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include static struct proto_ops econet_ops; static struct sock *econet_sklist; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 87dca3e7c..526dd4dd6 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.95 1999/08/30 10:17:00 davem Exp $ + * Version: $Id: af_inet.c,v 1.97 1999/09/08 03:46:46 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 4cd66b41e..5e6b50ea7 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.70 1999/08/31 07:03:39 davem Exp $ + * Version: $Id: ip_output.c,v 1.72 1999/09/07 02:31:15 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -345,7 +345,7 @@ static inline int ip_queue_xmit2(struct sk_buff *skb) if (skb2 == NULL) return -ENOMEM; if (sk) - skb_set_owner_w(skb, sk); + skb_set_owner_w(skb2, sk); skb = skb2; iph = skb->nh.iph; } @@ -386,7 +386,7 @@ int ip_queue_xmit(struct sk_buff *skb) struct iphdr *iph; /* Make sure we can route this packet. */ - rt = (struct rtable *)sk_dst_check(sk, 0); + rt = (struct rtable *)__sk_dst_check(sk, 0); if (rt == NULL) { u32 daddr; @@ -403,10 +403,9 @@ int ip_queue_xmit(struct sk_buff *skb) RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute, sk->bound_dev_if)) goto no_route; - dst_clone(&rt->u.dst); - sk_dst_set(sk, &rt->u.dst); + __sk_dst_set(sk, &rt->u.dst); } - skb->dst = &rt->u.dst; + skb->dst = dst_clone(&rt->u.dst); if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto no_route; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0870ea98a..7278a0b4a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.44 1999/08/20 11:05:49 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.45 1999/09/06 04:58:03 davem Exp $ * * Authors: see ip.c * @@ -598,13 +598,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt default: #ifdef CONFIG_NETFILTER - release_sock(sk); - return nf_setsockopt(PF_INET, optname, optval, - (unsigned int)optlen); + err = nf_setsockopt(sk, PF_INET, optname, optval, + optlen); #else err = -ENOPROTOOPT; - break; #endif + break; } release_sock(sk); return err; @@ -758,8 +757,17 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op return put_user(len, optlen); } default: +#ifdef CONFIG_NETFILTER + val = nf_getsockopt(sk, PF_INET, optname, optval, + &len); + release_sock(sk); + if (val >= 0) + val = put_user(len, optlen); + return val; +#else release_sock(sk); return -ENOPROTOOPT; +#endif } release_sock(sk); diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 298cd925b..1ff1566af 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.39 1999/08/20 11:06:00 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.40 1999/09/07 02:31:17 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -150,6 +150,9 @@ ctl_table ipv4_table[] = { {NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes", &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl", + &sysctl_tcp_keepalive_intvl, sizeof(int), 0644, NULL, + &proc_dointvec_jiffies, &sysctl_jiffies}, {NET_IPV4_TCP_RETRIES1, "tcp_retries1", &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, NULL, &tcp_retr1_max}, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7a547a404..b8e5d197c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.149 1999/08/30 10:17:17 davem Exp $ + * Version: $Id: tcp.c,v 1.151 1999/09/07 02:31:21 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1580,7 +1580,7 @@ void tcp_close(struct sock *sk, long timeout) if(data_was_unread != 0) { /* Unread data was tossed, zap the connection. */ tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk); + tcp_send_active_reset(sk, GFP_KERNEL); } else if (tcp_close_state(sk,1)) { /* We FIN if the application ate all the data before * zapping the connection. @@ -1658,7 +1658,7 @@ int tcp_disconnect(struct sock *sk, int flags) if (old_state == TCP_LISTEN) { tcp_close_pending(sk); } else if (tcp_connected(old_state)) { - tcp_send_active_reset(sk); + tcp_send_active_reset(sk, GFP_KERNEL); sk->err = ECONNRESET; } else if (old_state == TCP_SYN_SENT) sk->err = ECONNRESET; @@ -1870,6 +1870,40 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, tcp_push_pending_frames(sk, tp); } break; + + case TCP_KEEPIDLE: + if (val < 1 || val > MAX_TCP_KEEPIDLE) + err = -EINVAL; + else { + tp->keepalive_time = val * HZ; + if (sk->keepopen) { + __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp; + if (tp->keepalive_time > elapsed) + elapsed = tp->keepalive_time - elapsed; + else + elapsed = 0; + tcp_reset_keepalive_timer(sk, elapsed); + } + } + break; + case TCP_KEEPINTVL: + if (val < 1 || val > MAX_TCP_KEEPINTVL) + err = -EINVAL; + else + tp->keepalive_intvl = val * HZ; + break; + case TCP_KEEPCNT: + if (val < 1 || val > MAX_TCP_KEEPCNT) + err = -EINVAL; + else + tp->keepalive_probes = val; + break; + case TCP_SYNCNT: + if (val < 1 || val > MAX_TCP_SYNCNT) + err = -EINVAL; + else + tp->syn_retries = val; + break; default: err = -ENOPROTOOPT; @@ -1904,6 +1938,30 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, case TCP_CORK: val = (sk->nonagle == 2); break; + case TCP_KEEPIDLE: + if (tp->keepalive_time) + val = tp->keepalive_time / HZ; + else + val = sysctl_tcp_keepalive_time / HZ; + break; + case TCP_KEEPINTVL: + if (tp->keepalive_intvl) + val = tp->keepalive_intvl / HZ; + else + val = sysctl_tcp_keepalive_intvl / HZ; + break; + case TCP_KEEPCNT: + if (tp->keepalive_probes) + val = tp->keepalive_probes; + else + val = sysctl_tcp_keepalive_probes; + break; + case TCP_SYNCNT: + if (tp->syn_retries) + val = tp->syn_retries; + else + val = sysctl_tcp_syn_retries; + break; default: return -ENOPROTOOPT; }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 517ec8a97..f0711fccc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.172 1999/08/23 06:30:35 davem Exp $ + * Version: $Id: tcp_input.c,v 1.173 1999/09/07 02:31:27 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -2423,7 +2423,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, newsk->timer.function = &tcp_keepalive_timer; newsk->timer.data = (unsigned long) newsk; if (newsk->keepopen) - tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time); + tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp)); newsk->socket = NULL; newsk->sleep = NULL; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 7a953a1b4..986868b4f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.187 1999/08/31 07:03:48 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.189 1999/09/07 02:31:33 davem Exp $ * * IPv4 specific functions * @@ -1822,7 +1822,7 @@ static void __tcp_v4_rehash(struct sock *sk) int tcp_v4_rebuild_header(struct sock *sk) { - struct rtable *rt = (struct rtable *)sk->dst_cache; + struct rtable *rt = (struct rtable *)__sk_dst_get(sk); __u32 new_saddr; int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 222aa07cf..77f8b98ca 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.112 1999/08/23 06:30:37 davem Exp $ + * Version: $Id: tcp_output.c,v 1.113 1999/09/07 02:31:39 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -825,13 +825,13 @@ void tcp_send_fin(struct sock *sk) * was unread data in the receive queue. This behavior is recommended * by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM */ -void tcp_send_active_reset(struct sock *sk) +void tcp_send_active_reset(struct sock *sk, int priority) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct sk_buff *skb; /* NOTE: No TCP options attached and we never retransmit this. */ - skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL); + skb = alloc_skb(MAX_HEADER + sk->prot->max_header, priority); if (!skb) return; @@ -947,7 +947,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, int tcp_connect(struct sock *sk, struct sk_buff *buff) { - struct dst_entry *dst = sk->dst_cache; + struct dst_entry *dst = __sk_dst_get(sk); struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); /* Reserve space for headers. */ diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e08968490..a38724e42 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.67 1999/08/30 12:14:43 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.68 1999/09/07 02:31:43 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -25,6 +25,7 @@ int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME; int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES; +int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL; int sysctl_tcp_retries1 = TCP_RETR1; int sysctl_tcp_retries2 = TCP_RETR2; @@ -183,7 +184,9 @@ static void tcp_write_timeout(struct sock *sk) } /* Have we tried to SYN too many times (repent repent 8)) */ - if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) { + if (sk->state == TCP_SYN_SENT && + ((!tp->syn_retries && tp->retransmits > sysctl_tcp_syn_retries) || + (tp->syn_retries && tp->retransmits > tp->syn_retries))) { tcp_write_err(sk, 1); /* Don't FIN, we got nothing back */ } else if (tp->retransmits > sysctl_tcp_retries2) { @@ -593,7 +596,7 @@ void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len) void tcp_set_keepalive(struct sock *sk, int val) { if (val && !sk->keepopen) - tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time); + tcp_reset_keepalive_timer(sk, keepalive_time_when(&sk->tp_pinfo.af_tcp)); else if (!val) tcp_delete_keepalive_timer(sk); } @@ -619,25 +622,29 @@ void tcp_keepalive_timer (unsigned long data) if (!sk->keepopen) goto out; - elapsed = sysctl_tcp_keepalive_time; + elapsed = keepalive_time_when(tp); if (!((1<state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2))) goto resched; elapsed = tcp_time_stamp - tp->rcv_tstamp; - if (elapsed >= sysctl_tcp_keepalive_time) { - if (tp->probes_out > sysctl_tcp_keepalive_probes) { + if (elapsed >= keepalive_time_when(tp)) { + if ((!tp->keepalive_probes && tp->probes_out >= sysctl_tcp_keepalive_probes) || + (tp->keepalive_probes && tp->probes_out >= tp->keepalive_probes)) { + tcp_send_active_reset(sk, GFP_ATOMIC); tcp_write_err(sk, 1); goto out; } tp->probes_out++; tp->pending = TIME_KEEPOPEN; tcp_write_wakeup(sk); - /* Randomize to avoid synchronization */ - elapsed = (TCP_KEEPALIVE_PERIOD>>1) + (net_random()%TCP_KEEPALIVE_PERIOD); + elapsed = keepalive_intvl_when(tp); } else { - /* It is tp->rcv_tstamp + sysctl_tcp_keepalive_time */ - elapsed = sysctl_tcp_keepalive_time - elapsed; + /* It is tp->rcv_tstamp + keepalive_time_when(tp) */ + if (keepalive_time_when(tp) > elapsed) + elapsed = keepalive_time_when(tp) - elapsed; + else + elapsed = 0; } resched: diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 09c25a263..1f4571a5d 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -36,12 +36,12 @@ #include #include #include +#include #include #include #include #include -#include #include diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index a703e1939..79901319d 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -375,7 +375,7 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch) result = TC_POLICE_OK; /* be nice to gcc */ if (TC_H_MAJ(skb->priority) != sch->handle || !(flow = (struct atm_flow_data *) atm_tc_get(sch,skb->priority))) - for (flow = p->link.next; flow; flow = flow->next) + for (flow = p->flows; flow; flow = flow->next) if (flow->filter_list) { result = tc_classify(skb,flow->filter_list, &res); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 57de0f16f..d4bec3a5d 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: af_unix.c,v 1.82 1999/08/30 10:17:37 davem Exp $ + * Version: $Id: af_unix.c,v 1.84 1999/09/08 03:47:18 davem Exp $ * * Fixes: * Linus Torvalds : Assorted bug cures. -- 2.11.4.GIT