From 61fbe25f37fea32ccd21c8f51a4948fe49459752 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:01 -0500 Subject: [PATCH] Import 1.3.0 --- CREDITS | 2 +- Makefile | 10 +- arch/alpha/boot/main.c | 10 + arch/alpha/config.in | 49 +- arch/alpha/kernel/Makefile | 3 +- arch/alpha/kernel/bios32.c | 478 +++++ arch/alpha/kernel/entry.S | 409 ++++- arch/alpha/kernel/head.S | 40 +- arch/alpha/kernel/irq.c | 4 +- arch/alpha/kernel/lca.c | 254 +-- arch/alpha/kernel/osf_sys.c | 494 ++++++ arch/alpha/kernel/process.c | 108 +- arch/alpha/kernel/setup.c | 103 +- arch/alpha/kernel/signal.c | 284 ++- arch/alpha/kernel/traps.c | 92 +- arch/alpha/lib/Makefile | 2 +- arch/alpha/lib/divide.S | 32 +- arch/alpha/lib/io.c | 98 ++ arch/alpha/lib/memcpy.c | 74 + arch/alpha/mm/fault.c | 11 +- arch/alpha/mm/init.c | 10 +- arch/i386/config.in | 65 +- arch/i386/kernel/bios32.c | 380 +--- arch/i386/kernel/entry.S | 7 +- arch/i386/kernel/head.S | 4 +- arch/i386/kernel/process.c | 16 + arch/i386/kernel/setup.c | 47 + arch/i386/kernel/signal.c | 2 +- arch/i386/mm/init.c | 15 +- drivers/Makefile | 4 + drivers/block/ide-cd.c | 715 ++++++-- drivers/block/ll_rw_blk.c | 11 +- drivers/char/Makefile | 6 + drivers/char/README.scc | 933 ++++++++++ drivers/char/console.c | 6 +- drivers/char/keyboard.c | 2 +- drivers/char/n_tty.c | 2 +- drivers/char/scc.c | 2305 ++++++++++++++++++++++++ drivers/char/scc_config.h | 67 + drivers/char/selection.h | 25 + drivers/char/serial.c | 20 +- drivers/char/tty_io.c | 5 + drivers/net/3c501.c | 33 +- drivers/net/3c505.c | 2322 ++++++++++++------------- drivers/net/3c505.h | 178 +- drivers/net/3c505dta.h | 119 -- drivers/net/3c507.c | 1 + drivers/net/3c509.c | 1 + drivers/net/8390.c | 1 + drivers/net/CONFIG | 1 + drivers/net/Makefile | 16 +- drivers/net/README.3c505 | 39 +- drivers/net/README.eql | 528 ++++++ drivers/net/README.tunnel | 123 ++ drivers/net/Space.c | 121 ++ drivers/net/apricot.c | 1 + drivers/net/arcnet.c | 57 +- drivers/net/at1700.c | 1 + drivers/net/atp.c | 1 + drivers/net/de4x5.c | 1 + drivers/net/de600.c | 3 +- drivers/net/de620.c | 1 + drivers/net/depca.c | 1 + drivers/net/eexpress.c | 1 + drivers/net/eql.c | 1153 ++++++++++++ drivers/net/ewrk3.c | 2 + drivers/net/ibmtr.c | 1180 +++++++++++++ drivers/net/ibmtr.h | 426 +++++ drivers/net/lance.c | 1 + drivers/net/loopback.c | 162 +- drivers/net/net_init.c | 34 +- drivers/net/ni52.c | 1 + drivers/net/ni65.c | 1 + drivers/net/pi2.c | 1693 ++++++++++++++++++ drivers/net/pi2.h | 133 ++ drivers/net/plip.c | 1 + drivers/net/ppp.c | 23 +- drivers/net/sk_g16.c | 1 + drivers/net/slhc.c | 11 +- drivers/net/slip.c | 61 +- drivers/net/slip.h | 1 + drivers/net/tulip.c | 1 + drivers/net/tunnel.c | 311 ++++ drivers/net/wavelan.c | 1 + drivers/net/z8530.h | 220 +++ drivers/net/znet.c | 15 +- drivers/pci/Makefile | 40 + drivers/pci/pci.c | 752 ++++++++ drivers/scsi/53c7,8xx.c | 8 +- drivers/scsi/Makefile | 2 +- drivers/scsi/aha1740.c | 18 +- drivers/scsi/aha1740.h | 42 +- drivers/scsi/qlogic.c | 2 +- drivers/scsi/scsi.c | 38 +- drivers/scsi/sd.c | 4 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/sg.h | 2 +- drivers/scsi/sr.c | 4 +- fs/Makefile | 2 +- fs/buffer.c | 7 +- fs/ext/dir.c | 38 +- fs/ext/inode.c | 26 +- fs/ext2/dir.c | 45 +- fs/ext2/super.c | 30 +- fs/fcntl.c | 2 +- fs/hpfs/hpfs_fs.c | 146 +- fs/inode.c | 3 + fs/ioctl.c | 4 +- fs/isofs/dir.c | 330 ++-- fs/isofs/inode.c | 22 +- fs/locks.c | 723 +++++--- fs/minix/dir.c | 45 +- fs/minix/inode.c | 27 +- fs/msdos/dir.c | 53 +- fs/msdos/inode.c | 20 +- fs/namei.c | 1 - fs/nfs/cache.c | 63 + fs/nfs/dir.c | 37 +- fs/nfs/inode.c | 24 +- fs/open.c | 56 +- fs/pipe.c | 57 +- fs/proc/array.c | 51 - fs/proc/base.c | 20 +- fs/proc/fd.c | 79 +- fs/proc/inode.c | 22 +- fs/proc/net.c | 18 +- fs/proc/root.c | 66 +- fs/read_write.c | 31 - fs/readdir.c | 145 ++ fs/select.c | 52 +- fs/sysv/dir.c | 63 +- fs/sysv/inode.c | 27 +- fs/umsdos/inode.c | 4 +- fs/xiafs/dir.c | 35 +- fs/xiafs/inode.c | 25 +- include/asm-alpha/dirent.h | 11 + include/asm-alpha/dma.h | 44 +- include/asm-alpha/errno.h | 134 ++ include/asm-alpha/fcntl.h | 52 + include/asm-alpha/hwrpb.h | 33 + include/asm-alpha/io.h | 51 +- include/asm-alpha/ioctl.h | 57 + include/asm-alpha/ipsum.h | 45 + include/asm-alpha/jensen.h | 177 +- include/asm-alpha/lca.h | 227 ++- include/asm-alpha/pgtable.h | 80 +- include/asm-alpha/processor.h | 40 +- include/asm-alpha/ptrace.h | 16 + include/asm-alpha/resource.h | 24 + include/asm-alpha/segment.h | 55 +- include/asm-alpha/signal.h | 102 ++ include/asm-alpha/stat.h | 40 + include/asm-alpha/statfs.h | 27 + include/asm-alpha/string.h | 3 + include/asm-alpha/system.h | 39 +- include/asm-alpha/termios.h | 334 ++++ include/asm-alpha/types.h | 21 + include/asm-alpha/unaligned.h | 112 ++ include/asm-alpha/unistd.h | 70 +- include/asm-i386/errno.h | 127 ++ include/asm-i386/fcntl.h | 64 + include/asm-i386/io.h | 22 + include/asm-i386/pgtable.h | 10 +- include/asm-i386/resource.h | 23 + include/asm-i386/segment.h | 95 +- include/asm-i386/signal.h | 79 + include/asm-i386/stat.h | 41 + include/asm-i386/statfs.h | 21 + include/asm-i386/string.h | 39 +- include/asm-i386/system.h | 1 + include/asm-i386/termios.h | 266 +++ include/asm-i386/types.h | 21 + include/linux/ax25.h | 39 + include/linux/bios32.h | 48 +- include/linux/errno.h | 127 +- include/linux/ext2_fs.h | 26 +- include/linux/ext_fs.h | 2 +- include/linux/fcntl.h | 47 +- include/linux/fs.h | 20 +- include/linux/if.h | 2 +- include/linux/if_eql.h | 79 + include/linux/if_ether.h | 1 + include/linux/if_ppp.h | 237 +++ include/linux/if_tr.h | 104 ++ include/linux/igmp.h | 17 + include/linux/ip_fw.h | 38 +- include/linux/iso_fs.h | 2 +- include/linux/minix_fs.h | 2 +- include/linux/mm.h | 2 +- include/linux/modules/ksyms.ver | 194 +++ include/linux/modversions.h | 1 + include/linux/msdos_fs.h | 4 +- include/linux/netdevice.h | 9 +- include/linux/netrom.h | 40 + include/linux/pci.h | 425 ++--- include/linux/ppp.h | 233 +-- include/linux/proc_fs.h | 5 +- include/linux/resource.h | 25 +- include/linux/route.h | 21 +- include/linux/scc.h | 553 ++++++ include/linux/sched.h | 3 +- include/linux/serial.h | 2 +- include/linux/signal.h | 79 - include/linux/skbuff.h | 84 +- include/linux/socket.h | 22 +- include/linux/stat.h | 37 +- include/linux/sysv_fs.h | 2 +- include/linux/tcp.h | 2 +- include/linux/time.h | 4 +- include/linux/trdevice.h | 41 + include/linux/tty.h | 2 +- include/linux/tty_driver.h | 1 + include/linux/types.h | 23 +- include/linux/umsdos_fs.p | 2 +- include/linux/unistd.h | 3 + include/linux/vfs.h | 17 +- include/linux/xia_fs.h | 2 +- {net/inet => include/net}/arp.h | 2 + include/net/atalk.h | 144 ++ include/net/atalkcall.h | 2 + include/net/ax25.h | 188 ++ include/net/ax25call.h | 2 + include/net/checksum.h | 158 ++ {net/inet => include/net}/datalink.h | 0 {net/inet => include/net}/eth.h | 1 + include/net/head_explode.h | 140 ++ {net/inet => include/net}/icmp.h | 0 {net/inet => include/net}/ip.h | 49 +- include/net/ipip.h | 4 + {net/inet => include/net}/ipx.h | 0 {net/inet => include/net}/ipxcall.h | 0 include/net/netrom.h | 131 ++ include/net/nrcall.h | 2 + {net/inet => include/net}/p8022.h | 0 {net/inet => include/net}/p8022call.h | 0 {net/inet => include/net}/protocol.h | 0 {net/inet => include/net}/psnap.h | 0 {net/inet => include/net}/psnapcall.h | 0 {net/inet => include/net}/rarp.h | 0 {net/inet => include/net}/raw.h | 0 {net/inet => include/net}/route.h | 5 +- {net/inet => include/net}/snmp.h | 0 {net/inet => include/net}/sock.h | 94 +- {net/inet => include/net}/tcp.h | 6 +- {net/inet => include/net}/udp.h | 4 +- {net/unix => include/net}/unix.h | 0 init/main.c | 10 +- ipc/shm.c | 6 +- kernel/exit.c | 4 +- kernel/ksyms.c | 7 +- kernel/ksyms.ver | 194 +++ kernel/sched.c | 3 +- kernel/sys.c | 53 +- kernel/time.c | 6 +- lib/string.c | 19 +- mm/kmalloc.c | 25 +- mm/memory.c | 2 +- mm/mmap.c | 31 +- mm/swap.c | 18 +- net/802/Makefile | 55 + net/802/llc.c | 412 +++++ net/{inet => 802}/p8022.c | 2 +- net/{inet => 802}/p8023.c | 2 +- net/{inet => 802}/psnap.c | 6 +- net/802/tr.c | 285 +++ net/Changes | 206 +++ net/Makefile | 7 +- net/{inet => }/README | 0 net/appletalk/Makefile | 35 + net/appletalk/aarp.c | 721 ++++++++ net/appletalk/ddp.c | 1843 ++++++++++++++++++++ net/ax25/Makefile | 40 + net/ax25/README.AX25 | 20 + net/ax25/af_ax25.c | 1972 +++++++++++++++++++++ net/ax25/ax25_in.c | 591 +++++++ net/ax25/ax25_out.c | 235 +++ net/ax25/ax25_route.c | 288 +++ net/ax25/ax25_subr.c | 383 ++++ net/ax25/ax25_timer.c | 226 +++ net/core/Makefile | 43 + net/{inet => core}/datagram.c | 16 +- net/{inet => core}/dev.c | 287 +-- net/{inet => core}/dev_mcast.c | 8 +- net/{inet => core}/skbuff.c | 14 +- net/{inet => core}/sock.c | 152 +- net/ethernet/Makefile | 57 + net/{inet => ethernet}/eth.c | 27 +- net/{inet => ethernet}/pe2.c | 2 +- net/{inet => ipv4}/Makefile | 40 +- net/ipv4/README.TCP | 39 + net/{inet => ipv4}/af_inet.c | 150 +- net/{inet => ipv4}/arp.c | 124 +- net/ipv4/checksum.c | 181 ++ net/{inet => ipv4}/devinet.c | 16 +- net/{inet => ipv4}/icmp.c | 45 +- net/{inet => ipv4}/igmp.c | 72 +- net/{inet => ipv4}/ip.c | 1252 +++++++------ net/{inet => ipv4}/ip_fw.c | 560 +++++- net/ipv4/ipip.c | 95 + net/{inet => ipv4}/packet.c | 10 +- net/{inet => ipv4}/proc.c | 43 +- net/{inet => ipv4}/protocol.c | 37 +- net/{inet => ipv4}/rarp.c | 16 +- net/{inet => ipv4}/raw.c | 93 +- net/{inet => ipv4}/route.c | 70 +- net/{inet => ipv4}/tcp.c | 355 ++-- net/{inet => ipv4}/timer.c | 111 +- net/{inet => ipv4}/udp.c | 345 ++-- net/{inet => ipv4}/utils.c | 6 +- net/ipx/Makefile | 35 + net/{inet/ipx.c => ipx/af_ipx.c} | 22 +- net/netrom/Makefile | 40 + net/netrom/af_netrom.c | 1339 ++++++++++++++ net/netrom/nr_dev.c | 254 +++ net/netrom/nr_in.c | 313 ++++ net/netrom/nr_out.c | 243 +++ net/netrom/nr_route.c | 750 ++++++++ net/netrom/nr_subr.c | 295 ++++ net/netrom/nr_timer.c | 192 ++ net/protocols.c | 43 +- net/socket.c | 177 +- net/unix/proc.c | 2 +- net/unix/sock.c | 4 +- 323 files changed, 34719 insertions(+), 6626 deletions(-) create mode 100644 arch/alpha/kernel/bios32.c create mode 100644 arch/alpha/kernel/osf_sys.c create mode 100644 arch/alpha/lib/io.c create mode 100644 arch/alpha/lib/memcpy.c create mode 100644 drivers/char/README.scc create mode 100644 drivers/char/scc.c create mode 100644 drivers/char/scc_config.h delete mode 100644 drivers/net/3c505dta.h create mode 100644 drivers/net/README.eql create mode 100644 drivers/net/README.tunnel create mode 100644 drivers/net/eql.c create mode 100644 drivers/net/ibmtr.c create mode 100644 drivers/net/ibmtr.h create mode 100644 drivers/net/pi2.c create mode 100644 drivers/net/pi2.h create mode 100644 drivers/net/tunnel.c create mode 100644 drivers/net/z8530.h create mode 100644 drivers/pci/Makefile create mode 100644 drivers/pci/pci.c create mode 100644 fs/nfs/cache.c create mode 100644 fs/readdir.c create mode 100644 include/asm-alpha/dirent.h create mode 100644 include/asm-alpha/errno.h create mode 100644 include/asm-alpha/fcntl.h create mode 100644 include/asm-alpha/ioctl.h create mode 100644 include/asm-alpha/ipsum.h create mode 100644 include/asm-alpha/resource.h create mode 100644 include/asm-alpha/stat.h create mode 100644 include/asm-alpha/statfs.h create mode 100644 include/asm-alpha/termios.h create mode 100644 include/asm-alpha/unaligned.h create mode 100644 include/asm-i386/errno.h create mode 100644 include/asm-i386/fcntl.h create mode 100644 include/asm-i386/resource.h create mode 100644 include/asm-i386/stat.h create mode 100644 include/asm-i386/statfs.h create mode 100644 include/asm-i386/termios.h create mode 100644 include/linux/ax25.h create mode 100644 include/linux/if_eql.h create mode 100644 include/linux/if_ppp.h create mode 100644 include/linux/if_tr.h create mode 100644 include/linux/modules/ksyms.ver create mode 100644 include/linux/modversions.h create mode 100644 include/linux/netrom.h create mode 100644 include/linux/scc.h create mode 100644 include/linux/trdevice.h rename {net/inet => include/net}/arp.h (85%) create mode 100644 include/net/atalk.h create mode 100644 include/net/atalkcall.h create mode 100644 include/net/ax25.h create mode 100644 include/net/ax25call.h create mode 100644 include/net/checksum.h rename {net/inet => include/net}/datalink.h (100%) rename {net/inet => include/net}/eth.h (91%) create mode 100644 include/net/head_explode.h rename {net/inet => include/net}/icmp.h (100%) rename {net/inet => include/net}/ip.h (81%) create mode 100644 include/net/ipip.h rename {net/inet => include/net}/ipx.h (100%) rename {net/inet => include/net}/ipxcall.h (100%) create mode 100644 include/net/netrom.h create mode 100644 include/net/nrcall.h rename {net/inet => include/net}/p8022.h (100%) rename {net/inet => include/net}/p8022call.h (100%) rename {net/inet => include/net}/protocol.h (100%) rename {net/inet => include/net}/psnap.h (100%) rename {net/inet => include/net}/psnapcall.h (100%) rename {net/inet => include/net}/rarp.h (100%) rename {net/inet => include/net}/raw.h (100%) rename {net/inet => include/net}/route.h (94%) rename {net/inet => include/net}/snmp.h (100%) rename {net/inet => include/net}/sock.h (79%) rename {net/inet => include/net}/tcp.h (96%) rename {net/inet => include/net}/udp.h (89%) rename {net/unix => include/net}/unix.h (100%) create mode 100644 kernel/ksyms.ver create mode 100644 net/802/Makefile create mode 100644 net/802/llc.c rename net/{inet => 802}/p8022.c (98%) rename net/{inet => 802}/p8023.c (96%) rename net/{inet => 802}/psnap.c (97%) create mode 100644 net/802/tr.c create mode 100644 net/Changes rename net/{inet => }/README (100%) create mode 100644 net/appletalk/Makefile create mode 100644 net/appletalk/aarp.c create mode 100644 net/appletalk/ddp.c create mode 100644 net/ax25/Makefile create mode 100644 net/ax25/README.AX25 create mode 100644 net/ax25/af_ax25.c create mode 100644 net/ax25/ax25_in.c create mode 100644 net/ax25/ax25_out.c create mode 100644 net/ax25/ax25_route.c create mode 100644 net/ax25/ax25_subr.c create mode 100644 net/ax25/ax25_timer.c create mode 100644 net/core/Makefile rename net/{inet => core}/datagram.c (95%) rename net/{inet => core}/dev.c (84%) rename net/{inet => core}/dev_mcast.c (97%) rename net/{inet => core}/skbuff.c (98%) rename net/{inet => core}/sock.c (90%) create mode 100644 net/ethernet/Makefile rename net/{inet => ethernet}/eth.c (88%) rename net/{inet => ethernet}/pe2.c (96%) rename net/{inet => ipv4}/Makefile (56%) create mode 100644 net/ipv4/README.TCP rename net/{inet => ipv4}/af_inet.c (95%) rename net/{inet => ipv4}/arp.c (92%) create mode 100644 net/ipv4/checksum.c rename net/{inet => ipv4}/devinet.c (95%) rename net/{inet => ipv4}/icmp.c (95%) rename net/{inet => ipv4}/igmp.c (81%) rename net/{inet => ipv4}/ip.c (69%) rename net/{inet => ipv4}/ip_fw.c (63%) create mode 100644 net/ipv4/ipip.c rename net/{inet => ipv4}/packet.c (98%) rename net/{inet => ipv4}/proc.c (89%) rename net/{inet => ipv4}/protocol.c (83%) rename net/{inet => ipv4}/rarp.c (98%) rename net/{inet => ipv4}/raw.c (85%) rename net/{inet => ipv4}/route.c (91%) rename net/{inet => ipv4}/tcp.c (95%) rename net/{inet => ipv4}/timer.c (60%) rename net/{inet => ipv4}/udp.c (74%) rename net/{inet => ipv4}/utils.c (96%) create mode 100644 net/ipx/Makefile rename net/{inet/ipx.c => ipx/af_ipx.c} (99%) create mode 100644 net/netrom/Makefile create mode 100644 net/netrom/af_netrom.c create mode 100644 net/netrom/nr_dev.c create mode 100644 net/netrom/nr_in.c create mode 100644 net/netrom/nr_out.c create mode 100644 net/netrom/nr_route.c create mode 100644 net/netrom/nr_subr.c create mode 100644 net/netrom/nr_timer.c diff --git a/CREDITS b/CREDITS index 46b3aa128851..2bda0cf13f26 100644 --- a/CREDITS +++ b/CREDITS @@ -217,7 +217,7 @@ S: 47807 Krefeld S: Germany N: Drew Eckhardt -E: drew@Colorado.EDU +E: drew@PoohSticks.ORG D: SCSI code D: Assorted snippets elsewhere D: Boot sector "..." printing diff --git a/Makefile b/Makefile index 2f2c17ea9c9f..c48e0b2c9fbd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 -PATCHLEVEL = 2 -SUBLEVEL = 10 +PATCHLEVEL = 3 +SUBLEVEL = 0 ARCH = i386 @@ -100,6 +100,10 @@ ifdef CONFIG_SOUND DRIVERS := $(DRIVERS) drivers/sound/sound.a endif +ifdef CONFIG_PCI +DRIVERS := $(DRIVERS) drivers/pci/pci.a +endif + include arch/$(ARCH)/Makefile .c.s: @@ -224,7 +228,7 @@ modules_install: clean: archclean rm -f kernel/ksyms.lst rm -f core `find . -name '*.[oas]' -print` - rm -f core `find . -name 'core' -print` + rm -f core `find . -type f -name 'core' -print` rm -f vmlinux System.map rm -f .tmp* drivers/sound/configure rm -fr modules/* diff --git a/arch/alpha/boot/main.c b/arch/alpha/boot/main.c index 5518e533b94f..d122eb6f61c2 100644 --- a/arch/alpha/boot/main.c +++ b/arch/alpha/boot/main.c @@ -179,6 +179,8 @@ void start_kernel(void) { long i; long dev; + int nbytes; + char envval[256]; printk("Linux/AXP bootloader for Linux " UTS_RELEASE "\n"); if (hwrpb.pagesize != 8192) { @@ -199,6 +201,14 @@ void start_kernel(void) printk("Failed (%lx)\n", i); return; } + + nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + envval, sizeof(envval)); + if (nbytes > 0) { + envval[nbytes] = '\0'; + strcpy((char*)ZERO_PGE, envval); + } + printk(" Ok\nNow booting the kernel\n"); runkernel(); for (i = 0 ; i < 0x100000000 ; i++) diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 2bd47c1e0616..8906e8c8cc81 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -6,19 +6,35 @@ comment 'General setup' bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y -bool 'Normal harddisk support' CONFIG_BLK_DEV_HD n +bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 n +if [ "$CONFIG_ST506" = "y" ]; then + comment 'Please see drivers/block/README.ide for help/info on IDE drives' + bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD n + if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then + bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n + else + bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE y + fi + if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then + bool ' Include support for IDE/ATAPI CDROMs' CONFIG_BLK_DEV_IDECD n + fi +fi + bool 'XT harddisk support' CONFIG_BLK_DEV_XD n -bool 'Networking support' CONFIG_NET n +bool 'Networking support' CONFIG_NET y bool 'PCI alpha motherboard' CONFIG_PCI n bool 'System V IPC' CONFIG_SYSVIPC n bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y +comment 'Loadable module support' +bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n + if [ "$CONFIG_NET" = "y" ]; then comment 'Networking options' -bool 'TCP/IP networking' CONFIG_INET n -if [ "$CONFIG_INET" "=" "y" ]; then +bool 'TCP/IP networking' CONFIG_INET y +if [ "$CONFIG_INET" = "y" ]; then bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n -bool 'IP multicasting (ALPHA)' CONFIG_IP_MULTICAST n +bool 'IP multicasting' CONFIG_IP_MULTICAST n bool 'IP firewalling' CONFIG_IP_FIREWALL n bool 'IP accounting' CONFIG_IP_ACCT n comment '(it is safe to leave these untouched)' @@ -28,12 +44,13 @@ bool 'Assume subnets are local' CONFIG_INET_SNARL y bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n fi bool 'The IPX protocol' CONFIG_IPX n +#bool 'Appletalk DDP' CONFIG_ATALK n #bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n fi comment 'SCSI support' -bool 'SCSI support?' CONFIG_SCSI n +bool 'SCSI support?' CONFIG_SCSI y if [ "$CONFIG_SCSI" = "n" ]; then @@ -45,7 +62,7 @@ comment 'SCSI support type (disk, tape, CDrom)' bool 'SCSI disk support' CONFIG_BLK_DEV_SD y bool 'SCSI tape support' CONFIG_CHR_DEV_ST n -bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR n +bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR y bool 'SCSI generic support' CONFIG_CHR_DEV_SG n comment 'SCSI low-level drivers' @@ -55,6 +72,7 @@ bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n +bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n @@ -68,7 +86,7 @@ bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n -bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n +#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n #bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n fi @@ -86,13 +104,12 @@ else bool 'Dummy net driver support' CONFIG_DUMMY n bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then - bool ' CSLIP compressed headers' SL_COMPRESSED y + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y bool ' 16 channels instead of 4' SL_SLIP_LOTS n # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n bool 'PLIP (parallel port) support' CONFIG_PLIP n -bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then @@ -116,12 +133,13 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then bool 'DEPCA support' CONFIG_DEPCA y bool 'EtherWorks 3 support' CONFIG_EWRK3 n if [ "$CONFIG_NET_ALPHA" = "y" ]; then -# bool 'Arcnet support' CONFIG_ARCNET n + bool 'Arcnet support' CONFIG_ARCNET n bool 'AT1700 support' CONFIG_AT1700 n # bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n bool 'EtherExpress support' CONFIG_EEXPRESS n bool 'NI5210 support' CONFIG_NI52 n bool 'NI6510 support' CONFIG_NI65 n + bool 'WaveLAN support' CONFIG_WAVELAN n fi bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n @@ -134,6 +152,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n fi bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n + bool 'DE425, DE434, DE435 support' CONFIG_DE4X5 n # bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n # bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n # bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n @@ -151,10 +170,10 @@ fi fi fi -comment 'CD-ROM drivers' +comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n -bool 'Mitsumi CDROM driver support' CONFIG_MCD n +bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n if [ "$CONFIG_SBPCD" = "y" ]; then bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n @@ -165,6 +184,8 @@ if [ "$CONFIG_SBPCD" = "y" ]; then fi fi fi +bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n +bool 'Sony CDU535 CDROM driver support' CONFIG_CDU535 n comment 'Filesystems' @@ -180,7 +201,7 @@ bool '/proc filesystem support' CONFIG_PROC_FS y if [ "$CONFIG_INET" = "y" ]; then bool 'NFS filesystem support' CONFIG_NFS_FS y fi -if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then +if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" -o "$CONFIG_CDU535" = "y" ]; then bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y else bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 240a649e8090..2843d44812ee 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -18,7 +18,8 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -OBJS = entry.o traps.o process.o irq.o signal.o setup.o +OBJS = entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ + lca.o bios32.o all: kernel.o head.o diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c new file mode 100644 index 000000000000..37c566fb11a8 --- /dev/null +++ b/arch/alpha/kernel/bios32.c @@ -0,0 +1,478 @@ +#define DEBUG +/* + * bios32.c - PCI BIOS functions for Alpha systems not using BIOS + * emulation code. + * + * Written by Dave Rusling (david.rusling@reo.mts.dec.com) + * + * Adapted to 64-bit kernel and then rewritten by David Mosberger + * (davidm@cs.arizona.edu) + * + * For more information, please consult + * + * PCI BIOS Specification Revision + * PCI Local Bus Specification + * PCI System Design Guide + * + * PCI Special Interest Group + * M/S HF3-15A + * 5200 N.E. Elam Young Parkway + * Hillsboro, Oregon 97124-6497 + * +1 (503) 696-2000 + * +1 (800) 433-5177 + * + * Manuals are $25 each or $50 for all three, plus $7 shipping + * within the United States, $35 abroad. + */ +#include + +#ifndef CONFIG_PCI + +int pcibios_present(void) +{ + return 0; +} + +#else /* CONFIG_PCI */ + +#include +#include +#include +#include +#include + +#include +#include + + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define MAJOR_REV 0 +#define MINOR_REV 2 + +/* + * Align VAL to ALIGN, which must be a power of two. + */ +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) + + +/* + * Temporary internal macro. If this 0, then do not write to any of + * the PCI registers, merely read them (i.e., use configuration as + * determined by SRM). The SRM seem do be doing a less than perfect + * job in configuring PCI devices, so for now we do it ourselves. + * Reconfiguring PCI devices breaks console (RPB) callbacks, but + * those don't work properly with 64 bit addresses anyways. + * + * The accepted convention seems to be that the console (POST + * software) should fully configure boot devices and configure the + * interrupt routing of *all* devices. In particular, the base + * addresses of non-boot devices need not be initialized. For + * example, on the AXPpci33 board, the base address a #9 GXE PCI + * graphics card reads as zero (this may, however, be due to a bug in + * the graphics card---there have been some rumor that the #9 BIOS + * incorrectly resets that address to 0...). + */ +#define PCI_MODIFY 1 + + +extern struct hwrpb_struct *hwrpb; + + +#if PCI_MODIFY + +static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */ +static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */ + + +/* + * Layout memory and I/O for a device: + */ +static void layout_dev(struct pci_dev *dev) +{ + struct pci_bus *bus; + unsigned short cmd; + unsigned int base, mask, size, reg; + + bus = dev->bus; + pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + + for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) { + /* + * Figure out how much space and of what type this + * device wants. + */ + pcibios_write_config_dword(bus->number, dev->devfn, reg, + 0xffffffff); + pcibios_read_config_dword(bus->number, dev->devfn, reg, &base); + if (!base) { + break; /* done with this device */ + } + /* + * We've read the base address register back after + * writing all ones and so now we must decode it. + */ + if (base & PCI_BASE_ADDRESS_SPACE_IO) { + /* + * I/O space base address register. + */ + cmd |= PCI_COMMAND_IO; + + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + base = ALIGN(io_base, size); + io_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base | 0x1); + } else { + unsigned int type; + /* + * Memory space base address register. + */ + cmd |= PCI_COMMAND_MEMORY; + + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch (type) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + + case PCI_BASE_ADDRESS_MEM_TYPE_64: + printk("bios32 WARNING: " + "ignoring 64-bit device in " + "slot %d, function %d: \n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + reg += 4; /* skip extra 4 bytes */ + continue; + + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + /* + * Allocating memory below 1MB is *very* + * tricky, as there may be all kinds of + * ISA devices lurking that we don't know + * about. For now, we just cross fingers + * and hope nobody tries to do this on an + * Alpha (or that the console has set it + * up properly). + */ + printk("bios32 WARNING: slot %d, function %d " + "requests memory below 1MB---don't " + "know how to do that.\n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + continue; + } + /* + * The following holds at least for the Low Cost + * Alpha implementation of the PCI interface: + * + * In sparse memory address space, the first + * octant (16MB) of every 128MB segment is + * aliased to the the very first 16MB of the + * address space (i.e., it aliases the ISA + * memory address space). Thus, we try to + * avoid allocating PCI devices in that range. + * Can be allocated in 2nd-7th octant only. + * Devices that need more than 112MB of + * address space must be accessed through + * dense memory space only! + */ + base = ALIGN(mem_base, size); + if (size > 7 * 16*MB) { + printk("bios32 WARNING: slot %d, function %d " + "requests %dB of contiguous address " + " space---don't use sparse memory " + " accesses on this device!!\n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), size); + } else { + if (((base / 16*MB) & 0x7) == 0) { + base &= ~(128*MB - 1); + base += 16*MB; + base = ALIGN(base, size); + } + if (base / 128*MB != (base + size) / 128*MB) { + base &= ~(128*MB - 1); + base += (128 + 16)*MB; + base = ALIGN(base, size); + } + } + mem_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base); + } + } + /* enable device: */ + pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); +} + + +static void layout_bus(struct pci_bus *bus) +{ + unsigned int l, tio, bio, tmem, bmem; + struct pci_bus *child; + struct pci_dev *dev; + + if (!bus->devices && !bus->children) + return; + + /* + * Align the current bases on appropriate boundaries (4K for + * IO and 1MB for memory). + */ + bio = io_base = ALIGN(io_base, 4*KB); + bmem = mem_base = ALIGN(mem_base, 1*MB); + + /* + * Allocate space to each device: + */ + for (dev = bus->devices; dev; dev = dev->sibling) { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { + layout_dev(dev); + } + } + /* + * Recursively allocate space for all of the sub-buses: + */ + for (child = bus->children; child; child = child->next) { + layout_bus(child); + } + /* + * Align the current bases on 4K and 1MB boundaries: + */ + tio = io_base = ALIGN(io_base, 4*KB); + tmem = mem_base = ALIGN(mem_base, 1*MB); + + if (bus->self) { + struct pci_dev *bridge = bus->self; + /* + * Set up the top and bottom of the I/O memory segment + * for this bus. + */ + pcibios_read_config_dword(bridge->bus->number, bridge->devfn, + 0x1c, &l); + l = l | (bio >> 8) | ((tio - 1) & 0xf000); + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + 0x1c, l); + + l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000); + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + 0x20, l); + /* + * Turn off downstream PF memory address range: + */ + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + 0x24, 0x0000ffff); + /* + * Tell bridge that there is an ISA bus in the system: + */ + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + 0x3c, 0x00040000); + /* + * Clear status bits, enable I/O (for downstream I/O), + * turn on master enable (for upstream I/O), turn on + * memory enable (for downstream memory), turn on + * master enable (for upstream memory and I/O). + */ + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + 0x4, 0xffff0007); + } +} + +#endif /* !PCI_MODIFY */ + + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int current = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->vendor == vendor && dev->device == device_id) { + if (current == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++current; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int current = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (current == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++current; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + + +int pcibios_present(void) +{ + return 1; +} + + +unsigned long pcibios_init(unsigned long mem_start, + unsigned long mem_end) +{ + printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + +#if !PCI_MODIFY + printk("...NOT modifying existing (SRM) PCI configuration\n"); +#endif + return mem_start; +} + + +/* + * Fixup configuration for Noname boards (AXPpci33). + */ +static void noname_fixup(void) +{ + struct pci_dev *dev; + + /* + * The Noname board has 5 PCI slots with each of the 4 + * interrupt pins routed to different pins on the PCI/ISA + * bridge (PIRQ0-PIRQ3). I don't have any information yet as + * to how INTB, INTC, and INTD get routed (4/12/95, + * davidm@cs.arizona.edu). + */ + static const char pirq_tab[5][4] = { + { 3, -1, -1, -1}, /* slot 6 (53c810) */ + {-1, -1, -1, -1}, /* slot 7 (PCI/ISA bridge) */ + { 2, -1, -1, -1}, /* slot 8 (slot closest to ISA) */ + { 1, -1, -1, -1}, /* slot 9 (middle slot) */ + { 0, -1, -1, -1}, /* slot 10 (slot furthest from ISA) */ + }; + /* + * route_tab selects irq routing in PCI/ISA bridge so that: + * PIRQ0 -> irq 15 + * PIRQ1 -> irq 9 + * PIRQ2 -> irq 10 + * PIRQ3 -> irq 11 + */ + const unsigned int route_tab = 0x0b0a090f; + unsigned char pin; + int pirq; + + pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, route_tab); + + /* ensure irq 9, 10, 11, and 15 are level sensitive: */ + outb((1<<(9-8)) | (1<<(10-8)) | (1<<(11-8)) | (1<<(15-8)), 0x4d1); + + /* + * Go through all devices, fixing up irqs as we see fit: + */ + for (dev = pci_devices; dev; dev = dev->next) { + dev->irq = 0; + if (dev->bus->number != 0 || + PCI_SLOT(dev->devfn) < 6 || PCI_SLOT(dev->devfn) > 10) + { + printk("noname_set_irq: no dev on bus %d, slot %d!!\n", + dev->bus->number, PCI_SLOT(dev->devfn)); + continue; + } + + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &pin); + if (!pin) { + if (dev->vendor == PCI_VENDOR_ID_S3 && + (dev->device == PCI_DEVICE_ID_S3_864_1 || + dev->device == PCI_DEVICE_ID_S3_864_2)) + { + pin = 1; + } else { + continue; /* no interrupt line */ + } + } + pirq = pirq_tab[PCI_SLOT(dev->devfn) - 6][pin - 1]; + if (pirq < 0) { + continue; + } + dev->irq = (route_tab >> (8 * pirq)) & 0xff; +#if PCI_MODIFY + /* tell the device: */ + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); +#endif + } + +#if PCI_MODIFY + { + unsigned char hostid; + /* + * SRM console version X3.9 seems to reset the SCSI + * host-id to 0 no matter what console environment + * variable pka0_host_id is set to. Thus, if the + * host-id reads out as a zero, we set it to 7. The + * SCSI controller is on the motherboard on bus 0, + * slot 6 + */ + if (pcibios_read_config_byte(0, PCI_DEVFN(6, 0), 0x84, &hostid) + == PCIBIOS_SUCCESSFUL && (hostid == 0)) + { + pcibios_write_config_byte(0, PCI_DEVFN(6, 0), + 0x84, 7); + } + } +#endif /* !PCI_MODIFY */ +} + + +unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +{ +#if PCI_MODIFY + /* + * Scan the tree, allocating PCI memory and I/O space. + */ + layout_bus(&pci_root); +#endif + + /* + * Now is the time to do all those dirty little deeds... + */ + switch (hwrpb->sys_type) { + case ST_DEC_AXPPCI_33: noname_fixup(); break; + + default: + printk("pcibios_fixup: don't know how to fixup sys type %ld\n", + hwrpb->sys_type); + break; + } + return mem_start; +} + +#endif /* CONFIG_PCI */ diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 48796dcf0186..b54ea220b4ea 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -9,6 +9,32 @@ #define halt .long PAL_halt #define rti .long PAL_rti +#define NR_SYSCALLS 310 +#define osf_vfork sys_fork + +/* + * These offsets must match with "struct hae" in io.h: + */ +#define HAE_CACHE 0 +#define HAE_REG 8 + +/* + * stack offsets + */ +#define SP_OFF 160 + +#define SWITCH_STACK_SIZE 320 + +/* + * task structure offsets + */ +#define TASK_STATE 0 +#define TASK_COUNTER 8 +#define TASK_PRIORITY 16 +#define TASK_SIGNAL 24 +#define TASK_BLOCKED 32 +#define TASK_FLAGS 40 + /* * This defines the normal kernel pt-regs layout. * @@ -36,9 +62,26 @@ stq $25,120($30); \ stq $26,128($30); \ stq $27,136($30); \ - stq $28,144($30) + stq $28,144($30); \ + lda $2,hae; \ + ldq $2,HAE_CACHE($2); \ + stq $2,152($30) #define RESTORE_ALL \ + lda $8,hae; \ + ldq $7,HAE_CACHE($8); \ + ldq $6,152($30); \ + subq $7,$6,$5; \ + beq $5,99f; \ + ldq $7,HAE_REG($8); \ + addq $31,7,$16; \ + call_pal PAL_swpipl; \ + stq $6,HAE_CACHE($8); \ + stq $6,0($7); \ + mb; \ + bis $0,$0,$16; \ + call_pal PAL_swpipl; \ +99:; \ ldq $0,0($30); \ ldq $1,8($30); \ ldq $2,16($30); \ @@ -87,9 +130,11 @@ entInt: ldq $2,0($2) and $2,$3,$2 bne $2,3f + stq $1,0($0) + br $31,ret_from_sys_call +.align 3 2: stq $1,0($0) - RESTORE_ALL - rti + br $31,restore_all .align 3 3: lda $27,do_bottom_half jsr $26,($27),do_bottom_half @@ -102,9 +147,8 @@ entInt: entMM: SAVE_ALL lda $27,do_page_fault - jsr $26,($27),do_page_fault - RESTORE_ALL - rti + lda $26,ret_from_sys_call + jsr $31,($27),do_page_fault .end entMM .align 3 @@ -113,9 +157,8 @@ entMM: entArith: SAVE_ALL lda $27,do_entArith - jsr $26,($27),do_entArith - RESTORE_ALL - rti + lda $26,ret_from_sys_call + jsr $31,($27),do_entArith .end entArith .align 3 @@ -124,22 +167,10 @@ entArith: entIF: SAVE_ALL lda $27,do_entIF - jsr $26,($27),do_entIF - RESTORE_ALL - rti + lda $26,ret_from_sys_call + jsr $31,($27),do_entIF .end entIF -.align 3 -.globl entUna -.ent entUna -entUna: - SAVE_ALL - lda $27,do_entUna - jsr $26,($27),do_entUna - RESTORE_ALL - rti -.end entUna - /* * Fork() is one of the special system calls: it needs to * save the callee-saved regs so that the regs can be found @@ -167,10 +198,9 @@ kernel_fork: .end kernel_fork .align 3 -.globl sys_fork -.ent sys_fork -sys_fork: - subq $30,64,$30 +.ent do_switch_stack +do_switch_stack: + lda $30,-SWITCH_STACK_SIZE($30) stq $9,0($30) stq $10,8($30) stq $11,16($30) @@ -179,11 +209,43 @@ sys_fork: stq $14,40($30) stq $15,48($30) stq $26,56($30) + stt $f0,64($30) + stt $f1,72($30) + stt $f2,80($30) + stt $f3,88($30) + stt $f4,96($30) + stt $f5,104($30) + stt $f6,112($30) + stt $f7,120($30) + stt $f8,128($30) + stt $f9,136($30) + stt $f10,144($30) + stt $f11,152($30) + stt $f12,160($30) + stt $f13,168($30) + stt $f14,176($30) + stt $f15,184($30) + stt $f16,192($30) + stt $f17,200($30) + stt $f18,208($30) + stt $f19,216($30) + stt $f20,224($30) + stt $f21,232($30) + stt $f22,240($30) + stt $f23,248($30) + stt $f24,256($30) + stt $f25,264($30) + stt $f26,272($30) + stt $f27,280($30) + stt $f28,288($30) + stt $f29,296($30) + stt $f30,304($30) + ret $31,($0),1 +.end do_switch_stack - bis $30,$30,$16 - lda $27,alpha_fork - jsr $26,($27),alpha_fork - +.align 3 +.ent undo_switch_stack +undo_switch_stack: ldq $9,0($30) ldq $10,8($30) ldq $11,16($30) @@ -192,26 +254,301 @@ sys_fork: ldq $14,40($30) ldq $15,48($30) ldq $26,56($30) - ldq $0,64($30) - addq $30,64,$30 + ldt $f0,64($30) + ldt $f1,72($30) + ldt $f2,80($30) + ldt $f3,88($30) + ldt $f4,96($30) + ldt $f5,104($30) + ldt $f6,112($30) + ldt $f7,120($30) + ldt $f8,128($30) + ldt $f9,136($30) + ldt $f10,144($30) + ldt $f11,152($30) + ldt $f12,160($30) + ldt $f13,168($30) + ldt $f14,176($30) + ldt $f15,184($30) + ldt $f16,192($30) + ldt $f17,200($30) + ldt $f18,208($30) + ldt $f19,216($30) + ldt $f20,224($30) + ldt $f21,232($30) + ldt $f22,240($30) + ldt $f23,248($30) + ldt $f24,256($30) + ldt $f25,264($30) + ldt $f26,272($30) + ldt $f27,280($30) + ldt $f28,288($30) + ldt $f29,296($30) + ldt $f30,304($30) + lda $30,SWITCH_STACK_SIZE($30) + ret $31,($0),1 +.end undo_switch_stack + +.align 3 +.globl entUna +.ent entUna +entUna: + lda $30,-256($30) + stq $0,0($30) + stq $1,8($30) + stq $2,16($30) + stq $3,24($30) + stq $4,32($30) + stq $5,40($30) + stq $6,48($30) + stq $7,56($30) + stq $8,64($30) + stq $9,72($30) + stq $10,80($30) + stq $11,88($30) + stq $12,96($30) + stq $13,104($30) + stq $14,112($30) + stq $15,120($30) + /* 16-18 PAL-saved */ + stq $19,152($30) + stq $20,160($30) + stq $21,168($30) + stq $22,176($30) + stq $23,184($30) + stq $24,192($30) + stq $25,200($30) + stq $26,208($30) + stq $27,216($30) + stq $28,224($30) + stq $29,232($30) + stq $30,240($30) + stq $31,248($30) + lda $27,do_entUna + jsr $26,($27),do_entUna + ldq $0,0($30) + ldq $1,8($30) + ldq $2,16($30) + ldq $3,24($30) + ldq $4,32($30) + ldq $5,40($30) + ldq $6,48($30) + ldq $7,56($30) + ldq $8,64($30) + ldq $9,72($30) + ldq $10,80($30) + ldq $11,88($30) + ldq $12,96($30) + ldq $13,104($30) + ldq $14,112($30) + ldq $15,120($30) + /* 16-18 PAL-saved */ + ldq $19,152($30) + ldq $20,160($30) + ldq $21,168($30) + ldq $22,176($30) + ldq $23,184($30) + ldq $24,192($30) + ldq $25,200($30) + ldq $26,208($30) + ldq $27,216($30) + ldq $28,224($30) + ldq $29,232($30) + ldq $30,240($30) + lda $30,256($30) + rti +.end entUna + +.align 3 +.globl sys_fork +.ent sys_fork +sys_fork: + br $0,do_switch_stack + bis $30,$30,$16 + lda $27,alpha_fork + jsr $26,($27),alpha_fork + br $0,undo_switch_stack + ldq $0,0($30) ret $31,($26),1 .end sys_fork +.align 3 +.globl alpha_switch_to +.ent alpha_switch_to +alpha_switch_to: + br $0,do_switch_stack + call_pal PAL_swpctx + br $0,undo_switch_stack + ret $31,($26),1 +.end alpha_switch_to + +/* + * Oh, well.. Disassembling OSF/1 binaries to find out how the + * system calls work isn't much fun. + * + * entSys is special in that the PAL-code doesn't save a0-a2, so + * we start off by doing that by hand. + */ .align 3 .globl entSys .globl ret_from_sys_call .ent entSys entSys: + stq $16,24($30) + stq $17,32($30) + stq $18,40($30) SAVE_ALL + lda $1,NR_SYSCALLS($31) + lda $2,sys_call_table lda $27,do_entSys - jsr $26,($27),do_entSys - stq $0,0($30) + cmpult $0,$1,$1 + s8addq $0,$2,$2 + beq $1,1f + ldq $27,0($2) +1: jsr $26,($27),do_entSys + bis $31,$31,$1 + bge $0,2f + bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */ + ldq $19,0($30) /* .. with this syscall nr */ + ldq $20,72($30) /* .. and this a3 */ + addq $31,1,$1 /* set a3 for errno return */ + subq $31,$0,$0 /* with error in v0 */ +2: stq $0,0($30) + stq $1,72($30) /* a3 for return */ +.align 3 ret_from_sys_call: + ldq $0,SP_OFF($30) + cmovne $26,0,$19 + and $0,8,$0 + beq $0,restore_all +ret_from_reschedule: + lda $0,need_resched + lda $1,current + ldl $2,0($0) + lda $4,init_task + ldq $3,0($1) + bne $2,reschedule + subq $4,$3,$4 + beq $4,restore_all + ldq $4,TASK_SIGNAL($3) + ldq $16,TASK_BLOCKED($3) + bic $4,$16,$4 + bne $4,signal_return +restore_all: RESTORE_ALL rti +.align 3 +signal_return: + bis $30,$30,$17 + br $0,do_switch_stack + bis $30,$30,$18 + lda $27,do_signal + jsr $26,($27),do_signal + lda $30,SWITCH_STACK_SIZE($30) + br $31,restore_all .end entSys +.align 3 +.ent reschedule +reschedule: + subq $30,16,$30 + stq $19,0($30) + stq $20,8($30) + lda $27,schedule + jsr $26,($27),schedule + ldq $19,0($30) + ldq $20,8($30) + addq $30,16,$30 + br $31,ret_from_reschedule +.end reschedule + +.align 3 +.ent sys_sigreturn +sys_sigreturn: + bis $30,$30,$17 + lda $30,-SWITCH_STACK_SIZE($30) + bis $30,$30,$18 + lda $27,do_sigreturn + jsr $26,($27),do_sigreturn + br $0,undo_switch_stack + br $31,ret_from_sys_call +.end sys_sigreturn + +.align 3 +.ent sys_sigsuspend +sys_sigsuspend: + bis $30,$30,$17 + br $0,do_switch_stack + bis $30,$30,$18 + lda $27,do_sigsuspend + jsr $26,($27),do_sigsuspend + lda $30,SWITCH_STACK_SIZE($30) + br $31,ret_from_sys_call +.end sys_sigreturn + .align 3 .globl sys_call_table sys_call_table: - .quad 0 +/*0*/ .quad do_entSys, sys_exit, sys_fork, sys_read, sys_write + .quad do_entSys, sys_close, sys_wait4, do_entSys, sys_link + .quad sys_unlink, do_entSys, sys_chdir, sys_fchdir, sys_mknod + .quad sys_chmod, sys_chown, sys_brk, do_entSys, sys_lseek + .quad sys_getxpid, osf_mount, osf_umount, sys_setuid, sys_getxuid + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys + .quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid + .quad do_entSys, sys_dup, sys_pipe, do_entSys, do_entSys + .quad sys_open, do_entSys, sys_getxgid, osf_sigprocmask, do_entSys +/*50*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, sys_ioctl + .quad do_entSys, do_entSys, sys_symlink, sys_readlink, sys_execve + .quad sys_umask, do_entSys, do_entSys, sys_getpgrp, sys_getpagesize + .quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys + .quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect + .quad sys_madvise, do_entSys, do_entSys, do_entSys, sys_getgroups + .quad do_entSys, do_entSys, do_entSys, sys_setitimer, do_entSys + .quad do_entSys, sys_getitimer, sys_gethostname, do_entSys, sys_getdtablesize + .quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, do_entSys + .quad sys_fsync, do_entSys, sys_socket, do_entSys, do_entSys +/*100*/ .quad do_entSys, do_entSys, do_entSys, sys_sigreturn, sys_bind + .quad do_entSys, sys_listen, do_entSys, do_entSys, do_entSys + .quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys + .quad do_entSys, sys_gettimeofday, sys_getrusage, do_entSys, do_entSys + .quad do_entSys, do_entSys, sys_settimeofday, sys_fchown, sys_fchmod + .quad do_entSys, sys_setreuid, sys_setregid, sys_rename, sys_truncate + .quad sys_ftruncate, do_entSys, sys_setgid, do_entSys, do_entSys + .quad do_entSys, sys_mkdir, sys_rmdir, sys_utimes, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, sys_getrlimit + .quad sys_setrlimit, do_entSys, sys_setsid, do_entSys, do_entSys +/*150*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries + .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys + .quad osf_getdomainname, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, osf_swapon +/*200*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, osf_utsname, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys +/*250*/ .quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys +/* linux-specific system calls start at 300 */ +/*300*/ .quad sys_bdflush, sys_sethae, do_entSys, do_entSys, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S index 4e166d9e0c18..2cff1159a17c 100644 --- a/arch/alpha/kernel/head.S +++ b/arch/alpha/kernel/head.S @@ -27,7 +27,7 @@ __start: halt .end __start - .align 5 + .align 3 .globl wrent .ent wrent wrent: @@ -35,7 +35,7 @@ wrent: ret ($26) .end wrent - .align 5 + .align 3 .globl wrkgp .ent wrkgp wrkgp: @@ -43,7 +43,7 @@ wrkgp: ret ($26) .end wrkgp - .align 5 + .align 3 .globl wrusp .ent wrusp wrusp: @@ -51,7 +51,7 @@ wrusp: ret ($26) .end wrusp - .align 5 + .align 3 .globl rdusp .ent rdusp rdusp: @@ -59,6 +59,38 @@ rdusp: ret ($26) .end rdusp + .align 3 + .globl tbi + .ent tbi +tbi: + .long PAL_tbi + ret ($26) + .end tbi + + .align 3 + .globl imb + .ent imb +imb: + .long PAL_imb + ret ($26) + .end imb + + .align 3 + .globl rdmces + .ent rdmces +rdmces: + call_pal PAL_rdmces + ret ($26) + .end rdmces + + .align 3 + .globl wrmces + .ent wrmces +wrmces: + call_pal PAL_wrmces + ret ($26) + .end wrmces + .align 9 .globl floppy_track_buffer floppy_track_buffer: diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 212554ff2794..a59077539246 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -250,9 +250,9 @@ static void local_device_interrupt(unsigned long vector, struct pt_regs * regs) handle_irq(1, regs); return; - /* mouse: map to irq 12 */ + /* mouse: map to irq 9 */ case 0x990: - handle_irq(12, regs); + handle_irq(9, regs); return; default: printk("Unknown local interrupt %lx\n", vector); diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/lca.c index 7ee9cb270491..c32c308fb1f6 100644 --- a/arch/alpha/kernel/lca.c +++ b/arch/alpha/kernel/lca.c @@ -1,40 +1,26 @@ /* * Code common to all LCA chips. + * + * Written by David Mosberger (davidm@cs.arizona.edu) with some code + * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit + * bios code. */ - +#include #include #include #include #include #include -#include +#include /* * BIOS32-style PCI interface: */ -/* - * PCI BIOS32 interface: - */ -#define MAJOR_REV 0 -#define MINOR_REV 0 - #ifdef CONFIG_PCI -#define mtpr_mces(v) \ -({ \ - register unsigned long v0 asm ("0"); \ - register unsigned long a0 asm ("16"); \ - a0 = (v); \ - asm volatile ("call_pal %1 # %0 %2" : "r="(v0) \ - : "i"(PAL_mtpr_mces), "r"(a0) \ - : "memory", "0", "1", "16", "22", "23", "24", "25"); \ - v0; \ -}) - -#define draina() asm volatile ("call_pal %0" :: "i"(PAL_draina)) - +#define vulp volatile unsigned long * /* * Given a bus, device, and function number, compute resulting @@ -42,10 +28,43 @@ * accordingly. It is therefore not safe to have concurrent * invocations to configuration space access routines, but there * really shouldn't be any need for this. + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., scsi and ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. */ -static int -mk_conf_addr(unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *pci_addr) +static int mk_conf_addr(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned long *pci_addr) { unsigned long addr; @@ -72,8 +91,7 @@ mk_conf_addr(unsigned char bus, unsigned char device_fn, } -static unsigned int -conf_read(unsigned long addr) +static unsigned int conf_read(unsigned long addr) { unsigned long old_ipl, code, stat0; unsigned int value; @@ -101,7 +119,7 @@ conf_read(unsigned long addr) /* reset error status: */ *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; mb(); - mtpr_mces(0x7); /* reset machine check */ + wrmces(0x7); /* reset machine check */ value = 0xffffffff; } @@ -111,73 +129,41 @@ conf_read(unsigned long addr) } -static void -conf_write(unsigned long addr, unsigned int value) -{ -} - - -int -pcibios_present (void) +static void conf_write(unsigned long addr, unsigned int value) { - return 1; /* present if configured */ -} - + unsigned long old_ipl, code, stat0; -int -pcibios_find_class (unsigned long class_code, unsigned short index, - unsigned char *bus, unsigned char *device_fn) -{ - pci_resource_t *dev; - unsigned long w; - - for (dev = pci_device_list; dev; dev = dev->next) { - pcibios_read_config_dword(dev->bus, dev->dev_fn, - PCI_CLASS_REVISION, &w); - if ((w >> 8) == class_code) { - if (index == 0) { - *bus = dev->bus; - *device_fn = dev->dev_fn; - return PCIBIOS_SUCCESSFUL; - } - --index; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} + old_ipl = swpipl(7); /* avoid getting hit by machine check */ + /* reset status register to avoid loosing errors: */ + stat0 = *((volatile unsigned long*)LCA_IOC_STAT0); + *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + mb(); -int -pcibios_find_device (unsigned short vendor, unsigned short device_id, - unsigned short index, unsigned char *bus, - unsigned char *device_fn) -{ - unsigned long w, desired = (device_id << 16) | vendor; - pci_resource_t *dev; + /* access configuration space: */ - if (vendor == 0xffff) { - return PCIBIOS_BAD_VENDOR_ID; - } + *((volatile unsigned int*)addr) = value; + draina(); - for (dev = pci_device_list; dev; dev = dev->next) { - pcibios_read_config_dword(dev->bus, dev->dev_fn, - PCI_VENDOR_ID, &w); - if (w == desired) { - if (index == 0) { - *bus = dev->bus; - *device_fn = dev->dev_fn; - return PCIBIOS_SUCCESSFUL; - } - --index; + stat0 = *((unsigned long*)LCA_IOC_STAT0); + if (stat0 & LCA_IOC_STAT0_ERR) { + code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT) + & LCA_IOC_STAT0_CODE_MASK); + if (code != 1) { + printk("lca.c:conf_write: got stat0=%lx\n", stat0); } + + /* reset error status: */ + *((volatile unsigned long*)LCA_IOC_STAT0) = stat0; + mb(); + wrmces(0x7); /* reset machine check */ } - return PCIBIOS_DEVICE_NOT_FOUND; + swpipl(old_ipl); } -int -pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char *value) +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; @@ -196,9 +182,8 @@ pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, } -int -pcibios_read_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short *value) +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; @@ -220,9 +205,8 @@ pcibios_read_config_word (unsigned char bus, unsigned char device_fn, } -int -pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long *value) +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) { unsigned long addr = LCA_CONF; unsigned long pci_addr; @@ -245,56 +229,76 @@ pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, } -int -pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned char value) +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) { - panic("pcibios_write_config_byte"); + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } /* if */ + + addr |= (pci_addr << 5) + 0x00; + + conf_write(addr, value << ((where & 3) * 8)); + + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_word (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned short value) + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) { - panic("pcibios_write_config_word"); + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } /* if */ + + addr |= (pci_addr << 5) + 0x08; + + conf_write(addr, value << ((where & 3) * 8)); + + return PCIBIOS_SUCCESSFUL; } -int -pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, - unsigned char where, unsigned long value) + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) { - panic("pcibios_write_config_dword"); -} + unsigned long addr = LCA_CONF; + unsigned long pci_addr; -#endif /* CONFIG_PCI */ + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } /* if */ + addr |= (pci_addr << 5) + 0x18; -unsigned long -bios32_init(unsigned long memory_start, unsigned long memory_end) -{ -#ifdef CONFIG_PCI - printk("LCA PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + conf_write(addr, value << ((where & 3) * 8)); - probe_pci(); + return PCIBIOS_SUCCESSFUL; +} -#if 0 - { - char buf[4096]; - get_pci_list(buf); - printk("%s", buf); - } -#endif +unsigned long lca_init(unsigned long mem_start, unsigned long mem_end) +{ + /* + * Set up the PCI->physical memory translation windows. + * For now, window 1 is disabled. In the future, we may + * want to use it to do scatter/gather DMA. Window 0 + * goes at 1 GB and is 1 GB large. + */ + *(vulp)LCA_IOC_W_BASE1 = 0UL<<33; + *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE; + *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1; + *(vulp)LCA_IOC_T_BASE0 = 0; + + return mem_start; +} -#if 0 - { - extern void NCR53c810_test(void); - NCR53c810_test(); - } -#endif #endif /* CONFIG_PCI */ - return memory_start; -} /* bios32_init */ - /*** end of lca.c ***/ diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c new file mode 100644 index 000000000000..ddf090283683 --- /dev/null +++ b/arch/alpha/kernel/osf_sys.c @@ -0,0 +1,494 @@ +/* + * linux/arch/alpha/kernel/osf_sys.c + * + * Copyright (C) 1995 Linus Torvalds + */ + +/* + * This file handles some of the stranger OSF/1 system call interfaces. + * Some of the system calls expect a non-C calling standard, others have + * special parameter blocks.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern int do_mount(dev_t, const char *, char *, int, void *); +extern int do_pipe(int *); + +extern struct file_operations * get_blkfops(unsigned int); +extern struct file_operations * get_chrfops(unsigned int); + +extern dev_t get_unnamed_dev(void); +extern void put_unnamed_dev(dev_t); + +extern asmlinkage int sys_umount(char *); +extern asmlinkage int sys_swapon(const char *specialfile); + +/* + * OSF/1 directory handling functions... + * + * The "getdents()" interface is much more sane: the "basep" stuff is + * braindamage (it can't really handle filesystems where the directory + * offset differences aren't the same as "d_reclen"). + */ +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+7) & ~7) + +struct osf_dirent { + unsigned int d_ino; + unsigned short d_reclen; + unsigned short d_namlen; + char d_name[1]; +}; + +struct osf_dirent_callback { + struct osf_dirent * dirent; + long *basep; + int count; + int error; +}; + +static int osf_filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino) +{ + struct osf_dirent * dirent; + struct osf_dirent_callback * buf = (struct osf_dirent_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* unly used if we fail */ + if (reclen > buf->count) + return -EINVAL; + if (buf->basep) { + put_user(offset, buf->basep); + buf->basep = NULL; + } + dirent = buf->dirent; + put_user(ino, &dirent->d_ino); + put_user(namlen, &dirent->d_namlen); + put_user(reclen, &dirent->d_reclen); + memcpy_tofs(dirent->d_name, name, namlen); + put_fs_byte(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + buf->dirent = dirent; + buf->count -= reclen; + return 0; +} + +asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent * dirent, + unsigned int count, long *basep) +{ + int error; + struct file * file; + struct osf_dirent_callback buf; + + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + if (!file->f_op || !file->f_op->readdir) + return -ENOTDIR; + error = verify_area(VERIFY_WRITE, dirent, count); + if (error) + return error; + if (basep) { + error = verify_area(VERIFY_WRITE, basep, sizeof(long)); + if (error) + return error; + } + buf.dirent = dirent; + buf.basep = basep; + buf.count = count; + buf.error = 0; + error = file->f_op->readdir(file->f_inode, file, dirent, osf_filldir); + if (error < 0) + return error; + if (count == buf.count) + return buf.error; + return count - buf.count; +} + +/* + * Heh. As documented by DEC.. + */ +asmlinkage unsigned long sys_madvise(void) +{ + return 0; +} + +asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5, + struct pt_regs regs) +{ + (®s)->r20 = current->euid; + return current->uid; +} + +asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5, + struct pt_regs regs) +{ + (®s)->r20 = current->egid; + return current->gid; +} + +asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5, + struct pt_regs regs) +{ + (®s)->r20 = current->p_opptr->pid; + return current->pid; +} + +#define OSF_MAP_ANONYMOUS 0x0010 +#define OSF_MAP_FIXED 0x0100 +#define OSF_MAP_HASSEMAPHORE 0x0200 +#define OSF_MAP_INHERIT 0x0400 +#define OSF_MAP_UNALIGNED 0x0800 + +asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long osf_flags, unsigned long fd, + unsigned long off) +{ + struct file * file = NULL; + unsigned long flags = osf_flags & 0x0f; + + if (osf_flags & (OSF_MAP_HASSEMAPHORE | OSF_MAP_INHERIT | OSF_MAP_UNALIGNED)) + printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, osf_flags); + if (osf_flags & OSF_MAP_FIXED) + flags |= MAP_FIXED; + if (osf_flags & OSF_MAP_ANONYMOUS) + flags |= MAP_ANONYMOUS; + else { + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + } + return do_mmap(file, addr, len, prot, flags, off); +} + +asmlinkage int osf_statfs(char * path, struct statfs * buffer, unsigned long bufsiz) +{ + struct inode * inode; + int retval; + + if (bufsiz > sizeof(struct statfs)) + bufsiz = sizeof(struct statfs); + retval = verify_area(VERIFY_WRITE, buffer, bufsiz); + if (retval) + return retval; + retval = namei(path, &inode); + if (retval) + return retval; + if (!inode->i_sb->s_op->statfs) { + iput(inode); + return -ENOSYS; + } + inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz); + iput(inode); + return 0; +} + +asmlinkage int osf_fstatfs(unsigned long fd, struct statfs * buffer, unsigned long bufsiz) +{ + struct file * file; + struct inode * inode; + int retval; + + retval = verify_area(VERIFY_WRITE, buffer, bufsiz); + if (retval) + return retval; + if (bufsiz > sizeof(struct statfs)) + bufsiz = sizeof(struct statfs); + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; + inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz); + return 0; +} + +/* + * Uhh.. OSF/1 mount parameters aren't exactly obvious.. + * + * Although to be frank, neither are the native Linux/i386 ones.. + */ +struct ufs_args { + char * devname; + int flags; + uid_t exroot; +}; + +struct cdfs_args { + char * devname; + int flags; + uid_t exroot; +/* + * this has lots more here, which linux handles with the option block + * but I'm too lazy to do the translation into ascii.. + */ +}; + +struct procfs_args { + char * devname; + int flags; + uid_t exroot; +}; + +static int getdev(const char * name, int rdonly, struct inode ** ino) +{ + dev_t dev; + struct inode * inode; + struct file_operations * fops; + int retval; + + retval = namei(name, &inode); + if (retval) + return retval; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + if (IS_NODEV(inode)) { + iput(inode); + return -EACCES; + } + dev = inode->i_rdev; + if (MAJOR(dev) >= MAX_BLKDEV) { + iput(inode); + return -ENXIO; + } + fops = get_blkfops(MAJOR(dev)); + if (!fops) { + iput(inode); + return -ENODEV; + } + if (fops->open) { + struct file dummy; + memset(&dummy, 0, sizeof(dummy)); + dummy.f_inode = inode; + dummy.f_mode = rdonly ? 1 : 3; + retval = fops->open(inode, &dummy); + if (retval) { + iput(inode); + return retval; + } + } + *ino = inode; + return 0; +} + +static void putdev(struct inode * inode) +{ + struct file_operations * fops; + + fops = get_blkfops(MAJOR(inode->i_rdev)); + if (fops->release) + fops->release(inode, NULL); +} + +/* + * We can't actually handle ufs yet, so we translate UFS mounts to + * ext2fs mounts... I wouldn't mind a USF filesystem, but the UFS + * layout is so braindead it's a major headache doing it.. + */ +static int osf_ufs_mount(char * dirname, struct ufs_args * args, int flags) +{ + int retval; + struct inode * inode; + struct cdfs_args tmp; + + retval = verify_area(VERIFY_READ, args, sizeof(*args)); + if (retval) + return retval; + memcpy_fromfs(&tmp, args, sizeof(tmp)); + retval = getdev(tmp.devname, 0, &inode); + if (retval) + return retval; + retval = do_mount(inode->i_rdev, dirname, "ext2", flags, NULL); + if (retval) + putdev(inode); + iput(inode); + return retval; +} + +static int osf_cdfs_mount(char * dirname, struct cdfs_args * args, int flags) +{ + int retval; + struct inode * inode; + struct cdfs_args tmp; + + retval = verify_area(VERIFY_READ, args, sizeof(*args)); + if (retval) + return retval; + memcpy_fromfs(&tmp, args, sizeof(tmp)); + retval = getdev(tmp.devname, 1, &inode); + if (retval) + return retval; + retval = do_mount(inode->i_rdev, dirname, "iso9660", flags, NULL); + if (retval) + putdev(inode); + iput(inode); + return retval; +} + +static int osf_procfs_mount(char * dirname, struct procfs_args * args, int flags) +{ + dev_t dev; + int retval; + struct procfs_args tmp; + + retval = verify_area(VERIFY_READ, args, sizeof(*args)); + if (retval) + return retval; + memcpy_fromfs(&tmp, args, sizeof(tmp)); + dev = get_unnamed_dev(); + if (!dev) + return -ENODEV; + retval = do_mount(dev, dirname, "proc", flags, NULL); + if (retval) + put_unnamed_dev(dev); + return retval; +} + +asmlinkage int osf_mount(unsigned long typenr, char * path, int flag, void * data) +{ + int retval; + + retval = -EINVAL; + switch (typenr) { + case 1: + retval = osf_ufs_mount(path, (struct ufs_args *) data, flag); + break; + case 6: + retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag); + break; + case 9: + retval = osf_procfs_mount(path, (struct procfs_args *) data, flag); + break; + default: + printk("osf_mount(%ld, %x)\n", typenr, flag); + } + return retval; +} + +asmlinkage int osf_umount(char * path, int flag) +{ + return sys_umount(path); +} + +/* + * I don't know what the parameters are: the first one + * seems to be a timeval pointer, and I suspect the second + * one is the time remaining.. Ho humm.. No documentation. + */ +asmlinkage int osf_usleep_thread(struct timeval * sleep, struct timeval * remain) +{ + struct timeval tmp; + unsigned long ticks; + int retval; + + retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep)); + if (retval) + return retval; + if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain)))) + return retval; + memcpy_fromfs(&tmp, sleep, sizeof(*sleep)); + ticks = tmp.tv_usec; + ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ); + ticks += tmp.tv_sec * HZ; + current->timeout = ticks + jiffies; + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (!remain) + return 0; + ticks = jiffies; + if (ticks < current->timeout) + ticks = current->timeout - ticks; + else + ticks = 0; + current->timeout = 0; + tmp.tv_sec = ticks / HZ; + tmp.tv_usec = ticks % HZ; + memcpy_tofs(remain, &tmp, sizeof(*remain)); + return 0; +} + +asmlinkage int osf_utsname(char * name) +{ + int error = verify_area(VERIFY_WRITE, name, 5*32); + if (error) + return error; + memcpy_tofs(name + 0, system_utsname.sysname, 32); + memcpy_tofs(name + 32, system_utsname.nodename, 32); + memcpy_tofs(name + 64, system_utsname.release, 32); + memcpy_tofs(name + 96, system_utsname.version, 32); + memcpy_tofs(name + 128, system_utsname.machine, 32); + return 0; +} + +asmlinkage int osf_swapon(const char * path, int flags, int lowat, int hiwat) +{ + /* for now, simply ignore flags, lowat and hiwat... */ + return sys_swapon(path); +} + +asmlinkage unsigned long sys_getpagesize(void) +{ + return PAGE_SIZE; +} + +asmlinkage unsigned long sys_getdtablesize(void) +{ + return NR_OPEN; +} + +asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5, + struct pt_regs regs) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (error) + return error; + (®s)->r20 = fd[1]; + return fd[0]; +} + +/* + * For compatibility with OSF/1 only. Use utsname(2) instead. + */ +asmlinkage int osf_getdomainname(char *name, int namelen) +{ + unsigned len; + int i, error; + + error = verify_area(VERIFY_WRITE, name, namelen); + if (error) + return error; + + len = namelen; + if (namelen > 32) + len = 32; + + for (i = 0; i < len; ++i) { + put_user(system_utsname.domainname[i], name + i); + if (system_utsname.domainname[i] == '\0') + break; + } + return 0; +} diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 0db90eaa740f..257f431a5662 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -19,11 +19,24 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include +asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) +{ + (®s)->hae = hae; + return 0; +} + asmlinkage int sys_idle(void) { if (current->pid != 0) @@ -44,7 +57,19 @@ void hard_reset_now(void) void show_regs(struct pt_regs * regs) { printk("\nps: %04lx pc: %016lx\n", regs->ps, regs->pc); - printk("rp: %04lx sp: %p\n", regs->r26, regs+1); + printk("rp: %016lx sp: %p\n", regs->r26, regs+1); + printk(" r0: %016lx r1: %016lx r2: %016lx r3: %016lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); + printk(" r4: %016lx r5: %016lx r6: %016lx r7: %016lx\n", + regs->r4, regs->r5, regs->r6, regs->r7); + printk(" r8: %016lx r16: %016lx r17: %016lx r18: %016lx\n", + regs->r8, regs->r16, regs->r17, regs->r18); + printk("r19: %016lx r20: %016lx r21: %016lx r22: %016lx\n", + regs->r19, regs->r20, regs->r21, regs->r22); + printk("r23: %016lx r24: %016lx r25: %016lx r26: %016lx\n", + regs->r23, regs->r24, regs->r25, regs->r26); + printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n", + regs->r27, regs->r28, regs->gp, regs->hae); } /* @@ -58,82 +83,55 @@ void flush_thread(void) { } -struct alpha_switch_stack { - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long r14; - unsigned long r15; - unsigned long r26; -}; - -/* - * "alpha_switch_to()".. Done completely in assembly, due to the - * fact that we obviously don't returns to the caller directly. - * Also, we have to save the regs that the C compiler expects to be - * saved across a function call.. (9-15) - * - * NOTE! The stack switches from under us when we do the swpctx call: - * this *looks* like it restores the same registers that it just saved, - * but it actually restores the new context regs and return address. - */ -__asm__(".align 3\n\t" - ".globl alpha_switch_to\n\t" - ".ent alpha_switch_to\n" - "alpha_switch_to:\n\t" - "subq $30,64,$30\n\t" - "stq $9,0($30)\n\t" - "stq $10,8($30)\n\t" - "stq $11,16($30)\n\t" - "stq $12,24($30)\n\t" - "stq $13,32($30)\n\t" - "stq $14,40($30)\n\t" - "stq $15,48($30)\n\t" - "stq $26,56($30)\n\t" - "call_pal 48\n\t" - "ldq $9,0($30)\n\t" - "ldq $10,8($30)\n\t" - "ldq $11,16($30)\n\t" - "ldq $12,24($30)\n\t" - "ldq $13,32($30)\n\t" - "ldq $14,40($30)\n\t" - "ldq $15,48($30)\n\t" - "ldq $26,56($30)\n\t" - "addq $30,64,$30\n\t" - "ret $31,($26),1\n\t" - ".end alpha_switch_to"); - /* * "alpha_fork()".. By the time we get here, the * non-volatile registers have also been saved on the * stack. We do some ugly pointer stuff here.. (see * also copy_thread) */ -int alpha_fork(struct alpha_switch_stack * swstack) +int alpha_fork(struct switch_stack * swstack) { - return do_fork(COPYVM | SIGCHLD, 0, (struct pt_regs *) (swstack+1)); + return do_fork(COPYVM | SIGCHLD, + rdusp(), + (struct pt_regs *) (swstack+1)); } +extern void ret_from_sys_call(void); /* * Copy an alpha thread.. + * + * Note the "stack_offset" stuff: when returning to kernel mode, we need + * to have some extra stack-space for the kernel stack that still exists + * after the "ret_from_sys_call". When returning to user mode, we only + * want the space needed by the syscall stack frame (ie "struct pt_regs"). + * Use the passed "regs" pointer to determine how much space we need + * for a kernel fork(). */ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; - struct alpha_switch_stack * childstack, *stack; - - childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; + struct switch_stack * childstack, *stack; + unsigned long stack_offset; + + stack_offset = PAGE_SIZE - sizeof(struct pt_regs); + if (!(regs->ps & 8)) + stack_offset = (PAGE_SIZE-1) & (unsigned long) regs; + childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset); + *childregs = *regs; childregs->r0 = 0; + childregs->r19 = 0; + childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */ regs->r0 = p->pid; - stack = ((struct alpha_switch_stack *) regs) - 1; - childstack = ((struct alpha_switch_stack *) childregs) - 1; + regs->r20 = 0; + stack = ((struct switch_stack *) regs) - 1; + childstack = ((struct switch_stack *) childregs) - 1; *childstack = *stack; + childstack->r26 = (unsigned long) ret_from_sys_call; p->tss.usp = usp; p->tss.ksp = (unsigned long) childstack; + p->tss.flags = 1; } /* diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index e6ad10e51f6d..23a2efd65198 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -20,14 +20,35 @@ #include #include #include +#include #include #include #include +#include #include +struct hae hae = { + 0, + (unsigned long*) HAE_ADDRESS +}; + +struct hwrpb_struct *hwrpb; + unsigned char aux_device_present; +/* + * This is setup by the secondary bootstrap loader. Because + * the zero page is zeroed out as soon as the vm system is + * initialized, we need to copy things out into a more permanent + * place. + */ +#define PARAM ZERO_PGE +#define COMMAND_LINE ((char*)(PARAM + 0x0000)) +#define COMMAND_LINE_SIZE 256 + +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + /* * The format of "screen_info" is strange, and due to early * i386-setup code. This is just enough to make the console @@ -35,7 +56,7 @@ unsigned char aux_device_present; */ struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ - 0, 0, /* unused */ + { 0, 0 }, /* unused */ 0, /* orig-video-page */ 0, /* orig-video-mode */ 80, /* orig-video-cols */ @@ -43,11 +64,6 @@ struct screen_info screen_info = { 25 /* orig-video-lines */ }; -unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) -{ - return memory_start; -} - static unsigned long find_end_memory(void) { int i; @@ -71,17 +87,86 @@ static unsigned long find_end_memory(void) void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - static char cmdline[] = ""; extern int _end; - ROOT_DEV = 0x0200; /* fd0 */ + hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr); + + set_hae(hae.cache); /* sync HAE register w/hae_cache */ + + ROOT_DEV = 0x0802; /* sda2 */ +#ifndef CONFIG_PCI aux_device_present = 0xaa; - *cmdline_p = cmdline; +#else + aux_device_present = 0x00; +#endif + command_line[COMMAND_LINE_SIZE - 1] = '\0'; + strcpy(command_line, COMMAND_LINE); + + *cmdline_p = command_line; *memory_start_p = (unsigned long) &_end; *memory_end_p = find_end_memory(); + +#ifdef CONFIG_PCI + *memory_start_p = lca_init(*memory_start_p, *memory_end_p); +#endif } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) { return -EIO; } + + +/* + * BUFFER is PAGE_SIZE bytes long. + */ +int get_cpuinfo(char *buffer) +{ + const char *cpu_name[] = { + "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45" + }; + const char *systype_name[] = { + "ADU", "Cobra", "Ruby", "Flamingo", "Unknown 1", "Jensen", + "Pelican", "Unknown 2", "Sable", "AXPvme", "Noname", + "Turbolaser", "Avanti", "Mustang", "Alcor", "Unknown 3", + "Mikasa", "Unknown3", "EB66", "EB64+" + }; + struct percpu_struct *cpu; + unsigned int cpu_index, system_index; +# define N(a) (sizeof(a)/sizeof(a[0])) + + cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); + cpu_index = (unsigned) (cpu->type - 1); + system_index = (unsigned) (hwrpb->sys_type - 1); + + return sprintf(buffer, + "cpu\t\t\t: Alpha\n" + "cpu model\t\t: %s\n" + "cpu variation\t\t: %ld\n" + "cpu revision\t\t: %ld\n" + "cpu serial number\t: %s\n" + "system type\t\t: %s\n" + "system variation\t: %ld\n" + "system revision\t\t: %ld\n" + "system serial number\t: %s\n" + "cycle frequency [Hz]\t: %lu\n" + "timer frequency [Hz]\t: %lu.%02lu\n" + "page size [bytes]\t: %ld\n" + "phys. address bits\t: %ld\n" + "max. addr. space #\t: %ld\n" + "BogoMIPS\t\t: %lu.%02lu\n", + + (cpu_index < N(cpu_name) ? cpu_name[cpu_index] : "Unknown"), + cpu->variation, cpu->revision, (char*)cpu->serial_no, + (system_index < N(systype_name) ? systype_name[system_index] : "Unknown"), + hwrpb->sys_variation, hwrpb->sys_revision, + (char*)hwrpb->ssn, + hwrpb->cycle_freq, + hwrpb->intr_freq / 4096, + (100 * hwrpb->intr_freq / 4096) % 100, + hwrpb->pagesize, + hwrpb->pa_bits, + hwrpb->max_asn, + loops_per_sec / 500000, (loops_per_sec / 5000) % 100); +# undef N +} diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index b4b3f3621e86..cc7069728479 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -11,50 +11,183 @@ #include #include #include +#include +#include #include #define _S(nr) (1<<((nr)-1)) - #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage void ret_from_sys_call(void); +asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *, + unsigned long, unsigned long); +asmlinkage void imb(void); /* - * atomically swap in the new signal mask, and wait for a signal. + * The OSF/1 sigprocmask calling sequence is different from the + * C sigprocmask() sequence.. */ -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) +asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask) { - unsigned long mask; - struct pt_regs * regs = (struct pt_regs *) &restart; + unsigned long oldmask = current->blocked; + + newmask &= _BLOCKABLE; + switch (how) { + case SIG_BLOCK: + current->blocked |= newmask; + return oldmask; + case SIG_UNBLOCK: + current->blocked &= ~newmask; + return oldmask; + case SIG_SETMASK: + current->blocked = newmask; + return oldmask; + } + return -EINVAL; +} - halt(); - mask = current->blocked; - current->blocked = set & _BLOCKABLE; +/* + * atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw) +{ + unsigned long oldmask = current->blocked; + current->blocked = mask & _BLOCKABLE; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) + if (do_signal(oldmask,regs, sw, 0, 0)) return -EINTR; } } /* - * this should do a signal return with the info on the stack.. + * Do a signal return; undo the signal stack. */ -asmlinkage int sys_sigreturn(unsigned long __unused) +asmlinkage void do_sigreturn(struct sigcontext_struct * sc, + struct pt_regs * regs, struct switch_stack * sw) { - halt(); - return 0; + unsigned long mask; + int i; + + /* verify that it's a good sigcontext before using it */ + if (verify_area(VERIFY_READ, sc, sizeof(*sc))) + do_exit(SIGSEGV); + if (get_fs_quad(&sc->sc_ps) != 8) + do_exit(SIGSEGV); + mask = get_fs_quad(&sc->sc_mask); + if (mask & ~_BLOCKABLE) + do_exit(SIGSEGV); + + /* ok, looks fine, start restoring */ + wrusp(get_fs_quad(sc->sc_regs+30)); + regs->pc = get_fs_quad(&sc->sc_pc); + sw->r26 = (unsigned long) ret_from_sys_call; + current->blocked = mask; + + regs->r0 = get_fs_quad(sc->sc_regs+0); + regs->r1 = get_fs_quad(sc->sc_regs+1); + regs->r2 = get_fs_quad(sc->sc_regs+2); + regs->r3 = get_fs_quad(sc->sc_regs+3); + regs->r4 = get_fs_quad(sc->sc_regs+4); + regs->r5 = get_fs_quad(sc->sc_regs+5); + regs->r6 = get_fs_quad(sc->sc_regs+6); + regs->r7 = get_fs_quad(sc->sc_regs+7); + regs->r8 = get_fs_quad(sc->sc_regs+8); + sw->r9 = get_fs_quad(sc->sc_regs+9); + sw->r10 = get_fs_quad(sc->sc_regs+10); + sw->r11 = get_fs_quad(sc->sc_regs+11); + sw->r12 = get_fs_quad(sc->sc_regs+12); + sw->r13 = get_fs_quad(sc->sc_regs+13); + sw->r14 = get_fs_quad(sc->sc_regs+14); + sw->r15 = get_fs_quad(sc->sc_regs+15); + regs->r16 = get_fs_quad(sc->sc_regs+16); + regs->r17 = get_fs_quad(sc->sc_regs+17); + regs->r18 = get_fs_quad(sc->sc_regs+18); + regs->r19 = get_fs_quad(sc->sc_regs+19); + regs->r20 = get_fs_quad(sc->sc_regs+20); + regs->r21 = get_fs_quad(sc->sc_regs+21); + regs->r22 = get_fs_quad(sc->sc_regs+22); + regs->r23 = get_fs_quad(sc->sc_regs+23); + regs->r24 = get_fs_quad(sc->sc_regs+24); + regs->r25 = get_fs_quad(sc->sc_regs+25); + regs->r26 = get_fs_quad(sc->sc_regs+26); + regs->r27 = get_fs_quad(sc->sc_regs+27); + regs->r28 = get_fs_quad(sc->sc_regs+28); + regs->gp = get_fs_quad(sc->sc_regs+29); + for (i = 0; i < 31; i++) + sw->fp[i] = get_fs_quad(sc->sc_fpregs+i); } /* - * Set up a signal frame... I don't know what it should look like yet. + * Set up a signal frame... */ -void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long pc, - struct pt_regs * regs, int signr, unsigned long oldmask) +static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp, unsigned long pc, + struct pt_regs * regs, struct switch_stack * sw, int signr, unsigned long oldmask) { - halt(); + int i; + struct sigcontext_struct * sc; + + sc = *fp; + /* check here if we would need to switch stacks.. */ + sc--; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + do_exit(SIGSEGV); + + put_fs_quad(oldmask, &sc->sc_mask); + put_fs_quad(8, &sc->sc_ps); + put_fs_quad(pc, &sc->sc_pc); + put_fs_quad((unsigned long)*fp, sc->sc_regs+30); + + put_fs_quad(regs->r0 , sc->sc_regs+0); + put_fs_quad(regs->r1 , sc->sc_regs+1); + put_fs_quad(regs->r2 , sc->sc_regs+2); + put_fs_quad(regs->r3 , sc->sc_regs+3); + put_fs_quad(regs->r4 , sc->sc_regs+4); + put_fs_quad(regs->r5 , sc->sc_regs+5); + put_fs_quad(regs->r6 , sc->sc_regs+6); + put_fs_quad(regs->r7 , sc->sc_regs+7); + put_fs_quad(regs->r8 , sc->sc_regs+8); + put_fs_quad(sw->r9 , sc->sc_regs+9); + put_fs_quad(sw->r10 , sc->sc_regs+10); + put_fs_quad(sw->r11 , sc->sc_regs+11); + put_fs_quad(sw->r12 , sc->sc_regs+12); + put_fs_quad(sw->r13 , sc->sc_regs+13); + put_fs_quad(sw->r14 , sc->sc_regs+14); + put_fs_quad(sw->r15 , sc->sc_regs+15); + put_fs_quad(regs->r16, sc->sc_regs+16); + put_fs_quad(regs->r17, sc->sc_regs+17); + put_fs_quad(regs->r18, sc->sc_regs+18); + put_fs_quad(regs->r19, sc->sc_regs+19); + put_fs_quad(regs->r20, sc->sc_regs+20); + put_fs_quad(regs->r21, sc->sc_regs+21); + put_fs_quad(regs->r22, sc->sc_regs+22); + put_fs_quad(regs->r23, sc->sc_regs+23); + put_fs_quad(regs->r24, sc->sc_regs+24); + put_fs_quad(regs->r25, sc->sc_regs+25); + put_fs_quad(regs->r26, sc->sc_regs+26); + put_fs_quad(regs->r27, sc->sc_regs+27); + put_fs_quad(regs->r28, sc->sc_regs+28); + put_fs_quad(regs->gp , sc->sc_regs+29); + for (i = 0; i < 31; i++) + put_fs_quad(sw->fp[i], sc->sc_fpregs+i); + + /* + * The following is: + * + * bis $30,$30,$16 + * addq $31,0x67,$0 + * call_pal callsys + * + * ie, "sigreturn(stack-pointer)" + */ + put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0); + put_fs_quad(0x0000000000000083, sc->sc_retcode+1); + regs->r26 = (unsigned long) sc->sc_retcode; + regs->r16 = signr; + *fp = sc; } /* @@ -66,10 +199,121 @@ void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long pc, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. * - * Not that any of this is actually implemented yet ;-) + * "r0" and "r19" are the registers we need to restore for system call + * restart. "r0" is also used as an indicator whether we can restart at + * all (if we get here from anything but a syscall return, it will be 0) */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) +asmlinkage int do_signal(unsigned long oldmask, + struct pt_regs * regs, + struct switch_stack * sw, + unsigned long r0, unsigned long r19) { - halt(); + unsigned long mask = ~current->blocked; + unsigned long handler_signal = 0; + struct sigcontext_struct *frame = NULL; + unsigned long pc = 0; + unsigned long signr; + struct sigaction * sa; + + while ((signr = current->signal & mask) != 0) { + signr = ffz(~signr); + clear_bit(signr, ¤t->signal); + sa = current->sigaction + signr; + signr++; + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + if (signr == SIGSTOP) + continue; + if (_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sigaction + signr - 1; + } + if (sa->sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* check for SIGCHLD: it's special */ + while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* nothing */; + continue; + } + if (sa->sa_handler == SIG_DFL) { + if (current->pid == 1) + continue; + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + if (current->binfmt && current->binfmt->core_dump) { + if (current->binfmt->core_dump(signr, regs)) + signr |= 0x80; + } + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + do_exit(signr); + } + } + /* + * OK, we're invoking a handler + */ + if (r0) { + if (regs->r0 == ERESTARTNOHAND || + (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) + regs->r0 = EINTR; + } + handler_signal |= 1 << (signr-1); + mask &= ~sa->sa_mask; + } + if (r0 && + (regs->r0 == ERESTARTNOHAND || + regs->r0 == ERESTARTSYS || + regs->r0 == ERESTARTNOINTR)) { + regs->r0 = r0; + regs->r19 = r19; + regs->pc -= 4; + } + if (!handler_signal) /* no handler will be called - return 0 */ + return 0; + pc = regs->pc; + frame = (struct sigcontext_struct *) rdusp(); + signr = 1; + sa = current->sigaction; + for (mask = 1 ; mask ; sa++,signr++,mask += mask) { + if (mask > handler_signal) + break; + if (!(mask & handler_signal)) + continue; + setup_frame(sa,&frame,pc,regs,sw,signr,oldmask); + pc = (unsigned long) sa->sa_handler; + regs->r27 = pc; + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + current->blocked |= sa->sa_mask; + oldmask |= sa->sa_mask; + } + imb(); + wrusp((unsigned long) frame); + regs->pc = pc; /* "return" to the first handler */ return 1; } diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 3d24095390f9..4e3512ddd9a3 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -9,14 +9,40 @@ */ #include +#include + +#include void die_if_kernel(char * str, struct pt_regs * regs, long err) { - unsigned long i; + long i; + unsigned long sp; + unsigned int * pc; - printk("%s %ld\n", str, err); - printk("pc = %016lx ps = %04lx\n", regs->pc, regs->ps); - printk("rp = %016lx sp = %p\n", regs->r26, regs+1); + printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); + sp = (unsigned long) (regs+1); + if (regs->ps & 8) + sp = rdusp(); + printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps); + printk("rp = %lx sp = %lx\n", regs->r26, sp); + printk("r0=%lx r1=%lx r2=%lx r3=%lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); + printk("r8=%lx\n", regs->r8); + printk("r16=%lx r17=%lx r18=%lx r19=%lx\n", + regs->r16, regs->r17, regs->r18, regs->r19); + printk("r20=%lx r21=%lx r22=%lx r23=%lx\n", + regs->r20, regs->r21, regs->r22, regs->r23); + printk("r24=%lx r25=%lx r26=%lx r27=%lx\n", + regs->r24, regs->r25, regs->r26, regs->r27); + printk("r28=%lx r29=%lx r30=%lx\n", + regs->r28, regs->gp, sp); + if (regs->ps & 8) + return; + printk("Code:"); + pc = (unsigned int *) regs->pc; + for (i = -3; i < 6; i++) + printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>'); + printk("\n"); for (i = 0 ; i < 5000000000 ; i++) /* pause */; halt(); @@ -37,12 +63,56 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, die_if_kernel("Instruction fault", ®s, type); } -asmlinkage void do_entUna(unsigned long va, unsigned long opcode, unsigned long reg, +/* + * entUna has a different register layout to be reasonably simple. It + * needs access to all the integer registers (the kernel doesn't use + * fp-regs), and it needs to have them in order for simpler access. + * + * Due to the non-standard register layout (and because we don't want + * to handle floating-point regs), we disallow user-mode unaligned + * accesses (we'd need to do "verify_area()" checking, as well as + * do a full "ret_from_sys_call" return). + * + * Oh, btw, we don't handle the "gp" register correctly, but if we fault + * on a gp-register unaligned load/store, something is _very_ wrong + * in the kernel anyway.. + */ +struct allregs { + unsigned long regs[32]; + unsigned long ps, pc, gp, a0, a1, a2; +}; + +asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg, unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) + struct allregs regs) { - printk("Unaligned trap: %016lx %ld %ld\n", va, opcode, reg); - die_if_kernel("Unaligned", ®s, 0); + static int cnt = 0; + + if (regs.ps & 8) + do_exit(SIGSEGV); + if (++cnt < 5) + printk("Unaligned trap at %016lx: %p %lx %ld\n", + regs.pc, va, opcode, reg); + /* $16-$18 are PAL-saved, and are offset by 19 entries */ + if (reg >= 16 && reg <= 18) + reg += 19; + switch (opcode) { + case 0x28: /* ldl */ + *(reg+regs.regs) = (int) ldl_u(va); + return; + case 0x29: /* ldq */ + *(reg+regs.regs) = ldq_u(va); + return; + case 0x2c: /* stl */ + stl_u(*(reg+regs.regs), va); + return; + case 0x2d: /* stq */ + stq_u(*(reg+regs.regs), va); + return; + } + printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", + regs.pc, va, opcode, reg); + do_exit(SIGSEGV); } /* @@ -56,11 +126,11 @@ asmlinkage void do_entUna(unsigned long va, unsigned long opcode, unsigned long * are a thinko. DEC palcode is strange. The PAL-code designers probably * got terminally tainted by VMS at some point. */ -asmlinkage void do_entSys(unsigned long a0, unsigned long a1, unsigned long a2, +asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - printk("System call %ld(%ld,%ld)\n", regs.r0, a0, a1); - die_if_kernel("Syscall", ®s, 0); + printk("", regs.r0, a0, a1, a2); + return -1; } extern asmlinkage void entMM(void); diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 4ede2ad15993..9ac9310b2845 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -9,7 +9,7 @@ .c.o: $(CC) $(CFLAGS) -c $< -OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o +OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/alpha/lib/divide.S b/arch/alpha/lib/divide.S index ad5bd89b4bd9..9388d3f34243 100644 --- a/arch/alpha/lib/divide.S +++ b/arch/alpha/lib/divide.S @@ -58,10 +58,12 @@ #define func(x) __div##x #define modulus $2 #define quotient $27 +#define GETSIGN(x) xor $24,$25,x #else #define func(x) __rem##x #define modulus $27 #define quotient $2 +#define GETSIGN(x) bis $24,$24,x #endif /* @@ -122,9 +124,14 @@ ufunction: .end ufunction /* - * The "signed" version just does a halt if either of the value is - * signed: the kernel shouldn't mess with signed divides anyway (who - * knows what way they'll round..) + * Uhh.. Ugly signed division. I'd rather not have it at all, but + * it's needed in some circumstances. There are different ways to + * handle this, really. This does: + * -a / b = a / -b = -(a / b) + * -a % b = -(a % b) + * a % -b = a % b + * which is probably not the best solution, but at least should + * have the property that (x/y)*y + (x%y) = x. */ .globl sfunction .ent sfunction @@ -132,5 +139,22 @@ sfunction: bis $24,$25,$28 SLONGIFY($28) bge $28,ufunction - halt + subq $30,32,$30 + stq $23,0($30) + stq $24,8($30) + stq $25,16($30) + subq $31,$24,$28 + cmovlt $24,$28,$24 /* abs($24) */ + subq $31,$25,$28 + cmovlt $25,$28,$25 /* abs($25) */ + bsr $23,ufunction + ldq $23,0($30) + ldq $24,8($30) + ldq $25,16($30) + addq $30,32,$30 + GETSIGN($28) + SLONGIFY($28) + bge $28,1f + subq $31,$27,$27 +1: ret $31,($23),1 .end sfunction diff --git a/arch/alpha/lib/io.c b/arch/alpha/lib/io.c new file mode 100644 index 000000000000..b5f7290abecb --- /dev/null +++ b/arch/alpha/lib/io.c @@ -0,0 +1,98 @@ +/* + * Alpha IO and memory functions.. Just expand the inlines in the header + * files.. + */ +#include + +/* + * Jensen has a separate "local" and "bus" IO space for + * byte-wide IO. + */ +#ifdef __is_local +#undef __bus_inb +unsigned int __bus_inb(unsigned long addr) +{ + return ___bus_inb(addr); +} + +#undef __bus_outb +void __bus_outb(unsigned char b, unsigned long addr) +{ + ___bus_outb(b, addr); +} +#endif + +#undef inb +unsigned int inb(unsigned long addr) +{ + return __inb(addr); +} + +#undef inw +unsigned int inw(unsigned long addr) +{ + return __inw(addr); +} + +#undef inl +unsigned int inl(unsigned long addr) +{ + return __inl(addr); +} + + +#undef outb +void outb(unsigned char b, unsigned long addr) +{ + __outb(b, addr); +} + +#undef outw +void outw(unsigned short b, unsigned long addr) +{ + __outw(b, addr); +} + +#undef outl +void outl(unsigned int b, unsigned long addr) +{ + __outl(b, addr); +} + + +#undef readb +unsigned long readb(unsigned long addr) +{ + return __readb(addr); +} + +#undef readw +unsigned long readw(unsigned long addr) +{ + return __readw(addr); +} + +#undef readl +unsigned long readl(unsigned long addr) +{ + return __readl(addr); +} + + +#undef writeb +void writeb(unsigned short b, unsigned long addr) +{ + __writeb(b, addr); +} + +#undef writew +void writew(unsigned short b, unsigned long addr) +{ + __writew(b, addr); +} + +#undef writel +void writel(unsigned int b, unsigned long addr) +{ + __writel(b, addr); +} diff --git a/arch/alpha/lib/memcpy.c b/arch/alpha/lib/memcpy.c new file mode 100644 index 000000000000..4bbf92f69044 --- /dev/null +++ b/arch/alpha/lib/memcpy.c @@ -0,0 +1,74 @@ +/* + * linux/arch/alpha/lib/memcpy.c + * + * Copyright (C) 1995 Linus Torvalds + */ + +/* + * This is reasonably optimized for the quad-word-aligned case, which + * happens with page/buffer copies. It's horribly bad for the unaligned + * case: it could be made much better, but that would require lots of + * assembly (unaligned 8-byte load + shift + aligned 4-byte store, for + * example). + */ + +#include + +static inline void __memcpy_b(unsigned long d, unsigned long s, long n) +{ + while (--n >= 0) + *(char *) (d++) = *(char *) (s++); +} + +static inline void __memcpy_q(unsigned long d, unsigned long s, long n) +{ + /* this first part could be done in one go with ldq_u*2/mask/stq_u */ + while (d & 7) { + if (--n < 0) + return; + *(char *) d = *(char *) s; + d++; + s++; + } + while ((n -= 8) >= 0) { + *(unsigned long *) d = *(unsigned long *) s; + d += 8; + s += 8; + } + /* as could this.. */ + __memcpy_b(d,s,n+8); +} + +static inline void __memcpy_l(unsigned long d, unsigned long s, long n) +{ + while (d & 3) { + if (--n < 0) + return; + *(char *) d = *(char *) s; + d++; + s++; + } + while ((n -= 4) >= 0) { + *(unsigned int *) d = *(unsigned int *) s; + d += 4; + s += 4; + } + __memcpy_b(d,s,n+4); +} + +void * __memcpy(void * dest, const void *src, size_t n) +{ + unsigned long differ; + differ = ((unsigned long) dest ^ (unsigned long) src) & 7; + + if (!differ) { + __memcpy_q((unsigned long) dest, (unsigned long) src, n); + return dest; + } + if (differ == 4) { + __memcpy_l((unsigned long) dest, (unsigned long) src, n); + return dest; + } + __memcpy_b((unsigned long) dest, (unsigned long) src, n); + return dest; +} diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index ae7a7a39ba95..10ac8f496500 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -21,6 +21,10 @@ #include extern void die_if_kernel(char *,struct pt_regs *,long); +extern void tbi(unsigned long type, unsigned long arg); +#define tbisi(x) tbi(1,(x)) +#define tbisd(x) tbi(2,(x)) +#define tbis(x) tbi(3,(x)) /* * This routine handles page faults. It determines the address, @@ -64,13 +68,14 @@ good_area: if (!(vma->vm_flags & VM_EXEC)) goto bad_area; } else if (!cause) { - if (!(vma->vm_flags & VM_READ)) + /* Allow reads even for write-only mappings */ + if (!(vma->vm_flags & (VM_READ | VM_WRITE))) goto bad_area; } else { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } - + tbis(address); handle_mm_fault(vma, address, cause > 0); return; @@ -80,6 +85,8 @@ good_area: */ bad_area: if (user_mode(®s)) { + printk("memory violation at pc=%08lx (%08lx)\n", regs.pc, address); + die_if_kernel("oops", ®s, cause); send_sig(SIGSEGV, current, 1); return; } diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 7606c198ae9d..62203ef84b4a 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -62,10 +62,10 @@ void show_mem(void) int i,free = 0,total = 0,reserved = 0; int shared = 0; - printk("Mem-info:\n"); + printk("\nMem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = high_memory >> PAGE_SHIFT; + i = MAP_NR(high_memory); while (i-- > 0) { total++; if (mem_map[i] & MAP_PAGE_RESERVED) @@ -92,7 +92,7 @@ static void load_PCB(struct thread_struct * pcb) __asm__ __volatile__( "stq $30,0(%0)\n\t" "bis %0,%0,$16\n\t" - ".long %1" + "call_pal %1" : /* no outputs */ : "r" (pcb), "i" (PAL_swpctx) : "$0", "$1", "$16", "$22", "$23", "$24", "$25"); @@ -137,6 +137,8 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL); init_task.tss.ptbr = newptbr; + init_task.tss.flags = 1; + init_task.kernel_stack_page = INIT_STACK; load_PCB(&init_task.tss); invalidate_all(); @@ -183,7 +185,7 @@ void si_meminfo(struct sysinfo *val) { int i; - i = high_memory >> PAGE_SHIFT; + i = MAP_NR(high_memory); val->totalram = 0; val->sharedram = 0; val->freeram = nr_free_pages << PAGE_SHIFT; diff --git a/arch/i386/config.in b/arch/i386/config.in index 26a80d7efac1..bfbf42acb3fc 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -24,9 +24,9 @@ fi bool 'XT harddisk support' CONFIG_BLK_DEV_XD n bool 'Networking support' CONFIG_NET y bool 'Limit memory to low 16MB' CONFIG_MAX_16M n -bool 'PCI bios support' CONFIG_PCI n +bool 'PCI bios support' CONFIG_PCI y if [ "$CONFIG_PCI" = "y" ]; then - bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE n + bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE y fi bool 'System V IPC' CONFIG_SYSVIPC y bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y @@ -42,24 +42,33 @@ if [ "$CONFIG_NET" = "y" ]; then comment 'Networking options' bool 'TCP/IP networking' CONFIG_INET y if [ "$CONFIG_INET" = "y" ]; then -bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n -bool 'IP multicasting' CONFIG_IP_MULTICAST n -bool 'IP firewalling' CONFIG_IP_FIREWALL n -bool 'IP accounting' CONFIG_IP_ACCT n +bool 'IP: forwarding/gatewaying' CONFIG_IP_FORWARD n +bool 'IP: multicasting' CONFIG_IP_MULTICAST n +bool 'IP: firewalling' CONFIG_IP_FIREWALL n +bool 'IP: accounting' CONFIG_IP_ACCT n +bool 'IP: tunneling' CONFIG_NET_IPIP n +if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_FIREWALL" = "y" ]; then + bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y + bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n +fi comment '(it is safe to leave these untouched)' -bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n -bool 'Reverse ARP' CONFIG_INET_RARP n -bool 'Assume subnets are local' CONFIG_INET_SNARL y -bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n +bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP n +bool 'IP: Reverse ARP' CONFIG_INET_RARP n +bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y +bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n +bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y fi bool 'The IPX protocol' CONFIG_IPX n -#bool 'Appletalk DDP' CONFIG_ATALK n -#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n +bool 'Appletalk DDP' CONFIG_ATALK n +bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n +if [ "$CONFIG_AX25" = "y" ]; then + bool 'Amateur Radio NET/ROM' CONFIG_NETROM n +fi fi comment 'SCSI support' -bool 'SCSI support?' CONFIG_SCSI n +bool 'SCSI support?' CONFIG_SCSI y if [ "$CONFIG_SCSI" = "n" ]; then @@ -71,7 +80,7 @@ comment 'SCSI support type (disk, tape, CDrom)' bool 'SCSI disk support' CONFIG_BLK_DEV_SD y bool 'SCSI tape support' CONFIG_CHR_DEV_ST n -bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR n +bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR y bool 'SCSI generic support' CONFIG_CHR_DEV_SG n comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' @@ -80,9 +89,9 @@ bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN n comment 'SCSI low-level drivers' -bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n -bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y -bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n +bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y +bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n +bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n @@ -119,10 +128,16 @@ bool 'SLIP (serial line) support' CONFIG_SLIP n if [ "$CONFIG_SLIP" = "y" ]; then bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y bool ' 16 channels instead of 4' SL_SLIP_LOTS n -# bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n +if [ "$CONFIG_PPP" = "y" ]; then + bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n +fi +if [ "$CONFIG_AX25" = "y" ]; then + bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y +fi bool 'PLIP (parallel port) support' CONFIG_PLIP n +bool 'EQL (serial line load balancing) support' CONFIG_EQUALIZER n bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then @@ -142,11 +157,11 @@ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then fi bool 'Other ISA cards' CONFIG_NET_ISA n if [ "$CONFIG_NET_ISA" = "y" ]; then + bool 'Arcnet support' CONFIG_ARCNET n bool 'Cabletron E21xx support' CONFIG_E2100 n bool 'DEPCA support' CONFIG_DEPCA n bool 'EtherWorks 3 support' CONFIG_EWRK3 n if [ "$CONFIG_NET_ALPHA" = "y" ]; then - bool 'Arcnet support' CONFIG_ARCNET n bool 'AT1700 support' CONFIG_AT1700 n # bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n bool 'EtherExpress support' CONFIG_EEXPRESS n @@ -157,6 +172,9 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n bool 'NE2000/NE1000 support' CONFIG_NE2000 y + if [ "$CONFIG_AX25" = "y" ]; then + bool 'Ottawa PI and PI/2 support' CONFIG_PI y + fi bool 'SK_G16 support' CONFIG_SK_G16 n fi bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n @@ -180,6 +198,10 @@ if [ "$CONFIG_NET_POCKET" = "y" ]; then # bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n # bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n fi +bool 'Token Ring driver support' CONFIG_TR n +if [ "$CONFIG_TR" = "y" ]; then + bool 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y +fi fi fi @@ -208,7 +230,8 @@ bool 'Second extended fs support' CONFIG_EXT2_FS y bool 'xiafs filesystem support' CONFIG_XIA_FS n bool 'msdos fs support' CONFIG_MSDOS_FS y if [ "$CONFIG_MSDOS_FS" = "y" ]; then -bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n +#bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n +comment 'Umsdos is not supported in 1.3.0: wait for 1.3.1' fi bool '/proc filesystem support' CONFIG_PROC_FS y if [ "$CONFIG_INET" = "y" ]; then @@ -262,7 +285,7 @@ bool 'Sound card support' CONFIG_SOUND n comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n -bool 'Kernel profiling support' CONFIG_PROFILE n +bool 'Kernel profiling support' CONFIG_PROFILE y if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index a7c58b714528..8cc3d76faf75 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -41,7 +41,12 @@ * Curtis Varner, cvarner@cs.ucr.edu * * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter. - * Alpha version. Intel & UMC chipset support only. See pci.h for more. + * Alpha version. Intel & UMC chipset support only. + * + * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code + * moved to drivers/pci/pci.c. + * + * */ #include @@ -64,9 +69,6 @@ #define PCIBIOS_WRITE_CONFIG_WORD 0xb10c #define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d -#ifdef CONFIG_PCI -extern void add_pci_resource(unsigned char, unsigned char); -#endif /* BIOS32 signature: "_32_" */ #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) @@ -87,15 +89,6 @@ extern void add_pci_resource(unsigned char, unsigned char); * and the PCI BIOS specification. */ -#ifdef CONFIG_PCI -typedef struct pci_resource_t -{ - unsigned char bus; - unsigned char dev_fn; - struct pci_resource_t *next; -} pci_resource_t; -#endif - union bios32 { struct { unsigned long signature; /* _32_ */ @@ -111,7 +104,7 @@ union bios32 { /* * Physical address of the service directory. I don't know if we're * allowed to have more than one of these or not, so just in case - * we'll make bios32_init() take a memory start parameter and store + * we'll make pcibios_present() take a memory start parameter and store * the array there. */ @@ -126,21 +119,6 @@ static struct { * Returns the entry point for the given service, NULL on error */ -#define PCI_LIST_SIZE 32 - -static pci_resource_t pci_list = { 0, 0, NULL }; -static int pci_index = 0; -static pci_resource_t pci_table[PCI_LIST_SIZE]; - -static struct pci_class_type pci_class[PCI_CLASS_NUM] = PCI_CLASS_TYPE; -static struct pci_vendor_type pci_vendor[PCI_VENDOR_NUM] = PCI_VENDOR_TYPE; -static struct pci_device_type pci_device[PCI_DEVICE_NUM] = PCI_DEVICE_TYPE; - -#ifdef CONFIG_PCI_OPTIMIZE -static struct bridge_mapping_type bridge_mapping[5*BRIDGE_MAPPING_NUM] = BRIDGE_MAPPING_TYPE; -static struct optimisation_type optimisation[OPTIMISATION_NUM] = OPTIMISATION_TYPE; -#endif - static unsigned long bios32_service(unsigned long service) { unsigned char return_code; /* %al */ @@ -176,9 +154,8 @@ static struct { unsigned short segment; } pci_indirect = { 0, KERNEL_CS }; -void NCR53c810_test(void); -static unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +extern unsigned long check_pcibios(unsigned long memory_start, unsigned long memory_end) { unsigned long signature; unsigned char present_status; @@ -220,10 +197,6 @@ static unsigned long pcibios_init(unsigned long memory_start, unsigned long memo major_revision, minor_revision, pcibios_entry); } } - -#if 0 - NCR53c810_test(); -#endif return memory_start; } @@ -232,7 +205,7 @@ int pcibios_present(void) return pcibios_entry ? 1 : 0; } -int pcibios_find_class (unsigned long class_code, unsigned short index, +int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *device_fn) { unsigned long bx; @@ -315,7 +288,7 @@ int pcibios_read_config_word (unsigned char bus, } int pcibios_read_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned long *value) + unsigned char device_fn, unsigned char where, unsigned int *value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -372,7 +345,7 @@ int pcibios_write_config_word (unsigned char bus, } int pcibios_write_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned long value) + unsigned char device_fn, unsigned char where, unsigned int value) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; @@ -390,36 +363,6 @@ int pcibios_write_config_dword (unsigned char bus, return (int) (ret & 0xff00) >> 8; } -void NCR53c810_test(void) -{ - unsigned char bus, device_fn; - unsigned short index; - int ret; - unsigned char row, col; - unsigned long val; - - for (index = 0; index < 4; ++index) { - ret = pcibios_find_device ( - (unsigned short) PCI_VENDOR_ID_NCR, - (unsigned short) PCI_DEVICE_ID_NCR_53C810, - index, &bus, &device_fn); - if (ret) - break; - printk ("ncr53c810 : at PCI bus %d, device %d, function %d.", - bus, ((device_fn & 0xf8) >> 3), (device_fn & 7)); - for (row = 0; row < 0x3c; row += 0x10) { - printk ("\n reg 0x%02x ", row); - for (col = 0; col < 0x10; col += 4) { - if (!(ret = pcibios_read_config_dword (bus, device_fn, row+col, &val))) - printk ("0x%08lx ", val); - else - printk ("error 0x%02x ", ret); - } - } - printk ("\n"); - } -} - char *pcibios_strerror (int error) { static char buf[80]; @@ -447,292 +390,15 @@ char *pcibios_strerror (int error) } -/* Recognize multi-function device */ - -int multi_function(unsigned char bus,unsigned char dev_fn) -{ - unsigned char header; - pcibios_read_config_byte( - bus, dev_fn, (unsigned char) PCI_HEADER_TYPE, &header); - return (header&7==7); -} - -/* Returns Interrupt register */ - -int interrupt_decode(unsigned char bus,unsigned char dev_fn) -{ - unsigned char interrupt; - pcibios_read_config_byte( - bus, dev_fn, (unsigned char) PCI_INTERRUPT_LINE, &interrupt); - if (interrupt>16) return 0; - return interrupt; -} - -/* probe for being bist capable */ - -int bist_probe(unsigned char bus,unsigned char dev_fn) +unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) { - unsigned char bist; - pcibios_read_config_byte( - bus, dev_fn, (unsigned char) PCI_BIST, &bist); - return (bist & PCI_BIST_CAPABLE !=0); +return mem_start; } -/* Get the chip revision */ - -int revision_decode(unsigned char bus,unsigned char dev_fn) -{ - unsigned char revision; - pcibios_read_config_byte( - bus, dev_fn, (unsigned char) PCI_CLASS_REVISION, &revision); - return (int) revision; -} - - - -/* Gives the Class code using the 16 higher bits */ -/* of the PCI_CLASS_REVISION configuration register */ - -int class_decode(unsigned char bus,unsigned char dev_fn) -{ - int i; - unsigned long class; - pcibios_read_config_dword( - bus, dev_fn, (unsigned char) PCI_CLASS_REVISION, &class); - class=class >> 16; - for (i=0;i PCI_LIST_SIZE-1) - { - printk("PCI resource list full.\n"); - return; - } - - - new_pci = &pci_table[pci_index]; - pci_index++; - - /* - * Enter the new node into the list.... - * - */ - if(pci_list.next != NULL) - { - for(temp = pci_list.next; (temp->next); temp = temp->next) - /* nothing */; - - temp->next = new_pci; - } - else - pci_list.next = new_pci; - - /* - * Set the information for the node - */ - new_pci->next = NULL; - new_pci->bus = bus; - new_pci->dev_fn = dev_fn; - - return; -} - - -int get_pci_list(char* buf) -{ - int pr, length; - pci_resource_t* temp = pci_list.next; - - pr = sprintf(buf, "PCI devices found :\n"); - for (length = pr ; (temp) && (length<4000); temp = temp->next) - { - pr=vendor_decode(temp->bus,temp->dev_fn); - - length += sprintf(buf+length, "Bus %2d Device %3d Function %2d.\n", - (int)temp->bus, - (int)((temp->dev_fn & 0xf8) >> 3), - (int) (temp->dev_fn & 7)); - - length += sprintf(buf+length, " %s : %s %s (rev %d). ", - pci_class[class_decode(temp->bus, temp->dev_fn)].class_name, - pci_vendor[pr].vendor_name, - pci_device[device_decode(temp->bus, temp->dev_fn, pr)].device_name, - revision_decode(temp->bus, temp->dev_fn)); - - if (bist_probe(temp->bus, temp->dev_fn)) - length += sprintf(buf+length, "BIST capable. "); - - if ((pr = interrupt_decode(temp->bus, temp->dev_fn)) != 0) - length += sprintf(buf+length, "8259's interrupt %d.", pr); - - length += sprintf(buf+length, "\n"); - } - - if (temp) - length += sprintf(buf+length, "4K limit reached!\n"); - - return length; -} - - -#endif - -unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) +unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) { union bios32 *check; unsigned char sum; @@ -743,8 +409,6 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) * directory by scanning the permissible address range from * 0xe0000 through 0xfffff for a valid BIOS32 structure. * - * The PCI BIOS doesn't seem to work too well on many machines, - * so we disable this unless it's really needed (NCR SCSI driver) */ for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) { @@ -759,35 +423,31 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) if (sum != 0) continue; if (check->fields.revision != 0) { - printk("bios32_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n", + printk("pcibios_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n", check->fields.revision, check); continue; } - printk ("bios32_init : BIOS32 Service Directory structure at 0x%p\n", check); + printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check); if (!bios32_entry) { if (check->fields.entry >= 0x100000) { - printk("bios32_init: entry in high memory, unable to access\n"); + printk("pcibios_init: entry in high memory, unable to access\n"); } else { bios32_indirect.address = bios32_entry = check->fields.entry; - printk ("bios32_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); + printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); } } else { - printk ("bios32_init : multiple entries, mail drew@colorado.edu\n"); + printk ("pcibios_init : multiple entries, mail drew@colorado.edu\n"); /* * Jeremy Fitzhardinge reports at least one PCI BIOS * with two different service directories, and as both * worked for him, we'll just mention the fact, and * not actually disallow it.. */ -#if 0 - return memory_start; -#endif } } #ifdef CONFIG_PCI if (bios32_entry) { - memory_start = pcibios_init (memory_start, memory_end); - probe_pci(); + memory_start = check_pcibios (memory_start, memory_end); } #endif return memory_start; diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 60f769c220f3..1bdf062c8a0f 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -482,14 +482,14 @@ _sys_call_table: .long _sys_settimeofday .long _sys_getgroups /* 80 */ .long _sys_setgroups - .long _sys_select + .long _old_select .long _sys_symlink .long _sys_lstat .long _sys_readlink /* 85 */ .long _sys_uselib .long _sys_swapon .long _sys_reboot - .long _sys_readdir + .long _old_readdir .long _sys_mmap /* 90 */ .long _sys_munmap .long _sys_truncate @@ -541,4 +541,7 @@ _sys_call_table: .long _sys_setfsuid .long _sys_setfsgid .long _sys_llseek /* 140 */ + .long _sys_getdents + .long _sys_select + .long _sys_flock .space (NR_syscalls-140)*4 diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index c78beca1fbd3..a3e0df2132c0 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -9,7 +9,7 @@ */ .text -.globl _idt,_gdt, +.globl _idt,_gdt,_stext,__stext .globl _swapper_pg_dir,_pg0 .globl _empty_bad_page .globl _empty_bad_page_table @@ -30,6 +30,8 @@ * swapper_pg_dir is the main page directory, address 0x00001000 (or at * address 0x00101000 for a compressed boot). */ +_stext: +__stext: startup_32: cld movl $(KERNEL_DS),%eax diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 77254751b7ac..a5e8777bf34f 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -39,6 +39,22 @@ void enable_hlt(void) hlt_counter--; } +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = verify_area(VERIFY_WRITE,fildes,8); + if (error) + return error; + error = do_pipe(fd); + if (error) + return error; + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} + /* * The idle loop on a i386.. */ diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index ca3448f9254c..5cc4c5d7d5fb 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -132,3 +133,49 @@ void setup_arch(char **cmdline_p, request_region(0xf0,0x2,"npu"); request_region(0xf8,0x8,"npu"); } + +int get_cpuinfo(char * buffer) +{ + char *model[2][9]={{"DX","SX","DX/2","4","SX/2","6", + "DX/2-WB","DX/4"}, + {"Pentium 60/66","Pentium 90/100","3", + "4","5","6","7","8"}}; + char mask[2]; + mask[0] = x86_mask+'@'; + mask[1] = '\0'; + return sprintf(buffer,"cpu\t\t: %c86\n" + "model\t\t: %s\n" + "mask\t\t: %s\n" + "vid\t\t: %s\n" + "fdiv_bug\t: %s\n" + "math\t\t: %s\n" + "hlt\t\t: %s\n" + "wp\t\t: %s\n" + "Integrated NPU\t: %s\n" + "Enhanced VM86\t: %s\n" + "IO Breakpoints\t: %s\n" + "4MB Pages\t: %s\n" + "TS Counters\t: %s\n" + "Pentium MSR\t: %s\n" + "Mach. Ch. Exep.\t: %s\n" + "CMPXCHGB8B\t: %s\n" + "BogoMips\t: %lu.%02lu\n", + x86+'0', + x86_model ? model[x86-4][x86_model-1] : "Unknown", + x86_mask ? mask : "Unknown", + x86_vendor_id, + fdiv_bug ? "yes" : "no", + hard_math ? "yes" : "no", + hlt_works_ok ? "yes" : "no", + wp_works_ok ? "yes" : "no", + x86_capability & 1 ? "yes" : "no", + x86_capability & 2 ? "yes" : "no", + x86_capability & 4 ? "yes" : "no", + x86_capability & 8 ? "yes" : "no", + x86_capability & 16 ? "yes" : "no", + x86_capability & 32 ? "yes" : "no", + x86_capability & 128 ? "yes" : "no", + x86_capability & 256 ? "yes" : "no", + loops_per_sec/500000, (loops_per_sec/5000) % 100 + ); +} diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index c14279b81856..3db1a69850d4 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -200,7 +200,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) continue; case SIGQUIT: case SIGILL: case SIGTRAP: - case SIGIOT: case SIGFPE: case SIGSEGV: + case SIGABRT: case SIGFPE: case SIGSEGV: if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) signr |= 0x80; diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 9c6dd0c95183..296595644af3 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -62,18 +62,6 @@ pte_t __bad_page(void) return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)); } -unsigned long __zero_page(void) -{ - extern char empty_zero_page[PAGE_SIZE]; - - __asm__ __volatile__("cld ; rep ; stosl": - :"a" (0), - "D" ((long) empty_zero_page), - "c" (PAGE_SIZE/4) - :"di","cx"); - return (unsigned long) empty_zero_page; -} - void show_mem(void) { int i,free = 0,total = 0,reserved = 0; @@ -166,6 +154,9 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) end_mem &= PAGE_MASK; high_memory = end_mem; + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + /* mark usable pages in the mem_map[] */ start_low_mem = PAGE_ALIGN(start_low_mem); start_mem = PAGE_ALIGN(start_mem); diff --git a/drivers/Makefile b/drivers/Makefile index 18085092b9a5..f981b8fe072e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,6 +18,10 @@ SUBDIRS = block char net #streams +ifdef CONFIG_PCI +SUBDIRS := $(SUBDIRS) pci +endif + ifdef CONFIG_SCSI SUBDIRS := $(SUBDIRS) scsi endif diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c index 987fe429f6a6..1aef40dcf3d3 100644 --- a/drivers/block/ide-cd.c +++ b/drivers/block/ide-cd.c @@ -25,6 +25,21 @@ * help in figuring this out. Ditto for Acer and * Aztech drives, which seem to have the same problem. * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml + * 2.05 Jun 8, 1995 -- Don't attempt to retry after an illegal request + * or data protect error. + * Use HWIF and DEV_HWIF macros as in ide.c. + * Always try to do a request_sense after + * a failed command. + * Include an option to give textual descriptions + * of ATAPI errors. + * Fix a bug in handling the sector cache which + * showed up if the drive returned data in 512 byte + * blocks (like Pioneer drives). Thanks to + * Richard Hirst for diagnosing this. + * Properly supply the page number field in the + * MODE_SELECT command. + * PLAYAUDIO12 is broken on the Aztech; work around it. + * * * ATAPI cd-rom driver. To be used with ide.c. * @@ -33,6 +48,17 @@ * (../../COPYING). */ + +/* Turn this on to have the driver print out the meanings of the + ATAPI error codes. This will use up additional kernel-space + memory, though. */ + +#ifndef VERBOSE_IDE_CD_ERRORS +#define VERBOSE_IDE_CD_ERRORS 0 +#endif + +/***************************************************************************/ + #include #define SECTOR_SIZE 512 @@ -42,8 +68,8 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #if 1 /* "old" method */ -#define OUT_WORDS(b,n) outsw (IDE_PORT (HD_DATA, dev->hwif), (b), (n)) -#define IN_WORDS(b,n) insw (IDE_PORT (HD_DATA, dev->hwif), (b), (n)) +#define OUT_WORDS(b,n) outsw (IDE_PORT (HD_DATA, DEV_HWIF), (b), (n)) +#define IN_WORDS(b,n) insw (IDE_PORT (HD_DATA, DEV_HWIF), (b), (n)) #else /* "new" method -- should really fix each instance instead of this */ #define OUT_WORDS(b,n) output_ide_data(dev,b,(n)/2) #define IN_WORDS(b,n) input_ide_data(dev,b,(n)/2) @@ -51,6 +77,7 @@ /* special command codes for strategy routine. */ #define PACKET_COMMAND 4315 +#define REQUEST_SENSE_COMMAND 4316 #define WIN_PACKETCMD 0xa0 /* Send a packet command. */ @@ -64,6 +91,21 @@ #define MODE_SENSE_10 0x5a #define MODE_SELECT_10 0x55 + +/* ATAPI sense keys (mostly copied from scsi.h). */ + +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define ABORTED_COMMAND 0x0b +#define MISCOMPARE 0x0e + + struct packet_command { char *buffer; int buflen; @@ -100,8 +142,9 @@ struct ide_cd_flags { unsigned media_changed : 1; /* Driver has noticed a media change. */ unsigned toc_valid : 1; /* Saved TOC information is current. */ - unsigned no_lba_toc : 1; /* Drive cannot return TOC info in LBA format */ - unsigned reserved : 3; + unsigned no_lba_toc : 1; /* Drive cannot return TOC info in LBA format. */ + unsigned msf_as_bcd : 1; /* Drive uses BCD in PLAYAUDIO_MSF. */ + unsigned reserved : 2; }; #define CDROM_FLAGS(dev) ((struct ide_cd_flags *)&((dev)->bios_sect)) @@ -151,11 +194,163 @@ struct cdrom_info { unsigned long sector_buffered; unsigned long nsectors_buffered; char *sector_buffer; + + /* The result of the last successful request sense command + on this device. */ + struct atapi_request_sense sense_data; }; static struct cdrom_info cdrom_info[2][MAX_DRIVES]; +/* Statically allocate one request packet and one packet command struct + for each interface for retrieving sense data during error recovery. */ + +static struct request request_sense_request[2]; +static struct packet_command request_sense_pc[2]; + + + +/**************************************************************************** + * Descriptions of ATAPI error codes. + */ + +#define ARY_LEN(a) ((sizeof(a) / sizeof(a[0]))) + +#if VERBOSE_IDE_CD_ERRORS + +/* From Table 124 of the ATAPI 1.2 spec. */ + +char *sense_key_texts[16] = { + "No sense data", + "Recovered error", + "Not ready", + "Medium error", + "Hardware error", + "Illegal request", + "Unit attention", + "Data protect", + "(reserved)", + "(reserved)", + "(reserved)", + "Aborted command", + "(reserved)", + "(reserved)", + "Miscompare", + "(reserved)", +}; + + +/* From Table 125 of the ATAPI 1.2 spec. */ + +struct { + short asc_ascq; + char *text; +} sense_data_texts[] = { + { 0x0000, "No additional sense information" }, + { 0x0011, "Audio play operation in progress" }, + { 0x0012, "Audio play operation paused" }, + { 0x0013, "Audio play operation successfully completed" }, + { 0x0014, "Audio play operation stopped due to error" }, + { 0x0015, "No current audio status to return" }, + + { 0x0200, "No seek complete" }, + + { 0x0400, "Logical unit not ready - cause not reportable" }, + { 0x0401, "Logical unit not ready - in progress (sic) of becoming ready" }, + { 0x0402, "Logical unit not ready - initializing command required" }, + { 0x0403, "Logical unit not ready - manual intervention required" }, + + { 0x0600, "No reference position found" }, + + { 0x0900, "Track following error" }, + { 0x0901, "Tracking servo failure" }, + { 0x0902, "Focus servo failure" }, + { 0x0903, "Spindle servo failure" }, + + { 0x1100, "Unrecovered read error" }, + { 0x1106, "CIRC unrecovered error" }, + + { 0x1500, "Random positioning error" }, + { 0x1501, "Mechanical positioning error" }, + { 0x1502, "Positioning error detected by read of medium" }, + + { 0x1700, "Recovered data with no error correction applied" }, + { 0x1701, "Recovered data with retries" }, + { 0x1702, "Recovered data with positive head offset" }, + { 0x1703, "Recovered data with negative head offset" }, + { 0x1704, "Recovered data with retries and/or CIRC applied" }, + { 0x1705, "Recovered data using previous sector ID" }, + + { 0x1800, "Recovered data with error correction applied" }, + { 0x1801, "Recovered data with error correction and retries applied" }, + { 0x1802, "Recovered data - the data was auto-reallocated" }, + { 0x1803, "Recovered data with CIRC" }, + { 0x1804, "Recovered data with L-EC" }, + { 0x1805, "Recovered data - recommend reassignment" }, + { 0x1806, "Recovered data - recommend rewrite" }, + + { 0x1a00, "Parameter list length error" }, + + { 0x2000, "Invalid command operation code" }, + + { 0x2100, "Logical block address out of range" }, + + { 0x2400, "Invalid field in command packet" }, + + { 0x2600, "Invalid field in parameter list" }, + { 0x2601, "Parameter not supported" }, + { 0x2602, "Parameter value invalid" }, + { 0x2603, "Threshold parameters not supported" }, + + { 0x2800, "Not ready to ready transition, medium may have changed" }, + + { 0x2900, "Power on, reset or bus device reset occurred" }, + + { 0x2a00, "Parameters changed" }, + { 0x2a01, "Mode parameters changed" }, + + { 0x3000, "Incompatible medium installed" }, + { 0x3001, "Cannot read medium - unknown format" }, + { 0x3002, "Cannot read medium - incompatible format" }, + + { 0x3700, "Rounded parameter" }, + + { 0x3900, "Saving parameters not supported" }, + + { 0x3a00, "Medium not present" }, + + { 0x3f00, "ATAPI CD-ROM drive operating conditions have changed" }, + { 0x3f01, "Microcode has been changed" }, + { 0x3f02, "Changed operating definition" }, + { 0x3f03, "Inquiry data has changed" }, + + { 0x4000, "Diagnostic failure on component (ASCQ)" }, + + { 0x4400, "Internal ATAPI CD-ROM drive failure" }, + + { 0x4e00, "Overlapped commands attempted" }, + + { 0x5300, "Media load or eject failed" }, + { 0x5302, "Medium removal prevented" }, + + { 0x5700, "Unable to recover table of contents" }, + + { 0x5a00, "Operator request or state change input (unspecified)" }, + { 0x5a01, "Operator medium removal request" }, + + { 0x5b00, "Threshold condition met" }, + + { 0x5c00, "Status change" }, + + { 0x6300, "End of user area encountered on this track" }, + + { 0x6400, "Illegal mode for this track" }, + + { 0xbf00, "Loss of streaming" }, +}; +#endif + /**************************************************************************** @@ -163,9 +358,169 @@ static struct cdrom_info cdrom_info[2][MAX_DRIVES]; */ +static +void cdrom_analyze_sense_data (ide_dev_t *dev, + struct atapi_request_sense *reqbuf, + struct packet_command *failed_command) +{ + /* Don't print not ready or unit attention errors for READ_SUBCHANNEL. + Workman (and probably other programs) uses this command to poll + the drive, and we don't want to fill the syslog with useless errors. */ + if (failed_command && + failed_command->c[0] == SCMD_READ_SUBCHANNEL && + (reqbuf->sense_key == 2 || reqbuf->sense_key == 6)) + return; + +#if VERBOSE_IDE_CD_ERRORS + { + int i; + char *s; + char buf[80]; + + printk ("ATAPI device %s:\n", dev->name); + + printk (" Error code: %x\n", reqbuf->error_code); + + if (reqbuf->sense_key >= 0 && + reqbuf->sense_key < ARY_LEN (sense_key_texts)) + s = sense_key_texts[reqbuf->sense_key]; + else + s = "(bad sense key)"; + + printk (" Sense key: %x - %s\n", reqbuf->sense_key, s); + + if (reqbuf->asc == 0x40) { + sprintf (buf, "Diagnostic failure on component %x", reqbuf->ascq); + s = buf; + } + + else { + int lo, hi; + int key = (reqbuf->asc << 8); + if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) + key |= reqbuf->ascq; + + lo = 0; + hi = ARY_LEN (sense_data_texts); + s = NULL; + + while (hi > lo) { + int mid = (lo + hi) / 2; + if (sense_data_texts[mid].asc_ascq == key) { + s = sense_data_texts[mid].text; + break; + } + else if (sense_data_texts[mid].asc_ascq > key) + hi = mid; + else + lo = mid+1; + } + } + + if (s == NULL) { + if (reqbuf->asc > 0x80) + s = "(vendor-specific error)"; + else + s = "(reserved error code)"; + } + + printk (" Additional sense data: %x, %x - %s\n", + reqbuf->asc, reqbuf->ascq, s); + + if (failed_command != NULL) { + printk (" Failed packet command: "); + for (i=0; ic); i++) + printk ("%02x ", failed_command->c[i]); + printk ("\n"); + } + } + +#else + printk ("%s: code: %x key: %x asc: %x ascq: %x\n", + dev->name, + reqbuf->error_code, reqbuf->sense_key, reqbuf->asc, reqbuf->ascq); +#endif +} + + +/* Fix up a possibly partially-processed request so that we can + start it over entirely, or even put it back on the request queue. */ +static void restore_request (struct request *rq) +{ + if (rq->buffer != rq->bh->b_data) + { + int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; + rq->buffer = rq->bh->b_data; + rq->nr_sectors += n; + rq->sector -= n; + } + rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS; +} + + +static void cdrom_queue_request_sense (ide_dev_t *dev) +{ + struct request *rq; + struct packet_command *pc; + struct atapi_request_sense *reqbuf; + unsigned long flags; + + int major = ide_major[DEV_HWIF]; + + save_flags (flags); + cli (); /* safety */ + + rq = ide_cur_rq[DEV_HWIF]; + + /* If we're processing a request, put it back on the request queue. */ + if (rq != NULL) + { + restore_request (rq); + rq->next = blk_dev[major].current_request; + blk_dev[major].current_request = rq; + ide_cur_rq[DEV_HWIF] = NULL; + } + + restore_flags (flags); + + /* Make up a new request to retrieve sense information. */ + reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data; + + pc = &request_sense_pc[DEV_HWIF]; + memset (pc, 0, sizeof (*pc)); + + pc->c[0] = REQUEST_SENSE; + pc->c[4] = sizeof (*reqbuf); + pc->buffer = (char *)reqbuf; + pc->buflen = sizeof (*reqbuf); + + rq = &request_sense_request[DEV_HWIF]; + rq->dev = MKDEV (major, (dev->select.b.drive) << PARTN_BITS); + rq->cmd = REQUEST_SENSE_COMMAND; + rq->errors = 0; + rq->sector = 0; + rq->nr_sectors = 0; + rq->current_nr_sectors = 0; + rq->buffer = (char *)pc; + rq->sem = NULL; + rq->bh = NULL; + rq->bhtail = NULL; + rq->next = NULL; + + save_flags (flags); + cli (); /* safety */ + + /* Stick it onto the front of the queue. */ + rq->next = blk_dev[major].current_request; + blk_dev[major].current_request = rq; + + restore_flags (flags); +} + + static void cdrom_end_request (int uptodate, ide_dev_t *dev) { - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; /* The code in blk.h can screw us up on error recovery if the block size is larger than 1k. Fix that up here. */ @@ -176,7 +531,14 @@ static void cdrom_end_request (int uptodate, ide_dev_t *dev) rq->sector += adj; } - end_request (uptodate, dev->hwif); + if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) + { + struct atapi_request_sense *reqbuf; + reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data; + cdrom_analyze_sense_data (dev, reqbuf, NULL); + } + + end_request (uptodate, DEV_HWIF); } @@ -186,7 +548,7 @@ static void cdrom_saw_media_change (ide_dev_t *dev) { CDROM_FLAGS (dev)->media_changed = 1; CDROM_FLAGS (dev)->toc_valid = 0; - cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0; + cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0; } @@ -194,83 +556,116 @@ static void cdrom_saw_media_change (ide_dev_t *dev) Returns 1 if the request was ended. */ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret) { - struct request *rq = ide_cur_rq[dev->hwif]; - int stat, err; + struct request *rq = ide_cur_rq[DEV_HWIF]; + int stat, err, sense_key, cmd; /* Check for errors. */ - stat = GET_STAT (dev->hwif); + stat = GET_STAT (DEV_HWIF); *stat_ret = stat; if (OK_STAT (stat, good_stat, BAD_R_STAT)) return 0; /* Got an error. */ - err = IN_BYTE (HD_ERROR, dev->hwif); + err = IN_BYTE (HD_ERROR, DEV_HWIF); + sense_key = err >> 4; - /* Check for tray open */ - if ((err & 0xf0) == 0x20) + if (rq == NULL) + printk ("%s : missing request in cdrom_decode_status\n", dev->name); + else { - struct packet_command *pc; - cdrom_saw_media_change (dev); + cmd = rq->cmd; - /* Fail the request if this is a read command. */ - if (rq->cmd == READ) - { - printk ("%s : tray open\n", dev->name); - cdrom_end_request (0, dev); - } + /* Check for tray open */ + if (sense_key == NOT_READY) + { + struct packet_command *pc; + cdrom_saw_media_change (dev); + + /* Fail the request if this is a read command. */ + if (cmd == READ) + { + printk ("%s : tray open\n", dev->name); + cdrom_end_request (0, dev); + } + + else + { + /* Otherwise, it's some other packet command. + Print an error message to the syslog. + Exception: don't print anything if this is a read subchannel + command. This is because workman constantly polls the drive + with this command, and we don't want to uselessly fill up + the syslog. */ + pc = (struct packet_command *)rq->buffer; + if (pc->c[0] != SCMD_READ_SUBCHANNEL) + printk ("%s : tray open\n", dev->name); + + /* Set the error flag and complete the request. */ + pc->stat = 1; + cdrom_end_request (1, dev); + } + } - else - { - /* Otherwise, it's some other packet command. - Print an error message to the syslog. - Exception: don't print anything if this is a read subchannel - command. This is because workman constantly polls the drive - with this command, and we don't want to uselessly fill up - the syslog. */ - pc = (struct packet_command *)rq->buffer; - if (pc->c[0] != SCMD_READ_SUBCHANNEL) - printk ("%s : tray open\n", dev->name); - - /* Set the error flag and complete the request. */ - pc->stat = 1; - cdrom_end_request (1, dev); - } - } + /* Check for media change. */ + else if (sense_key == UNIT_ATTENTION) + { + cdrom_saw_media_change (dev); + printk ("%s: media changed\n", dev->name); + + /* Return failure for a packet command, so that + cdrom_queue_packet_command can do a request sense before + the command gets retried. */ + + if (cmd == PACKET_COMMAND) + { + struct packet_command *pc = (struct packet_command *)rq->buffer; + pc->stat = 1; + cdrom_end_request (1, dev); + } + + /* Otherwise, it's a block read. Arrange to retry it. + But be sure to give up if we've retried too many times. */ + else if ((++rq->errors > ERROR_MAX)) + { + cdrom_end_request (0, dev); + } + } - /* Check for media change. */ - else if ((err & 0xf0) == 0x60) - { - cdrom_saw_media_change (dev); - printk ("%s: media changed\n", dev->name); + /* Don't attempt to retry if this was a packet command. */ + else if (cmd == PACKET_COMMAND) + { + struct packet_command *pc = (struct packet_command *)rq->buffer; + dump_status (DEV_HWIF, "packet command error", stat); + pc->stat = 1; /* signal error */ + cdrom_end_request (1, dev); + } - /* We're going to retry this command. - But be sure to give up if we've retried too many times. */ - if ((++rq->errors > ERROR_MAX)) - { - cdrom_end_request (0, dev); - } - } + /* No point in retrying after an illegal request or data protect error.*/ + else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT) + { + dump_status (DEV_HWIF, "command error", stat); + cdrom_end_request (0, dev); + } - /* Don't attempt to retry if this was a packet command. */ - else if (rq->cmd == PACKET_COMMAND) - { - struct packet_command *pc = (struct packet_command *)rq->buffer; - dump_status (dev->hwif, "packet command error", stat); - pc->stat = 1; /* signal error */ - cdrom_end_request (1, dev); - } + /* If there were other errors, go to the default handler. */ + else if ((err & ~ABRT_ERR) != 0) + { + ide_error (dev, "cdrom_decode_status", stat); + } - /* If there were other errors, go to the default handler. */ - else if ((err & ~ABRT_ERR) != 0) - { - ide_error (dev, "cdrom_decode_status", stat); - } + /* Else, abort if we've racked up too many retries. */ + else if ((++rq->errors > ERROR_MAX)) + { + cdrom_end_request (0, dev); + } - /* Else, abort if we've racked up too many retries. */ - else if ((++rq->errors > ERROR_MAX)) - { - cdrom_end_request (0, dev); + /* If we got a CHECK_STATUS condition, and this was a READ request, + queue a request sense command to try to find out more about + what went wrong (and clear a unit attention)? For packet commands, + this is done separately in cdrom_queue_packet_command. */ + if ((stat & ERR_STAT) != 0 && cmd == READ) + cdrom_queue_request_sense (dev); } /* Retry, or handle the next request. */ @@ -320,7 +715,7 @@ static int cdrom_transfer_packet_command (ide_dev_t *dev, else { /* Otherwise, we must wait for DRQ to get set. */ - if (wait_stat (dev, DRQ_STAT, BAD_STAT, WAIT_READY)) return 1; + if (wait_stat (dev, DRQ_STAT, BUSY_STAT, WAIT_READY)) return 1; } /* Send the command to the device. */ @@ -337,16 +732,20 @@ static int cdrom_transfer_packet_command (ide_dev_t *dev, /* * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector - * buffer. SECTOR is the number of the first sector to be buffered. + * buffer. Once the first sector is added, any subsequent sectors are + * assumed to be continuous (until the buffer is cleared). For the first + * sector added, SECTOR is its sector number. (SECTOR is then ignored until + * the buffer is cleared.) */ static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector, int sectors_to_transfer) { - struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive]; + struct cdrom_info *info = &cdrom_info[DEV_HWIF][dev->select.b.drive]; /* Number of sectors to read into the buffer. */ int sectors_to_buffer = MIN (sectors_to_transfer, - (SECTOR_BUFFER_SIZE >> SECTOR_BITS)); + (SECTOR_BUFFER_SIZE >> SECTOR_BITS) - + info->nsectors_buffered); char *dest; @@ -362,17 +761,18 @@ static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector, sectors_to_buffer = 0; } - /* Remember the sector number and the number of sectors we're storing. */ - info->sector_buffered = sector; - info->nsectors_buffered = sectors_to_buffer; + /* If this is the first sector in the buffer, remember its number. */ + if (info->nsectors_buffered == 0) + info->sector_buffered = sector; /* Read the data into the buffer. */ - dest = info->sector_buffer; + dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE; while (sectors_to_buffer > 0) { IN_WORDS (dest, SECTOR_SIZE / 2); --sectors_to_buffer; --sectors_to_transfer; + ++info->nsectors_buffered; dest += SECTOR_SIZE; } @@ -380,7 +780,7 @@ static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector, while (sectors_to_transfer > 0) { char dum[SECTOR_SIZE]; - IN_WORDS (dest, sizeof (dum) / 2); + IN_WORDS (dum, sizeof (dum) / 2); --sectors_to_transfer; } } @@ -435,14 +835,14 @@ static void cdrom_read_intr (ide_dev_t *dev) int stat; int ireason, len, sectors_to_transfer, nskip; - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; /* Check for errors. */ if (cdrom_decode_status (dev, 0, &stat)) return; /* Read the interrupt reason and the transfer length. */ - ireason = IN_BYTE (HD_NSECTOR, dev->hwif); - len = IN_BYTE (HD_LCYL, dev->hwif) + 256 * IN_BYTE (HD_HCYL, dev->hwif); + ireason = IN_BYTE (HD_NSECTOR, DEV_HWIF); + len = IN_BYTE (HD_LCYL, DEV_HWIF) + 256 * IN_BYTE (HD_HCYL, DEV_HWIF); /* If DRQ is clear, the command has completed. */ if ((stat & DRQ_STAT) == 0) @@ -537,7 +937,7 @@ static void cdrom_read_intr (ide_dev_t *dev) /* Done moving data! Wait for another interrupt. */ - ide_handler[dev->hwif] = cdrom_read_intr; + ide_handler[DEV_HWIF] = cdrom_read_intr; } @@ -547,8 +947,8 @@ static void cdrom_read_intr (ide_dev_t *dev) */ static int cdrom_read_from_buffer (ide_dev_t *dev) { - struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive]; - struct request *rq = ide_cur_rq[dev->hwif]; + struct cdrom_info *info = &cdrom_info[DEV_HWIF][dev->select.b.drive]; + struct request *rq = ide_cur_rq[DEV_HWIF]; /* Can't do anything if there's no buffer. */ if (info->sector_buffer == NULL) return 0; @@ -610,7 +1010,7 @@ static int cdrom_read_from_buffer (ide_dev_t *dev) static int cdrom_start_read_continuation (ide_dev_t *dev) { struct packet_command pc; - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; int nsect, sector, nframes, frame, nskip; @@ -675,7 +1075,7 @@ static int cdrom_start_read_continuation (ide_dev_t *dev) return 1; /* Set up our interrupt handler and return. */ - ide_handler[dev->hwif] = cdrom_read_intr; + ide_handler[DEV_HWIF] = cdrom_read_intr; return 0; } @@ -689,31 +1089,24 @@ static int cdrom_start_read_continuation (ide_dev_t *dev) */ static int cdrom_start_read (ide_dev_t *dev, unsigned int block) { - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; /* We may be retrying this request after an error. Fix up any weirdness which might be present in the request packet. */ - if (rq->buffer != rq->bh->b_data) - { - int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE; - rq->buffer = rq->bh->b_data; - rq->nr_sectors += n; - rq->current_nr_sectors += n; - rq->sector -= n; - } - - if (rq->current_nr_sectors > (rq->bh->b_size >> SECTOR_BITS)) - rq->current_nr_sectors = rq->bh->b_size; + restore_request (rq); /* Satisfy whatever we can of this request from our cached sector. */ if (cdrom_read_from_buffer (dev)) return 1; + /* Clear the local sector buffer. */ + cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0; + if (cdrom_start_packet_command (dev, 32768)) return 1; if (CDROM_FLAGS (dev)->drq_interrupt) - ide_handler[dev->hwif] = (void (*)(ide_dev_t *))cdrom_start_read_continuation; + ide_handler[DEV_HWIF] = (void (*)(ide_dev_t *))cdrom_start_read_continuation; else { if (cdrom_start_read_continuation (dev)) @@ -730,23 +1123,38 @@ static int cdrom_start_read (ide_dev_t *dev, unsigned int block) * Execute all other packet commands. */ +/* Forward declaration */ +static int +cdrom_request_sense (ide_dev_t *dev, struct atapi_request_sense *reqbuf); + + +/* Interrupt routine for packet command completion. */ static void cdrom_pc_intr (ide_dev_t *dev) { int ireason, len, stat, thislen; - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; struct packet_command *pc = (struct packet_command *)rq->buffer; /* Check for errors. */ if (cdrom_decode_status (dev, 0, &stat)) return; /* Read the interrupt reason and the transfer length. */ - ireason = IN_BYTE (HD_NSECTOR, dev->hwif); - len = IN_BYTE (HD_LCYL, dev->hwif) + 256 * IN_BYTE (HD_HCYL, dev->hwif); + ireason = IN_BYTE (HD_NSECTOR, DEV_HWIF); + len = IN_BYTE (HD_LCYL, DEV_HWIF) + 256 * IN_BYTE (HD_HCYL, DEV_HWIF); /* If DRQ is clear, the command has completed. Complain if we still have data left to transfer. */ if ((stat & DRQ_STAT) == 0) { + /* Some of the trailing request sense fields are optional, and + some drives don't send them. Sigh. */ + if (pc->c[0] == REQUEST_SENSE && pc->buflen > 0 && pc->buflen <= 5) { + while (pc->buflen > 0) { + *pc->buffer++ = 0; + --pc->buflen; + } + } + if (pc->buflen == 0) cdrom_end_request (1, dev); else @@ -831,20 +1239,20 @@ static void cdrom_pc_intr (ide_dev_t *dev) } /* Now we wait for another interrupt. */ - ide_handler[dev->hwif] = cdrom_pc_intr; + ide_handler[DEV_HWIF] = cdrom_pc_intr; } static int cdrom_do_pc_continuation (ide_dev_t *dev) { - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; struct packet_command *pc = (struct packet_command *)rq->buffer; if (cdrom_transfer_packet_command (dev, pc->c, sizeof (pc->c))) return 1; /* Set up our interrupt handler and return. */ - ide_handler[dev->hwif] = cdrom_pc_intr; + ide_handler[DEV_HWIF] = cdrom_pc_intr; return 0; } @@ -853,7 +1261,7 @@ static int cdrom_do_pc_continuation (ide_dev_t *dev) static int cdrom_do_packet_command (ide_dev_t *dev) { int len; - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; struct packet_command *pc = (struct packet_command *)rq->buffer; len = pc->buflen; @@ -865,7 +1273,7 @@ static int cdrom_do_packet_command (ide_dev_t *dev) return 1; if (CDROM_FLAGS (dev)->drq_interrupt) - ide_handler[dev->hwif] = (void (*)(ide_dev_t *))cdrom_do_pc_continuation; + ide_handler[DEV_HWIF] = (void (*)(ide_dev_t *))cdrom_do_pc_continuation; else { if (cdrom_do_pc_continuation (dev)) @@ -879,11 +1287,13 @@ static int cdrom_do_packet_command (ide_dev_t *dev) static int cdrom_queue_packet_command (ide_dev_t *dev, struct packet_command *pc) { + int retries = 3; unsigned long flags; struct request req, **p, **pfirst; struct semaphore sem = MUTEX_LOCKED; - int major = ide_major[dev->hwif]; + int major = ide_major[DEV_HWIF]; + retry: req.dev = MKDEV (major, (dev->select.b.drive) << PARTN_BITS); req.cmd = PACKET_COMMAND; req.errors = 0; @@ -914,7 +1324,32 @@ int cdrom_queue_packet_command (ide_dev_t *dev, struct packet_command *pc) down (&sem); if (pc->stat != 0) - return -EIO; + { + /* The request failed. Try to do a request sense to get more information + about the error; store the result in the cdrom_info struct + for this drive. Check to be sure that it wasn't a request sense + request that failed, though, to prevent infinite loops. */ + + struct atapi_request_sense *reqbuf = + &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data; + + if (pc->c[0] == REQUEST_SENSE || cdrom_request_sense (dev, reqbuf)) + { + memset (reqbuf, 0, sizeof (*reqbuf)); + reqbuf->asc = 0xff; + } + cdrom_analyze_sense_data (dev, reqbuf, pc); + + /* If the error was a unit attention (usually means media was changed), + retry the command. */ + if (reqbuf->sense_key == UNIT_ATTENTION && retries > 0) + { + --retries; + goto retry; + } + + return -EIO; + } else return 0; } @@ -927,9 +1362,9 @@ int cdrom_queue_packet_command (ide_dev_t *dev, struct packet_command *pc) static int do_rw_cdrom (ide_dev_t *dev, unsigned long block) { - struct request *rq = ide_cur_rq[dev->hwif]; + struct request *rq = ide_cur_rq[DEV_HWIF]; - if (rq -> cmd == PACKET_COMMAND) + if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) return cdrom_do_packet_command (dev); if (rq -> cmd != READ) @@ -1109,14 +1544,14 @@ cdrom_read_toc (ide_dev_t *dev) { int msf_flag; int stat, ntracks, i; - struct atapi_toc *toc = cdrom_info[dev->hwif][dev->select.b.drive].toc; + struct atapi_toc *toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc; if (toc == NULL) { /* Try to allocate space. */ toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc), GFP_KERNEL); - cdrom_info[dev->hwif][dev->select.b.drive].toc = toc; + cdrom_info[DEV_HWIF][dev->select.b.drive].toc = toc; } if (toc == NULL) @@ -1208,7 +1643,7 @@ cdrom_mode_sense (ide_dev_t *dev, int pageno, int modeflag, static int -cdrom_mode_select (ide_dev_t *dev, char *buf, int buflen) +cdrom_mode_select (ide_dev_t *dev, int pageno, char *buf, int buflen) { struct packet_command pc; @@ -1218,6 +1653,7 @@ cdrom_mode_select (ide_dev_t *dev, char *buf, int buflen) pc.buflen = - buflen; pc.c[0] = MODE_SELECT_10; pc.c[1] = 0x10; + pc.c[2] = pageno; pc.c[7] = (buflen >> 8); pc.c[8] = (buflen & 0xff); return cdrom_queue_packet_command (dev, &pc); @@ -1252,12 +1688,15 @@ cdrom_play_lba_range_msf (ide_dev_t *dev, int lba_start, int lba_end) lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); - pc.c[3] = bin2bcd (pc.c[3]); - pc.c[4] = bin2bcd (pc.c[4]); - pc.c[5] = bin2bcd (pc.c[5]); - pc.c[6] = bin2bcd (pc.c[6]); - pc.c[7] = bin2bcd (pc.c[7]); - pc.c[8] = bin2bcd (pc.c[8]); + if (CDROM_FLAGS (dev)->msf_as_bcd) + { + pc.c[3] = bin2bcd (pc.c[3]); + pc.c[4] = bin2bcd (pc.c[4]); + pc.c[5] = bin2bcd (pc.c[5]); + pc.c[6] = bin2bcd (pc.c[6]); + pc.c[7] = bin2bcd (pc.c[7]); + pc.c[8] = bin2bcd (pc.c[8]); + } return cdrom_queue_packet_command (dev, &pc); } @@ -1283,23 +1722,22 @@ cdrom_play_lba_range (ide_dev_t *dev, int lba_start, int lba_end) return cdrom_play_lba_range_msf (dev, lba_start, lba_end); else { - int stat, stat2; - struct atapi_request_sense reqbuf; + int stat; + struct atapi_request_sense *reqbuf; stat = cdrom_play_lba_range_play12 (dev, lba_start, lba_end); if (stat == 0) return 0; /* It failed. Try to find out why. */ - stat2 = cdrom_request_sense (dev, &reqbuf); - if (stat2) return stat; - - if (reqbuf.sense_key == 0x05 && reqbuf.asc == 0x20) + reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data; + if (reqbuf->sense_key == 0x05 && reqbuf->asc == 0x20) { /* The drive didn't recognize the command. Retry with the MSF variant. */ printk ("%s: Drive does not support PLAYAUDIO12; " "trying PLAYAUDIO_MSF\n", dev->name); CDROM_FLAGS (dev)->no_playaudio12 = 1; + CDROM_FLAGS (dev)->msf_as_bcd = 1; return cdrom_play_lba_range_msf (dev, lba_start, lba_end); } @@ -1320,7 +1758,7 @@ int cdrom_get_toc_entry (ide_dev_t *dev, int track, stat = cdrom_read_toc (dev); if (stat) return stat; - toc = cdrom_info[dev->hwif][dev->select.b.drive].toc; + toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc; /* Check validity of requested track number. */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; @@ -1416,7 +1854,7 @@ static int ide_cdrom_ioctl (ide_dev_t *dev, struct inode *inode, stat = cdrom_read_toc (dev); if (stat) return stat; - toc = cdrom_info[dev->hwif][dev->select.b.drive].toc; + toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc; tochdr.cdth_trk0 = toc->hdr.first_track; tochdr.cdth_trk1 = toc->hdr.last_track; @@ -1530,7 +1968,7 @@ static int ide_cdrom_ioctl (ide_dev_t *dev, struct inode *inode, buffer[21] = volctrl.channel2 & mask[21]; buffer[23] = volctrl.channel3 & mask[23]; - return cdrom_mode_select (dev, buffer, sizeof (buffer)); + return cdrom_mode_select (dev, 0x0e, buffer, sizeof (buffer)); } #ifdef TEST @@ -1633,9 +2071,9 @@ cdrom_release (struct inode *inode, struct file *file, ide_dev_t *dev) static void cdrom_setup (ide_dev_t *dev) { /* Just guess at capacity for now. */ - ide_capacity[dev->hwif][dev->select.b.drive] = 0x1fffff; + ide_capacity[DEV_HWIF][dev->select.b.drive] = 0x1fffff; - ide_blksizes[dev->hwif][dev->select.b.drive << PARTN_BITS] = CD_FRAMESIZE; + ide_blksizes[DEV_HWIF][dev->select.b.drive << PARTN_BITS] = CD_FRAMESIZE; dev->special.all = 0; @@ -1644,6 +2082,7 @@ static void cdrom_setup (ide_dev_t *dev) CDROM_FLAGS (dev)->no_playaudio12 = 0; CDROM_FLAGS (dev)->no_lba_toc = 0; + CDROM_FLAGS (dev)->msf_as_bcd = 0; CDROM_FLAGS (dev)->drq_interrupt = ((dev->id->config & 0x0060) == 0x20); /* Accommodate some broken drives... */ @@ -1655,12 +2094,17 @@ static void cdrom_setup (ide_dev_t *dev) CDROM_FLAGS (dev)->no_lba_toc = 1; else if (strcmp (dev->id->model, "CDA26803I SE") == 0) /* Aztech */ - CDROM_FLAGS (dev)->no_lba_toc = 1; + { + CDROM_FLAGS (dev)->no_lba_toc = 1; + + /* This drive _also_ does not implement PLAYAUDIO12 correctly. */ + CDROM_FLAGS (dev)->no_playaudio12 = 1; + } - cdrom_info[dev->hwif][dev->select.b.drive].toc = NULL; - cdrom_info[dev->hwif][dev->select.b.drive].sector_buffer = NULL; - cdrom_info[dev->hwif][dev->select.b.drive].sector_buffered = 0; - cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0; + cdrom_info[DEV_HWIF][dev->select.b.drive].toc = NULL; + cdrom_info[DEV_HWIF][dev->select.b.drive].sector_buffer = NULL; + cdrom_info[DEV_HWIF][dev->select.b.drive].sector_buffered = 0; + cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0; } @@ -1671,11 +2115,12 @@ static void cdrom_setup (ide_dev_t *dev) /* * TODO: - * Retrieve and interpret extended ATAPI error codes. * Read actual disk capacity. * Multisession support. * Direct reading of audio data. * Eject-on-dismount. * Lock door while there's a mounted volume. + * Establish interfaces for an IDE port driver, and break out the cdrom + * code into a loadable module. */ diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 6728be0546db..53c1f97a0db1 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -406,14 +406,15 @@ static void make_request(int major,int rw, struct buffer_head * bh) add_request(major+blk_dev,req); } -void ll_rw_page(int rw, int dev, int page, char * buffer) +void ll_rw_page(int rw, int dev, unsigned long page, char * buffer) { struct request * req; unsigned int major = MAJOR(dev); + unsigned long sector = page * (PAGE_SIZE / 512); struct semaphore sem = MUTEX_LOCKED; if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) { - printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8); + printk("Trying to read nonexistent block-device %04x (%ld)\n",dev,sector); return; } if (rw!=READ && rw!=WRITE) @@ -426,9 +427,9 @@ void ll_rw_page(int rw, int dev, int page, char * buffer) /* fill up the request-info, and add it to the queue */ req->cmd = rw; req->errors = 0; - req->sector = page<<3; - req->nr_sectors = 8; - req->current_nr_sectors = 8; + req->sector = sector; + req->nr_sectors = PAGE_SIZE / 512; + req->current_nr_sectors = PAGE_SIZE / 512; req->buffer = buffer; req->sem = &sem; req->bh = NULL; diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 45fd9de6d1d8..4e05a907ec76 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -74,6 +74,12 @@ ifdef M OBJS := $(OBJS) mouse.o SRCS := $(SRCS) mouse.c endif + +ifdef CONFIG_SCC +OBJS := $(OBJS) scc.o +SRCS := $(SRCS) scc.c +endif + all: char.a diff --git a/drivers/char/README.scc b/drivers/char/README.scc new file mode 100644 index 000000000000..c48c33c2365d --- /dev/null +++ b/drivers/char/README.scc @@ -0,0 +1,933 @@ +This is a subset of the documentation. To use this driver you MUST have the +full package from: + +Internet: +========= + +ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-1.8.dl1bke.tar.gz + +and various mirrors (i.e. nic.switch.ch) + +AX.25 BBS +========= + +UNIX @ DB0ACH.#NRW.DEU.EU, subject: Z8530D18.Pxx/Pyy + +(AX.25 call: DB0ACH-8) + +and various BBS that received the file through AUTO7P or 7PSERV +with the filename Z8530D18.TGZ + + +--------------------------------------------------------------------------- + +!! Version 1.8 +!! +!! Deutscher Text siehe scc_ger.doc +!! +!! perhaps somebody could correct the English documentation (grammar, +!! spelling)? +!! +!! BTW: REAL programmers don't document... +!! + + + SCC.C - Linux driver for Z8530 based HDLC cards for AX.25 + + ******************************************************************** + + (c) 1994 by Joerg Reuter DL1BKE + + portions (c) 1994 Hans Alblas PE1AYX + and (c) 1993 Guido ten Dolle PE1NNZ + + for the complete copyright notice see >> Copying.Z8530DRV << + + ******************************************************************** + + +0. Installation of the package +============================== + +Run SCC-Install. If one (or more) of the patches fails PLEASE consult +chapter 2 (and READ IT of course!) + + + +1. Initialization and attachment of the channels +================================================ + +To use the driver, 3 steps must be performed: + + 1. Global initialization of the driver in the kernel + 2. Setup of parameters with sccinit + 2. Attachment of each channel in the packet software + +The global initialization is needed to reset all SCCs and to +install a common interrupt handler. Also, the hardware addresses +of the chips are defined in this step. In the second step, each +channel is set up for the intended use. + + + +1.1. Initialization +=================== + +Initialization of the hardware is performed by setting the defines and +variables in the file "/linux/drivers/char/scc_config.h". You can change +a number of parameters. + + + +################################################################################################ +# For OptoSCC card e.g: +# + +int Nchips = 2 ; /* number of chips */ +io_port Vector_Latch = 0x168 ; /* addr. of INTACK-Latch (0 for poll mode) +*/ +int Ivec = 9 ; /* interrupt vector */ +long Clock = 4915200 ; /* frequency of the scc clock */ +char Pclk = 1 ; /* use PCLK (1) or RTxC (0) */ +char Board = PA0HZP ; /* what type of SCC card do you use? */ +int Option = 0 ; /* command for extra hardware */ +io_port Special_Port = 0 ; /* port address for special hardware */ + /* (for EAGLE, PC100, PRIMUS, DRSI) */ + + /* ^ never remove the semicolon !! */ + + +/* Channel A B Chip */ +/* ============ ======== */ +/* Control ports: */ + +io_port SCC_ctrl[MAXSCC * 2] = {0x152, 0x150, /* ...one... */ + 0x156, 0x154, /* ...two... */ + 0, 0, /* ...three... */ + 0, 0}; /* ...four... */ + + +/* Data ports: */ + +io_port SCC_data[MAXSCC * 2] = {0x153, 0x151, /* ...one... */ + 0x157, 0x155, /* ...two... */ + 0, 0, /* ...three... */ + 0, 0}; /* ...four... */ + + +/* set to '1' if you have and want ESCC chip (8580/85180/85280) support */ + +/* Chip */ +/* ======== */ +int SCC_Enhanced[MAXSCC] = {0, /* ...one... */ + 0, /* ...two... */ + 0, /* ...three... */ + 0}; /* ...four... */ + +/* some useful #defines. You might need them or not */ + +#define VERBOSE_BOOTMSG 1 +#undef SCC_DELAY /* perhaps a 486DX2 is a *bit* too fast */ +#undef SCC_LDELAY /* slow it even a bit more down */ +#undef DONT_CHECK /* don't look if the SCCs you specified are available */ + + +/*********** END OF CONFIGURATION PARAMETERS ********************************************/ + + + + +################################################################################################ +# For Baycom (U)SCC card e.g: +# + +int Nchips = 2 ; /* number of chips */ +io_port Vector_Latch = 0 ; /* addr. of INTACK-Latch (0 for poll mode) */ +int Ivec = 7 ; /* interrupt vector */ +long Clock = 4915200 ; /* frequency of the scc clock */ +char Board = BAYCOM ; /* what type of SCC card do you use? */ +int Option = 0 ; /* command for extra hardware */ +io_port Special_Port = 0 ; /* port address for special hardware */ + /* (for EAGLE, PC100, PRIMUS, DRSI) */ + + /* ^ never remove the semicolon !! */ + + + +/* Channel A B Chip */ +/* ============ ======== */ +/* Control ports: */ + +io_port SCC_ctrl[MAXSCC * 2] = {0x304, 0x305, /* ...one... */ + 0x306, 0x307, /* ...two... */ + 0, 0, /* ...three... */ + 0, 0}; /* ...four... */ + +/* Data ports: */ + +io_port SCC_data[MAXSCC * 2] = {0x300, 0x301, /* ...one... */ + 0x302, 0x303, /* ...two... */ + 0, 0, /* ...three... */ + 0, 0}; /* ...four... */ + + +/* set to '1' if you have and want ESCC chip (8580/85180/85280) support */ + +/* Chip */ +/* ======== */ +int SCC_Enhanced[MAXSCC] = {0, /* ...one... */ + 0, /* ...two... */ + 0, /* ...three... */ + 0}; /* ...four... */ + +/* some useful #defines. You might need them or not */ + +#define VERBOSE_BOOTMSG 1 +#undef SCC_DELAY /* perhaps a 486DX2 is a *bit* too fast */ +#undef SCC_LDELAY /* slow it even a bit more down */ +#undef DONT_CHECK /* don't look if the SCCs you specified are available */ + +After you changed a parameter you have to recompile a new kernel image file. + +The channel number ranges from 0 to (2 * Nchips) - 1, +where Nchips is the number of chips. + +The crystal clock is specified as 4.9152 MHz. Other frequencies +can be used, and this parameter should be adjusted accordingly. + + +You can define your scc type with Board + + SCC type value + --------------------------------- + PA0HZP SCC card PA0HZP + EAGLE card EAGLE + PC100 card PC100 + PRIMUS-PC (DG9BL) card PRIMUS + BayCom (U)SCC card BAYCOM + + +NOTE: +===== + +If you only know the parameters for the PE1CHL driver for DOS, +run gencfg. It will generate the correct port addresses (I hope). +Its parameters are exactly the same as the ones you use with +the "attach scc" command in net, except that the string "init" must +not appear. Example: + +gencfg 2 0x150 4 2 0 1 0x168 9 4915200 + +will print a short form of scc_config.h for the OptoSCC to stdout. +("short" <=> few comments). + +gencfg 2 0x300 2 4 5 -4 0 7 4915200 0x10 + +does the same for the BayCom USCC card. I my opinion it is much easier +to edit scc_config.h... + + +1.2 initializing the driver on bootup +===================================== + + +To setup a number parameters you must run /sbin/sccinit from one +of your rc.*-files. This has to be done BEFORE the start of +NET or the ax25attach. Sccinit reads the file /etc/z8530drv.rc +and sets the MODEM and KISS parameters. A sample file is +delivered with this package. Change it to your needs: + +Each channel definition is divided into three sections. An +example for /dev/sc1: + +# DEVICE + +device /dev/sc1 # the device for the following params + +# MODEM + +speed 1200 # the default baudrate +clock dpll # clock source: + # dpll = normal halfduplex operation + # external = MODEM provides own Rx/Tx clock + # divider = use fullduplex divider if + # installed (1) +mode nrzi # HDLC encoding mode + # nrzi = 1k2 MODEM, G3RUH 9k6 MODEM + # nrz = DF9IC 9k6 MODEM +# KISS (Layer 1) + +txdelay 36 # (see chapter 1.4) +persist 64 +slot 8 +tail 8 +fulldup 0 +wait 12 +min 3 +maxkey 7 +idle 3 +maxdef 120 +group 0 +txoff off +softdcd on +slip off + +The order WITHIN these sections is unimportant. The order OF these +sections IS important. The MODEM parameters are set with the first +recognized KISS paramer... + +Please note that you can initialize the board only once after boot. +You can change all paramters but "mode" and "clock" later with the +Sccparam program or through KISS. Just to avoid securety holes... + +(1) this divider is usually mounted on the SCC-PBC (PA0HZP) or not + present at all (BayCom). It feeds back the output of the DPLL + (digital pll) as transmit clock. Using this mode without a divider + installed will normally result in keying the transceiver until + maxkey expires --- of course without sending anything (useful). + + +1.3. Attach commands +==================== + +When the linux has startup, the SCC driver has been initialized, +you can attach the channels in your packet software. This is done +by open the scc devices by using the attach asy command. +The SCC-drivers emulates the scc devices as serial asy ports, +this means e.g. that the baudrate can be set in the attach command. + + +Example Wampes: + +############################################################################################# +# Wampes device attach +# NOTE: Interfacename and the device must be the same!! +# Usage: attach asy 0 0 slip|vjslip|ax25ui|ax25i|nrs|kissui